about summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2007-05-03 03:39:06 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2007-05-03 03:39:06 +0000
commit85540f51bc1f0bccd074b4465dd5ea94c92c33ea (patch)
treedb2a2fdb8d007c8f87151721c35387e480fc7959 /lib
parentbb8e587faa4ca484c1946e99a95ca0de533bddb0 (diff)
downloadnetpbm-mirror-85540f51bc1f0bccd074b4465dd5ea94c92c33ea.tar.gz
netpbm-mirror-85540f51bc1f0bccd074b4465dd5ea94c92c33ea.tar.xz
netpbm-mirror-85540f51bc1f0bccd074b4465dd5ea94c92c33ea.zip
cleanup
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@284 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'lib')
-rw-r--r--lib/libpbmfont.c517
-rw-r--r--lib/pbmfont.h28
2 files changed, 390 insertions, 155 deletions
diff --git a/lib/libpbmfont.c b/lib/libpbmfont.c
index d79b9262..708205a2 100644
--- a/lib/libpbmfont.c
+++ b/lib/libpbmfont.c
@@ -14,6 +14,7 @@
 ** implied warranty.
 */
 
+#include <assert.h>
 #include <string.h>
 
 #include "pm_c_util.h"
@@ -1070,166 +1071,400 @@ pbm_dumpfont( fn )
 
 /* Routines for loading a BDF font file */
 
-static int readline ARGS((FILE* fp, char* buf, char* arg[]));
 
-#define expect(str) if (readline(fp, line, arg) < 0 || strcmp(arg[0], (str))) \
-    { fclose(fp); return 0; }
+static unsigned int
+mk_argvn(char *        const s,
+         const char ** const vec,
+         unsigned int  const mk_max) {
 
-struct font* pbm_loadbdffont(const char * const name)
-{
-    FILE* fp;
-    char line[1024], *arg[32], *hex;
-    char *b;
-    int n, numchar, hdig, encoding;
-    struct font* font;
-    struct glyph* glyph;
-
-    if (!(fp = fopen(name, "rb")))
-        return 0;
+    int n;
+    char * p;
 
-    expect("STARTFONT");
+    p = &s[0];
+    n = 0;
 
-    MALLOCVAR(font);
-    if (font == NULL)
-        pm_error("no memory for font");
-    font->oldfont = 0;
-    { 
-        /* Initialize all characters to nonexistent; we will fill the ones we
-           find in the bdf file later.
-        */
-        int i;
-        for (i = 0; i < 256; i++) 
-            font->glyph[i] = NULL;
+    while (*p) {
+        if (ISSPACE(*p))
+            *p++ = '\0';
+        else {
+            vec[n++] = p;
+            if (n >= mk_max)
+                break;
+            while (*p && !ISSPACE(*p))
+                ++p;
+        }
     }
+    vec[n] = NULL;
 
-    while (readline(fp, line, arg) >= 0) {
-        if (!strcmp(arg[0], "COMMENT"))
-            continue;
-        if (!strcmp(arg[0], "SIZE"))
-            continue;
-        
-        if (!strcmp(arg[0], "STARTPROPERTIES")) {
-            n = atoi(arg[1]);
-            for (; n > 0 && readline(fp, line, arg) >= 0; n--)
-                ;
-        }
-        else if (!strcmp(arg[0], "FONTBOUNDINGBOX")) {
-            font->maxwidth = atoi(arg[1]);
-            font->maxheight = atoi(arg[2]);
-            font->x = atoi(arg[3]);
-            font->y = atoi(arg[4]);
-        }
-        else if (!strcmp(arg[0], "ENDFONT")) {
-            fclose(fp);
-            return font;
+    return n;
+}
+
+
+
+static int
+readline(FILE *        const fp,
+         char *        const buf,
+         const char ** const arg) {
+
+    int retval;
+    char * rc;
+
+    rc = fgets(buf, 1024, fp);
+    if (rc == NULL)
+        retval = -1;
+    else
+        retval = mk_argvn(buf, arg, 32);
+
+    return retval;
+}
+
+
+
+static void
+readBitmap(FILE *          const fp,
+           unsigned int    const glyphWidth,
+           unsigned int    const glyphHeight,
+           const char *    const charName,
+           unsigned char * const bmap) {
+
+    int n;
+    unsigned int bmapIndex;
+
+    bmapIndex = 0;
+           
+    for (n = glyphHeight; n > 0; --n) {
+        int i;  /* dot counter */
+        int rc;
+        char * hex;
+        char line[1024];
+        const char * arg[32];
+
+        rc = readline(fp, line, arg);
+
+        if (rc < 0)
+            pm_error("End of file in bitmap for character '%s' in BDF "
+                     "font file.", charName);
+
+        hex = line;
+        for (i = glyphWidth; i > 0; i -= 4) {
+            char hdig;
+            unsigned int hdigValue;
+            hdig = *hex++;
+            if (hdig >= '0' && hdig <= '9')
+                hdigValue = hdig - '0';
+            else if (hdig >= 'a' && hdig <= 'f')
+                hdigValue = 10 + (hdig - 'a');
+            else if (hdig >= 'A' && hdig <= 'F')
+                hdigValue = 10 + (hdig - 'A');
+            else
+                pm_error("Invalid hex digit '%c' in line '%s' of "
+                         "bitmap for character '%s' "
+                         "in BDF font file", hdig, line, charName);
+                        
+            if (i > 0)
+                bmap[bmapIndex++] = hdigValue & 0x8 ? 1 : 0;
+            if (i > 1)
+                bmap[bmapIndex++] = hdigValue & 0x4 ? 1 : 0;
+            if (i > 2)
+                bmap[bmapIndex++] = hdigValue & 0x2 ? 1 : 0;
+            if (i > 3)
+                bmap[bmapIndex++] = hdigValue & 0x1 ? 1 : 0;
         }
-        else if (!strcmp(arg[0], "CHARS")) {
-            numchar = atoi(arg[1]);
-            while (numchar > 0) {
-                if (readline(fp, line, arg) < 0) { fclose(fp); return 0; }
-                if (!strcmp(arg[0], "COMMENT"))
-                    continue;
-                if (strcmp(arg[0], "STARTCHAR")) { fclose(fp); return 0; }
-                MALLOCVAR(glyph);
-                if (glyph == NULL)
-                    pm_error("no memory for font glyph");
-
-                expect("ENCODING");
-                if ((encoding = atoi(arg[1])) < 0) {
-                    if (arg[2])
-                        encoding = atoi(arg[2]);
-                    else {
-                        while (readline(fp, line, arg) >= 0)
-                            if (!strcmp(arg[0], "ENDCHAR"))
-                                break;
+    }
+}
+
+
+
+static void
+createBmap(unsigned int  const glyphWidth,
+           unsigned int  const glyphHeight,
+           FILE *        const fp,
+           const char *  const charName,
+           const char ** const bmapP) {
+
+    char line[1024];
+    const char * arg[32];
+    unsigned char * bmap;
+    int rc;
+
+    if (UINT_MAX / glyphWidth < glyphHeight)
+        pm_error("Ridiculously large glyph");
+
+    MALLOCARRAY(bmap, glyphWidth * glyphHeight);
+
+    if (!bmap)
+        pm_error("no memory for font glyph byte map");
+
+    rc = readline(fp, line, arg);
+    if (rc < 0)
+        pm_error("End of file encountered reading font glyph byte map from "
+                 "BDF font file.");
+
+    if (streq(arg[0], "ATTRIBUTES")) {
+        rc = readline(fp, line, arg);
+        if (rc < 0)
+            pm_error("End of file encountered after ATTRIBUTES in BDF "
+                     "font file.");
+    }                
+    if (!streq(arg[0], "BITMAP"))
+        pm_error("'%s' found where BITMAP expected in definition of "
+                 "character '%s' in BDF font file.", line, charName);
+
+    assert(streq(arg[0], "BITMAP"));
+
+    readBitmap(fp, glyphWidth, glyphHeight, charName, bmap);
+
+    *bmapP = (char *)bmap;
+}
+
+
+
+static void
+expect(FILE *        const fp,
+       const char *  const expected,
+       const char ** const arg) {
+
+    char line[1024];
+    int rc;
+
+    rc = readline(fp, line, arg);
+
+    if (rc < 0)
+        pm_error("EOF in BDF font file where '%s' expected", expected);
+    else if (!streq(arg[0], expected))
+        pm_error("'%s' where '%s' expected in BDF font file",
+                 line, expected);
+}
+
+
+
+static void
+skipCharacter(FILE * const fp) {
+/*----------------------------------------------------------------------------
+  In BDF font file 'fp', skip through the end of the character we are
+  presently in.
+-----------------------------------------------------------------------------*/
+    bool endChar;
                         
-                        numchar--;
-                        continue;
-                    }
-                }
-                expect("SWIDTH");
-                expect("DWIDTH");
-                glyph->xadd = atoi(arg[1]);
-                expect("BBX");
-                glyph->width = atoi(arg[1]);
-                glyph->height = atoi(arg[2]);
-                glyph->x = atoi(arg[3]);
-                glyph->y = atoi(arg[4]);
-
-                b = (char*)malloc(glyph->width * glyph->height * sizeof(char));
-                glyph->bmap = b;
-                if (!glyph->bmap)
-                    pm_error("no memory for font glyph byte map");
-
-                if (readline(fp, line, arg) < 0) { fclose(fp); return 0; }
-                if (!strcmp(arg[0], "ATTRIBUTES"))
-                    if (readline(fp, line, arg) < 0) { fclose(fp); return 0; }
-                
-                for (n = glyph->height; n > 0; n--) {
-                    int i;  /* dot counter */
-                    if (readline(fp, line, arg) < 0) { fclose(fp); return 0; }
-                    hex = line;
-                    for (i = glyph->width; i > 0; i -= 4) {
-                        hdig = *hex++;
-                        if (hdig >= '0' && hdig <= '9')
-                            hdig -= '0';
-                        else if (hdig >= 'a' && hdig <= 'f')
-                            hdig -= 'a' - 10;
-                        else if (hdig >= 'A' && hdig <= 'F')
-                            hdig -= 'A' - 10;
+    endChar = FALSE;
                         
-                        *b++ = hdig & 8 ? 1 : 0;
-                        if (i > 1) *b++ = hdig & 4 ? 1 : 0;
-                        if (i > 2) *b++ = hdig & 2 ? 1 : 0;
-                        if (i > 3) *b++ = hdig & 1;
-                    }
-                }
+    while (!endChar) {
+        char line[1024];
+        const char * arg[32];
+        int rc;
+        rc = readline(fp, line, arg);
+        if (rc < 0)
+            pm_error("End of file in the middle of a character (before "
+                     "ENDCHAR) in BDF font file.");
+        endChar = streq(arg[0], "ENDCHAR");
+    }                        
+}
+
+
+
+static void
+validateEncoding(const char **  const arg,
+                 unsigned int * const codepointP,
+                 bool *         const badCodepointP) {
+/*----------------------------------------------------------------------------
+   With arg[] being the ENCODING statement from the font, return as
+   *codepointP the codepoint that it indicates (code point is the character
+   code, e.g. in ASCII, 48 is '0').
+
+   But if the statement doesn't give an acceptable codepoint return
+   *badCodepointP == TRUE.
+-----------------------------------------------------------------------------*/
+
+    bool gotCodepoint;
+    bool badCodepoint;
+    unsigned int codepoint;
+
+    if (atoi(arg[1]) >= 0) {
+        codepoint = atoi(arg[1]);
+        gotCodepoint = true;
+    } else {
+        if (arg[2]) {
+            codepoint = atoi(arg[2]);
+            gotCodepoint = true;
+        } else
+            gotCodepoint = false;
+    }
+    if (gotCodepoint) {
+        if (codepoint > 255)
+            badCodepoint = true;
+        else
+            badCodepoint = false;
+    } else
+        badCodepoint = true;
+
+    *badCodepointP = badCodepoint;
+    *codepointP    = codepoint;
+}
 
-                expect("ENDCHAR");
 
-                if (encoding < 256)
-                    /* We ignore any characters with codes that don't fit 
-                       in 8 bits.  We may want to change this someday.
-                       */
-                    font->glyph[encoding] = glyph;
 
-                numchar--;
+
+static void
+processCharsLine(FILE *        const fp,
+                 const char ** const arg,
+                 struct font * const fontP) {
+
+    unsigned int const nCharacters = atoi(arg[1]);
+
+    unsigned int nCharsDone;
+
+    nCharsDone = 0;
+
+    while (nCharsDone < nCharacters) {
+        char line[1024];
+        const char * arg[32];
+        int rc;
+
+        rc = readline(fp, line, arg);
+        if (rc < 0)
+            pm_error("End of file after CHARS reading BDF font file");
+
+        if (streq(arg[0], "COMMENT")) {
+            /* ignore */
+        } else if (!streq(arg[0], "STARTCHAR"))
+            pm_error("no STARTCHAR after CHARS in BDF font file");
+        else {
+            const char * const charName = arg[1];
+            struct glyph * glyphP;
+            unsigned int codepoint;
+            bool badCodepoint;
+
+            assert(streq(arg[0], "STARTCHAR"));
+
+            MALLOCVAR(glyphP);
+
+            if (glyphP == NULL)
+                pm_error("no memory for font glyph for '%s' character",
+                         charName);
+
+            {
+                const char * arg[32];
+                expect(fp, "ENCODING", arg);
+
+                validateEncoding(arg, &codepoint, &badCodepoint);
+            }
+            if (badCodepoint)
+                skipCharacter(fp);
+            else {
+                {
+                    const char * arg[32];
+                    expect(fp, "SWIDTH", arg);
+                }
+                {
+                    const char * arg[32];
+                    
+                    expect(fp, "DWIDTH", arg);
+                    glyphP->xadd = atoi(arg[1]);
+                }
+                {
+                    const char * arg[32];
+                    
+                    expect(fp, "BBX", arg);
+                    glyphP->width  = atoi(arg[1]);
+                    glyphP->height = atoi(arg[2]);
+                    glyphP->x      = atoi(arg[3]);
+                    glyphP->y      = atoi(arg[4]);
+                }
+                createBmap(glyphP->width, glyphP->height, fp, charName,
+                           &glyphP->bmap);
+                
+                {
+                    const char * arg[32];
+                    expect(fp, "ENDCHAR", arg);
+                }
+                assert(codepoint < 256); /* Ensured by validateEncoding() */
+
+                fontP->glyph[codepoint] = glyphP;
             }
+            ++nCharsDone;
         }
     }
-    return font;
 }
 
-static int readline(fp, buf, arg)
-FILE* fp;
-char* buf;
-char* arg[];
-{
-    if (!fgets(buf, 1024, fp))
-        return -1;
-    
-    return mk_argvn(buf, arg, 32);
-}
 
-int mk_argvn(s, vec, mk_max)
-char* s;
-char* vec[];
-int mk_max;
-{
-    int n;
 
-    n = 0;
-    while (*s) {
-        if (ISSPACE(*s)) {
-            *s++ = '\0';
-            continue;
+static void
+processFontLine(FILE *        const fp,
+                const char *  const line,
+                const char ** const arg,
+                struct font * const fontP,
+                bool *        const endOfFontP) {
+
+    *endOfFontP = FALSE;  /* initial assumption */
+
+    if (streq(arg[0], "COMMENT")) {
+        /* ignore */
+    } else if (streq(arg[0], "SIZE")) {
+        /* ignore */
+    } else if (streq(arg[0], "STARTPROPERTIES")) {
+        unsigned int const propCount = atoi(arg[1]);
+        unsigned int i;
+        for (i = 0; i < propCount; ++i) {
+            char line[1024];
+            const char * arg[32];
+            int rc;
+            rc = readline(fp, line, arg);
+            if (rc < 0)
+                pm_error("End of file after STARTPROPERTIES in BDF font file");
         }
-        vec[n++] = s;
-        if (n >= mk_max)
-            break;
-        while (*s && !ISSPACE(*s))
-            s++;
+    } else if (streq(arg[0], "FONTBOUNDINGBOX")) {
+        fontP->maxwidth  = atoi(arg[1]);
+        fontP->maxheight = atoi(arg[2]);
+        fontP->x         = atoi(arg[3]);
+        fontP->y         = atoi(arg[4]);
+    } else if (streq(arg[0], "ENDFONT")) {
+        *endOfFontP = true;
+    } else if (!strcmp(arg[0], "CHARS"))
+        processCharsLine(fp, arg, fontP);
+}
+
+
+
+struct font *
+pbm_loadbdffont(const char * const name) {
+
+    FILE * fp;
+    char line[1024];
+    const char * arg[32];
+    struct font * fontP;
+    bool endOfFont;
+
+    fp = fopen(name, "rb");
+    if (!fp)
+        pm_error("Unable to open BDF font file name '%s'.  errno=%d (%s)",
+                 name, errno, strerror(errno));
+
+    expect(fp, "STARTFONT", arg);
+
+    MALLOCVAR(fontP);
+    if (fontP == NULL)
+        pm_error("no memory for font");
+
+    fontP->oldfont = 0;
+    { 
+        /* Initialize all characters to nonexistent; we will fill the ones we
+           find in the bdf file later.
+        */
+        unsigned int i;
+        for (i = 0; i < 256; i++) 
+            fontP->glyph[i] = NULL;
     }
-    vec[n] = 0;
-    return n;
+    fontP->x = fontP->y = 0;
+
+    endOfFont = FALSE;
+
+    while (!endOfFont) {
+        int rc;
+        rc = readline(fp, line, arg);
+        if (rc < 0)
+            pm_error("End of file before ENDFONT statement in BDF font file");
+
+        processFontLine(fp, line, arg, fontP, &endOfFont);
+    }
+    return fontP;
 }
diff --git a/lib/pbmfont.h b/lib/pbmfont.h
index 9fdec0e1..8a81c37a 100644
--- a/lib/pbmfont.h
+++ b/lib/pbmfont.h
@@ -13,22 +13,23 @@ struct glyph {
        can be anything, but normally does not have white borders because
        it's more efficient to represent white borders explicitly.
     */
-	int width, height;
+    unsigned int width;
+    unsigned int height;
         /* The dimensions of the central glyph, i.e. the 'bmap' array */
-	int x;
+    unsigned int x;
         /* Width in pixels of the white left border of this glyph.
            This can actually be negative to indicate that the central
            glyph backs up over the previous character in the line.  In
            that case, if there is no previous character in the line, it
            is as if 'x' is 0.
         */
-    int y;
+    unsigned int y;
         /* Height in pixels of the white bottom border of this glyph */
-	int xadd;
+    unsigned int xadd;
         /* Width of glyph -- white left border plus central glyph
            plus white right border
         */
-	const char * bmap;
+    const char * bmap;
         /* The raster of the central glyph.  It is an 'width' by
            'height' array in row major order, with each byte being 1
            for black; 0 for white.  E.g. if 'width' is 20 pixels and
@@ -44,19 +45,19 @@ struct font {
        an code point in the range 0..255, this structure describes the
        glyph for that character.
     */
-	int maxwidth, maxheight;
-	int x;
+    int maxwidth, maxheight;
+    int x;
         /* ?? Not used by Pbmtext */
     int y;
         /* Amount of white space that should be added between lines of
-           this font.
+           this font.  Can be negative.
         */
-	struct glyph * glyph[256];
+    struct glyph * glyph[256];
         /* glyph[i] is the glyph for code point i */
-	const bit ** oldfont;
-	    /* for compatibility with old pbmtext routines */
-	    /* oldfont is NULL if the font is BDF derived */
-	int fcols, frows;
+    const bit ** oldfont;
+        /* for compatibility with old pbmtext routines */
+        /* oldfont is NULL if the font is BDF derived */
+    int fcols, frows;
 };
 
 struct font* pbm_defaultfont(const char* const which);
@@ -68,7 +69,6 @@ struct font* pbm_loadfont(const char * const filename);
 struct font* pbm_loadpbmfont(const char * const filename);
 struct font* pbm_loadbdffont(const char * const filename);
 void pbm_dumpfont ARGS(( struct font* fn ));
-int mk_argvn ARGS(( char* s, char* vec[], int max ));
 
 #ifdef __cplusplus
 }