From e4e6614dfa133420adb1763a962fff8ea04ab941 Mon Sep 17 00:00:00 2001 From: giraffedata Date: Wed, 4 Jul 2018 15:15:43 +0000 Subject: Rewrite font processing for proper memory management; make built-in fonts work with wide characters; fix wild pointer dereference with invalid BDF input git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@3291 9d0c8265-081b-0410-96cb-a4ca84ce46f8 --- lib/Makefile | 5 +- lib/libpbmfont.c | 1155 -------------------------------------------------- lib/libpbmfont0.c | 333 +++++++++++++++ lib/libpbmfont1.c | 359 ++++++++++++++++ lib/libpbmfont2.c | 995 +++++++++++++++++++++++++++++++++++++++++++ lib/libpbmfontdump.c | 96 +++++ lib/pbmfont.h | 229 +++++++++- lib/pbmfontdata.h | 7 + lib/pbmfontdata0.c | 9 + lib/pbmfontdata1.c | 24 +- lib/pbmfontdata2.c | 27 +- 11 files changed, 2056 insertions(+), 1183 deletions(-) delete mode 100644 lib/libpbmfont.c create mode 100644 lib/libpbmfont0.c create mode 100644 lib/libpbmfont1.c create mode 100644 lib/libpbmfont2.c create mode 100644 lib/libpbmfontdump.c create mode 100644 lib/pbmfontdata.h create mode 100644 lib/pbmfontdata0.c (limited to 'lib') diff --git a/lib/Makefile b/lib/Makefile index a0f33745..65177758 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -28,7 +28,8 @@ endif LIBOBJECTS = libpm.o pmfileio.o fileio.o colorname.o \ libpamd.o \ libpbm1.o libpbm2.o libpbm3.o \ - libpbmfont.o pbmfontdata1.o pbmfontdata2.o \ + libpbmfont0.o libpbmfont1.o libpbmfont2.o \ + pbmfontdata0.o pbmfontdata1.o pbmfontdata2.o \ libpgm1.o libpgm2.o \ libppm1.o libppm2.o libppmcmap.o libppmcolor.o libppmfuzzy.o \ libppmd.o ppmdfont.o standardppmdfont.o path.o \ @@ -56,7 +57,7 @@ MANUALS3 = libnetpbm MANUALS5 = pbm pgm ppm pnm pam INTERFACE_HEADERS = colorname.h \ - pam.h pamdraw.h pammap.h pbm.h pbmfont.h \ + pam.h pamdraw.h pammap.h pbm.h pbmfont.h pbmfontdata.h \ pgm.h pm.h pm_gamma.h pm_system.h pnm.h \ ppm.h ppmcmap.h ppmdfont.h ppmdraw.h ppmfloyd.h \ util/mallocvar.h util/runlength.h util/shhopt.h \ diff --git a/lib/libpbmfont.c b/lib/libpbmfont.c deleted file mode 100644 index 8f308eda..00000000 --- a/lib/libpbmfont.c +++ /dev/null @@ -1,1155 +0,0 @@ -/* -** -** Font routines. -** -** BDF font code Copyright 1993 by George Phillips. -** -** Copyright (C) 1991 by Jef Poskanzer. -** -** Permission to use, copy, modify, and distribute this software and its -** documentation for any purpose and without fee is hereby granted, provided -** that the above copyright notice appear in all copies and that both that -** copyright notice and this permission notice appear in supporting -** documentation. This software is provided "as is" without express or -** implied warranty. -** -** BDF font specs available from: -** https://partners.adobe.com/public/developer/en/font/5005.BDF_Spec.pdf -** Glyph Bitmap Distribution Format (BDF) Specification -** Version 2.2 -** 22 March 1993 -** Adobe Developer Support -*/ - -#include -#include -#include - -#include "netpbm/pm_c_util.h" -#include "netpbm/mallocvar.h" -#include "netpbm/nstring.h" - -#include "pbmfont.h" -#include "pbm.h" - -static unsigned int const firstCodePoint = 32; - /* This is the code point of the first character in a pbmfont font. - In ASCII, it is a space. - */ - -static unsigned int const nCharsInFont = 96; - /* The number of characters in a pbmfont font. A pbmfont font defines - characters at position 32 (ASCII space) through 127, so that's 96. - */ - - -struct font * -pbm_defaultfont(const char * const name) { -/*---------------------------------------------------------------------------- - Generate the built-in font with name 'name'. ------------------------------------------------------------------------------*/ - struct font * retval; - - if (streq(name, "bdf")) - retval = &pbm_defaultBdffont; - else if (streq(name, "fixed")) - retval = &pbm_defaultFixedfont; - else - pm_error( "built-in font name unknown, try 'bdf' or 'fixed'"); - - return retval; -} - - - -static void -findFirstBlankRow(const bit ** const font, - unsigned int const fcols, - unsigned int const frows, - unsigned int * const browP) { - - unsigned int row; - bool foundBlank; - - for (row = 0, foundBlank = false; row < frows / 6 && !foundBlank; ++row) { - unsigned int col; - bit col0Value = font[row][0]; - bool rowIsBlank; - rowIsBlank = true; /* initial assumption */ - for (col = 1; col < fcols; ++col) - if (font[row][col] != col0Value) - rowIsBlank = false; - - if (rowIsBlank) { - foundBlank = true; - *browP = row; - } - } - - if (!foundBlank) - pm_error("couldn't find blank pixel row in font"); -} - - - -static void -findFirstBlankCol(const bit ** const font, - unsigned int const fcols, - unsigned int const frows, - unsigned int * const bcolP) { - - unsigned int col; - bool foundBlank; - - for (col = 0, foundBlank = false; col < fcols / 6 && !foundBlank; ++col) { - unsigned int row; - bit row0Value = font[0][col]; - bool colIsBlank; - colIsBlank = true; /* initial assumption */ - for (row = 1; row < frows; ++row) - if (font[row][col] != row0Value) - colIsBlank = false; - - if (colIsBlank) { - foundBlank = true; - *bcolP = col; - } - } - - if (!foundBlank) - pm_error("couldn't find blank pixel column in font"); -} - - - -static void -computeCharacterSize(const bit ** const font, - unsigned int const fcols, - unsigned int const frows, - unsigned int * const cellWidthP, - unsigned int * const cellHeightP, - unsigned int * const charWidthP, - unsigned int * const charHeightP) { - - unsigned int firstBlankRow; - unsigned int firstBlankCol; - unsigned int heightLast11Rows; - - findFirstBlankRow(font, fcols, frows, &firstBlankRow); - - findFirstBlankCol(font, fcols, frows, &firstBlankCol); - - heightLast11Rows = frows - firstBlankRow; - - if (heightLast11Rows % 11 != 0) - pm_error("The rows of characters in the font do not appear to " - "be all the same height. The last 11 rows are %u pixel " - "rows high (from pixel row %u up to %u), " - "which is not a multiple of 11.", - heightLast11Rows, firstBlankRow, frows); - else { - unsigned int widthLast15Cols; - - *cellHeightP = heightLast11Rows / 11; - - widthLast15Cols = fcols - firstBlankCol; - - if (widthLast15Cols % 15 != 0) - pm_error("The columns of characters in the font do not appear to " - "be all the same width. " - "The last 15 columns are %u pixel " - "columns wide (from pixel col %u up to %u), " - "which is not a multiple of 15.", - widthLast15Cols, firstBlankCol, fcols); - else { - *cellWidthP = widthLast15Cols / 15; - - *charWidthP = firstBlankCol; - *charHeightP = firstBlankRow; - } - } -} - - - -struct font* -pbm_dissectfont(const bit ** const font, - unsigned int const frows, - unsigned int const fcols) { - /* - This routine expects a font bitmap representing the following text: - - (0,0) - M ",/^_[`jpqy| M - - / !"#$%&'()*+ / - < ,-./01234567 < - > 89:;<=>?@ABC > - @ DEFGHIJKLMNO @ - _ PQRSTUVWXYZ[ _ - { \]^_`abcdefg { - } hijklmnopqrs } - ~ tuvwxyz{|}~ ~ - - M ",/^_[`jpqy| M - - The bitmap must be cropped exactly to the edges. - - The characters in the border you see are irrelevant except for - character size compuations. The 12 x 8 array in the center is - the font. The top left character there belongs to code point - 0, and the code points increase in standard reading order, so - the bottom right character is code point 127. You can't define - code points < 32 or > 127 with this font format. - - The characters in the top and bottom border rows must include a - character with the lowest reach of any in the font (e.g. "y", - "_") and one with the highest reach (e.g. '"'). The characters - in the left and right border columns must include characters - with the rightmost and leftmost reach of any in the font - (e.g. "M" for both). - - The border must be separated from the font by one blank text - row or text column. - - The dissection works by finding the first blank row and column; - i.e the lower right corner of the "M" in the upper left corner - of the matrix. That gives the height and width of the - maximum-sized character, which is not too useful. But the - distance from there to the opposite side is an integral - multiple of the cell size, and that's what we need. Then it's - just a matter of filling in all the coordinates. */ - - unsigned int cellWidth, cellHeight; - /* Dimensions in pixels of each cell of the font -- that - includes the glyph and the white space above and to the - right of it. Each cell is a tile of the font image. The - top character row and left character row don't count -- - those cells are smaller because they are missing the white - space. - */ - unsigned int charWidth, charHeight; - /* Maximum dimensions of glyph itself, inside its cell */ - - int row, col, ch, r, c, i; - struct font * fn; - struct glyph * glyph; - char* bmap; - - computeCharacterSize(font, fcols, frows, - &cellWidth, &cellHeight, &charWidth, &charHeight); - - /* Now convert to a general font */ - - MALLOCVAR(fn); - if (fn == NULL) - pm_error("out of memory allocating font structure"); - - fn->maxwidth = charWidth; - fn->maxheight = charHeight; - fn->x = fn->y = 0; - - fn->oldfont = font; - fn->frows = frows; - fn->fcols = fcols; - - /* Initialize all character positions to "undefined." Those that - are defined in the font will be filled in below. - */ - for (i = 0; i < PM_FONT_MAXGLYPH + 1; i++) - fn->glyph[i] = NULL; - - MALLOCARRAY(glyph, nCharsInFont); - if ( glyph == NULL ) - pm_error( "out of memory allocating glyphs" ); - - bmap = (char*) malloc( fn->maxwidth * fn->maxheight * nCharsInFont ); - if ( bmap == (char*) 0) - pm_error( "out of memory allocating glyph data" ); - - /* Now fill in the 0,0 coords. */ - row = cellHeight * 2; - col = cellWidth * 2; - for (i = 0; i < firstCodePoint; ++i) - fn->glyph[i] = NULL; - - for ( ch = 0; ch < nCharsInFont; ++ch ) { - glyph[ch].width = fn->maxwidth; - glyph[ch].height = fn->maxheight; - glyph[ch].x = glyph[ch].y = 0; - glyph[ch].xadd = cellWidth; - - for ( r = 0; r < glyph[ch].height; ++r ) - for ( c = 0; c < glyph[ch].width; ++c ) - bmap[r * glyph[ch].width + c] = font[row + r][col + c]; - - glyph[ch].bmap = bmap; - bmap += glyph[ch].width * glyph[ch].height; - - fn->glyph[firstCodePoint + ch] = &glyph[ch]; - - col += cellWidth; - if ( col >= cellWidth * 14 ) { - col = cellWidth * 2; - row += cellHeight; - } - } - for (i = firstCodePoint + nCharsInFont; i < PM_FONT_MAXGLYPH + 1; ++i) - fn->glyph[i] = NULL; - - return fn; -} - - - -struct font * -pbm_loadfont(const char * const filename) { - - FILE * fileP; - struct font * fontP; - char line[10] = "\0\0\0\0\0\0\0\0\0\0"; - /* Initialize to suppress Valgrind error which is reported when file - is empty or very small. - */ - - fileP = pm_openr(filename); - fgets(line, 10, fileP); - pm_close(fileP); - - if (line[0] == PBM_MAGIC1 && - (line[1] == PBM_MAGIC2 || line[1] == RPBM_MAGIC2)) { - fontP = pbm_loadpbmfont(filename); - } else if (!strncmp(line, "STARTFONT", 9)) { - fontP = pbm_loadbdffont(filename); - if (!fontP) - pm_error("could not load BDF font file"); - } else { - pm_error("font file not in a recognized format. Does not start " - "with the signature of a PBM file or BDF font file"); - assert(false); - fontP = NULL; /* defeat compiler warning */ - } - return fontP; -} - - - -struct font * -pbm_loadpbmfont(const char * const filename) { - - FILE * ifP; - bit ** font; - int fcols, frows; - - ifP = pm_openr(filename); - - font = pbm_readpbm(ifP, &fcols, &frows); - - if ((fcols - 1) / 16 >= pbm_maxfontwidth() || - (frows - 1) / 12 >= pbm_maxfontheight()) - pm_error("Absurdly large PBM font file: %s", filename); - else if (fcols < 31 || frows < 23) { - /* Need at least one pixel per character, and this is too small to - have that. - */ - pm_error("PBM font file '%s' too small to be a font file: %u x %u. " - "Minimum sensible size is 31 x 23", - filename, fcols, frows); - } - - pm_close(ifP); - - return pbm_dissectfont((const bit **)font, frows, fcols); -} - - - -void -pbm_dumpfont(struct font * const fontP, - FILE * const ofP) { -/*---------------------------------------------------------------------------- - Dump out font as C source code. ------------------------------------------------------------------------------*/ - unsigned int i; - unsigned int ng; - - if (fontP->oldfont) - pm_message("Netpbm no longer has the capability to generate " - "a font in long hexadecimal data format"); - - for (i = 0, ng = 0; i < PM_FONT_MAXGLYPH +1; ++i) { - if (fontP->glyph[i]) - ++ng; - } - - printf("static struct glyph _g[%d] = {\n", ng); - - for (i = 0; i < PM_FONT_MAXGLYPH + 1; ++i) { - struct glyph * const glyphP = fontP->glyph[i]; - if (glyphP) { - unsigned int j; - printf(" { %d, %d, %d, %d, %d, \"", glyphP->width, glyphP->height, - glyphP->x, glyphP->y, glyphP->xadd); - - for (j = 0; j < glyphP->width * glyphP->height; ++j) { - if (glyphP->bmap[j]) - printf("\\1"); - else - printf("\\0"); - } - --ng; - printf("\" }%s\n", ng ? "," : ""); - } - } - printf("};\n"); - - printf("struct font XXX_font = { %d, %d, %d, %d, {\n", - fontP->maxwidth, fontP->maxheight, fontP->x, fontP->y); - - { - unsigned int i; - - for (i = 0; i < PM_FONT_MAXGLYPH + 1; ++i) { - if (fontP->glyph[i]) - printf(" _g + %d", ng++); - else - printf(" NULL"); - - if (i != PM_FONT_MAXGLYPH) printf(","); - printf("\n"); - } - } - - printf(" }\n};\n"); -} - - -/*---------------------------------------------------------------------------- - Routines for loading a BDF font file ------------------------------------------------------------------------------*/ - - -/* The following are not recognized in individual glyph data; library - routines do a pm_error if they see one: - - Vertical writing systems: DWIDTH1, SWIDTH1, VVECTOR, METRICSET, - CONTENTVERSION. - - The following is not recognized and is thus ignored at the global level: - DWIDTH -*/ - - -#define MAXBDFLINE 1024 - -/* Official Adobe document says max length of string is 65535 characters. - However the value 1024 is sufficient for practical uses. -*/ - -typedef struct { -/*---------------------------------------------------------------------------- - This is an object for reading lines of a font file. It reads and tokenizes - them into words. ------------------------------------------------------------------------------*/ - FILE * ifP; - - char line[MAXBDFLINE+1]; - /* This is the storage space for the words of the line. The - words go in here, one after another, separated by NULs. - - It also functions as a work area for readline_read(). - */ - const char * arg[6]; - /* These are the words; each entry is a pointer into line[] (above) */ -} Readline; - - - -static void -readline_init(Readline * const readlineP, - FILE * const ifP) { - - readlineP->ifP = ifP; - - readlineP->arg[0] = NULL; -} - - - -static void -tokenize(char * const s, - const char ** const words, - unsigned int const wordsSz) { -/*---------------------------------------------------------------------------- - Chop up 's' into words by changing space characters to NUL. Return as - 'words' an array of pointers to the beginnings of those words in 's'. - Terminate the words[] list with a null pointer. - - 'wordsSz' is the number of elements of space in 'words'. If there are more - words in 's' than will fit in that space (including the terminating null - pointer), ignore the excess on the right. ------------------------------------------------------------------------------*/ - unsigned int n; /* Number of words in words[] so far */ - char * p; - - p = &s[0]; - n = 0; - - while (*p) { - if (ISSPACE(*p)) - *p++ = '\0'; - else { - words[n++] = p; - if (n >= wordsSz - 1) - break; - while (*p && !ISSPACE(*p)) - ++p; - } - } - assert(n <= wordsSz - 1); - words[n] = NULL; -} - - - -static void -readline_read(Readline * const readlineP, - bool * const eofP) { -/*---------------------------------------------------------------------------- - Read a nonblank line from the file. Make its contents available - as readlineP->arg[]. - - Return *eofP == true iff there is no nonblank line before EOF or we - are unable to read the file. ------------------------------------------------------------------------------*/ - bool gotLine; - bool error; - - for (gotLine = false, error = false; !gotLine && !error; ) { - char * rc; - - rc = fgets(readlineP->line, MAXBDFLINE+1, readlineP->ifP); - if (rc == NULL) - error = true; - else { - tokenize(readlineP->line, - readlineP->arg, ARRAY_SIZE(readlineP->arg)); - if (readlineP->arg[0] != NULL) - gotLine = true; - } - } - *eofP = error; -} - - - -static void -parseBitmapRow(const char * const hex, - unsigned int const glyphWidth, - unsigned char * const bmap, - unsigned int const origBmapIndex, - unsigned int * const newBmapIndexP, - const char ** const errorP) { -/*---------------------------------------------------------------------------- - Parse one row of the bitmap for a glyph, from the hexadecimal string - for that row in the font file, 'hex'. The glyph is 'glyphWidth' - pixels wide. - - We place our result in 'bmap' at *bmapIndexP and advanced *bmapIndexP. ------------------------------------------------------------------------------*/ - unsigned int bmapIndex; - int i; /* dot counter */ - const char * p; - - bmapIndex = origBmapIndex; - - for (i = glyphWidth, p = &hex[0], *errorP = NULL; - i > 0 && !*errorP; - i -= 4) { - - if (*p == '\0') - pm_asprintf(errorP, "Not enough hexadecimal digits for glyph " - "of width %u in '%s'", - glyphWidth, hex); - else { - char const hdig = *p++; - unsigned int hdigValue; - - 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_asprintf(errorP, - "Invalid hex digit x%02x (%c) in bitmap data '%s'", - (unsigned int)(unsigned char)hdig, - isprint(hdig) ? hdig : '.', - hex); - - if (!*errorP) { - 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; - } - } - } - *newBmapIndexP = bmapIndex; -} - - - -static void -readBitmap(Readline * const readlineP, - 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) { - bool eof; - const char * error; - - readline_read(readlineP, &eof); - - if (eof) - pm_error("End of file in bitmap for character '%s' in BDF " - "font file.", charName); - - if (!readlineP->arg[0]) - pm_error("A line that is supposed to contain bitmap data, " - "in hexadecimal, for character '%s' is empty", charName); - - parseBitmapRow(readlineP->arg[0], glyphWidth, bmap, bmapIndex, - &bmapIndex, &error); - - if (error) { - pm_error("Error in line %d of bitmap for character '%s': %s", - n, charName, error); - pm_strfree(error); - } - } -} - - - -static void -createBmap(unsigned int const glyphWidth, - unsigned int const glyphHeight, - Readline * const readlineP, - const char * const charName, - const char ** const bmapP) { - - unsigned char * bmap; - bool eof; - - if (glyphWidth > 0 && UINT_MAX / glyphWidth < glyphHeight) - pm_error("Ridiculously large glyph"); - - MALLOCARRAY(bmap, glyphWidth * glyphHeight); - - if (!bmap) - pm_error("no memory for font glyph byte map"); - - readline_read(readlineP, &eof); - if (eof) - pm_error("End of file encountered reading font glyph byte map from " - "BDF font file."); - - if (streq(readlineP->arg[0], "ATTRIBUTES")) { - /* ATTRIBUTES is defined in Glyph Bitmap Distribution Format (BDF) - Specification Version 2.1, but not in Version 2.2. - */ - bool eof; - readline_read(readlineP, &eof); - if (eof) - pm_error("End of file encountered after ATTRIBUTES in BDF " - "font file."); - } - if (!streq(readlineP->arg[0], "BITMAP")) - pm_error("'%s' found where BITMAP expected in definition of " - "character '%s' in BDF font file.", - readlineP->arg[0], charName); - - assert(streq(readlineP->arg[0], "BITMAP")); - - readBitmap(readlineP, glyphWidth, glyphHeight, charName, bmap); - - *bmapP = (char *)bmap; -} - - - -static void -readExpectedStatement(Readline * const readlineP, - const char * const expected) { -/*---------------------------------------------------------------------------- - Have the readline object *readlineP read the next line from the file, but - expect it to be a line of type 'expected' (i.e. the verb token at the - beginning of the line is that, e.g. "STARTFONT"). If it isn't, fail the - program. ------------------------------------------------------------------------------*/ - bool eof; - - readline_read(readlineP, &eof); - - if (eof) - pm_error("EOF in BDF font file where '%s' expected", expected); - else if (!streq(readlineP->arg[0], expected)) - pm_error("Statement of type '%s' where '%s' expected in BDF font file", - readlineP->arg[0], expected); -} - - - -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. ------------------------------------------------------------------------------*/ - bool endChar; - - endChar = FALSE; - - 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"); - } -} - - - -static void -interpEncoding(const char ** const arg, - unsigned int * const codepointP, - bool * const badCodepointP, - PM_WCHAR const maxglyph) { -/*---------------------------------------------------------------------------- - 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. - - 'maxglyph' is the maximum codepoint in the font. ------------------------------------------------------------------------------*/ - bool gotCodepoint; - bool badCodepoint; - unsigned int codepoint; - - if (atoi(arg[1]) >= 0) { - codepoint = atoi(arg[1]); - gotCodepoint = true; - } else { - if (atoi(arg[1]) == -1 && arg[2] != NULL) { - codepoint = atoi(arg[2]); - gotCodepoint = true; - } else - gotCodepoint = false; - } - if (gotCodepoint) { - if (codepoint > maxglyph) - badCodepoint = true; - else - badCodepoint = false; - } else - badCodepoint = true; - - *badCodepointP = badCodepoint; - *codepointP = codepoint; -} - - - -static void -readEncoding(Readline * const readlineP, - unsigned int * const codepointP, - bool * const badCodepointP, - PM_WCHAR const maxglyph) { - - readExpectedStatement(readlineP, "ENCODING"); - - interpEncoding(readlineP->arg, codepointP, badCodepointP, maxglyph); -} - - - -static void -validateFontLimits(const struct font2 * const fontP) { - - assert(pbm_maxfontheight() > 0 && pbm_maxfontwidth() > 0); - - if (fontP->maxwidth <= 0 || - fontP->maxheight <= 0 || - fontP->maxwidth > pbm_maxfontwidth() || - fontP->maxheight > pbm_maxfontheight() || - -fontP->x + 1 > fontP->maxwidth || - -fontP->y + 1 > fontP->maxheight || - fontP->x > fontP->maxwidth || - fontP->y > fontP->maxheight || - fontP->x + fontP->maxwidth > pbm_maxfontwidth() || - fontP->y + fontP->maxheight > pbm_maxfontheight() - ) { - - pm_error("Global font metric(s) out of bounds."); - } - - if (fontP->maxglyph > PM_FONT2_MAXGLYPH) - pm_error("Internal error. Glyph table too large: %u glyphs; " - "Maximum possible in Netpbm is %u", - fontP->maxglyph, PM_FONT2_MAXGLYPH); -} - - - -static void -validateGlyphLimits(const struct font2 * const fontP, - const struct glyph * const glyphP, - const char * const charName) { - - /* Some BDF files code space with zero width and height, - no bitmap data and just the xadd value. - We allow zero width and height, iff both are zero. - */ - - if (((glyphP->width == 0 || glyphP->height == 0) && - !(glyphP->width == 0 && glyphP->height == 0)) || - glyphP->width > fontP->maxwidth || - glyphP->height > fontP->maxheight || - glyphP->x < fontP->x || - glyphP->y < fontP->y || - glyphP->x + (int) glyphP->width > fontP->x + fontP->maxwidth || - glyphP->y + (int) glyphP->height > fontP->y + fontP->maxheight || - glyphP->xadd > pbm_maxfontwidth() || - glyphP->xadd + MAX(glyphP->x,0) + (int) glyphP->width > - pbm_maxfontwidth() - ) { - - pm_error("Font metric(s) for char '%s' out of bounds.\n", charName); - } -} - - - -static void -processChars(Readline * const readlineP, - struct font2 * const fontP, - PM_WCHAR const maxglyph ) { -/*---------------------------------------------------------------------------- - 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 *fontP. ------------------------------------------------------------------------------*/ - unsigned int const nCharacters = atoi(readlineP->arg[1]); - - unsigned int nCharsDone; - - nCharsDone = 0; - - while (nCharsDone < nCharacters) { - 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")) { - /* ignore */ - } else if (!streq(readlineP->arg[0], "STARTCHAR")) - pm_error("no STARTCHAR after CHARS in BDF font file"); - else { - const char * const charName = pm_strdup(readlineP->arg[1]); - - struct glyph * glyphP; - unsigned int codepoint; - bool badCodepoint; - - assert(streq(readlineP->arg[0], "STARTCHAR")); - - MALLOCVAR(glyphP); - - if (glyphP == NULL) - pm_error("no memory for font glyph for '%s' character", - charName); - - readEncoding(readlineP, &codepoint, &badCodepoint, maxglyph); - - if (badCodepoint) - skipCharacter(readlineP); - else if (fontP->glyph[codepoint] != NULL) - pm_error("Multiple definition of code point %d " - "in font file", (unsigned int) codepoint); - else { - readExpectedStatement(readlineP, "SWIDTH"); - - readExpectedStatement(readlineP, "DWIDTH"); - glyphP->xadd = atoi(readlineP->arg[1]); - - readExpectedStatement(readlineP, "BBX"); - glyphP->width = atoi(readlineP->arg[1]); - glyphP->height = atoi(readlineP->arg[2]); - glyphP->x = atoi(readlineP->arg[3]); - glyphP->y = atoi(readlineP->arg[4]); - - validateGlyphLimits(fontP, glyphP, charName); - - createBmap(glyphP->width, glyphP->height, readlineP, charName, - &glyphP->bmap); - - - readExpectedStatement(readlineP, "ENDCHAR"); - - assert(codepoint <= maxglyph); /* Ensured by readEncoding() */ - - fontP->glyph[codepoint] = glyphP; - pm_strfree(charName); - } - ++nCharsDone; - } - } -} - - - -static void -processBdfFontLine(Readline * const readlineP, - struct font2 * const fontP, - bool * const endOfFontP, - PM_WCHAR const maxglyph) { -/*---------------------------------------------------------------------------- - Process a nonblank line just read from a BDF font file. - - This processing may involve reading more lines. ------------------------------------------------------------------------------*/ - *endOfFontP = FALSE; /* initial assumption */ - - assert(readlineP->arg[0] != NULL); /* Entry condition */ - - if (streq(readlineP->arg[0], "COMMENT")) { - /* ignore */ - } else if (streq(readlineP->arg[0], "SIZE")) { - /* ignore */ - } else if (streq(readlineP->arg[0], "STARTPROPERTIES")) { - /* Read off the properties and ignore them all */ - unsigned int const propCount = atoi(readlineP->arg[1]); - - unsigned int i; - for (i = 0; i < propCount; ++i) { - bool eof; - readline_read(readlineP, &eof); - if (eof) - pm_error("End of file after STARTPROPERTIES in BDF font file"); - } - } else if (streq(readlineP->arg[0], "FONTBOUNDINGBOX")) { - fontP->maxwidth = atoi(readlineP->arg[1]); - fontP->maxheight = atoi(readlineP->arg[2]); - fontP->x = atoi(readlineP->arg[3]); - fontP->y = atoi(readlineP->arg[4]); - validateFontLimits(fontP); - } else if (streq(readlineP->arg[0], "ENDPROPERTIES")) { - if (fontP->maxwidth ==0) - pm_error("Encountered ENDPROPERTIES before FONTBOUNDINGBOX " - "in BDF font file"); - } else if (streq(readlineP->arg[0], "ENDFONT")) { - *endOfFontP = true; - } else if (streq(readlineP->arg[0], "CHARS")) { - if (fontP->maxwidth ==0) - pm_error("Encountered CHARS before FONTBOUNDINGBOX " - "in BDF font file"); - else - processChars(readlineP, fontP, maxglyph); - } else { - /* ignore */ - } -} - - - -struct font2 * -pbm_loadbdffont2(const char * const filename, - PM_WCHAR const maxglyph) { -/*---------------------------------------------------------------------------- - Read a BDF font file "filename" as a 'font2' structure. A 'font2' - structure is more expressive than a 'font' structure, most notably in that - it can handle wide code points and many more glyphs. - - Codepoints up to maxglyph inclusive are valid in the file. - - The returned object is in new malloc'ed storage, in many pieces, and - cannot be destroyed. ------------------------------------------------------------------------------*/ - /* For our return object to be destroyable, we need to supply a destroy - function, and it needs to return glyph and raster memory, and - struct font needs to manage glyph memory separately from mapping - code points to glyphs. - */ - FILE * ifP; - Readline readline; - struct font2 * font2P; - bool endOfFont; - - ifP = fopen(filename, "rb"); - if (!ifP) - pm_error("Unable to open BDF font file name '%s'. errno=%d (%s)", - filename, errno, strerror(errno)); - - readline_init(&readline, ifP); - - MALLOCVAR(font2P); - if (font2P == NULL) - pm_error("no memory for font"); - - MALLOCARRAY(font2P->glyph, maxglyph + 1); - if (font2P->glyph == NULL) - pm_error("no memory for font glyphs"); - - font2P->maxglyph = maxglyph; - - font2P->oldfont = NULL; - { - /* Initialize all characters to nonexistent; we will fill the ones we - find in the bdf file later. - */ - PM_WCHAR i; - for (i = 0; i <= maxglyph; ++i) - font2P->glyph[i] = NULL; - } - - font2P->maxwidth = font2P->maxheight = font2P->x = font2P->y = 0; - - readExpectedStatement(&readline, "STARTFONT"); - - endOfFont = FALSE; - - while (!endOfFont) { - bool eof; - readline_read(&readline, &eof); - if (eof) - pm_error("End of file before ENDFONT statement in BDF font file"); - - processBdfFontLine(&readline, font2P, &endOfFont, maxglyph); - } - return font2P; -} - - - -struct font * -pbm_loadbdffont(const char * const filename) { -/*---------------------------------------------------------------------------- - Read a BDF font file "filename" into a traditional font structure. - - Codepoints up to 255 (PM_FONT_MAXGLYPH) are valid. - - Can handle ASCII, ISO-8859-1, ISO-8859-2, ISO-8859-15, etc. - - The returned object is in new malloc'ed storage, in many pieces, and - cannot be destroyed. ------------------------------------------------------------------------------*/ - /* For our return object to deep copy the glyphs and fonts from - the struct font2be destroyable, we need to supply a destroy - function, and it needs to return glyph and raster memory, and - struct font needs to manage glyph memory separately from mapping - code points to glyphs. - */ - struct font * fontP; - struct font2 * font2P; - unsigned int codePoint; - - MALLOCVAR(fontP); - if (fontP == NULL) - pm_error("no memory for font"); - - font2P = pbm_loadbdffont2(filename, PM_FONT_MAXGLYPH); - - fontP->maxwidth = font2P->maxwidth; - fontP->maxheight = font2P->maxheight; - - fontP->x = font2P->x; - fontP->y = font2P->y; - - for (codePoint = 0; codePoint < PM_FONT_MAXGLYPH + 1; ++codePoint) - fontP->glyph[codePoint] = font2P->glyph[codePoint]; - - fontP->oldfont = NULL; - - fontP->fcols = 0; - fontP->frows = 0; - - /* Note that *fontP2 is unfreeable. See pbm_loadbdffont2. And even if it - were, we hooked *fontP into it above, so that would have to turn into a - deep copy before we could free *fontP2. - */ - - return fontP; -} - - - -struct font2 * -pbm_expandbdffont(const struct font * const fontP) { -/*---------------------------------------------------------------------------- - Convert a traditional font structure into an expanded font2 structure. - - This function depends upon the fact that *fontP, like any struct font, - cannot be destroyed. The returned object refers to memory that belongs - to *fontP. - - The returned object is in new malloc'ed storage, in many pieces, and - cannot be destroyed. ------------------------------------------------------------------------------*/ - /* If we ever make struct font destroyable, this function needs to - copy the glyphs and rasters, and struct font and struct font2 need - to manage glyph memory separately from mapping code points to the - glyphs. - */ - PM_WCHAR const maxglyph = PM_FONT_MAXGLYPH; - - struct font2 * font2P; - unsigned int codePoint; - - MALLOCVAR(font2P); - if (font2P == NULL) - pm_error("no memory for font"); - - MALLOCARRAY(font2P->glyph, maxglyph + 1); - if (font2P->glyph == NULL) - pm_error("no memory for font glyphs"); - - font2P->maxwidth = fontP->maxwidth; - font2P->maxheight = fontP->maxheight; - - font2P->x = fontP->x; - font2P->y = fontP->y; - - font2P->maxglyph = maxglyph; - - for (codePoint = 0; codePoint < maxglyph + 1; ++codePoint) - font2P->glyph[codePoint] = fontP->glyph[codePoint]; - - font2P->oldfont = fontP->oldfont; - - font2P->fcols = fontP->fcols; - font2P->frows = fontP->frows; - - return font2P; -} - - diff --git a/lib/libpbmfont0.c b/lib/libpbmfont0.c new file mode 100644 index 00000000..5a645249 --- /dev/null +++ b/lib/libpbmfont0.c @@ -0,0 +1,333 @@ +/* +** +** Font routines. +** +** Wide character stuff written by Akira Urushibata, 2018 +** +** Also copyright (C) 1991 by Jef Poskanzer. +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +*/ + +#include +#include + +#include "netpbm/pm_c_util.h" +#include "netpbm/mallocvar.h" +#include "netpbm/nstring.h" + +#include "pbm.h" +#include "pbmfont.h" +#include "pbmfontdata.h" + + +struct font * +pbm_defaultfont(const char * const name) { +/*---------------------------------------------------------------------------- + Generate the built-in font with name 'name'. +-----------------------------------------------------------------------------*/ + struct font * retval; + + if (streq(name, "bdf")) + retval = &pbm_defaultBdffont; + else if (streq(name, "fixed")) + retval = &pbm_defaultFixedfont; + else + pm_error( "built-in font name unknown, try 'bdf' or 'fixed'"); + + return retval; +} + + + +struct font2 * +pbm_defaultfont2(const char * const requestedFontName) { + + struct font2 * font2P; + struct font2 * retval = NULL; /* initial value */ + unsigned int i; + + for (i = 0; retval == NULL; ++i) { + const char * longName; + const char * shortName; + font2P = (struct font2 * ) pbm_builtinFonts[i]; + if (font2P == NULL) + break; + + longName = font2P->name; + shortName = &longName[strlen("builtin ")]; + + if (streq(shortName, requestedFontName)) + retval = font2P; + } + + if (retval == NULL) + pm_error("No builtin font named %s", requestedFontName); + + return retval; +} + + + +static void +selectFontType(const char * const filename, + PM_WCHAR const maxmaxglyph, + unsigned int const isWide, + struct font ** const fontPP, + struct font2 ** const font2PP) { + + FILE * fileP; + struct font * fontP = NULL; /* initial value */ + struct font2 * font2P = NULL; /* initial value */ + char line[10] = "\0\0\0\0\0\0\0\0\0\0"; + /* Initialize to suppress Valgrind error which is reported when file + is empty or very small. + */ + + fileP = pm_openr(filename); + fgets(line, 10, fileP); + pm_close(fileP); + + if (line[0] == PBM_MAGIC1 && + (line[1] == PBM_MAGIC2 || line[1] == RPBM_MAGIC2)) { + if (isWide == TRUE) + font2P = pbm_loadpbmfont2(filename); + else + fontP = pbm_loadpbmfont(filename); + if (fontP == NULL && font2P == NULL) + pm_error("could not load PBM font file"); + + } else if (!strncmp(line, "STARTFONT", 9)) { + if (isWide == TRUE) + font2P = pbm_loadbdffont2(filename, maxmaxglyph); + else + fontP = pbm_loadbdffont(filename); + if (fontP == NULL && font2P == NULL) + pm_error("could not load BDF font file"); + + } else { + pm_error("font file not in a recognized format. Does not start " + "with the signature of a PBM file or BDF font file"); + assert(false); + fontP = NULL; /* defeat compiler warning */ + } + + if (isWide) + *font2PP = font2P; + else + *fontPP = fontP; +} + + + +struct font * +pbm_loadfont(const char * const filename) { + + struct font * fontP; + struct font2 * font2P; + + selectFontType(filename, PM_FONT_MAXGLYPH, FALSE, &fontP, &font2P); + return fontP; +} + + + +struct font2 * +pbm_loadfont2(const char * const filename, + PM_WCHAR const maxmaxglyph) { + + struct font * fontP; + struct font2 * font2P; + + selectFontType(filename, maxmaxglyph, TRUE, &fontP, &font2P); + return font2P; +} + + + +void +pbm_createbdffont2_base(struct font2 ** const font2PP, + PM_WCHAR const maxmaxglyph) { + + struct font2 * font2P; + + MALLOCVAR(font2P); + if (font2P == NULL) + pm_error("no memory for font"); + + MALLOCARRAY(font2P->glyph, maxmaxglyph + 1); + if (font2P->glyph == NULL) + pm_error("no memory for font glyphs"); + + /* Initialize */ + font2P->size = sizeof (struct font2); + font2P->len = PBM_FONT2_STRUCT_SIZE(charset_string); + + /* Caller should overwrite following fields as necessary */ + font2P->oldfont = NULL; + font2P->fcols = font2P->frows = 0; + font2P->selector = NULL; + font2P->default_char = 0; + font2P->default_char_defined = FALSE; + font2P->total_chars = font2P->chars = 0; + font2P->name = NULL; + font2P->charset = ENCODING_UNKNOWN; + font2P->charset_string = NULL; + + *font2PP = font2P; +} + + + +static void +destroyGlyphData(struct glyph ** const glyph, + PM_WCHAR const maxglyph) { +/*---------------------------------------------------------------------------- + Free glyph objects and bitmap objects. + + This does not work when an object is "shared" through multiple pointers + referencing an identical address and thus pointing to a common glyph + or bitmap object. +-----------------------------------------------------------------------------*/ + + PM_WCHAR i; + + for(i = 0; i <= maxglyph; ++i) { + if (glyph[i]!=NULL) { + free((void *) (glyph[i]->bmap)); + free(glyph[i]); + } + } +} + + +void +pbm_destroybdffont2_base(struct font2 * const font2P) { +/*---------------------------------------------------------------------------- + Free font2 structure, but not the glyph data +---------------------------------------------------------------------------- */ + + free(font2P->selector); + + free(font2P->name); + free(font2P->charset_string); + free(font2P->glyph); + + if (font2P->oldfont !=NULL) + pbm_freearray(font2P->oldfont, font2P->frows); + + free((void *)font2P); + +} + + + +void +pbm_destroybdffont2(struct font2 * const font2P) { +/*---------------------------------------------------------------------------- + Free font2 structure and glyph data + + Examines the 'load_fn' field to check whether the object is fixed data. + Do nothing if 'load_fn' is 'FIXED_DATA'. +---------------------------------------------------------------------------- */ + + if (font2P->load_fn != FIXED_DATA) { + destroyGlyphData(font2P->glyph, font2P->maxglyph); + pbm_destroybdffont2_base(font2P); + } +} + + + +void +pbm_destroybdffont(struct font * const fontP) { +/*---------------------------------------------------------------------------- + Free font structure and glyph data. + + For freeing a structure created by pbm_loadbdffont() or pbm_loadpbmfont(). +---------------------------------------------------------------------------- */ + + destroyGlyphData(fontP->glyph, PM_FONT_MAXGLYPH); + + if (fontP->oldfont !=NULL) + pbm_freearray(fontP->oldfont, fontP->frows); + + free(fontP); +} + + + +struct font2 * +pbm_expandbdffont(const struct font * const fontP) { +/*---------------------------------------------------------------------------- + Convert a traditional 'font' structure into an expanded 'font2' structure. + + After calling this function *fontP may be freed, but not the individual + glyph data: fontP->glyph[0...255] . + + Using this function on static data is not recommended. Rather add + the extra fields to make a font2 structure. See file pbmfontdata1.c + for an example. + + The returned object is in new malloc'ed storage, in many pieces. + + Destroy with pbm_destroybdffont2() if *fontP is read from a file. + + Destroy with pbm_destroybdffont2_base() if *fontP is static data + and you desire to defy the above-stated recommendation. + + The general function for conversion in the opposite direction + 'font2' => 'font' is font2ToFont() in libpbmfont2.c . It is currently + declared as static. + ---------------------------------------------------------------------------*/ + PM_WCHAR maxglyph, codePoint; + unsigned int nCharacters; + struct font2 * font2P; + + pbm_createbdffont2_base(&font2P, PM_FONT_MAXGLYPH); + + font2P->maxwidth = fontP->maxwidth; + font2P->maxheight = fontP->maxheight; + + font2P->x = fontP->x; + font2P->y = fontP->y; + + /* Hunt for max non-NULL entry in glyph table */ + for (codePoint = PM_FONT_MAXGLYPH; + fontP->glyph[codePoint] == NULL && codePoint > 0; --codePoint) + ; + + maxglyph = font2P->maxglyph = codePoint; + assert (0 <= maxglyph && maxglyph <= PM_FONT_MAXGLYPH); + + if (maxglyph == 0 && fontP->glyph[0] == NULL) + pm_error("no glyphs loaded"); + + REALLOCARRAY(font2P->glyph, font2P->maxglyph + 1); + + for (codePoint = 0; codePoint <= maxglyph; ++codePoint) { + font2P->glyph[codePoint] = fontP->glyph[codePoint]; + + if (font2P->glyph[codePoint] != NULL) + ++nCharacters; + } + + font2P->oldfont = fontP->oldfont; + font2P->fcols = fontP->fcols; + font2P->frows = fontP->frows; + + font2P->bit_format = PBM_FORMAT; + font2P->total_chars = font2P->chars = nCharacters; + font2P->load_fn = CONVERTED_TYPE1_FONT; + /* Caller should be overwrite the above to a more descriptive + value */ + return font2P; +} + + + diff --git a/lib/libpbmfont1.c b/lib/libpbmfont1.c new file mode 100644 index 00000000..2b0993a9 --- /dev/null +++ b/lib/libpbmfont1.c @@ -0,0 +1,359 @@ +/* +** +** Routines for loading a PBM sheet font file +** +** Copyright (C) 1991 by Jef Poskanzer. +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +*/ + +#include +#include + +#include "netpbm/pm_c_util.h" +#include "netpbm/mallocvar.h" +#include "netpbm/nstring.h" + +#include "pbm.h" +#include "pbmfont.h" + + +/*---------------------------------------------------------------------------- + + The routines in this file reads a font bitmap representing + the following text: + + (0,0) + M ",/^_[`jpqy| M + + / !"#$%&'()*+ / + < ,-./01234567 < + > 89:;<=>?@ABC > + @ DEFGHIJKLMNO @ + _ PQRSTUVWXYZ[ _ + { \]^_`abcdefg { + } hijklmnopqrs } + ~ tuvwxyz{|}~ ~ + + M ",/^_[`jpqy| M + + The bitmap must be cropped exactly to the edges. + + The characters in the border you see are irrelevant except for + character size compuations. The 12 x 8 array in the center is + the font. The top left character there belongs to code point + 0, and the code points increase in standard reading order, so + the bottom right character is code point 127. You can't define + code points < 32 or > 127 with this font format. + + The characters in the top and bottom border rows must include a + character with the lowest reach of any in the font (e.g. "y", + "_") and one with the highest reach (e.g. '"'). The characters + in the left and right border columns must include characters + with the rightmost and leftmost reach of any in the font + (e.g. "M" for both). + + The border must be separated from the font by one blank text + row or text column. +-----------------------------------------------------------------------------*/ + + +static unsigned int const firstCodePoint = 32; + /* This is the code point of the first character in a pbmfont font. + In ASCII, it is a space. + */ + +static unsigned int const nCharsInFont = 96; + /* The number of characters in a pbmfont font. A pbmfont font defines + characters at position 32 (ASCII space) through 127, so that's 96. + */ + + +static void +findFirstBlankRow(const bit ** const font, + unsigned int const fcols, + unsigned int const frows, + unsigned int * const browP) { + + unsigned int row; + bool foundBlank; + + for (row = 0, foundBlank = false; row < frows / 6 && !foundBlank; ++row) { + unsigned int col; + bit col0Value = font[row][0]; + bool rowIsBlank; + rowIsBlank = true; /* initial assumption */ + for (col = 1; col < fcols; ++col) + if (font[row][col] != col0Value) + rowIsBlank = false; + + if (rowIsBlank) { + foundBlank = true; + *browP = row; + } + } + + if (!foundBlank) + pm_error("couldn't find blank pixel row in font"); +} + + + +static void +findFirstBlankCol(const bit ** const font, + unsigned int const fcols, + unsigned int const frows, + unsigned int * const bcolP) { + + unsigned int col; + bool foundBlank; + + for (col = 0, foundBlank = false; col < fcols / 6 && !foundBlank; ++col) { + unsigned int row; + bit row0Value = font[0][col]; + bool colIsBlank; + colIsBlank = true; /* initial assumption */ + for (row = 1; row < frows; ++row) + if (font[row][col] != row0Value) + colIsBlank = false; + + if (colIsBlank) { + foundBlank = true; + *bcolP = col; + } + } + + if (!foundBlank) + pm_error("couldn't find blank pixel column in font"); +} + + + +static void +computeCharacterSize(const bit ** const font, + unsigned int const fcols, + unsigned int const frows, + unsigned int * const cellWidthP, + unsigned int * const cellHeightP, + unsigned int * const charWidthP, + unsigned int * const charHeightP) { + + unsigned int firstBlankRow; + unsigned int firstBlankCol; + unsigned int heightLast11Rows; + + findFirstBlankRow(font, fcols, frows, &firstBlankRow); + + findFirstBlankCol(font, fcols, frows, &firstBlankCol); + + heightLast11Rows = frows - firstBlankRow; + + if (heightLast11Rows % 11 != 0) + pm_error("The rows of characters in the font do not appear to " + "be all the same height. The last 11 rows are %u pixel " + "rows high (from pixel row %u up to %u), " + "which is not a multiple of 11.", + heightLast11Rows, firstBlankRow, frows); + else { + unsigned int widthLast15Cols; + + *cellHeightP = heightLast11Rows / 11; + + widthLast15Cols = fcols - firstBlankCol; + + if (widthLast15Cols % 15 != 0) + pm_error("The columns of characters in the font do not appear to " + "be all the same width. " + "The last 15 columns are %u pixel " + "columns wide (from pixel col %u up to %u), " + "which is not a multiple of 15.", + widthLast15Cols, firstBlankCol, fcols); + else { + *cellWidthP = widthLast15Cols / 15; + + *charWidthP = firstBlankCol; + *charHeightP = firstBlankRow; + } + } +} + + + +struct font* +pbm_dissectfont(const bit ** const fontsheet, + unsigned int const frows, + unsigned int const fcols) { +/*---------------------------------------------------------------------------- + Dissect PBM sheet font data, create a font structre, + load bitmap data into it. + + Return value is a pointer to the newly created font structure + + The input bitmap data is in memory, in one byte per pixel format. + + The dissection works by finding the first blank row and column; + i.e the lower right corner of the "M" in the upper left corner + of the matrix. That gives the height and width of the + maximum-sized character, which is not too useful. But the + distance from there to the opposite side is an integral + multiple of the cell size, and that's what we need. Then it's + just a matter of filling in all the coordinates. + + Struct font has fields 'oldfont', 'fcols', 'frows' for backward + compability. If there is any need to load data stored in this format + feed the above three, in order, as arguments to this function: + + pbm_dissectfont(oldfont, fcols, frows); + ----------------------------------------------------------------------------*/ + + unsigned int cellWidth, cellHeight; + /* Dimensions in pixels of each cell of the font -- that + includes the glyph and the white space above and to the + right of it. Each cell is a tile of the font image. The + top character row and left character row don't count -- + those cells are smaller because they are missing the white + space. + */ + unsigned int charWidth, charHeight; + /* Maximum dimensions of glyph itself, inside its cell */ + + int row, col, ch, r, c, i; + struct font * fn; + + computeCharacterSize(fontsheet, fcols, frows, + &cellWidth, &cellHeight, &charWidth, &charHeight); + + /* Now convert to a general font */ + + MALLOCVAR(fn); + if (fn == NULL) + pm_error("out of memory allocating font structure"); + + fn->maxwidth = charWidth; + fn->maxheight = charHeight; + fn->x = fn->y = 0; + + fn->oldfont = fontsheet; + fn->frows = frows; + fn->fcols = fcols; + + /* Now fill in the 0,0 coords. */ + row = cellHeight * 2; + col = cellWidth * 2; + + /* Load individual glyphs */ + for ( ch = 0; ch < nCharsInFont; ++ch ) { + /* Allocate memory separately for each glyph. + pbm_loadbdffont2() does this in exactly the same manner. + */ + struct glyph * const glyph = + (struct glyph *) malloc (sizeof (struct glyph)); + char * const bmap = (char*) malloc(fn->maxwidth * fn->maxheight); + + if ( bmap == NULL || glyph == NULL ) + pm_error( "out of memory allocating glyph data" ); + + glyph->width = fn->maxwidth; + glyph->height = fn->maxheight; + glyph->x = glyph->y = 0; + glyph->xadd = cellWidth; + + for ( r = 0; r < glyph->height; ++r ) + for ( c = 0; c < glyph->width; ++c ) + bmap[r * glyph->width + c] = fontsheet[row + r][col + c]; + + glyph->bmap = bmap; + fn->glyph[firstCodePoint + ch] = glyph; + + col += cellWidth; + if ( col >= cellWidth * 14 ) { + col = cellWidth * 2; + row += cellHeight; + } + } + + /* Initialize all remaining character positions to "undefined." */ + for (i = 0; i < firstCodePoint; ++i) + fn->glyph[i] = NULL; + + for (i = firstCodePoint + nCharsInFont; i <= PM_FONT_MAXGLYPH; ++i) + fn->glyph[i] = NULL; + + return fn; +} + + + + +struct font * +pbm_loadpbmfont(const char * const filename) { +/*---------------------------------------------------------------------------- + Read PBM font sheet data from file 'filename'. + Load data into font structure. + + When done with object, free with pbm_destroybdffont(). +-----------------------------------------------------------------------------*/ + + FILE * ifP; + bit ** fontsheet; + int fcols, frows; + struct font * retval; + + ifP = pm_openr(filename); + + fontsheet = pbm_readpbm(ifP, &fcols, &frows); + + if ((fcols - 1) / 16 >= pbm_maxfontwidth() || + (frows - 1) / 12 >= pbm_maxfontheight()) + pm_error("Absurdly large PBM font file: %s", filename); + else if (fcols < 31 || frows < 23) { + /* Need at least one pixel per character, and this is too small to + have that. + */ + pm_error("PBM font file '%s' too small to be a font file: %u x %u. " + "Minimum sensible size is 31 x 23", + filename, fcols, frows); + } + + pm_close(ifP); + + retval = pbm_dissectfont((const bit **)fontsheet, frows, fcols); + return (retval); + +} + + + +struct font2 * +pbm_loadpbmfont2(const char * const filename) { +/*---------------------------------------------------------------------------- + Like pbm_loadpbmfont, but return a pointer to struct font2. + + When done with object, free with pbm_destroybdffont2(). +-----------------------------------------------------------------------------*/ + + const struct font * const pbmfont = pbm_loadpbmfont(filename); + struct font2 * const retval = pbm_expandbdffont(pbmfont); + + free ((void *)pbmfont); + + /* Overwrite some fields */ + + retval->load_fn = LOAD_PBMSHEET; + retval->default_char = (PM_WCHAR) ' '; + retval->default_char_defined = TRUE; + retval->name = strdup("(PBM sheet font has no name)"); + retval->charset = ISO646_1991_IRV; + retval->charset_string = strdup("ASCII"); + retval->total_chars = retval->chars = nCharsInFont; + + return(retval); +} + + + diff --git a/lib/libpbmfont2.c b/lib/libpbmfont2.c new file mode 100644 index 00000000..993015a2 --- /dev/null +++ b/lib/libpbmfont2.c @@ -0,0 +1,995 @@ +/* +** +** Font routines. +** +** BDF font code by George Phillips, copyright 1993 +** +** Wide character stuff written by Akira Urushibata, copyright 2018 +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +** +** BDF font specs available from: +** https://partners.adobe.com/public/developer/en/font/5005.BDF_Spec.pdf +** Glyph Bitmap Distribution Format (BDF) Specification +** Version 2.2 +** 22 March 1993 +** Adobe Developer Support +*/ + +#include +#include + +#include "netpbm/pm_c_util.h" +#include "netpbm/mallocvar.h" +#include "netpbm/nstring.h" + +#include "pbmfont.h" +#include "pbm.h" + +/*---------------------------------------------------------------------------- + Routines for loading a BDF font file +-----------------------------------------------------------------------------*/ + +/* The following are not recognized in individual glyph data; library + routines do a pm_error if they see one: + + Vertical writing systems: DWIDTH1, SWIDTH1, VVECTOR, METRICSET, + CONTENTVERSION. + + The following is not recognized and is thus ignored at the global level: + DWIDTH +*/ + + +#define MAXBDFLINE 1024 + +/* Official Adobe document says max length of string is 65535 characters. + However the value 1024 is sufficient for practical uses. +*/ + +typedef struct { +/*---------------------------------------------------------------------------- + This is an object for reading lines of a font file. It reads and tokenizes + them into words. +-----------------------------------------------------------------------------*/ + FILE * ifP; + + char line[MAXBDFLINE+1]; + /* This is the storage space for the words of the line. The + words go in here, one after another, separated by NULs. + + It also functions as a work area for readline_read(). + */ + const char * arg[7]; + /* These are the words; each entry is a pointer into line[] (above) */ + + unsigned int wordCt; +} Readline; + + + +static void +readline_init(Readline * const readlineP, + FILE * const ifP) { + + readlineP->ifP = ifP; + + readlineP->arg[0] = NULL; + readlineP->wordCt = 0; +} + + + +static void +tokenize(char * const s, + const char ** const words, + unsigned int const wordsSz, + unsigned int * const wordCtP) { +/*---------------------------------------------------------------------------- + Chop up 's' into words by changing space characters to NUL. Return as + 'words' an array of pointers to the beginnings of those words in 's'. + Terminate the words[] list with a null pointer. + + 'wordsSz' is the number of elements of space in 'words'. If there are more + words in 's' than will fit in that space (including the terminating null + pointer), ignore the excess on the right. + + '*wordCtP' is the number elements actually found. +-----------------------------------------------------------------------------*/ + unsigned int n; /* Number of words in words[] so far */ + char * p; + + p = &s[0]; + n = 0; + + while (*p) { + if (!ISGRAPH(*p)) { + if(!ISSPACE(*p)) { + /* Control chars excluding 09 - 0d (space), 80-ff */ + pm_message("Warning: non-ASCII character '%x' in " + "BDF font file", *p); + } + *p++ = '\0'; + } + else { + words[n++] = p; + if (n >= wordsSz - 1) + break; + while (*p && ISGRAPH(*p)) + ++p; + } + } + assert(n <= wordsSz - 1); + words[n] = NULL; + *wordCtP = n; +} + + + +static void +readline_read(Readline * const readlineP, + bool * const eofP) { +/*---------------------------------------------------------------------------- + Read a nonblank line from the file. Make its contents available + as readlineP->arg[]. + + Return *eofP == true iff there is no nonblank line before EOF or we + are unable to read the file. +-----------------------------------------------------------------------------*/ + bool gotLine; + bool error; + + for (gotLine = false, error = false; !gotLine && !error; ) { + char * rc; + + rc = fgets(readlineP->line, MAXBDFLINE+1, readlineP->ifP); + if (rc == NULL) + error = true; + else { + tokenize(readlineP->line, readlineP->arg, + ARRAY_SIZE(readlineP->arg), &readlineP->wordCt); + if (readlineP->arg[0] != NULL) + gotLine = true; + } + } + *eofP = error; +} + + + +static void +parseBitmapRow(const char * const hex, + unsigned int const glyphWidth, + unsigned char * const bmap, + unsigned int const origBmapIndex, + unsigned int * const newBmapIndexP, + const char ** const errorP) { +/*---------------------------------------------------------------------------- + Parse one row of the bitmap for a glyph, from the hexadecimal string + for that row in the font file, 'hex'. The glyph is 'glyphWidth' + pixels wide. + + We place our result in 'bmap' at *bmapIndexP and advanced *bmapIndexP. +-----------------------------------------------------------------------------*/ + unsigned int bmapIndex; + int i; /* dot counter */ + const char * p; + + bmapIndex = origBmapIndex; + + for (i = glyphWidth, p = &hex[0], *errorP = NULL; + i > 0 && !*errorP; + i -= 4) { + + if (*p == '\0') + pm_asprintf(errorP, "Not enough hexadecimal digits for glyph " + "of width %u in '%s'", + glyphWidth, hex); + else { + char const hdig = *p++; + unsigned int hdigValue; + + 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_asprintf(errorP, + "Invalid hex digit x%02x (%c) in bitmap data '%s'", + (unsigned int)(unsigned char)hdig, + isprint(hdig) ? hdig : '.', + hex); + + if (!*errorP) { + 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; + } + } + } + *newBmapIndexP = bmapIndex; +} + + + +static void +readBitmap(Readline * const readlineP, + 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) { + bool eof; + const char * error; + + readline_read(readlineP, &eof); + + if (eof) + pm_error("End of file in bitmap for character '%s' in BDF " + "font file.", charName); + + if (!readlineP->arg[0]) + pm_error("A line that is supposed to contain bitmap data, " + "in hexadecimal, for character '%s' is empty", charName); + + parseBitmapRow(readlineP->arg[0], glyphWidth, bmap, bmapIndex, + &bmapIndex, &error); + + if (error) { + pm_error("Error in line %d of bitmap for character '%s': %s", + n, charName, error); + pm_strfree(error); + } + } +} + + + +static void +createBmap(unsigned int const glyphWidth, + unsigned int const glyphHeight, + Readline * const readlineP, + const char * const charName, + const char ** const bmapP) { + + unsigned char * bmap; + bool eof; + + if (glyphWidth > 0 && UINT_MAX / glyphWidth < glyphHeight) + pm_error("Ridiculously large glyph"); + + MALLOCARRAY(bmap, glyphWidth * glyphHeight); + + if (!bmap) + pm_error("no memory for font glyph byte map"); + + readline_read(readlineP, &eof); + if (eof) + pm_error("End of file encountered reading font glyph byte map from " + "BDF font file."); + + if (streq(readlineP->arg[0], "ATTRIBUTES")) { + /* ATTRIBUTES is defined in Glyph Bitmap Distribution Format (BDF) + Specification Version 2.1, but not in Version 2.2. + */ + bool eof; + readline_read(readlineP, &eof); + if (eof) + pm_error("End of file encountered after ATTRIBUTES in BDF " + "font file."); + } + if (!streq(readlineP->arg[0], "BITMAP")) + pm_error("'%s' found where BITMAP expected in definition of " + "character '%s' in BDF font file.", + readlineP->arg[0], charName); + + assert(streq(readlineP->arg[0], "BITMAP")); + + readBitmap(readlineP, glyphWidth, glyphHeight, charName, bmap); + + *bmapP = (char *)bmap; +} + + + +static void +validateWordCount(Readline * const readlineP, + unsigned int const nWords) { + + if( readlineP->wordCt != nWords ) + pm_error("Wrong number of arguments in '%s' line in BDF font file", + readlineP->arg[0]); + + /* We assume that the first word in line 'arg[0]' is a valid string */ + +} + + +static void +readExpectedStatement(Readline * const readlineP, + const char * const expected, + unsigned int const nWords) { +/*---------------------------------------------------------------------------- + Have the readline object *readlineP read the next line from the file, but + expect it to be a line of type 'expected' (i.e. the verb token at the + beginning of the line is that, e.g. "STARTFONT"). Check for the number + of words: 'nWords'. If either condition is not met, fail the program. +-----------------------------------------------------------------------------*/ + + bool eof; + + readline_read(readlineP, &eof); + + if (eof) + pm_error("EOF in BDF font file where '%s' expected", expected); + else if (!streq(readlineP->arg[0], expected)) + pm_error("Statement of type '%s' where '%s' expected in BDF font file", + readlineP->arg[0], expected); + + validateWordCount(readlineP, nWords); + +} + + + +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. +-----------------------------------------------------------------------------*/ + bool endChar; + + endChar = FALSE; + + 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"); + } +} + + + +static int +wordToInt(const char * const word) { + + unsigned int absValue; + + int retval; + + const char * error; + const int sign = (word[0] == '-') ? -1 : +1; + const char * const absString = (sign == -1) ? &word[1] : word; + /* No leading spaces allowed in 'word' */ + + if (!ISDIGIT(absString[0])) + error = "Non-digit character encountered"; + + else { + pm_string_to_uint(absString, &absValue, &error); + if (error == NULL && absValue > INT_MAX) + error = "Out of range"; + } + + if (error != NULL) + pm_error ("Error reading numerical argument in " + "BDF font file: %s %s %s", error, word, absString); + + retval = sign * absValue; + assert (INT_MIN < retval && retval < INT_MAX); + + return retval; +} + + + +static void +interpEncoding(const char ** const arg, + unsigned int * const codepointP, + bool * const badCodepointP, + PM_WCHAR const maxmaxglyph) { +/*---------------------------------------------------------------------------- + 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. + + 'maxmaxglyph' is the maximum codepoint in the font. +-----------------------------------------------------------------------------*/ + bool gotCodepoint; + bool badCodepoint; + unsigned int codepoint; + + if (wordToInt(arg[1]) >= 0) { + 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 (gotCodepoint) { + if (codepoint > maxmaxglyph) + badCodepoint = true; + else + badCodepoint = false; + } else + badCodepoint = true; + + *badCodepointP = badCodepoint; + *codepointP = codepoint; +} + + + +static void +readEncoding(Readline * const readlineP, + unsigned int * const codepointP, + bool * const badCodepointP, + PM_WCHAR const maxmaxglyph) { + + bool eof; + const char * expected = "ENCODING"; + + readline_read(readlineP, &eof); + + if (eof) + pm_error("EOF in BDF font file where '%s' expected", expected); + else if (!streq(readlineP->arg[0], expected)) + pm_error("Statement of type '%s' where '%s' expected in BDF font file", + readlineP->arg[0], expected); + else if(readlineP->wordCt != 2 && readlineP->wordCt != 3) + pm_error("Wrong number of arguments in '%s' line in BDF font file", + readlineP->arg[0]); + + interpEncoding(readlineP->arg, codepointP, badCodepointP, maxmaxglyph); +} + + + +static void +validateFontLimits(const struct font2 * const font2P) { + + assert(pbm_maxfontheight() > 0 && pbm_maxfontwidth() > 0); + + if (font2P->maxwidth <= 0 || + font2P->maxheight <= 0 || + font2P->maxwidth > pbm_maxfontwidth() || + font2P->maxheight > pbm_maxfontheight() || + -font2P->x + 1 > font2P->maxwidth || + -font2P->y + 1 > font2P->maxheight || + font2P->x > font2P->maxwidth || + font2P->y > font2P->maxheight || + font2P->x + font2P->maxwidth > pbm_maxfontwidth() || + font2P->y + font2P->maxheight > pbm_maxfontheight() + ) { + + pm_error("Global font metric(s) out of bounds."); + } + + if (font2P->maxglyph > PM_FONT2_MAXGLYPH) + pm_error("Internal error. Glyph table too large: %u glyphs; " + "Maximum possible in Netpbm is %u", + (unsigned int) font2P->maxglyph, PM_FONT2_MAXGLYPH); +} + + + +static void +validateGlyphLimits(const struct font2 * const font2P, + const struct glyph * const glyphP, + const char * const charName) { + + /* Some BDF files code space with zero width and height, + no bitmap data and just the xadd value. + We allow zero width and height, iff both are zero. + + Some BDF files have individual glyphs with a BBX value which + exceeds the global maximum stated by FONTBOUNDINGBOX. + Abort with error when this is encountered. + It seems some programs including emacs and bdftopcf tolerate + this violation. + */ + + if (((glyphP->width == 0 || glyphP->height == 0) && + !(glyphP->width == 0 && glyphP->height == 0)) || + glyphP->width > font2P->maxwidth || + glyphP->height > font2P->maxheight || + glyphP->x < font2P->x || + glyphP->y < font2P->y || + glyphP->x + (int) glyphP->width > font2P->x + font2P->maxwidth || + glyphP->y + (int) glyphP->height > font2P->y + font2P->maxheight || + glyphP->xadd > pbm_maxfontwidth() || + glyphP->xadd + MAX(glyphP->x,0) + (int) glyphP->width > + pbm_maxfontwidth() + ) { + + pm_error("Font metric(s) for char '%s' out of bounds.\n", charName); + } +} + + + +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 = 0; /* Initial value */ + unsigned int nCharsValid = 0; /* Initial value */ + + while (nCharsDone < nCharacters) { + 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")) { + /* ignore */ + } else 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"); + /* Character name may contain spaces: there may be more than + three words in the line. + */ + charName = pm_strdup(readlineP->arg[1]); + + assert(streq(readlineP->arg[0], "STARTCHAR")); + + MALLOCVAR(glyphP); + + if (glyphP == NULL) + pm_error("no memory for font glyph for '%s' character", + charName); + + readEncoding(readlineP, &codepoint, &badCodepoint, + font2P->maxmaxglyph); + + 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; + + for (i = oldMaxglyph + 1; i < newMaxglyph; ++i) + font2P->glyph[i] = NULL; + + font2P->maxglyph = newMaxglyph; + } + + readExpectedStatement(readlineP, "SWIDTH", 3); + + readExpectedStatement(readlineP, "DWIDTH", 3); + glyphP->xadd = wordToInt(readlineP->arg[1]); + + 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]); + + validateGlyphLimits(font2P, glyphP, charName); + + createBmap(glyphP->width, glyphP->height, readlineP, charName, + &glyphP->bmap); + + readExpectedStatement(readlineP, "ENDCHAR", 1); + + assert(codepoint <= font2P->maxmaxglyph); + /* Ensured by readEncoding() */ + + font2P->glyph[codepoint] = glyphP; + pm_strfree(charName); + + ++nCharsValid; + } + ++nCharsDone; + } + } + font2P->chars = nCharsValid; + font2P->total_chars = nCharacters; +} + + + +static void +processBdfFontNameLine(Readline * const readlineP, + struct font2 * const font2P) { + + if (font2P->name != NULL) + pm_error("Multiple FONT lines in BDF font file"); + + font2P->name = malloc (MAXBDFLINE+1); + if (font2P->name == NULL) + pm_error("No memory for font name"); + + if (readlineP->wordCt == 1) + strcpy(font2P->name, "(no name)"); + + else { + unsigned int tokenCt; + + font2P->name[0] ='\0'; + + for (tokenCt=1; + tokenCt < ARRAY_SIZE(readlineP->arg) && + readlineP->arg[tokenCt] != NULL; ++tokenCt) { + strcat(font2P->name, " "); + strcat(font2P->name, readlineP->arg[tokenCt]); + } + } +} + + +static void +loadCharsetString(char * const registry, + char * const encoding, + char ** const string) { + + unsigned int inCt, outCt; + char * const dest = malloc (strlen(registry) + strlen(encoding) + 1); + if (dest == NULL) + pm_error("no memory to load CHARSET_REGISTRY and CHARSET_ENCODING " + "from BDF file"); + + for (inCt = outCt = 0; inCt < strlen(registry); ++inCt) { + char const c = registry[inCt]; + if (isgraph(c) && c != '"') + dest[outCt++] = c; + } + dest[outCt++] = '-'; + + for (inCt = 0; inCt < strlen(encoding); ++inCt) { + char const c = encoding[inCt]; + if (isgraph(c) && c != '"') + dest[outCt++] = c; + } + + dest[outCt] = '\0'; + *string = dest; +} + + + +static void +processBdfPropertyLine(Readline * const readlineP, + struct font2 * const font2P) { + + char * registry; + char * encoding; + unsigned int propTotal; + bool gotRegistry = FALSE; /* Initial value */ + bool gotEncoding = FALSE; /* Initial value */ + PM_WCHAR defaultChar = 0; /* Initial value */ + bool gotDefaultchar = FALSE; /* Initial value */ + unsigned int propCt = 0; /* Initial value */ + unsigned int commentCt = 0; /* Initial value */ + unsigned int const maxTokenLen = 60; + + validateWordCount(readlineP, 2); /* STARTPROPERTIES n */ + + propTotal = wordToInt(readlineP->arg[1]); + + do { + bool eof; + + readline_read(readlineP, &eof); + if (eof) + pm_error("End of file after STARTPROPERTIES in BDF font file"); + else if (streq(readlineP->arg[0], "CHARSET_REGISTRY")) { + if (gotRegistry) + pm_error("Multiple CHARSET_REGISTRY lines in BDF font file"); + else if (readlineP->arg[2] != NULL) + pm_message("CHARSET_REGISTRY in BDF font file is not " + "a single word. Ignoring extra element(s) %s ...", + readlineP->arg[2]); + else if (strlen(readlineP->arg[1]) > maxTokenLen) + pm_message("CHARSET_REGISTRY in BDF font file is too long. " + "Truncating"); + + registry = strndup (readlineP->arg[1], maxTokenLen); + gotRegistry = TRUE; + } + else if (streq(readlineP->arg[0], "CHARSET_ENCODING")) { + if (gotEncoding) + pm_error("Multiple CHARSET_ENCODING lines in BDF font file"); + else if (readlineP->arg[2] != NULL) + pm_message("CHARSET_ENCODING in BDF font file is not " + "a single word. Ignoring extra element(s) %s ...", + readlineP->arg[2]); + else if (strlen(readlineP->arg[1]) > maxTokenLen) + pm_message("CHARSET_ENCODING in BDF font file is too long. " + "Truncating"); + + encoding = strndup (readlineP->arg[1], maxTokenLen); + gotEncoding = TRUE; + } + else if (streq(readlineP->arg[0], "DEFAULT_CHAR")) { + if (gotDefaultchar) + pm_error("Multiple DEFAULT_CHAR lines in BDF font file"); + else if (readlineP->arg[1] == NULL) + pm_error("Malformed DEFAULT_CHAR lines in BDF font file"); + else { + defaultChar = (PM_WCHAR) wordToInt(readlineP->arg[1]); + gotDefaultchar = TRUE; + } + } + else if (streq(readlineP->arg[0], "COMMENT")) { + commentCt++; + } + propCt++; + + } while (!streq(readlineP->arg[0], "ENDPROPERTIES")); + + --propCt; /* Subtract one for ENDPROPERTIES line */ + + if (propCt != propTotal && propCt - commentCt != propTotal) + /* Some BDF files have COMMENTs in the property section and leave + them out of the count. + Others just give a wrong count. + */ + pm_message ("Note: wrong number of property lines in BDF font file. " + "STARTPROPERTIES line says %u, actual count: %u. " + "Proceeding.", + propTotal, propCt); + + + if (gotRegistry && gotEncoding) + loadCharsetString(registry, encoding, &font2P->charset_string); + else if (gotRegistry != gotEncoding) { + pm_message ("CHARSET_%s absent in BDF font file. " + "Ignoring CHARSET_%s.", + gotEncoding ? "REGISTRY" : "ENCODING", + gotEncoding ? "ENCODING" : "REGISTRY"); + } + free(registry); free(encoding); + + if (gotDefaultchar) { + font2P->default_char = defaultChar; + font2P->default_char_defined = TRUE; + } + +} + + +static void +processBdfFontLine(Readline * const readlineP, + struct font2 * const font2P, + bool * const endOfFontP) { +/*---------------------------------------------------------------------------- + Process a nonblank line just read from a BDF font file. + + This processing may involve reading more lines. +-----------------------------------------------------------------------------*/ + *endOfFontP = FALSE; /* initial assumption */ + + assert(readlineP->arg[0] != NULL); /* Entry condition */ + + if (streq(readlineP->arg[0], "FONT")) { + processBdfFontNameLine(readlineP, font2P); + } else if (streq(readlineP->arg[0], "COMMENT")) { + /* ignore */ + } else if (streq(readlineP->arg[0], "SIZE")) { + /* ignore */ + } else if (streq(readlineP->arg[0], "STARTPROPERTIES")) { + if (font2P->maxwidth == 0) + pm_error("Encountered STARTROPERTIES before FONTBOUNDINGBOX " + "in BDF font file"); + else + processBdfPropertyLine(readlineP, font2P); + } else if (streq(readlineP->arg[0], "FONTBOUNDINGBOX")) { + validateWordCount(readlineP,5); + + font2P->maxwidth = wordToInt(readlineP->arg[1]); + font2P->maxheight = wordToInt(readlineP->arg[2]); + font2P->x = wordToInt(readlineP->arg[3]); + font2P->y = wordToInt(readlineP->arg[4]); + validateFontLimits(font2P); + } else if (streq(readlineP->arg[0], "ENDFONT")) { + *endOfFontP = true; + } else if (streq(readlineP->arg[0], "CHARS")) { + if (font2P->maxwidth == 0) + pm_error("Encountered CHARS before FONTBOUNDINGBOX " + "in BDF font file"); + else { + validateWordCount(readlineP, 2); /* CHARS n */ + processChars(readlineP, font2P); + } + } else { + /* ignore */ + } + +} + + + +struct font2 * +pbm_loadbdffont2(const char * const filename, + PM_WCHAR const maxmaxglyph) { +/*---------------------------------------------------------------------------- + Read a BDF font file "filename" as a 'font2' structure. A 'font2' + structure is more expressive than a 'font' structure, most notably in that + it can handle wide code points and many more glyphs. + + Codepoints up to maxmaxglyph inclusive are valid in the file. + + The returned object is in new malloc'ed storage, in many pieces. + When done with, destroy with pbm_destroybdffont2(). +-----------------------------------------------------------------------------*/ + + FILE * ifP; + Readline readline; + struct font2 * font2P; + bool endOfFont; + + ifP = fopen(filename, "rb"); + if (!ifP) + pm_error("Unable to open BDF font file name '%s'. errno=%d (%s)", + filename, errno, strerror(errno)); + + readline_init(&readline, ifP); + + pbm_createbdffont2_base(&font2P, maxmaxglyph); + + font2P->maxglyph = 0; + /* Initial value. Increases as new characters are loaded */ + font2P->glyph[0] = NULL; + /* Initial value. Overwrite later if codepoint 0 is defined. */ + + font2P->maxmaxglyph = maxmaxglyph; + + /* Initialize some values - to be overwritten if actual values are + stated in BDF file */ + font2P->maxwidth = font2P->maxheight = font2P->x = font2P->y = 0; + font2P->name = font2P->charset_string = NULL; + font2P->chars = font2P->total_chars = 0; + font2P->default_char = 0; + font2P->default_char_defined = FALSE; + + readExpectedStatement(&readline, "STARTFONT", 2); + + endOfFont = FALSE; + + while (!endOfFont) { + bool eof; + readline_read(&readline, &eof); + if (eof) + pm_error("End of file before ENDFONT statement in BDF font file"); + + processBdfFontLine(&readline, font2P, &endOfFont); + } + fclose(ifP); + + if(font2P->chars == 0) + pm_error("No glyphs found in BDF font file " + "in codepoint range 0 - %u", (unsigned int) maxmaxglyph); + + REALLOCARRAY(font2P->glyph, font2P->maxglyph + 1); + + font2P->bit_format = PBM_FORMAT; + font2P->load_fn = LOAD_BDFFILE; + font2P->charset = ENCODING_UNKNOWN; + font2P->oldfont = NULL; /* Legacy field */ + font2P->fcols = font2P->frows = 0; /* Legacy fields */ + + return font2P; +} + + +static struct font * +font2ToFont(const struct font2 * const font2P) { + struct font * fontP; + unsigned int codePoint; + + MALLOCVAR(fontP); + if (fontP == NULL) + pm_error("no memory for font"); + + fontP->maxwidth = font2P->maxwidth; + fontP->maxheight = font2P->maxheight; + + 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; + + /* Give values to legacy fields */ + fontP->oldfont = font2P->oldfont; + fontP->fcols = font2P->fcols; + fontP->frows = font2P->frows; + + return fontP; +} + + + +struct font * +pbm_loadbdffont(const char * const filename) { +/*---------------------------------------------------------------------------- + Read a BDF font file "filename" into a traditional font structure. + + Codepoints up to 255 (PM_FONT_MAXGLYPH) are valid. + + Can handle ASCII, ISO-8859-1, ISO-8859-2, ISO-8859-15, etc. + + The returned object is in new malloc'ed storage, in many pieces. + Destroy with pbm_destroybdffont(). +-----------------------------------------------------------------------------*/ + struct font * fontP; + struct font2 * const font2P = pbm_loadbdffont2(filename, PM_FONT_MAXGLYPH); + + fontP = font2ToFont(font2P); + + /* Free the base structure which was created by pbm_loadbdffont2() */ + pbm_destroybdffont2_base(font2P); + + return fontP; +} + + + diff --git a/lib/libpbmfontdump.c b/lib/libpbmfontdump.c new file mode 100644 index 00000000..f0c950f7 --- /dev/null +++ b/lib/libpbmfontdump.c @@ -0,0 +1,96 @@ +/* +** +** Font routines. +** +** BDF font code Copyright 1993 by George Phillips. +** +** Copyright (C) 1991 by Jef Poskanzer. +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +** +** BDF font specs available from: +** https://partners.adobe.com/public/developer/en/font/5005.BDF_Spec.pdf +** Glyph Bitmap Distribution Format (BDF) Specification +** Version 2.2 +** 22 March 1993 +** Adobe Developer Support +*/ + +#include +#include +#include + +#include "netpbm/pm_c_util.h" +#include "netpbm/mallocvar.h" +#include "netpbm/nstring.h" + +#include "pbmfont.h" +#include "pbm.h" + + +void +pbm_dumpfont(struct font * const fontP, + FILE * const ofP) { +/*---------------------------------------------------------------------------- + Dump out font as C source code. +-----------------------------------------------------------------------------*/ + unsigned int i; + unsigned int ng; + + if (fontP->oldfont) + pm_message("Netpbm no longer has the capability to generate " + "a font in long hexadecimal data format"); + + for (i = 0, ng = 0; i < PM_FONT_MAXGLYPH +1; ++i) { + if (fontP->glyph[i]) + ++ng; + } + + printf("static struct glyph _g[%d] = {\n", ng); + + for (i = 0; i < PM_FONT_MAXGLYPH + 1; ++i) { + struct glyph * const glyphP = fontP->glyph[i]; + if (glyphP) { + unsigned int j; + printf(" { %d, %d, %d, %d, %d, \"", glyphP->width, glyphP->height, + glyphP->x, glyphP->y, glyphP->xadd); + + for (j = 0; j < glyphP->width * glyphP->height; ++j) { + if (glyphP->bmap[j]) + printf("\\1"); + else + printf("\\0"); + } + --ng; + printf("\" }%s\n", ng ? "," : ""); + } + } + printf("};\n"); + + printf("struct font XXX_font = { %d, %d, %d, %d, {\n", + fontP->maxwidth, fontP->maxheight, fontP->x, fontP->y); + + { + unsigned int i; + + for (i = 0; i < PM_FONT_MAXGLYPH + 1; ++i) { + if (fontP->glyph[i]) + printf(" _g + %d", ng++); + else + printf(" NULL"); + + if (i != PM_FONT_MAXGLYPH) printf(","); + printf("\n"); + } + } + + printf(" }\n};\n"); +} + + + diff --git a/lib/pbmfont.h b/lib/pbmfont.h index ad5d3acf..57f19ddc 100644 --- a/lib/pbmfont.h +++ b/lib/pbmfont.h @@ -13,11 +13,14 @@ extern "C" { /* Maximum dimensions for fonts */ -#define pbm_maxfontwidth() 65536 -#define pbm_maxfontheight() 65536 +#define pbm_maxfontwidth() 65535 +#define pbm_maxfontheight() 65535 /* These limits are not in the official Adobe BDF definition, but should never be a problem for practical purposes, considering that - a 65536 x 65536 glyph occupies 4G pixels. + a 65536 x 65536 glyph occupies 4G pixels. + + Note that the maximum line length allowed in a BDF file imposes + another restriction. */ typedef wchar_t PM_WCHAR; @@ -38,6 +41,39 @@ typedef wchar_t PM_WCHAR; As of Unicode v. 11.0.0 planes up to 16 are defined. */ +enum pbmFontLoad { FIXED_DATA = 0, + LOAD_PBMSHEET = 1, + LOAD_BDFFILE = 2, + CONVERTED_TYPE1_FONT = 9 }; + +static const char * const pbmFontOrigin[10] = + {"Fixed data", /* 0 */ + "Loaded from PBM sheet by libnetpbm", /* 1 */ + "Loaded from BDF file by libnetpbm", /* 2 */ + NULL, NULL, NULL, NULL, NULL, NULL, + "Expanded from type 1 font structure by libnetpbm"}; /* 9 */ + +enum pbmFontEncoding { ENCODING_UNKNOWN = 0, + ISO646_1991_IRV = 1, /* ASCII */ + ISO_8859_1 = 1000, ISO_8859_2, ISO_8859_3, ISO_8859_4, + ISO_8859_5, ISO_8859_6, ISO_8859_7, ISO_8859_8, + ISO_8859_9, ISO_8859_10, ISO_8859_11, ISO_8859_12, + ISO_8859_13, ISO_8859_14, ISO_8859_15, ISO_8859_16, + ISO_10646 = 2000 }; + +/* For future use */ + +/* In addition to the above, the following CHARSET_REGISTRY-CHARSET_ENCODING + values have been observed in actual BDF files: + + ADOBE-FONTSPECIFIC, DEC-DECTECH, GOST19768.74-1, IS13194-DEVANAGARI, + JISX0201.1976-0, KOI8-C, KOI8-R, MISC-FONTSPECIFIC, + MULEARABIC-0, MULEARABIC-1, MULEARABIC-2, MULEIPA-1, MULELAO-1, + OMRON_UDC_ZH-0, TIS620.2529-0, TIS620.2529-1, VISCII1-1, VISCII1.1-1, + XTIS-0 + */ + + struct glyph { /* A glyph consists of white borders and the "central glyph" which can be anything, but normally does not have white borders because @@ -69,9 +105,14 @@ struct glyph { the top half and white on the bottom, this is an array of 800 bytes, with the first 400 having value 0x01 and the last 400 having value 0x00. + + Do not share bmap objects among glyphs if using + pbm_destroybdffont() or pbm_destroybdffont2() to free + the font/font2 structure. */ }; + struct font { /* This describes a combination of font and character set. Given an code point in the range 0..255, this structure describes the @@ -86,7 +127,9 @@ struct font { this font. Can be negative. */ struct glyph * glyph[256]; - /* glyph[i] is the glyph for code point i */ + /* glyph[i] is the glyph for code point i. + Glyph objects must be unique for pbm_destroybdffont() to work. + */ const bit ** oldfont; /* for compatibility with old pbmtext routines */ /* oldfont is NULL if the font is BDF derived */ @@ -95,34 +138,162 @@ struct font { struct font2 { - /* Font structure for expanded character set. Code point is in the - range 0..maxglyph . + /* Font structure for expanded character set. + Code points in the range 0...maxmaxglyph are loaded. + Loaded code point is in the range 0..maxglyph . + */ + + /* 'size' and 'len' are necessary in order to provide forward and + backward compatibility between library functions and calling programs + as this structure grows. See struct pam in pam.h. */ + unsigned int size; + /* The storage size of this entire structure, in bytes */ + + unsigned int len; + /* The length, in bytes, of the information in this structure. + The information starts in the first byte and is contiguous. + This cannot be greater than 'size' + */ + int maxwidth, maxheight; int x; - /* The minimum value of glyph.font. The left edge of the glyph - in the glyph set which advances furthest to the left. */ + /* The minimum value of glyph.font. The left edge of the glyph in + the glyph set which advances furthest to the left. + */ int y; - /* Amount of white space that should be added between lines of - this font. Can be negative. + /* Amount of white space that should be added between lines of this + font. Can be negative. */ + struct glyph ** glyph; - /* glyph[i] is the glyph for code point i */ + /* glyph[i] is the glyph for code point i + + Glyph objects must be unique for pbm_destroybdffont2() to work. + For example space and non-break-space are often identical at the + image data level; they must be loaded into separate memory + locations if using pbm_destroybdffont2(). + */ PM_WCHAR maxglyph; - /* max code point for glyphs, including vacant slots */ + /* max code point for glyphs, including vacant slots max value of + above i + */ + + void * selector; + /* Reserved + + Bit array or structure indicating which code points to load. + + When NULL, all available code points up to maxmaxglyph, inclusive + are loaded. + */ + + PM_WCHAR maxmaxglyph; + /* Code points above this value are not loaded, even if they occur + in the BDF font file + */ const bit ** oldfont; - /* for compatibility with old pbmtext routines */ - /* oldfont is NULL if the font is BDF derived */ + /* For compatibility with old pbmtext routines. + Valid only when data is in the form of a PBM sheet + */ unsigned int fcols, frows; + /* For compatibility with old pbmtext routines. + Valid only when oldfont is non-NULL + */ + + unsigned int bit_format; + /* PBM_FORMAT: glyph data: 1 byte per pixel (like P1, but not ASCII) + RPBM_FORMAT: glyph data: 1 bit per pixel + Currently only PBM_FORMAT is possible + */ + + unsigned int total_chars; + /* Number of glyphs defined in font file, as stated in the CHARS line + of the BDF file PBM sheet font. Always 96 + */ + + unsigned int chars; + /* Number of glyphs actually loaded into structure + + Maximum: total_chars + + Less than total_chars when a subset of the file is loaded + PBM sheet font: always 96 */ + + enum pbmFontLoad load_fn; + /* Description of the function that created the structure and loaded + the glyph data + + Used to choose a string to show in verbose messages. + + FIXED_DATA (==0) means memory for this structure was not + dynamically allocated by a function; all data is hardcoded in + source code and resides in static data. See file pbmfontdata1.c + */ + + PM_WCHAR default_char; + /* Code index of what to show when there is no glyph for a requested + code Available in many BDF fonts between STARPROPERTIES - + ENDPROPERTIES. + + Set to value read from BDF font file. + + Common values are 0, 32, 8481, 32382, 33, 159, 255. + */ + + unsigned int default_char_defined; + /* boolean + TRUE: above field is valid; DEFAULT_CHAR is defined in font file. + FALSE: font file has no DEFAULT_CHAR field. + */ + + char * name; + /* Name of the font. Available in BDF fonts. + NULL means no name. + */ + + enum pbmFontEncoding charset; + /* Reserved for future use. + Set by analyzing following charset_string. + */ + + char * charset_string; + /* Charset registry and encoding. + Available in most BDF fonts between STARPROPERTIES - ENDPROPERTIES. + NULL means no name. + */ }; + +/* PBM_FONT2_STRUCT_SIZE(x) tells you how big a struct font2 is up + through the member named x. This is useful in conjunction with the + 'len' value to determine which fields are present in the structure. +*/ + +/* Some compilers are really vigilant and recognize it as an error + to cast a 64 bit address to a 32 bit type. Hence the roundabout + casting. See PAM_MEMBER_OFFSET in pam.h . +*/ + + +#define PBM_FONT2_MEMBER_OFFSET(mbrname) \ + ((size_t)(unsigned long)(char*)&((struct font2 *)0)->mbrname) +#define PBM_FONT2_MEMBER_SIZE(mbrname) \ + sizeof(((struct font2 *)0)->mbrname) +#define PBM_FONT2_STRUCT_SIZE(mbrname) \ + (PBM_FONT2_MEMBER_OFFSET(mbrname) + PBM_FONT2_MEMBER_SIZE(mbrname)) + + struct font * pbm_defaultfont(const char* const which); +struct font2 * +pbm_defaultfont2(const char* const which); + struct font * pbm_dissectfont(const bit ** const font, unsigned int const frows, @@ -131,15 +302,40 @@ pbm_dissectfont(const bit ** const font, struct font * pbm_loadfont(const char * const filename); +struct font2 * +pbm_loadfont2(const char * const filename, + PM_WCHAR const maxmaxglyph); + struct font * pbm_loadpbmfont(const char * const filename); +struct font2 * +pbm_loadpbmfont2(const char * const filename); + struct font * pbm_loadbdffont(const char * const filename); struct font2 * pbm_loadbdffont2(const char * const filename, - PM_WCHAR const maxglyph); + PM_WCHAR const maxmaxglyph); + +struct font2 * +pbm_loadbdffont2_select(const char * const filename, + PM_WCHAR const maxmaxglyph, + const void * const selector); + +void +pbm_createbdffont2_base(struct font2 ** const font2P, + PM_WCHAR const maxmaxglyph); + +void +pbm_destroybdffont(struct font * const fontP); + +void +pbm_destroybdffont2_base(struct font2 * const font2P); + +void +pbm_destroybdffont2(struct font2 * const font2P); struct font2 * pbm_expandbdffont(const struct font * const font); @@ -148,9 +344,6 @@ void pbm_dumpfont(struct font * const fontP, FILE * const ofP); -extern struct font pbm_defaultFixedfont; -extern struct font pbm_defaultBdffont; - #ifdef __cplusplus } #endif diff --git a/lib/pbmfontdata.h b/lib/pbmfontdata.h new file mode 100644 index 00000000..7ac63abc --- /dev/null +++ b/lib/pbmfontdata.h @@ -0,0 +1,7 @@ +extern struct font pbm_defaultFixedfont; +extern struct font pbm_defaultBdffont; + +extern struct font2 const pbm_defaultFixedfont2; +extern struct font2 const pbm_defaultBdffont2; + +extern struct font2 const * pbm_builtinFonts[]; diff --git a/lib/pbmfontdata0.c b/lib/pbmfontdata0.c new file mode 100644 index 00000000..dfafc317 --- /dev/null +++ b/lib/pbmfontdata0.c @@ -0,0 +1,9 @@ +#include "pbm.h" +#include "pbmfont.h" +#include "pbmfontdata.h" + +struct font2 const * pbm_builtinFonts[] = { + &pbm_defaultFixedfont2, + &pbm_defaultBdffont2, + NULL, +}; diff --git a/lib/pbmfontdata1.c b/lib/pbmfontdata1.c index 8552d29e..ab6ce28d 100644 --- a/lib/pbmfontdata1.c +++ b/lib/pbmfontdata1.c @@ -1,4 +1,5 @@ #include "pbmfont.h" +#include "pbmfontdata.h" /* Default fixed-width font All glyphs fit into a 7 x 12 rectangular cell. @@ -20,7 +21,7 @@ */ static struct glyph glFxd[96] = { -/* 32 character */ +/* 32 character */ {7,12,0,0,7,"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" }, /* 33 character ! */ {7,12,0,0,7,"\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" }, @@ -210,9 +211,9 @@ static struct glyph glFxd[96] = { {7,12,0,0,7,"\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\0\1\0\0\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0" }, /* 126 character ~ */ {7,12,0,0,7,"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\1\0\0\1\0\1\0\1\0\0\1\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" }, -/* 127 character (?) */ +/* 127 character (Control character, retained for backward compatibility) */ {7,12,0,0,7,"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" } -}; +}; @@ -246,7 +247,22 @@ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL} +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, NULL, 0, 0 +}; + +struct font2 const pbm_defaultFixedfont2 = { + sizeof(pbm_defaultFixedfont2), /* len */ + PBM_FONT2_STRUCT_SIZE(charset_string), /* size */ + 7, 12, 0, 0, /* maxwidth, maxheight, x, y */ + pbm_defaultFixedfont.glyph, /* glyph table */ + 255, NULL, 255, /* maxglyph, selector, maxmaxglyph */ + NULL, 0, 0, /* oldfont, fcols, frows */ + PBM_FORMAT, /* bit_format */ + 96, 96, /* total_chars, chars */ + FIXED_DATA, /* load_fn */ + 32, 1, /* default_char, default_char_defined */ + (char *) "builtin fixed", /* name */ + ISO646_1991_IRV, (char *)"ASCII" /* charset, charset_string */ }; diff --git a/lib/pbmfontdata2.c b/lib/pbmfontdata2.c index 336fc773..11dd84e6 100644 --- a/lib/pbmfontdata2.c +++ b/lib/pbmfontdata2.c @@ -1,4 +1,5 @@ #include "pbmfont.h" +#include "pbmfontdata.h" /* Default proportional font. BDF-style advance value, bounding box dimensions and point of origin. @@ -15,7 +16,7 @@ from a libnetpbm font file or builtin font. */ -static struct glyph glBdf[190] = { +static struct glyph glBdf[191] = { /* 32 character */ { 1, 1, 0, 0, 3, "\0" }, /* 33 character ! */ @@ -204,8 +205,10 @@ static struct glyph glBdf[190] = { { 1, 9, 1, 0, 3, "\1\1\1\1\1\1\1\1\1" }, /* 125 character } */ { 4, 12, 0, -3, 6, "\1\1\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\1\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\1\1\0\0" }, -/* 160 */ +/* 126 character ~ */ { 6, 2, 0, 3, 7, "\0\1\1\0\0\1\1\0\0\1\1\0" }, +/* 160 */ +{ 1, 1, 0, 0, 3, "\0" }, /* 161 */ { 1, 9, 1, -3, 4, "\1\0\1\1\1\1\1\1\1" }, /* 162 */ @@ -421,7 +424,7 @@ glBdf+84, glBdf+85, glBdf+86, glBdf+87, glBdf+88, glBdf+89, glBdf+90, glBdf+91, glBdf+92, glBdf+93, glBdf+94, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, glBdf+95, glBdf+96, glBdf+97, glBdf+98, glBdf+99, glBdf+100, glBdf+101, glBdf+102, glBdf+103, glBdf+104, glBdf+105, glBdf+106, glBdf+107, glBdf+108, glBdf+109, glBdf+110, glBdf+111, glBdf+112, @@ -437,7 +440,23 @@ glBdf+161, glBdf+162, glBdf+163, glBdf+164, glBdf+165, glBdf+166, glBdf+167, glBdf+168, glBdf+169, glBdf+170, glBdf+171, glBdf+172, glBdf+173, glBdf+174, glBdf+175, glBdf+176, glBdf+177, glBdf+178, glBdf+179, glBdf+180, glBdf+181, glBdf+182, glBdf+183, glBdf+184, -glBdf+185, glBdf+186, glBdf+187, glBdf+188, glBdf+189 } +glBdf+185, glBdf+186, glBdf+187, glBdf+188, glBdf+189, glBdf+190 }, +NULL, 0, 0 +}; + +struct font2 const pbm_defaultBdffont2 = { + sizeof(pbm_defaultFixedfont2), /* len */ + PBM_FONT2_STRUCT_SIZE(charset_string), /* size */ + 14, 15, -1, -3, /* maxwidth, maxheight, x, y */ + pbm_defaultBdffont.glyph, /* glyph table */ + 255, NULL, 255, /* maxglyph, selector, maxmaxglyph */ + NULL, 0, 0, /* oldfont, fcols, frows */ + PBM_FORMAT, /* bit_format */ + 190, 190, /* total_chars, chars */ + FIXED_DATA, /* load_fn */ + 32, 1, /* default_char, default_char_defined */ + (char *) "builtin bdf", /* name */ + ISO_8859_1, (char *)"ISO8859-1" /* charset, charset_string */ }; -- cgit 1.4.1