about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2008-01-27 18:47:05 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2008-01-27 18:47:05 +0000
commit85712627fbdb78dd8a84f061d7c674c78709b19d (patch)
tree8a00578a1351481f01edfaf05f9b4948f5ff1506
parenta13b96e2453c318a76aff348e848ecbff73b830d (diff)
downloadnetpbm-mirror-85712627fbdb78dd8a84f061d7c674c78709b19d.tar.gz
netpbm-mirror-85712627fbdb78dd8a84f061d7c674c78709b19d.tar.xz
netpbm-mirror-85712627fbdb78dd8a84f061d7c674c78709b19d.zip
Detect too-large -width, -space, -lspace; detect too-long input line; fix negative -space
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@572 9d0c8265-081b-0410-96cb-a4ca84ce46f8
-rw-r--r--doc/HISTORY8
-rw-r--r--generator/pbmtext.c185
2 files changed, 131 insertions, 62 deletions
diff --git a/doc/HISTORY b/doc/HISTORY
index 24550879..9bc27fdf 100644
--- a/doc/HISTORY
+++ b/doc/HISTORY
@@ -17,6 +17,14 @@ not yet  BJH  Release 10.42.00
 
               Add pm_tmpfile_fd() and pm_make_tmpfile_fd().
 
+              pbmtext: fail cleanly if input line is > 5000 characters.
+
+              pbmtext: fail cleanly if -width, -space, or -lspace is
+              too large for computation.  Thanks Prophet of the Way
+              <afu@wta.att.ne.jp>.
+
+              pbmtext: fix negative -space.
+
               Various things to make it build on Windows without POSIX
               emulation.
 
diff --git a/generator/pbmtext.c b/generator/pbmtext.c
index 2f4d18c7..251f051a 100644
--- a/generator/pbmtext.c
+++ b/generator/pbmtext.c
@@ -14,6 +14,7 @@
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 
 #include <string.h>
+#include <limits.h>
 
 #include "pbm.h"
 #include "pbmfont.h"
@@ -257,35 +258,34 @@ fill_rect(bit** const bits,
 static void
 get_line_dimensions(const char line[], const struct font * const font_p, 
                     const float intercharacter_space,
-                    int * const bwid_p, int * const backup_space_needed_p) {
+                    double * const bwidP, int * const backup_space_needed_p) {
 /*----------------------------------------------------------------------------
    Determine the width in pixels of the line of text line[] in the font
-   *font_p, and return it as *bwid_p.  Also determine how much of this
+   *font_p, and return it as *bwidP.  Also determine how much of this
    width goes to the left of the nominal starting point of the line because
    the first character in the line has a "backup" distance.  Return that
    as *backup_space_needed_p.
 -----------------------------------------------------------------------------*/
     int cursor;  /* cursor into the line of text */
-    float accumulated_ics;
+    double accumulatedIcs;
         /* accumulated intercharacter space so far in the line we are 
            stepping through.  Because the intercharacter space might not be
            an integer, we accumulate it here and realize full pixels whenever
-           we have more than one pixel.
-           */
-
-    int no_chars_yet; 
-        /* logical: we haven't seen any renderable characters yet in 
-           the line.
+           we have more than one pixel.  Note that this can be negative
+           (which means were crowding, rather than spreading, text).
         */
+    double bwid;
+    bool no_chars_yet; 
+        /* We haven't seen any renderable characters yet in the line. */
     struct glyph * lastGlyphP;
         /* Glyph of last character processed so far.  Undefined if
            'no_chars_yet'.
         */
 
     no_chars_yet = TRUE;   /* initial value */
-    *bwid_p = 0;  /* initial value */
-    accumulated_ics = 0.0;  /* initial value */
-
+    accumulatedIcs = 0.0;  /* initial value */
+    bwid = 0.0;  /* initial value */
+    
     for (cursor = 0; line[cursor] != '\0'; cursor++) {
         struct glyph * const glyphP = 
             font_p->glyph[(unsigned char)line[cursor]];
@@ -297,20 +297,23 @@ get_line_dimensions(const char line[], const struct font * const font_p,
                     *backup_space_needed_p = -glyphP->x;
                 else {
                     *backup_space_needed_p = 0;
-                    *bwid_p += glyphP->x;
+                    bwid += glyphP->x;
                 }
             } else {
                 /* handle extra intercharacter space (-space option) */
-                int full_pixels;  /* integer part of accumulated_ics */
-                accumulated_ics += intercharacter_space;
-                full_pixels = (int) accumulated_ics;
-                if (full_pixels > 0) {
-                    *bwid_p += full_pixels;
-                    accumulated_ics -= full_pixels;
+                accumulatedIcs += intercharacter_space;
+                if (accumulatedIcs >= INT_MAX)
+                    pm_error("Image width too large.");
+                if (accumulatedIcs <= INT_MIN)
+                    pm_error("Absurdly large negative -space value.");
+                {
+                    int const fullPixels = (int) accumulatedIcs;
+                    bwid           += fullPixels;
+                    accumulatedIcs -= fullPixels;
                 }
             }
             lastGlyphP = glyphP;
-            *bwid_p += glyphP->xadd;
+            bwid += glyphP->xadd;
         }
     }
     if (no_chars_yet)
@@ -322,9 +325,13 @@ get_line_dimensions(const char line[], const struct font * const font_p,
            right at the right edge of the glyph (no extra space to
            anticipate another character).
         */
-        *bwid_p -= lastGlyphP->xadd;
-        *bwid_p += lastGlyphP->width + lastGlyphP->x;
+        bwid -= lastGlyphP->xadd;
+        bwid += lastGlyphP->width + lastGlyphP->x;
     }
+    if (bwid > INT_MAX)
+        pm_error("Image width too large.");
+    else
+        *bwidP = bwid; 
 }
 
 
@@ -441,7 +448,8 @@ struct outputTextCursor {
            are stepping through.  Because the intercharacter space
            might not be an integer, we accumulate it here and
            realize full pixels whenever we have more than one
-           pixel.  
+           pixel.  Note that this is negative if we're crowding, rather
+           than spreading, characters.
         */
 };
 
@@ -506,11 +514,10 @@ placeCharacterInOutput(char                      const lastch,
                     cursorP->widthSoFar += fontP->glyph[glyphIndex]->x;
             } else {
                 /* handle extra intercharacter space (-space option) */
-                unsigned int fullPixels;  /* integer part of accumulatedIcs */
                 cursorP->accumulatedIcs += cursorP->intercharacterSpace;
-                fullPixels = (int) cursorP->accumulatedIcs;
-                if (fullPixels > 0) {
-                    cursorP->widthSoFar += fullPixels;
+                {
+                    int const fullPixels = (int)cursorP->accumulatedIcs;
+                    cursorP->widthSoFar     += fullPixels;
                     cursorP->accumulatedIcs -= fullPixels;
                 }
             }
@@ -588,8 +595,9 @@ truncateText(struct text   const inputText,
         /* accumulated intercharacter space so far in the line we are 
            stepping through.  Because the intercharacter space might not be
            an integer, we accumulate it here and realize full pixels whenever
-           we have more than one pixel.
-           */
+           we have more than one pixel.  Note that this is negative if we're
+           crowding, not spreading, characters.
+        */
 
         int noCharsYet; 
         /* logical: we haven't seen any renderable characters yet in 
@@ -612,11 +620,10 @@ truncateText(struct text   const inputText,
                         widthSoFar += fontP->glyph[lastch]->x;
                 } else {
                     /* handle extra intercharacter space (-space option) */
-                    int fullPixels;  /* integer part of accumulatedIcs */
                     accumulatedIcs += intercharacterSpace;
-                    fullPixels = (int) intercharacterSpace;
-                    if (fullPixels > 0) {
-                        widthSoFar += fullPixels;
+                    {
+                        int const fullPixels = (int) intercharacterSpace;
+                        widthSoFar     += fullPixels;
                         accumulatedIcs -= fullPixels;
                     }
                 }
@@ -663,6 +670,9 @@ getText(const char          cmdline_text[],
         
         lineCount = 0;  /* initial value */
         while (fgets(buf, sizeof(buf), stdin) != NULL) {
+            if (strlen(buf) + 1 >= sizeof(buf))
+                pm_error("A line of input text is longer than %u characters."
+                         "Cannot process.", sizeof(buf)-1);
             fixControlChars(buf, fontP);
             if (lineCount >= maxlines) {
                 maxlines *= 2;
@@ -686,23 +696,72 @@ getText(const char          cmdline_text[],
 
 
 static void
-compute_image_width(struct text         const lp, 
-                    const struct font * const fn,
-                    float               const intercharacter_space,
-                    int *               const maxwidthP, 
-                    int *               const maxleftbP) {
-    int line;
-    
-    *maxwidthP = 0;  /* initial value */
-    *maxleftbP = 0;  /* initial value */
-    for (line = 0; line < lp.lineCount; ++line) {
-        int bwid, backup_space_needed;
-        
-        get_line_dimensions(lp.textArray[line], fn, intercharacter_space,
-                            &bwid, &backup_space_needed);
+computeImageHeight(struct text         const formattedText, 
+                   const struct font * const fontP,
+                   int                 const interlineSpace,
+                   unsigned int        const vmargin,
+                   unsigned int *      const rowsP) {
+
+    if (interlineSpace < 0 && fontP->maxheight < -interlineSpace)
+        pm_error("-lspace value (%d) negative and exceeds font height. "
+                 "No output.", interlineSpace);     
+    else {
+        double const rowsD = 2 * (double) vmargin + 
+            (double) formattedText.lineCount * fontP->maxheight + 
+            (double) (formattedText.lineCount-1) * interlineSpace;
         
-        *maxwidthP = MAX(*maxwidthP, bwid);
-        *maxleftbP = MAX(*maxleftbP, backup_space_needed);
+        if (rowsD > INT_MAX-10)
+            pm_error("Image height too large.");
+        else
+            *rowsP = (unsigned int) rowsD;
+    }
+}
+
+
+
+static void
+computeImageWidth(struct text         const formattedText, 
+                  const struct font * const fontP,
+                  float               const intercharacterSpace,
+                  unsigned int        const hmargin,
+                  unsigned int *      const colsP,
+                  int *               const maxleftbP) {
+
+    if (intercharacterSpace < 0 && fontP->maxwidth < -intercharacterSpace)
+        pm_error("-space value (%f) negative; exceeds font width. "
+                 "No output.", intercharacterSpace);     
+    else {
+        /* Find the widest line, and the one that backs up the most past
+           the nominal start of the line.
+        */
+    
+        unsigned int line;
+        double maxwidth;
+        int maxleftb;
+        double colsD;
+
+        for (line = 0, maxwidth = 0.0, maxleftb = 0;
+             line < formattedText.lineCount;
+             ++line) {
+
+            double bwid;
+            int backupSpaceNeeded;
+            
+            get_line_dimensions(formattedText.textArray[line], fontP,
+                                intercharacterSpace,
+                                &bwid, &backupSpaceNeeded);
+            
+            maxwidth = MAX(maxwidth, bwid);
+            maxleftb = MAX(maxleftb, backupSpaceNeeded);
+        }
+        colsD = 2 * (double) hmargin + (double) maxwidth;
+    
+        if (colsD > INT_MAX-10)
+            pm_error("Image width too large.");
+        else
+            *colsP = (unsigned int) colsD;
+    
+        *maxleftbP = maxleftb;
     }
 }
 
@@ -713,13 +772,11 @@ main(int argc, char *argv[]) {
 
     struct cmdlineInfo cmdline;
     bit ** bits;
-    int rows, cols;
+    unsigned int rows, cols;
     struct font * fontP;
-    int vmargin, hmargin;
+    unsigned int vmargin, hmargin;
     struct text inputText;
     struct text formattedText;
-    int maxwidth;
-        /* width in pixels of the longest line of text in the image */
     int maxleftb;
 
     pbm_init(&argc, argv);
@@ -729,7 +786,7 @@ main(int argc, char *argv[]) {
     computeFont(cmdline, &fontP);
 
     getText(cmdline.text, fontP, &inputText);
-    
+       
     if (cmdline.nomargins) {
         vmargin = 0;
         hmargin = 0;
@@ -742,8 +799,11 @@ main(int argc, char *argv[]) {
             hmargin = 2 * fontP->maxwidth;
         }
     }
-
+    
     if (cmdline.width > 0) {
+        if (cmdline.width > INT_MAX -10)
+            pm_error("-width value too large: %u", cmdline.width);
+            
         /* Flow or truncate lines to meet user's width request */
         if (inputText.lineCount == 1) 
             flowText(inputText, cmdline.width, fontP, cmdline.space,
@@ -754,15 +814,16 @@ main(int argc, char *argv[]) {
         freeTextArray(inputText);
     } else
         formattedText = inputText;
+        
+    if (formattedText.lineCount == 0)
+        pm_error("No input text.");
     
-    rows = 2 * vmargin + 
-        formattedText.lineCount * fontP->maxheight + 
-        (formattedText.lineCount-1) * cmdline.lspace;
-
-    compute_image_width(formattedText, fontP, cmdline.space,
-                        &maxwidth, &maxleftb);
+    computeImageHeight(formattedText, fontP, cmdline.lspace, vmargin,
+                       &rows);
 
-    cols = 2 * hmargin + maxwidth;
+    computeImageWidth(formattedText, fontP, cmdline.space, hmargin,
+                      &cols, &maxleftb);
+                        
     bits = pbm_allocarray(cols, rows);
 
     /* Fill background with white */