about summary refs log tree commit diff
path: root/lib/libpbmfont2.c
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2020-06-28 17:52:14 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2020-06-28 17:52:14 +0000
commit1cd3ef0dd6c2236d0b329879bacd9360d01c88a1 (patch)
treea60016b5dd48fbf681ebfb43a6ca0d7e20a391d8 /lib/libpbmfont2.c
parentcbbf595776cee6b8d8a24becf49ee6468eeba712 (diff)
downloadnetpbm-mirror-1cd3ef0dd6c2236d0b329879bacd9360d01c88a1.tar.gz
netpbm-mirror-1cd3ef0dd6c2236d0b329879bacd9360d01c88a1.tar.xz
netpbm-mirror-1cd3ef0dd6c2236d0b329879bacd9360d01c88a1.zip
Promote Development to Advaanced - Release 10.91
git-svn-id: http://svn.code.sf.net/p/netpbm/code/advanced@3877 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'lib/libpbmfont2.c')
-rw-r--r--lib/libpbmfont2.c515
1 files changed, 402 insertions, 113 deletions
diff --git a/lib/libpbmfont2.c b/lib/libpbmfont2.c
index b354e91b..1560b407 100644
--- a/lib/libpbmfont2.c
+++ b/lib/libpbmfont2.c
@@ -33,6 +33,208 @@
 #include "pbm.h"
 
 /*----------------------------------------------------------------------------
+  Font selector routines
+
+  The selector is a device consisting of a bitmap, min value, max value and
+  count.  It is used here to specify necessary fonts and record what entries
+  are valid in the glyph array.
+
+  This device may be used for other purposes.  In that case the code should
+  be put into an independent source file in the lib/util subdirectory.
+-----------------------------------------------------------------------------*/
+
+static void
+allocRecord(struct pm_selector * const selectorP,
+            unsigned int         const max) {
+
+    unsigned int const size = (max + 8) / 8;
+
+    MALLOCARRAY(selectorP->localRecord, size);
+
+    if (!selectorP->localRecord)
+        pm_error("Failed to allocate %u bytes of memory for font selector "
+                 "bitmap", size);
+
+    selectorP->record = selectorP->localRecord;
+}
+
+
+
+void
+pm_selector_create(unsigned int          const max,
+                   struct pm_selector ** const selectorPP) {
+
+    struct pm_selector * selectorP;
+
+    MALLOCVAR_NOFAIL(selectorP);
+
+    allocRecord(selectorP, max);
+
+    {
+        unsigned int byteIndex;
+        for (byteIndex = 0; byteIndex <= max/8; ++byteIndex)
+            selectorP->localRecord[byteIndex]= 0x00;
+    }
+
+    selectorP->maxmax = selectorP->min = max;
+    selectorP->max = 0;
+    selectorP->count = 0;
+
+    *selectorPP = selectorP;
+}
+
+
+
+void
+pm_selector_create_fixed(const unsigned char * const record,
+                         unsigned int          const min,
+                         unsigned int          const max,
+                         unsigned int          const count,
+                         struct pm_selector ** const selectorPP) {
+
+    struct pm_selector * selectorP;
+
+    MALLOCVAR_NOFAIL(selectorP);
+
+    selectorP->localRecord = NULL;
+    selectorP->record      = record;
+    selectorP->min         = min;
+    selectorP->max         = max;
+    selectorP->maxmax      = max;
+    selectorP->count       = count;
+
+    *selectorPP = selectorP;
+}
+
+
+
+void
+pm_selector_destroy(struct pm_selector * const selectorP) {
+
+    if (selectorP->localRecord)
+        free(selectorP->localRecord);
+
+    free(selectorP);
+}
+
+
+
+void
+pm_selector_copy(unsigned int               const max,
+                 const struct pm_selector * const srcSelectorP,
+                 struct pm_selector      ** const destSelectorPP) {
+
+    /* Create a new selector and copy into it the content of another */
+
+    struct pm_selector * destSelectorP;
+
+    if (max < srcSelectorP->max)
+        pm_error("internal error: attempt to copy a selector as "
+                 "another with a smaller max value %u -> %u",
+                 srcSelectorP->max, max);
+
+    MALLOCVAR_NOFAIL(destSelectorP);
+
+    destSelectorP->maxmax     = max;
+    destSelectorP->max        = srcSelectorP->max;
+    destSelectorP->min        = srcSelectorP->min;
+    destSelectorP->count      = srcSelectorP->count;
+
+    allocRecord(destSelectorP, max);
+
+    {
+        unsigned int const minByteIndex = srcSelectorP->min / 8;
+        unsigned int const maxByteIndex = srcSelectorP->max / 8;
+        unsigned int const maxmaxByteIndex = max / 8;
+
+        unsigned int byteIndex;
+
+        for (byteIndex = 0 ; byteIndex < minByteIndex; ++byteIndex)
+            destSelectorP->localRecord[byteIndex] = 0x00;
+        for (byteIndex = maxByteIndex + 1 ; byteIndex <= maxmaxByteIndex;
+             ++byteIndex)
+            destSelectorP->localRecord[byteIndex] = 0x00;
+        for (byteIndex = minByteIndex; byteIndex <= maxByteIndex; ++byteIndex)
+            destSelectorP->localRecord[byteIndex] =
+                srcSelectorP->record[byteIndex];
+    }
+
+    *destSelectorPP = destSelectorP;
+}
+
+
+
+void
+pm_selector_mark(struct pm_selector * const selectorP,
+                 unsigned int         const index) {
+/*----------------------------------------------------------------------------
+   Mark index 'index'.
+-----------------------------------------------------------------------------*/
+    unsigned int  byteIndex = index / 8;
+    unsigned int  bitIndex  = index % 8;
+    unsigned char mask = (0x01 <<7) >> bitIndex;
+
+    /* set bit on to indicate presence of this index */
+
+    if (!selectorP->localRecord)
+        pm_error("INTERNAL ERROR: attempt to mark in a fixed pm_selector");
+
+    if ((selectorP->localRecord[byteIndex] & mask) == 0x00) {
+        /* if bit is not already set */
+
+        selectorP->localRecord[byteIndex] |= mask;
+        ++selectorP->count;  /* increment count */
+
+        /* reset min and max */
+        if (selectorP->min > index)
+            selectorP->min = index;
+        if (selectorP->max < index)
+            selectorP->max = index;
+    }
+}
+
+/* There is no function for erasing a marked bit */
+
+
+int  /* boolean */
+pm_selector_is_marked(const struct pm_selector * const selectorP,
+                      unsigned int               const index) {
+/*----------------------------------------------------------------------------
+  Index 'index' is marked.
+-----------------------------------------------------------------------------*/
+    bool retval;
+
+    if (selectorP) {
+        unsigned int  const byteIndex = index / 8;
+        unsigned int  const bitIndex  = index % 8;
+        unsigned char const mask = (0x01 <<7) >> bitIndex;
+
+        if ( index < selectorP->min || index > selectorP->max)
+            retval = false;
+        else if ((selectorP->record[byteIndex] & mask) != 0x00)
+            retval = true;
+        else
+            retval = false;
+    } else {
+        /* All entries are set to "exist" */
+        retval = true;
+    }
+    return retval ? 1 : 0;
+}
+
+
+
+unsigned int
+pm_selector_marked_ct(const struct pm_selector * const selectorP) {
+/*----------------------------------------------------------------------------
+   Number of indices that are marked.
+-----------------------------------------------------------------------------*/
+    return selectorP->count;
+}
+
+
+
+/*----------------------------------------------------------------------------
   Routines for loading a BDF font file
 -----------------------------------------------------------------------------*/
 
@@ -354,21 +556,23 @@ readExpectedStatement(Readline *    const readlineP,
 static void
 skipCharacter(Readline * const readlineP) {
 /*----------------------------------------------------------------------------
-  In the BDF font file being read by readline object *readlineP, skip through
-  the end of the character we are presently in.
+  In the BDF font file being read by readline object *readlineP, skip
+  through to the end of the data for the character we are presently in.
+
+  At entry the stream must be positioned at the end of the ENCODING line.
 -----------------------------------------------------------------------------*/
-    bool endChar;
 
-    endChar = FALSE;
+    char * rc;
+    do {
+        rc = fgets(readlineP->line, MAXBDFLINE+1, readlineP->ifP);
+        readlineP->line[7] = '\0';
+
+    } while (rc != NULL && !streq(readlineP->line, "ENDCHAR"));
+
+    if (rc == NULL)
+        pm_error("End of file in the middle of a character (before "
+                 "ENDCHAR) in BDF font file.");
 
-    while (!endChar) {
-        bool eof;
-        readline_read(readlineP, &eof);
-        if (eof)
-            pm_error("End of file in the middle of a character (before "
-                     "ENDCHAR) in BDF font file.");
-        endChar = streq(readlineP->arg[0], "ENDCHAR");
-    }
 }
 
 
@@ -421,7 +625,7 @@ interpEncoding(const char **  const arg,
 
    'maxmaxglyph' is the maximum codepoint in the font.
 -----------------------------------------------------------------------------*/
-    bool gotCodepoint;
+    bool gotCodepoint = false;   /* initial value */
     bool badCodepoint;
     unsigned int codepoint;
 
@@ -429,12 +633,15 @@ interpEncoding(const char **  const arg,
         codepoint = wordToInt(arg[1]);
         gotCodepoint = true;
     } else {
-      if (wordToInt(arg[1]) == -1 && arg[2] != NULL) {
-            codepoint = wordToInt(arg[2]);
-            gotCodepoint = true;
-        } else
-            gotCodepoint = false;
+        if (wordToInt(arg[1]) == -1 && arg[2] != NULL) {
+            int const codepoint0 = wordToInt(arg[2]);
+            if (codepoint0 >= 0) {
+                codepoint = codepoint0;
+                gotCodepoint = true;
+            }
+        }
     }
+
     if (gotCodepoint) {
         if (codepoint > maxmaxglyph)
             badCodepoint = true;
@@ -538,112 +745,147 @@ validateGlyphLimits(const struct font2 * const font2P,
 
 
 static void
-processChars(Readline *     const readlineP,
-             struct font2 * const font2P) {
-/*----------------------------------------------------------------------------
-   Process the CHARS block in a BDF font file, assuming the file is positioned
-   just after the CHARS line.  Read the rest of the block and apply its
-   contents to *font2P.
------------------------------------------------------------------------------*/
-    unsigned int const nCharacters = wordToInt(readlineP->arg[1]);
-
-    unsigned int nCharsDone;
-    unsigned int nCharsValid;
-
-    for (nCharsDone = 0, nCharsValid = 0;
-         nCharsDone < nCharacters; ) {
-
+readStartchar(Readline * const readlineP,
+              const char ** charNameP) {
+        
+        const char * charName;
         bool eof;
 
         readline_read(readlineP, &eof);
         if (eof)
             pm_error("End of file after CHARS reading BDF font file");
 
-        if (streq(readlineP->arg[0], "COMMENT")) {
+        while (streq(readlineP->arg[0], "COMMENT")) {
+            readline_read(readlineP, &eof);
+            if (eof)
+                 pm_error("End of file after CHARS reading BDF font file");
             /* ignore */
-        } else if (!streq(readlineP->arg[0], "STARTCHAR"))
+        }
+
+        if (!streq(readlineP->arg[0], "STARTCHAR"))
             pm_error("%s detected where \'STARTCHAR\' expected "
                      "in BDF font file", readlineP->arg[0] );
-        else {
-            const char * charName;
-
-            struct glyph * glyphP;
-            unsigned int codepoint;
-            bool badCodepoint;
-
-            if (readlineP->wordCt < 2)
-                pm_error("Wrong number of arguments in STARTCHAR line "
-                         "in BDF font file");
+        else if (readlineP->wordCt < 2)
+            pm_error("Wrong number of arguments in STARTCHAR line "
+                      "in BDF font file");
             /* Character name may contain spaces: there may be more than
                three words in the line.
              */
+        else
             charName = pm_strdup(readlineP->arg[1]);
 
-            assert(streq(readlineP->arg[0], "STARTCHAR"));
+        *charNameP = charName;
+}
 
-            MALLOCVAR(glyphP);
 
-            if (glyphP == NULL)
-                pm_error("no memory for font glyph for '%s' character",
-                         charName);
 
-            readEncoding(readlineP, &codepoint, &badCodepoint,
-                         font2P->maxmaxglyph);
+static void
+readGlyph(Readline * const readlineP,
+          const char * const charName,
+          const struct font2 * const font2P,
+          struct glyph ** const glyphPP) {
 
-            if (badCodepoint)
-                skipCharacter(readlineP);
-            else {
-                if (codepoint < font2P->maxglyph) {
-                    if (font2P->glyph[codepoint] != NULL)
-                        pm_error("Multiple definition of code point %u "
-                                 "in BDF font file", (unsigned int) codepoint);
-                    else
-                        pm_message("Reverse order detected in BDF file. "
-                                   "Code point %u defined after %u",
-                                    (unsigned int) codepoint,
-                                    (unsigned int) font2P->maxglyph);
-                } else {
-                    /* Initialize all characters in the gap to nonexistent */
-                    unsigned int i;
-                    unsigned int const oldMaxglyph = font2P->maxglyph;
-                    unsigned int const newMaxglyph = codepoint;
+    struct glyph * glyphP;
+    MALLOCVAR(glyphP);
+    if (glyphP == NULL)
+        pm_error("no memory for font glyph for '%s' character",
+             charName);
 
-                    for (i = oldMaxglyph + 1; i < newMaxglyph; ++i)
-                        font2P->glyph[i] = NULL;
+    readExpectedStatement(readlineP, "SWIDTH", 3);
 
-                    font2P->maxglyph = newMaxglyph;
-                    }
+    readExpectedStatement(readlineP, "DWIDTH", 3);
+    glyphP->xadd = wordToInt(readlineP->arg[1]);
 
-                readExpectedStatement(readlineP, "SWIDTH", 3);
+    readExpectedStatement(readlineP, "BBX", 5);
+    glyphP->width  = wordToInt(readlineP->arg[1]);
+    glyphP->height = wordToInt(readlineP->arg[2]);
+    glyphP->x      = wordToInt(readlineP->arg[3]);
+    glyphP->y      = wordToInt(readlineP->arg[4]);
 
-                readExpectedStatement(readlineP, "DWIDTH", 3);
-                glyphP->xadd = wordToInt(readlineP->arg[1]);
+    validateGlyphLimits(font2P, glyphP, charName);
 
-                readExpectedStatement(readlineP, "BBX", 5);
-                glyphP->width  = wordToInt(readlineP->arg[1]);
-                glyphP->height = wordToInt(readlineP->arg[2]);
-                glyphP->x      = wordToInt(readlineP->arg[3]);
-                glyphP->y      = wordToInt(readlineP->arg[4]);
+    createBmap(glyphP->width, glyphP->height, readlineP, charName,
+               &glyphP->bmap);
 
-                validateGlyphLimits(font2P, glyphP, charName);
+    *glyphPP = glyphP;
+}
+
+
+
+static void
+processChars(Readline *     const readlineP,
+             struct font2 * const font2P) {
+/*----------------------------------------------------------------------------
+   Process the CHARS block in a BDF font file, assuming the file is positioned
+   just after the CHARS line.  Read the rest of the block and apply its
+   contents to *font2P.
+-----------------------------------------------------------------------------*/
+    unsigned int const nCharacters = wordToInt(readlineP->arg[1]);
+    unsigned int const nCharsWanted = (font2P->selectorP != NULL) ?
+        font2P->selectorP->count : nCharacters;
+
+    unsigned int nCharsEncountered;
+    unsigned int nCharsLoaded;
+
+    for (nCharsEncountered = 0, nCharsLoaded = 0;
+         nCharsEncountered < nCharacters && nCharsLoaded < nCharsWanted;
+         ++nCharsEncountered ) {
+
+        const char * charName;
+        unsigned int codepoint;
+        bool badCodepoint;
+
+        readStartchar(readlineP, &charName);
+
+        readEncoding(readlineP, &codepoint, &badCodepoint,
+                         font2P->maxmaxglyph);
+
+        if ( badCodepoint ) {
+            skipCharacter(readlineP);
+            pm_strfree (charName);
+            }
+        else if (!pm_selector_is_marked(font2P->selectorP, codepoint) ) {
+            skipCharacter(readlineP);
+            pm_strfree (charName);
+            font2P->maxglyph = codepoint;
+            }
+        else {
+            if (codepoint < font2P->maxglyph) {
+                if (font2P->glyph[codepoint] != NULL )
+                       pm_error("Multiple definition of code point %u "
+                                "in BDF font file", (unsigned int) codepoint);
+                else
+                       pm_message("Reverse order detected in BDF file. "
+                                  "Code point %u defined after %u",
+                                   (unsigned int) codepoint,
+                                   (unsigned int) font2P->maxglyph);
+            }
 
-                createBmap(glyphP->width, glyphP->height, readlineP, charName,
-                           &glyphP->bmap);
+            {
+            struct glyph * glyphP;
 
-                readExpectedStatement(readlineP, "ENDCHAR", 1);
+            readGlyph(readlineP, charName, font2P, &glyphP);
+            readExpectedStatement(readlineP, "ENDCHAR", 1);
 
-                assert(codepoint <= font2P->maxmaxglyph);
-                /* Ensured by readEncoding() */
+            assert(codepoint <= font2P->maxmaxglyph);
+            /* Ensured by readEncoding() */
 
-                font2P->glyph[codepoint] = glyphP;
-                pm_strfree(charName);
+            font2P->glyph[codepoint] = glyphP;
+            pm_strfree(charName);
 
-                ++nCharsValid;
+            font2P->maxglyph = codepoint;
+            ++nCharsLoaded;
             }
-            ++nCharsDone;
         }
     }
-    font2P->chars = nCharsValid;
+
+    /* Note that BDF file may have reached end before the largest entry
+       in selector was checked.  */
+    /*
+    if (font2P->selectorP->max > font2P->maxglyph)
+       font2P->maxglyph = font2P->selectorP->max;
+    */
+    font2P->chars       = nCharsLoaded;
     font2P->total_chars = nCharacters;
 }
 
@@ -717,12 +959,8 @@ loadCharsetString(const char *  const registry,
 }
 
 
-
-
 static unsigned int const maxTokenLen = 60;
 
-
-
 static void
 doCharsetRegistry(Readline *    const readlineP,
                   bool *        const gotRegistryP,
@@ -904,6 +1142,9 @@ processBdfFontLine(Readline     * const readlineP,
       else {
         validateWordCount(readlineP, 2);  /* CHARS n */
         processChars(readlineP, font2P);
+        if (font2P->selectorP != NULL &&
+            font2P->selectorP->count == font2P->chars)
+               *endOfFontP = true;
       }
     } else {
         /* ignore */
@@ -913,9 +1154,39 @@ processBdfFontLine(Readline     * const readlineP,
 
 
 
+static void
+initializeGlyphArray(struct font2 * const font2P,
+                     unsigned int   const maxmaxglyph) {
+/*----------------------------------------------------------------------------
+  Initialize glyph array based on entries in selector.
+  Note that only valid codepoints are set to NULL.
+  Entries for unused glyphs are left untouched.
+-----------------------------------------------------------------------------*/
+    const struct pm_selector * const selectorP = font2P->selectorP;
+    unsigned int const min = (selectorP == NULL) ? 0 : selectorP->min;
+    unsigned int const max =
+        (selectorP == NULL) ? font2P->maxglyph : selectorP->max;
+
+    unsigned int codepoint;
+
+    for (codepoint = min; codepoint <= max ; ++codepoint)
+        if (pm_selector_is_marked(selectorP, codepoint) == true)
+             font2P->glyph[codepoint] = NULL;
+
+    font2P->glyph[L' '] = NULL;
+        /* Clear the slot for space character.
+           It may not be defined in the font, but the program may try
+           to use space as a substitute char
+        */
+
+}
+
+
+
 struct font2 *
-pbm_loadbdffont2(const char * const filename,
-                 PM_WCHAR     const maxmaxglyph) {
+pbm_loadbdffont2select(const char *               const filename,
+                       PM_WCHAR                   const maxmaxglyph,
+                       const struct pm_selector * const selectorP) {
 /*----------------------------------------------------------------------------
    Read a BDF font file "filename" as a 'font2' structure.  A 'font2'
    structure is more expressive than a 'font' structure, most notably in that
@@ -943,8 +1214,14 @@ pbm_loadbdffont2(const char * const filename,
 
     font2P->maxglyph = 0;
         /* Initial value.  Increases as new characters are loaded */
-    font2P->glyph[0] = NULL;
-        /* Initial value.  Overwrite later if codepoint 0 is defined. */
+
+    if (font2P->selectorP == NULL) {
+        PM_WCHAR i;
+
+        for(i = 0; i <= maxmaxglyph; ++i)
+            font2P->glyph[i] = NULL;
+            /* Initial value.  Overwrite later if codepoint i is defined. */
+    }
 
     font2P->maxmaxglyph = maxmaxglyph;
 
@@ -955,6 +1232,9 @@ pbm_loadbdffont2(const char * const filename,
     font2P->chars = font2P->total_chars = 0;
     font2P->default_char = 0;
     font2P->default_char_defined = FALSE;
+    font2P->selectorP = (struct pm_selector * const) selectorP;
+
+    initializeGlyphArray(font2P, maxmaxglyph);
 
     readExpectedStatement(&readline, "STARTFONT", 2);
 
@@ -970,9 +1250,13 @@ pbm_loadbdffont2(const char * const filename,
     }
     fclose(ifP);
 
-    if(font2P->chars == 0)
+    if(font2P->total_chars == 0)
         pm_error("No glyphs found in BDF font file "
                  "in codepoint range 0 - %u", (unsigned int) maxmaxglyph);
+    if(font2P->chars == 0)
+        pm_error("Not any requested glyphs found in BDF font file "
+                 "in codepoint range 0 - %u", (unsigned int) maxmaxglyph);
+
 
     REALLOCARRAY(font2P->glyph, font2P->maxglyph + 1);
 
@@ -986,8 +1270,21 @@ pbm_loadbdffont2(const char * const filename,
 }
 
 
+struct font2 *
+pbm_loadbdffont2(const char * const filename,
+                 PM_WCHAR     const maxmaxglyph) {
+
+  return (pbm_loadbdffont2select(filename, maxmaxglyph, NULL));
+
+  return(0);
+}
+
+
+
+
 static struct font *
 font2ToFont(const struct font2 * const font2P) {
+
             struct font  * fontP;
             unsigned int   codePoint;
 
@@ -1001,18 +1298,10 @@ font2ToFont(const struct font2 * const font2P) {
     fontP->x = font2P->x;
     fontP->y = font2P->y;
 
-    for (codePoint = 0; codePoint <= font2P->maxglyph; ++codePoint)
-        fontP->glyph[codePoint] = font2P->glyph[codePoint];
-
-    /* font2P->maxglyph is typically 255 (PM_FONT_MAXGLYPH) or larger.
-       But in some rare cases it is smaller.
-       If an ASCII-only font is read, it will be 126 or 127.
-
-       Set remaining codepoints up to PM_FONT_MAXGLYPH, if any, to NULL
-    */
-
-    for ( ; codePoint <= PM_FONT_MAXGLYPH; ++codePoint)
-        fontP->glyph[codePoint] = NULL;
+    for (codePoint = 0; codePoint <= PM_FONT_MAXGLYPH; ++codePoint)
+        fontP->glyph[codePoint] =
+             pm_selector_is_marked(font2P->selectorP, codePoint) ?
+             font2P->glyph[codePoint] : NULL;
 
     /* Give values to legacy fields */
     fontP->oldfont = font2P->oldfont;