# gf_input.c: read objects from one GF file. # # Copyright (C) 1992, 2004, 2011 Free Software Foundation, Inc. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #include "config.h" #include "file-input.h" #include "gf.h" #include "scaled-num.h" #include "gf_opcodes.h" /* If true, print out what we read. */ static boolean tracing_gf_input = false; /* These identify the file we're reading, for our own use. */ static string gf_input_filename; static FILE *gf_input_file; /* Low-level input. These macros call the corresponding routines in kbase, using the static variables for the input file and filename. */ #define GF_FTELL() xftell (gf_input_file, gf_input_filename) #define GF_FSEEK(offset, from_where) \ xfseek (gf_input_file, offset, from_where, gf_input_filename) #define GF_GET_BYTE() get_byte (gf_input_file, gf_input_filename) #define GF_GET_PREVIOUS() get_previous_byte (gf_input_file, gf_input_filename) #define GF_GET_TWO() get_two (gf_input_file, gf_input_filename) #define GF_GET_FOUR() get_four (gf_input_file, gf_input_filename) #define GF_GET_SIGNED_FOUR() \ get_signed_four (gf_input_file, gf_input_filename) #define GF_GET_PREVIOUS_FOUR() \ get_previous_four (gf_input_file, gf_input_filename) #define GF_MATCH_BYTE(expected) \ match_byte (expected, gf_input_file, gf_input_filename) static void get_specials (byte_count_type special_ptr); static string gf_get_string (unsigned string_length); static four_bytes gf_get_three (void); /* We have occasion to refer to the postamble when reading the characters, so we keep a copy for ourselves. */ static gf_postamble_type *private_postamble; /* This reads into `private_postamble'. */ static void get_postamble (void); static void get_locators (void); /* Pointers to the characters we have read. */ static gf_char_type *char_list[MAX_CHARCODE + 1]; /* Subroutines for reading a character. */ static void get_full_boc (gf_char_type *); static void get_abbreviated_boc (gf_char_type *); static void get_character_bitmap (gf_char_type *); static void get_postamble_info (gf_char_type *); static void deblank (gf_char_type *); /* Subroutines for reading the bitmap. */ static void get_paint (coordinate_type *, boolean *, one_byte, gf_char_type *); static void get_skip (coordinate_type *, boolean *, one_byte, gf_char_type *); static void get_new_row (coordinate_type *, boolean *, one_byte, gf_char_type *); /* For handling raw characters. */ static void append_byte (raw_char_type *, one_byte); static void append_n_bytes (raw_char_type *, four_bytes, one_byte *); static raw_char_type new_raw_gf_char (gf_char_locator_type); /* Start reading FILENAME. Return false if it can't be opened. */ boolean gf_open_input_file (string filename) { if (gf_input_file != NULL) FATAL2 ("gf_open_input_file: Attempt to open `%s', but `%s' is \ already open", filename, gf_input_filename); gf_input_filename = filename; gf_input_file = fopen (filename, "r"); return gf_input_file != NULL; } void gf_close_input_file () { unsigned code; assert (gf_input_file != NULL); xfclose (gf_input_file, gf_input_filename); gf_input_filename = NULL; gf_input_file = NULL; private_postamble = NULL; for (code = 0; code <= MAX_CHARCODE; code++) char_list[code] = NULL; } /* The only interesting thing in the preamble, either to the user or to us, is the comment. It is wrong to save and restore the position in the gf file, since this routine is primarily useful if the user intends to use `gf_get_next_char', i.e., read the characters in the order they appear. In that case, the user has to read the preamble first. */ string gf_get_preamble () { one_byte comment_length; string answer; assert (gf_input_file != NULL); GF_MATCH_BYTE (PRE); GF_MATCH_BYTE (GF_ID); comment_length = GF_GET_BYTE (); answer = gf_get_string (comment_length); return answer; } /* Reading the postamble. This is the user-level call. We make no assumptions about the current position of the file pointer. */ gf_postamble_type gf_get_postamble () { one_byte b; byte_count_type old_pos, post_ptr; unsigned this_char; assert (gf_input_file != NULL); if (private_postamble != NULL) /* Previously read it? */ return *private_postamble; old_pos = GF_FTELL (); GF_FSEEK (0, SEEK_END); /* If the input file is empty, give a better message than `Invalid argument' (because we are trying to seek before the beginning). */ if (GF_FTELL () == 0) FATAL1 ("%s: empty file", gf_input_filename); do b = GF_GET_PREVIOUS (); while (b == GF_SIGNATURE); if (b != GF_ID) FATAL2 ("Expected GF id (%u), found %u", GF_ID, b); post_ptr = GF_GET_PREVIOUS_FOUR (); private_postamble = xmalloc (sizeof (gf_postamble_type)); for (this_char = 0; this_char <= MAX_CHARCODE; this_char++) { GF_CHAR_LOC (*private_postamble, this_char).charcode = this_char; GF_CHAR_LOC (*private_postamble, this_char).char_pointer = NULL_BYTE_PTR; } GF_FSEEK (post_ptr, SEEK_SET); get_postamble (); /* Fills in `private_postamble'. */ GF_FSEEK (old_pos, SEEK_SET); return *private_postamble; } /* Assume we are positioned at the beginning of the postamble. Fill in `private_postamble' with what we find. */ static void get_postamble () { GF_MATCH_BYTE (POST); (void) GF_GET_FOUR (); /* Ignore the special pointer. */ GF_DESIGN_SIZE (*private_postamble) = GF_GET_FOUR (); GF_CHECKSUM (*private_postamble) = GF_GET_FOUR (); /* The resolution values are stored in the file as pixels per point, scaled by 2^16. */ GF_H_RESOLUTION (*private_postamble) = GF_GET_FOUR (); GF_V_RESOLUTION (*private_postamble) = GF_GET_FOUR (); MIN_COL (GF_FONT_BB (*private_postamble)) = GF_GET_SIGNED_FOUR (); MAX_COL (GF_FONT_BB (*private_postamble)) = GF_GET_SIGNED_FOUR (); MIN_ROW (GF_FONT_BB (*private_postamble)) = GF_GET_SIGNED_FOUR (); MAX_ROW (GF_FONT_BB (*private_postamble)) = GF_GET_SIGNED_FOUR (); get_locators (); } /* We do not know in advance how many character locators exist, but we do place a maximum on it (contrary to what the GF format definition says), namely, MAX_CHARCODE. */ static void get_locators () { do { one_byte code; one_byte b = GF_GET_BYTE (); if (b == POST_POST) break; code = GF_GET_BYTE (); if (b == CHAR_LOC) { GF_CHAR_LOC (*private_postamble, code).h_escapement = scaled_to_real (GF_GET_FOUR ()) + .5; (void) GF_GET_FOUR (); /* Ignore vertical escapement. */ } else if (b == CHAR_LOC0) GF_CHAR_LOC (*private_postamble, code).h_escapement = GF_GET_BYTE (); else FATAL1 ("Expected a char_loc command, not %u", b); GF_CHAR_LOC (*private_postamble, code).tfm_width = GF_GET_FOUR (); GF_CHAR_LOC (*private_postamble, code).char_pointer = GF_GET_FOUR (); } while (true); } /* Unlike `gf_get_next_char' (which comes next), this routine will get any character by its code. It is meant to be called by the user. We save all the characters we read in the static `char_list', to avoid going out to the file each time. */ gf_char_type * gf_get_char (one_byte charcode) { gf_char_locator_type char_locator; byte_count_type char_pointer; if (char_list[charcode] != NULL) return char_list[charcode]; (void) gf_get_postamble (); assert (private_postamble != NULL); char_locator = GF_CHAR_LOC (*private_postamble, charcode); char_pointer = char_locator.char_pointer; if (char_pointer != NULL_BYTE_PTR) { boolean found; byte_count_type old_pos = GF_FTELL (); GF_FSEEK (char_pointer, SEEK_SET); char_list[charcode] = xmalloc (sizeof (gf_char_type)); *(char_list[charcode]) = gf_get_next_char (&found); assert (found); GF_FSEEK (old_pos, SEEK_SET); } return char_list[charcode]; } /* This reads the character starting from the current position (but some specials might come first). */ gf_char_type gf_get_next_char (boolean *found) { one_byte c; gf_char_type gf_char; get_specials (GF_FTELL ()); c = GF_GET_BYTE (); if (c == BOC) get_full_boc (&gf_char); else if (c == BOC1) get_abbreviated_boc (&gf_char); else if (c == POST) { *found = false; return gf_char; /* We are returning garbage, but that's OK. */ } else FATAL1 ("Expected a character (or the postamble), found %u", c); get_character_bitmap (&gf_char); get_postamble_info (&gf_char); deblank (&gf_char); *found = true; return gf_char; } /* If the back pointer actually points somewhere, this character is a ``residue'', and the font is probably too big. */ static void get_full_boc (gf_char_type *gf_char) { signed_4_bytes back_pointer, charcode; charcode = GF_GET_SIGNED_FOUR (); if (charcode < 0 || charcode > MAX_CHARCODE) /* Someone is trying to use a font with character codes that are out of our range. */ FATAL1 ("Character code %d out of range 0..255 in GF file (sorry)", charcode); GF_CHARCODE (*gf_char) = charcode; back_pointer = GF_GET_SIGNED_FOUR (); if (back_pointer != -1) WARNING2 ("Character %u has a non-null back pointer (to %d)", GF_CHARCODE (*gf_char), back_pointer); GF_CHAR_MIN_COL (*gf_char) = GF_GET_SIGNED_FOUR (); GF_CHAR_MAX_COL (*gf_char) = GF_GET_SIGNED_FOUR (); GF_CHAR_MIN_ROW (*gf_char) = GF_GET_SIGNED_FOUR (); GF_CHAR_MAX_ROW (*gf_char) = GF_GET_SIGNED_FOUR (); } static void get_abbreviated_boc (gf_char_type *gf_char) { one_byte col_delta, row_delta; GF_CHARCODE (*gf_char) = GF_GET_BYTE (); col_delta = GF_GET_BYTE (); GF_CHAR_MAX_COL (*gf_char) = GF_GET_BYTE (); GF_CHAR_MIN_COL (*gf_char) = GF_CHAR_MAX_COL (*gf_char) - col_delta; row_delta = GF_GET_BYTE (); GF_CHAR_MAX_ROW (*gf_char) = GF_GET_BYTE (); GF_CHAR_MIN_ROW (*gf_char) = GF_CHAR_MAX_ROW (*gf_char) - row_delta; } /* We also want to return the horizontal escapement (i.e., set width) and the TFM width as part of the character, although this information is not part of the boc..eoc, but rather the postamble. */ static void get_postamble_info (gf_char_type *gf_char) { gf_char_locator_type char_locator; (void) gf_get_postamble (); /* Use `private_postamble'. */ assert (private_postamble != NULL); char_locator = GF_CHAR_LOC (*private_postamble, GF_CHARCODE (*gf_char)); GF_H_ESCAPEMENT (*gf_char) = char_locator.h_escapement; GF_TFM_WIDTH (*gf_char) = char_locator.tfm_width; } /* The GF format does not guarantee that the bounding box is the smallest possible, i.e., that the character bitmap does not have blank rows or columns at an edge. We want to remove such blanks. */ static void deblank (gf_char_type *gf_char) { boolean all_white; bitmap_type gf_bitmap = GF_BITMAP (*gf_char); unsigned width = BITMAP_WIDTH (gf_bitmap), height = BITMAP_HEIGHT (gf_bitmap); unsigned white_on_left = 0, white_on_right = 0, white_on_top = 0, white_on_bottom = 0; int this_col, this_row; /* int in case GF_CHAR is zero pixels wide. */ /* Let's start with blank columns at the left-hand side. */ all_white = true; for (this_col = 0; this_col < width && all_white; this_col++) { for (this_row = 0; this_row < height && all_white; this_row++) { if (BITMAP_PIXEL (gf_bitmap, this_row, this_col) != 0) all_white = false; } if (all_white) white_on_left++; } /* Now let's check the right-hand side. */ all_white = true; for (this_col = width - 1; this_col >= 0 && all_white; this_col--) { for (this_row = 0; this_row < height && all_white; this_row++) { if (BITMAP_PIXEL (gf_bitmap, this_row, this_col) != WHITE) all_white = false; } if (all_white) white_on_right++; } /* Check for all-white rows on top now. */ all_white = true; for (this_row = 0; this_row < height && all_white; this_row++) { for (this_col = 0; this_col < width && all_white; this_col++) { if (BITMAP_PIXEL (gf_bitmap, this_row, this_col) != WHITE) all_white = false; } if (all_white) white_on_top++; } /* And, last, for all-white rows on the bottom. */ all_white = true; for (this_row = height - 1; this_row >= 0 && all_white; this_row--) { for (this_col = 0; this_col < width && all_white; this_col++) { if (BITMAP_PIXEL (gf_bitmap, this_row, this_col) != WHITE) all_white = false; } if (all_white) white_on_bottom++; } /* If we have to remove columns at either the left or the right, we have to reallocate the memory, since much code depends on the fact that the bitmap is in contiguous memory. If we have to remove rows, we don't necessarily have to reallocate the memory, but we might as well, to save space. */ if (white_on_left > 0 || white_on_right > 0 || white_on_top > 0 || white_on_bottom > 0) { bitmap_type condensed; if (white_on_left + white_on_right > width) { /* The character was entirely blank. */ BITMAP_WIDTH (condensed) = BITMAP_HEIGHT (condensed) = 0; GF_CHAR_MIN_COL (*gf_char) = GF_CHAR_MAX_COL (*gf_char) = GF_CHAR_MIN_ROW (*gf_char) = GF_CHAR_MAX_ROW (*gf_char) = 0; BITMAP_BITS (condensed) = NULL; } else { dimensions_type d; DIMENSIONS_HEIGHT (d) = height - white_on_top - white_on_bottom; DIMENSIONS_WIDTH (d) = width - white_on_left - white_on_right; condensed = new_bitmap (d); for (this_row = 0; this_row < BITMAP_HEIGHT (condensed); this_row++) for (this_col = 0; this_col < BITMAP_WIDTH (condensed); this_col++) { BITMAP_PIXEL (condensed, this_row, this_col) = BITMAP_PIXEL (gf_bitmap, this_row + white_on_top, this_col + white_on_left); } GF_CHAR_MIN_ROW (*gf_char) += white_on_bottom; GF_CHAR_MAX_ROW (*gf_char) -= white_on_top; GF_CHAR_MIN_COL (*gf_char) += white_on_left; GF_CHAR_MAX_COL (*gf_char) -= white_on_right; } free_bitmap (&GF_BITMAP (*gf_char)); GF_BITMAP (*gf_char) = condensed; } } /* The ``bitmap'' is a sequence of commands that describe it in terms of run-length encoding. GF's row and column numbers are the lower left corner of a pixel. GF (0,0) is the Cartesian unit square: 0 <= x (col) <= 1, 0 <= y (row) <= 1. Yes, it's <=, not <. What does this mean for the maxes and mins? Let's take the height first: if a character has min_row = 0 and max_row = 10, we start the ``current'' y at 10, (possibly) paint some pixels on that row, ..., and end up with it at zero, (possibly) painting some pixels on that row. Thus, there are 11 (10 - 0 + 1) rows in which we might paint pixels. Now the width: if a character has min_row = 0 and max_row = 4, the current x starts at zero, we paint four pixels (let's say), and now the current x is four (the max possible), so we cannot paint any more. Thus there are four (4 - 0) columns in which we might paint pixels. Weird, huh? */ static void get_character_bitmap (gf_char_type *gf_char) { /* We expect these to be >= 0, but if the GF file is improper, they might turn to be negative. */ int height, width; dimensions_type matrix_dimensions; coordinate_type current; /* This will be the GF position. */ boolean painting_black = false; current.x = GF_CHAR_MIN_COL (*gf_char); current.y = GF_CHAR_MAX_ROW (*gf_char); width = GF_CHAR_MAX_COL (*gf_char) - GF_CHAR_MIN_COL (*gf_char); height = GF_CHAR_MAX_ROW (*gf_char) - GF_CHAR_MIN_ROW (*gf_char) + 1; /* If the character has zero or negative extent in either dimension, it's not going to have a bitmap. (If this happens, the GF file is incorrect; but the discrepancy isn't serious, so we may as well not bomb out when it happens, especially since PKtoGF has a bug that produces such a bounding box when the character is all blank.) */ if (width <= 0 || height <= 0) { one_byte b; BITMAP_HEIGHT (GF_BITMAP (*gf_char)) = BITMAP_WIDTH (GF_BITMAP (*gf_char)) = 0; BITMAP_BITS (GF_BITMAP (*gf_char)) = NULL; /* The next non-NO_OP byte should be EOC. */ while ((b = GF_GET_BYTE ()) == NO_OP) /* do nothing */ ; if (b != EOC) FATAL1 ("Expected eoc (for a blank character), found %u", b); return; } DIMENSIONS_HEIGHT (matrix_dimensions) = height; DIMENSIONS_WIDTH (matrix_dimensions) = width; GF_BITMAP (*gf_char) = new_bitmap (matrix_dimensions); do { one_byte c = GF_GET_BYTE (); if (c == EOC) break; /* No need to test if `PAINT_0 <= c'; it must be, since PAINT_0 is zero and `c' is unsigned. */ if (/* PAINT_0 <= c && */ c <= PAINT3) get_paint (¤t, &painting_black, c, gf_char); else if (SKIP0 <= c && c <= SKIP3) get_skip (¤t, &painting_black, c, gf_char); else if (NEW_ROW_0 <= c && c <= NEW_ROW_164) get_new_row (¤t, &painting_black, c, gf_char); else if (c == NO_OP) /* do nothing */ ; else if ((XXX1 <= c && c <= XXX4) || c == YYY) get_specials (GF_FTELL ()); else FATAL1 ("Expected paint or skip or new_row, found %u", c); } while (true); if (tracing_gf_input) puts (""); } /* The paint commands come in two varieties -- either with the length implicitly part of the command, or where it is specified as a separate parameter. */ static void get_paint (coordinate_type *current, boolean *painting_black, one_byte command, gf_char_type *gf_char) { unsigned length; /* No need to test if `PAINT_0 <= command'; it must be, since PAINT_0 is zero and `command' is unsigned. */ if (/* PAINT_0 <= command && */ command <= PAINT_63) length = command - PAINT_0; else { switch (command) { case PAINT1: length = GF_GET_BYTE (); break; case PAINT2: length = GF_GET_TWO (); break; case PAINT3: length = gf_get_three (); break; default: FATAL1 ("Expected a paint command, found %u", command); } } /* We have to translate from Cartesian to C coordinates. That means the x's are the same, but the y's are flipped. */ if (*painting_black) { unsigned matrix_y = GF_CHAR_MAX_ROW (*gf_char) - current->y; if (tracing_gf_input) printf ("%u", length); for (; length != 0; length--) { unsigned matrix_x = current->x - GF_CHAR_MIN_COL (*gf_char); BITMAP_PIXEL (GF_BITMAP (*gf_char), matrix_y, matrix_x) = 1; current->x++; } } else { current->x += length; if (tracing_gf_input) printf ("(%u)", length); } *painting_black = !*painting_black; } /* Skip commands move down in the GF character, leaving blank rows. */ static void get_skip (coordinate_type * current, boolean * painting_black, one_byte command, gf_char_type *gf_char) { unsigned rows_to_skip; switch (command) { case SKIP0: rows_to_skip = 0; break; case SKIP1: rows_to_skip = GF_GET_BYTE (); break; case SKIP2: rows_to_skip = GF_GET_TWO (); break; case SKIP3: rows_to_skip = gf_get_three (); break; default: FATAL1 ("Expected skip command, found %u", command); } current->y -= rows_to_skip + 1; current->x = GF_CHAR_MIN_COL (*gf_char); *painting_black = false; if (tracing_gf_input) printf ("\nskip %u (y now %d) ", rows_to_skip + 1, current->y); } /* `new_row' commands move to the next line down and then over. */ static void get_new_row (coordinate_type *current, boolean *painting_black, one_byte command, gf_char_type *gf_char) { current->y--; current->x = GF_CHAR_MIN_COL (*gf_char) + command - NEW_ROW_0; *painting_black = true; if (tracing_gf_input) printf ("\nnew_row %u (x,y now %d,%d) ", command - NEW_ROW_0, current->x, current->y); } /* Instead of building a bitmap, this routine just reads the bytes that define the character CHARCODE. If the character doesn't exist, we return NULL. */ /* Append the byte `b' to the buffer in `raw_char', followed by (if WITH_SIZE_P is true) SIZE, followed SIZE bytes of the input. */ #define COMMON_APPEND(size, with_size_p) \ do \ { \ append_byte (raw_char, b); \ if (with_size_p) append_byte (raw_char, size); \ if (size > 0) append_n_bytes (raw_char, size, get_n_bytes (size, \ gf_input_file, gf_input_filename)); \ } \ while (0) #define APPEND_BYTES(n) COMMON_APPEND (n, false) #define APPEND_VAR_BYTES(n) COMMON_APPEND (n, true) raw_char_type * gf_get_raw_char (one_byte charcode) { one_byte b; /* Command byte we've just read. */ gf_char_locator_type char_locator; byte_count_type char_pointer; byte_count_type old_pos; raw_char_type *raw_char; (void) gf_get_postamble (); assert (private_postamble != NULL); char_locator = GF_CHAR_LOC (*private_postamble, charcode); char_pointer = char_locator.char_pointer; /* If the character doesn't exist in the font, we're done. */ if (char_pointer == NULL_BYTE_PTR) return NULL; /* Save where we are in the file; we'll restore it when we're done. */ old_pos = GF_FTELL (); GF_FSEEK (char_pointer, SEEK_SET); raw_char = xmalloc (sizeof (raw_char_type)); *raw_char = new_raw_gf_char (char_locator); /* Unfortunately, the GF format doesn't tell us how many bytes long the character description is. So, we must decode it enough to figure out how much to read. */ /* The first step is the boc: it might be either the one-byte or four-byte variant. */ b = GF_GET_BYTE (); if (b == BOC) /* The character code, the backpointer (which will probably be wrong in the new file, if it exists, but we don't handle non-null backpointers anyway), the bounding box. */ APPEND_BYTES (24); else /* b == BOC1 */ APPEND_BYTES (5); /* Read the character definition; exit when we get to EOC. */ while ((b = GF_GET_BYTE ()) != EOC) { /* First test all the commands that have no parameters. No need to test if `PAINT_0 <= b'; it must be, since PAINT_0 is zero and `b' is unsigned. */ if ((/* PAINT_0 <= b && */ b <= PAINT_63) || b == SKIP0 || (NEW_ROW_0 <= b && b <= NEW_ROW_164)) APPEND_BYTES (0); /* Now the ones with a one-byte parameter. */ else if (b == PAINT1 || b == SKIP1) APPEND_BYTES (1); /* A two-byte parameter. */ else if (b == PAINT2 || b == SKIP2) APPEND_BYTES (2); /* Three-byte. */ else if (b == PAINT3 || b == SKIP3) APPEND_BYTES (3); /* Four. */ else if (b == YYY) APPEND_BYTES (4); /* Commands with a variable-size parameter. */ else if (b == XXX1) { one_byte size = GF_GET_BYTE (); APPEND_VAR_BYTES (size); } else if (b == XXX2) { two_bytes size = GF_GET_TWO (); APPEND_VAR_BYTES (size); } else if (b == XXX3) { four_bytes size = gf_get_three (); APPEND_VAR_BYTES (size); } else if (b == XXX4) { four_bytes size = GF_GET_FOUR (); APPEND_VAR_BYTES (size); } else if (b == NO_OP) /* do nothing */; else FATAL1 ("gf_get_raw_char: Bad command byte %u", b); } /* This appends the `eoc'---and now we're done. */ APPEND_BYTES (0); GF_FSEEK (old_pos, SEEK_SET); return raw_char; } /* This macro makes sure the raw character RGC has at least NEEDED bytes free. */ #define ENSURE_AVAILABLE(rgc, needed) \ while (RAW_CHAR_ALLOCATED (rgc) - RAW_CHAR_USED (rgc) < needed) \ { \ RAW_CHAR_ALLOCATED (rgc) *= 2; \ RAW_CHAR_BYTES (rgc) \ = xrealloc (RAW_CHAR_BYTES (rgc), RAW_CHAR_ALLOCATED (rgc)); \ } /* Append the byte B to the end of the RAW_CHAR's buffer. */ static void append_byte (raw_char_type *raw_char, one_byte b) { ENSURE_AVAILABLE (*raw_char, 1); RAW_CHAR_UNUSED_START (*raw_char) = b; RAW_CHAR_USED (*raw_char)++; } /* Append the N bytes of data pointed to by DATA to the end of RAW_CHAR's buffer. Free DATA after copying. */ static void append_n_bytes (raw_char_type *raw_char, four_bytes n, one_byte *data) { ENSURE_AVAILABLE (*raw_char, n); memcpy (&RAW_CHAR_UNUSED_START (*raw_char), data, n); RAW_CHAR_USED (*raw_char) += n; free (data); } /* Make a new raw character. We have to start off the buffer with some nonempty amount of memory, so that the reallocation will have something to double. */ static raw_char_type new_raw_gf_char (gf_char_locator_type locator) { raw_char_type c; RAW_CHAR_ALLOCATED (c) = 1; RAW_CHAR_BYTES (c) = xmalloc (RAW_CHAR_ALLOCATED (c)); RAW_CHAR_USED (c) = 0; GF_CHARCODE (c) = locator.charcode; GF_H_ESCAPEMENT (c) = locator.h_escapement; GF_TFM_WIDTH (c) = locator.tfm_width; GF_CHAR_BB (c) = GF_FONT_BB (*private_postamble); /* Since we don't want to interpret the bounding box information in the character, we just make our bounding box be the font bounding box. Since the only thing a raw character is good for is being immediately written back out, this doesn't hurt. (The actual bounding box information in the character isn't lost.) */ return c; } /* Read all specials beginning from the given location, leaving the file pointer at the first non-special. We do not save the specials, though. */ static void get_specials (byte_count_type special_ptr) { boolean found_special = true; GF_FSEEK (special_ptr, SEEK_SET); do { one_byte c = GF_GET_BYTE (); switch (c) { case XXX1: (void) gf_get_string (GF_GET_BYTE ()); break; case XXX2: (void) gf_get_string (GF_GET_TWO ()); break; case XXX3: (void) gf_get_string (gf_get_three ()); break; case YYY: (void) GF_GET_FOUR (); break; default: found_special = false; GF_FSEEK (-1, SEEK_CUR); } } while (found_special); } static string gf_get_string (unsigned length) { string s; if (length == 0) return ""; s = get_n_bytes (length, gf_input_file, gf_input_filename); s = xrealloc (s, length + 1); s[length] = 0; return s; } /* C does not provide an obvious type for a 24-bit quantity, so we return a 32-bit one. */ static four_bytes gf_get_three () { four_bytes v = get_two (gf_input_file, gf_input_filename) << 8; v |= get_byte (gf_input_file, gf_input_filename); return v; }