diff options
Diffstat (limited to 'Build/source/texk/cjkutils/cjkutils-4.8.4/hbf2gf/hbf.c')
-rw-r--r-- | Build/source/texk/cjkutils/cjkutils-4.8.4/hbf2gf/hbf.c | 1494 |
1 files changed, 1494 insertions, 0 deletions
diff --git a/Build/source/texk/cjkutils/cjkutils-4.8.4/hbf2gf/hbf.c b/Build/source/texk/cjkutils/cjkutils-4.8.4/hbf2gf/hbf.c new file mode 100644 index 00000000000..dedb9650b21 --- /dev/null +++ b/Build/source/texk/cjkutils/cjkutils-4.8.4/hbf2gf/hbf.c @@ -0,0 +1,1494 @@ +/* + * Copyright 1993,1994,1995,2005 by Ross Paterson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * + * Ross Paterson <ross@soi.city.ac.uk> + * 17 October 1995 + * + * The following people have supplied bug fixes: + * + * Simon Chow <khsc@synoptics.com> + * Fung Fung Lee <lee@simd.stanford.edu> + * Man-Chi Pong <mcpong@cs.ust.hk> + * Steven Simpson <simpson@math.psu.edu> + * Charles Wang <charles.wang@infores.com> + * Werner Lemberg <wl@gnu.org> + * + * Ross no longer maintains this code. Please send bug reports to + * Werner Lemberg <wl@gnu.org>. + * + */ + +/* + * Two C interfaces to HBF files. + * + * The multiple interfaces make this code rather messy; I intend + * to clean it up as experience is gained on what is really needed. + * + * There are also two modes of operation: + * - the default is to read each bitmap from its file as demanded + * - if IN_MEMORY is defined, the whole bitmap file is held in memory. + * In this case, if running under Unix, the bitmap files may be gzipped + * (but the filename used in the HBF file should be the name of the + * file before it was gzipped). + */ +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include "hbf.h" + +#ifdef __MSDOS__ +#define msdos +#endif + +/* + * if the linker complains about an unresolved identifier '_strdup', + * uncomment the following definition. + */ +/* #define NO_STRDUP */ + +#ifdef __STDC__ +# define _(x) x +#else +# define _(x) () +#endif + +#define reg register + +typedef int bool; +#define TRUE 1 +#define FALSE 0 + +#define Bit(n) (1<<(7 - (n))) + +/* + * Messy file system issues + */ + +#ifdef unix +#define PATH_DELIMITER ':' +#define RelativeFileName(fn) ((fn)[0] != '/') +#define LocalFileName(fn) (strchr(fn, '/') == NULL) +#endif /* unix */ +#ifdef msdos +#define PATH_DELIMITER ';' +#define HasDrive(fn) (isalpha((fn)[0]) && (fn)[1] == ':') +#ifdef __EMX__ +#define RelativeFileName(fn) (! HasDrive(fn) && \ + !((fn)[0] == '\\' || (fn)[0] == '/')) +#define LocalFileName(fn) (! HasDrive(fn) && \ + strchr(fn, '\\') == NULL && \ + strchr(fn, '/') == NULL) +#else +#define RelativeFileName(fn) (! HasDrive(fn) && (fn)[0] != '\\') +#define LocalFileName(fn) (! HasDrive(fn) && strchr(fn, '\\') == NULL) +#endif /* __EMX__ */ +#define READ_BINARY "rb" +#endif /* msdos */ +#ifdef vms +#define PATH_DELIMITER ',' +#define RelativeFileName(fn) (strchr(fn, ':') == NULL && ((fn)[0] != '[' || (fn)[1] == '.' || (fn)[1] == '-')) +#define LocalFileName(fn) (strchr(fn, ':') == NULL && strchr(fn, ']') == NULL) +#endif + +#ifndef RelativeFileName +#define RelativeFileName(fn) FALSE +#endif + +#ifndef LocalFileName +#define LocalFileName(fn) FALSE +#endif + +#ifndef READ_BINARY +#define READ_BINARY "r" +#endif + +#define MAX_FILENAME 1024 + +/* + * Internal structures + */ + +typedef unsigned char byte; + +#define PROPERTY struct _PROPERTY +#define BM_FILE struct _BM_FILE +#define B2_RANGE struct _B2_RANGE +#define CODE_RANGE struct _CODE_RANGE + +PROPERTY { + char *prop_name; + char *prop_value; + PROPERTY *prop_next; +}; + +BM_FILE { + char *bmf_name; +#ifdef IN_MEMORY + byte *bmf_contents; +#else + FILE *bmf_file; +#endif + long bmf_size; + BM_FILE *bmf_next; +}; + +B2_RANGE { + byte b2r_start; + byte b2r_finish; + B2_RANGE *b2r_next; +}; + +typedef unsigned short CHAR; +typedef unsigned int CHAR_INDEX; /* character index in file */ +#define BAD_CHAR_INDEX 0xffff + +CODE_RANGE { + CHAR code_start; + CHAR code_finish; + BM_FILE *code_bm_file; + long code_offset; + CHAR_INDEX code_pos; + bool code_transposed; + bool code_inverted; + CODE_RANGE *code_next; +}; + +/* + * Extended internal version of HBF + */ + +typedef struct { + /* fields corresponding to the definition */ + HBF public; + /* plus internal stuff */ + char *filename; + byte *bitmap_buffer; + unsigned int b2_size; /* number of legal byte-2's */ + PROPERTY *property; + B2_RANGE *byte_2_range; + CODE_RANGE *code_range; + BM_FILE *bm_file; +} HBF_STRUCT; + +#define FirstByte(code) ((code)>>8) +#define SecondByte(code) ((code)&0xff) +#define MakeCode(byte1,byte2) (((byte1)<<8)|(byte2)) + +/* size of a bitmap in the file (may be affected by transposition) */ +#define FileBitmapSize(hbfFile,cp) \ + ((cp)->code_transposed ? \ + (hbfBitmapBBox(hbfFile)->hbf_height + 7)/8 * \ + hbfBitmapBBox(hbfFile)->hbf_width : \ + HBF_BitmapSize(hbfFile)) + +#define NEW(type) ((type *)malloc((unsigned)(sizeof(type)))) + +#define QUOTE '"' + +#define MAXLINE 1024 + +#ifdef WIN32 +#define strdup(x) _strdup(x) +#else + extern char *strdup _((const char *s)); +#endif + +static void add_b2r _((B2_RANGE **last_b2r, int start, int finish)); +static bool add_code_range _((HBF_STRUCT *hbf, const char *line)); +static void add_property _((HBF_STRUCT *hbf, const char *lp)); +static CHAR_INDEX b2_pos _((HBF_STRUCT *hbf, HBF_CHAR code)); +static int b2_size _((B2_RANGE *b2r)); +static void clear_bbox _((HBF_BBOX *bbox)); +static void clear_record _((HBF_STRUCT *hbf)); +static char *concat _((const char *dir, int dirlen, const char *stem)); +static char *expand_filename _((const char *name, const char *filename)); +static const byte *get_bitmap + _((HBF_STRUCT *hbf, HBF_CHAR code, byte *buffer)); +static byte *local_buffer _((HBF_STRUCT *hbf)); +static void invert _((byte *buffer, unsigned length)); +#ifdef IN_MEMORY +static bool read_bitmap_file _((BM_FILE *bmf, FILE *f)); +static bool copy_transposed + _((HBF *hbf, byte *bitmap, const byte *source)); +#else +static bool get_transposed _((HBF *hbf, FILE *f, byte *bitmap)); +#endif +static bool match _((const char *lp, const char *sp)); +static bool parse_file _((FILE *f, HBF_STRUCT *hbf)); +static FILE *path_open + _((const char *path, const char *filename, char **fullp)); +static bool real_open _((const char *filename, HBF_STRUCT *hbf)); + +/* Error reporting */ + +int hbfDebug; /* set this for error reporting */ + +#ifdef __STDC__ +#include <stdarg.h> + +static void +eprintf(const char *fmt, ...) +{ + if (hbfDebug) { + va_list args; + + (void)fprintf(stderr, "HBF: "); + va_start(args, fmt); + (void)vfprintf(stderr, fmt, args); + va_end(args); + (void)fprintf(stderr, "\n"); + } +} +#else /* ! __STDC__ */ +/* poor man's variable-length argument list */ +static void +eprintf(fmt, x1, x2, x3, x4, x5, x6, x7, x8, x9) + const char *fmt; + int x1, x2, x3, x4, x5, x6, x7, x8, x9; +{ + if (hbfDebug) { + (void)fprintf(stderr, "HBF: "); + (void)fprintf(stderr, fmt, x1, x2, x3, x4, x5, x6, x7, x8, x9); + (void)fprintf(stderr, "\n"); + } +} +#endif /* __STDC__ */ + +static void +clear_bbox(HBF_BBOX *bbox) +{ + bbox->hbf_width = bbox->hbf_height = 0; + bbox->hbf_xDisplacement = bbox->hbf_yDisplacement = 0; +} + +static void +clear_record(HBF_STRUCT *hbf) +{ + clear_bbox(&(hbf->public.hbf_bitmap_bbox)); + clear_bbox(&(hbf->public.hbf_font_bbox)); + hbf->property = NULL; + hbf->filename = NULL; + hbf->bitmap_buffer = NULL; + hbf->byte_2_range = NULL; + hbf->code_range = NULL; + hbf->bm_file = NULL; +} + +/* + * Byte-2 ranges + */ + +static void +add_b2r(reg B2_RANGE **last_b2r, int start, int finish) +{ +reg B2_RANGE *b2r; + + b2r = NEW(B2_RANGE); + while (*last_b2r != NULL && (*last_b2r)->b2r_start < start) + last_b2r = &((*last_b2r)->b2r_next); + b2r->b2r_next = *last_b2r; + b2r->b2r_start = start; + b2r->b2r_finish = finish; + *last_b2r = b2r; +} + +static CHAR_INDEX +b2_pos(HBF_STRUCT *hbf, HBF_CHAR code) +{ +reg B2_RANGE *b2r; +reg unsigned c; +reg CHAR_INDEX pos; + + c = SecondByte(code); + pos = 0; + for (b2r = hbf->byte_2_range; b2r != NULL; b2r = b2r->b2r_next) + if (b2r->b2r_start <= c && c <= b2r->b2r_finish) + return pos + c - b2r->b2r_start; + else + pos += b2r->b2r_finish - b2r->b2r_start + 1; + return BAD_CHAR_INDEX; +} + +static int +b2_size(reg B2_RANGE *b2r) +{ +reg int size; + + size = 0; + for ( ; b2r != NULL; b2r = b2r->b2r_next) + size += b2r->b2r_finish - b2r->b2r_start + 1; + return size; +} + +/* map a position to a character code */ +static long +code_of(HBF_STRUCT *hbf, long pos) +{ + long code; + int residue; +reg B2_RANGE *b2r; + + code = pos / hbf->b2_size * 256; + residue = pos % hbf->b2_size; + for (b2r = hbf->byte_2_range; b2r != NULL; b2r = b2r->b2r_next) + if (b2r->b2r_start + residue <= b2r->b2r_finish) + return code + b2r->b2r_start + residue; + else + residue -= b2r->b2r_finish - b2r->b2r_start + 1; + /* should never get here */ + return 0L; +} + +/* + * String stuff + */ + +static bool +match(reg const char *lp, reg const char *sp) +{ + while (*lp == *sp && *sp != '\0') { + lp++; + sp++; + } + return (*lp == '\0' || isspace((unsigned char)*lp)) && *sp == '\0'; +} + +#ifdef NO_STRDUP +char * +strdup(const char *s) +{ + char *new_s; + + new_s = malloc((unsigned)strlen(s) + 1); + strcpy(new_s, s); + return new_s; +} +#endif + +/* + * Properties + */ + +static void +add_property(reg HBF_STRUCT *hbf, const char *lp) +{ +reg PROPERTY *prop; + char tmp[MAXLINE]; +reg char *tp; + + prop = NEW(PROPERTY); + + tp = tmp; + while (*lp != '\0' && ! isspace((unsigned char)*lp)) + *tp++ = *lp++; + *tp = '\0'; + prop->prop_name = strdup(tmp); + + while (*lp != '\0' && isspace((unsigned char)*lp)) + lp++; + + tp = tmp; + if (*lp == QUOTE) { + lp++; + while (*lp != '\0' && ! (*lp == QUOTE && *++lp != QUOTE)) + *tp++ = *lp++; + } + else + for (;;) { + while (*lp != '\0' && ! isspace((unsigned char)*lp)) + *tp++ = *lp++; + while (*lp != '\0' && isspace((unsigned char)*lp)) + lp++; + if (*lp == '\0') + break; + *tp++ = ' '; + } + *tp = '\0'; + prop->prop_value = strdup(tmp); + + prop->prop_next = hbf->property; + hbf->property = prop; +} + +const char * +hbfProperty(HBF *hbfFile, const char *propName) +{ +reg HBF_STRUCT *hbf; +reg PROPERTY *prop; + + hbf = (HBF_STRUCT *)hbfFile; + for (prop = hbf->property; prop != NULL; prop = prop->prop_next) + if (strcmp(prop->prop_name, propName) == 0) + return prop->prop_value; + return NULL; +} + +/* + * Compatability routines + */ + +const char * +HBF_GetProperty(HBF *handle, const char *propertyName) +{ + return hbfProperty(handle, propertyName); +} + +int +HBF_GetFontBoundingBox(HBF_Handle handle, + unsigned int *width, unsigned int *height, + int *xDisplacement, int *yDisplacement) +{ + if (width != NULL) + *width = hbfFontBBox(handle)->hbf_width; + if (height != NULL) + *height = hbfFontBBox(handle)->hbf_height; + if (xDisplacement != NULL) + *xDisplacement = hbfFontBBox(handle)->hbf_xDisplacement; + if (yDisplacement != NULL) + *yDisplacement = hbfFontBBox(handle)->hbf_yDisplacement; + return 0; +} + +int +HBF_GetBitmapBoundingBox(HBF_Handle handle, + unsigned int *width, unsigned int *height, + int *xDisplacement, int *yDisplacement) +{ + if (width != NULL) + *width = hbfBitmapBBox(handle)->hbf_width; + if (height != NULL) + *height = hbfBitmapBBox(handle)->hbf_height; + if (xDisplacement != NULL) + *xDisplacement = hbfBitmapBBox(handle)->hbf_xDisplacement; + if (yDisplacement != NULL) + *yDisplacement = hbfBitmapBBox(handle)->hbf_yDisplacement; + return 0; +} + +/* + * Prepend a directory to a relative filename. + */ +static char * +concat(const char *dir, /* not necessarily null-terminated */ + int dirlen, /* number of significant chars in dir */ + const char *stem) /* relative filename */ +{ + char *fullname; + + if (dirlen == 0) /* null: current directory */ + return strdup(stem); +#ifdef unix + fullname = malloc(dirlen + strlen(stem) + 2); + (void)sprintf(fullname, "%.*s/%s", dirlen, dir, stem); +#else +#ifdef msdos + fullname = malloc(dirlen + strlen(stem) + 2); + (void)sprintf(fullname, "%.*s\\%s", dirlen, dir, stem); +#else +#ifdef vms + if (dir[dirlen-1] == ']' && stem[0] == '[' && stem[1] == '-') { + dirlen--; + stem++; + fullname = malloc(dirlen + strlen(stem) + 2); + (void)sprintf(fullname, "%.*s.%s", dirlen, dir, stem); + } + else { + if (dir[dirlen-1] == ']' && stem[0] == '[' && stem[1] == '.') { + dirlen--; + stem++; + } + fullname = malloc(dirlen + strlen(stem) + 1); + (void)sprintf(fullname, "%.*s%s", dirlen, dir, stem); + } +#else + fullname = strdup(stem); +#endif /* vms */ +#endif /* msdos */ +#endif /* unix */ + return fullname; +} + +/* + * Bitmap files + * + * If the host operating system has a heirarchical file system and + * the bitmap file name is relative, it is relative to the directory + * containing the HBF file. + */ +static char * +expand_filename(const char *name, const char *hbf_name) +{ +#ifdef unix +reg char *s; +reg int size; + + size = name[0] != '/' && (s = strrchr(hbf_name, '/')) != NULL ? + s - hbf_name + 1 : 0; + s = malloc((unsigned)size + strlen(name) + 1); + (void)sprintf(s, "%.*s%s", size, hbf_name, name); + return s; +#else +#ifdef msdos +reg char *s; +reg int size; + +#ifdef __EMX__ + s = (unsigned char *)hbf_name + strlen((unsigned char *)hbf_name) - 1; + for(;;) { + if (*s == '\\' || *s == '/') + break; + if (s == hbf_name) { + s = NULL; + break; + } + s--; + } + + size = HasDrive(name) ? 0 : + (name[0] == '\\' || name[0] == '/') ? + (HasDrive(hbf_name) ? 2 : 0) : + s != NULL ? s - hbf_name + 1 : 0; +#else + size = HasDrive(name) ? 0 : + name[0] == '\\' ? (HasDrive(hbf_name) ? 2 : 0) : + (s = strrchr(hbf_name, '\\')) != NULL ? + s - hbf_name + 1 : 0; +#endif /* __EMX__ */ + s = malloc((unsigned)size + strlen(name) + 1); + (void)sprintf(s, "%.*s%s", size, hbf_name, name); + return s; +#else +#ifdef vms +reg char *s; +reg const char *copyto; +reg int size; + + if ((s = strchr(hbf_name, ']')) != NULL && RelativeFileName(name)) + return concat(hbf_name, (s - hbf_name) + 1, name); + + copyto = hbf_name; + if ((s = strstr(copyto, "::")) != NULL && strstr(name, "::") == NULL) + copyto = s+2; + if ((s = strchr(copyto, ':')) != NULL && strchr(name, ':') == NULL) + copyto = s+1; + size = copyto - hbf_name; + s = malloc((unsigned)size + strlen(name) + 1); + (void)sprintf(s, "%.*s%s", size, hbf_name, name); + return s; +#else + return strdup(name); +#endif /* vms */ +#endif /* msdos */ +#endif /* unix */ +} + +static BM_FILE * +find_file(HBF_STRUCT *hbf, const char *filename) +{ + BM_FILE **fp; +reg BM_FILE *file; + FILE *f; + char *bmfname; +#ifdef IN_MEMORY +#ifdef unix + bool from_pipe; +#endif +#endif + + for (fp = &(hbf->bm_file); *fp != NULL; fp = &((*fp)->bmf_next)) { + bmfname = strrchr((*fp)->bmf_name, '/'); + bmfname = (bmfname) ? bmfname + 1 : (*fp)->bmf_name; + if (strcmp(bmfname, filename) == 0) + return *fp; + } + + file = NEW(BM_FILE); + if (file == NULL) { + eprintf("out of memory"); + return NULL; + } + file->bmf_name = expand_filename(filename, hbf->filename); + if (file->bmf_name == NULL) { + free((char *)file); + return NULL; + } + f = fopen(file->bmf_name, READ_BINARY); +#ifdef IN_MEMORY +#ifdef unix + from_pipe = FALSE; + if (f == NULL) { + char tmp[400]; + + sprintf(tmp, "%s.gz", file->bmf_name); + if ((f = fopen(tmp, "r")) != NULL) { + fclose(f); + sprintf(tmp, "gzcat %s.gz", file->bmf_name); + if ((f = popen(tmp, "r")) != NULL) + from_pipe = TRUE; + } + } +#endif /* unix */ +#endif /* IN_MEMORY */ + if (f == NULL) { + eprintf("can't open bitmap file '%s'", file->bmf_name); + free(file->bmf_name); + free((char *)file); + return NULL; + } +#ifdef IN_MEMORY + if (! read_bitmap_file(file, f)) { + free(file->bmf_name); + free((char *)file); + return NULL; + } +#ifdef unix + if (from_pipe) + pclose(f); + else + fclose(f); +#else /* ! unix */ + fclose(f); +#endif /* ! unix */ +#else /* ! IN_MEMORY */ + file->bmf_file = f; + fseek(f, 0L, 2); + file->bmf_size = ftell(f); +#endif /* ! IN_MEMORY */ + file->bmf_next = NULL; + *fp = file; + return file; +} + +#ifdef IN_MEMORY +#define GRAIN_SIZE 512 + +static bool +read_bitmap_file(BM_FILE *bmf, FILE *f) +{ + byte *contents, *cp; + long size; + int c; + + size = 0; + cp = contents = (byte *)malloc((unsigned)GRAIN_SIZE); + if (contents == NULL) { + eprintf("not enough space for bitmap file"); + return NULL; + } + while ((c = getc(f)) != EOF) { + if (size%GRAIN_SIZE == 0) { + contents = (byte *)realloc((char *)contents, + (unsigned)(size + GRAIN_SIZE)); + if (contents == NULL) { + eprintf("not enough space for bitmap file"); + return NULL; + } + cp = contents + size; + } + *cp++ = c; + size++; + } + bmf->bmf_size = size; + bmf->bmf_contents = (byte *)realloc((char *)contents, (unsigned)size); + return TRUE; +} +#endif /* IN_MEMORY */ + +/* + * Code ranges + */ + +/* check that a code range fits within its bitmap file */ +static bool +too_short(HBF_STRUCT *hbf, CODE_RANGE *cp) +{ + int bm_size; + long offset, end_offset; + BM_FILE *bmf; + long start, finish; + + bm_size = FileBitmapSize(&(hbf->public), cp); + offset = cp->code_offset; + start = cp->code_start; + finish = cp->code_finish; + end_offset = offset + bm_size * + (hbf->b2_size*(long)FirstByte(finish) + + b2_pos(hbf, finish) - cp->code_pos + 1); + bmf = cp->code_bm_file; + if (end_offset <= bmf->bmf_size) + return FALSE; + /* bitmap file is too short: produce a specific error message */ + if (offset > bmf->bmf_size) + eprintf("bitmap file '%s' is shorter than offset 0x%04lx", + bmf->bmf_name, offset); + else if (offset + bm_size > bmf->bmf_size) + eprintf("bitmap file '%s' too short: no room for any bitmaps at offset 0x%04lx", + bmf->bmf_name, offset); + else + eprintf("bitmap file '%s' is too short - code range appears to be 0x%04lx-0x%04lx", + bmf->bmf_name, + start, + code_of(hbf, cp->code_pos + + (bmf->bmf_size - offset)/bm_size) - 1); + return TRUE; +} + +static const char * +skip_word(int n, const char *s) +{ + for ( ; n > 0; n--) { + while (*s != '\0' && ! isspace((unsigned char)*s)) + s++; + while (*s != '\0' && isspace((unsigned char)*s)) + s++; + } + return s; +} + +/* optional keywords at the end of a CODE_RANGE line */ +static void +parse_keywords(CODE_RANGE *cp, const char *s) +{ + for (s = skip_word(4, s) ; *s != '\0'; s = skip_word(1, s)) { + switch (*s) { + case 's': case 'S': case 't': case 'T': + /* keyword "sideways" or "transposed" */ + cp->code_transposed = TRUE; + break; + case 'i': case 'I': + /* keyword "inverted" */ + cp->code_inverted = TRUE; + } + } +} + +static bool +add_code_range(HBF_STRUCT *hbf, const char *line) +{ + CODE_RANGE *cp; + CODE_RANGE **cpp; + long start, finish; + long offset; + char filename[MAXLINE]; + BM_FILE *bmf; + CHAR_INDEX b2pos; + + if (sscanf(line, "HBF_CODE_RANGE %li-%li %s %li", + &start, &finish, filename, &offset) != 4) { + eprintf("syntax error in HBF_CODE_RANGE"); + return FALSE; + } + /* code ranges are checked in real_open() */ + if ((bmf = find_file(hbf, filename)) == NULL) + return FALSE; + if ((cp = NEW(CODE_RANGE)) == NULL) { + eprintf("out of memory"); + return FALSE; + } + + cp->code_start = (CHAR)start; + cp->code_finish = (CHAR)finish; + cp->code_bm_file = bmf; + cp->code_offset = offset; + cp->code_transposed = cp->code_inverted = FALSE; + parse_keywords(cp, line); + /* insert it in order */ + for (cpp = &hbf->code_range; + *cpp != NULL && (*cpp)->code_finish < start; + cpp = &((*cpp)->code_next)) + ; + if (*cpp != NULL && (*cpp)->code_start <= finish) { + eprintf("code ranges overlap"); + return FALSE; + } + cp->code_next = *cpp; + *cpp = cp; + + /* set code_pos, and check range */ + if (start > finish) { + eprintf("illegal code range 0x%04lx-0x%04lx", start, finish); + return FALSE; + } + if ((b2pos = b2_pos(hbf, start)) == BAD_CHAR_INDEX) { + eprintf("illegal start code 0x%04lx", start); + return FALSE; + } + cp->code_pos = hbf->b2_size*(long)FirstByte(start) + b2pos; + if ((b2pos = b2_pos(hbf, finish)) == BAD_CHAR_INDEX) { + eprintf("illegal finish code 0x%04lx", finish); + return FALSE; + } + /* check that the bitmap file has enough bitmaps */ + return ! too_short(hbf, cp); +} + +/* + * Reading and parsing of an HBF file + */ + +/* get line, truncating to len, and trimming trailing spaces */ +static bool +get_line(char *buf, int len, FILE *f) +{ + int c; + char *bp; + + bp = buf; + for (;;) { + if ((c = getc(f)) == EOF) { + eprintf("unexpected end of file"); + return FALSE; + } + if (c == '\n' || c == '\r') { + /* trim trailing space */ + while (bp > buf && isspace((unsigned char)*(bp-1))) + bp--; + *bp = '\0'; + return TRUE; + } + if (len > 0) { + *bp++ = c; + len--; + } + } +} + +/* get next non-COMMENT line */ +static bool +get_text_line(char *buf, int len, FILE *f) +{ + while (get_line(buf, len, f)) + if (*buf != '\0' && ! match(buf, "COMMENT")) + return TRUE; + return FALSE; +} + +static bool +get_property(const char *line, const char *keyword, HBF_STRUCT *hbf) +{ + if (! match(line, keyword)) { + eprintf("%s expected", keyword); + return FALSE; + } + add_property(hbf, line); + return TRUE; +} + +static bool +get_bbox(const char *line, const char *keyword, HBF_BBOX *bbox) +{ + int w, h, xd, yd; + + if (! match(line, keyword) || + sscanf(line + strlen(keyword), "%i %i %i %i", + &w, &h, &xd, &yd) != 4) { + eprintf("%s expected", keyword); + return FALSE; + } + if (w <= 0 || h <= 0) { + eprintf("illegal %s dimensions %dx%d", keyword, w, h); + return FALSE; + } + bbox->hbf_width = w; + bbox->hbf_height = h; + bbox->hbf_xDisplacement = xd; + bbox->hbf_yDisplacement = yd; + return TRUE; +} + +/* + * HBFHeaderFile ::= + * 'HBF_START_FONT' version EOLN + * 'HBF_CODE_SCHEME' word ... EOLN + * 'FONT' fontName EOLN + * 'SIZE' ptsize xres yres EOLN + * 'HBF_BITMAP_BOUNDING_BOX' w h xd yd EOLN + * 'FONTBOUNDINGBOX' w h xd yd EOLN + * X11R5FontPropertySection + * 'CHARS' n EOLN + * HBFByte2RangeSection + * HBFCodeRangeSection + * 'HBF_END_FONT' EOLN . + * + * This implementation allows extra lines before HBF_END_FONT. + * Anything after HBF_END_FONT is ignored. + */ + +static bool +parse_file(FILE *f, reg HBF_STRUCT *hbf) +{ + char line[MAXLINE]; + int start, finish; + + if (! get_text_line(line, MAXLINE, f) || + ! get_property(line, "HBF_START_FONT", hbf)) + return FALSE; + + if (! get_text_line(line, MAXLINE, f) || + ! get_property(line, "HBF_CODE_SCHEME", hbf)) + return FALSE; + + if (! get_text_line(line, MAXLINE, f) || + ! get_property(line, "FONT", hbf)) + return FALSE; + + if (! get_text_line(line, MAXLINE, f) || + ! get_property(line, "SIZE", hbf)) + return FALSE; + + if (! get_text_line(line, MAXLINE, f) || + ! get_bbox(line, "HBF_BITMAP_BOUNDING_BOX", + &(hbf->public.hbf_bitmap_bbox))) + return FALSE; + + if (! get_text_line(line, MAXLINE, f) || + ! get_bbox(line, "FONTBOUNDINGBOX", &(hbf->public.hbf_font_bbox))) + return FALSE; + + if (! get_text_line(line, MAXLINE, f)) + return FALSE; + if (match(line, "STARTPROPERTIES")) { + for (;;) { + if (! get_text_line(line, MAXLINE, f)) + return FALSE; + if (match(line, "ENDPROPERTIES")) + break; + add_property(hbf, line); + } + if (! get_text_line(line, MAXLINE, f)) + return FALSE; + } + + if (match(line, "CHARS")) + if (! get_text_line(line, MAXLINE, f)) + return FALSE; + + if (match(line, "HBF_START_BYTE_2_RANGES")) { + for (;;) { + if (! get_text_line(line, MAXLINE, f)) + return FALSE; + if (match(line, "HBF_END_BYTE_2_RANGES")) + break; + if (sscanf(line, "HBF_BYTE_2_RANGE %i-%i", + &start, &finish) != 2) { + eprintf("HBF_BYTE_2_RANGE expected"); + return FALSE; + } + add_b2r(&(hbf->byte_2_range), start, finish); + } + if (! get_text_line(line, MAXLINE, f)) + return FALSE; + } + else + add_b2r(&(hbf->byte_2_range), 0, 0xff); + hbf->b2_size = b2_size(hbf->byte_2_range); + + if (! match(line, "HBF_START_CODE_RANGES")) { + eprintf("HBF_START_CODE_RANGES expected"); + return FALSE; + } + for (;;) { + if (! get_text_line(line, MAXLINE, f)) + return FALSE; + if (match(line, "HBF_END_CODE_RANGES")) + break; + if (! add_code_range(hbf, line)) + return FALSE; + } + + for (;;) { + if (! get_text_line(line, MAXLINE, f)) + return FALSE; + if (match(line, "HBF_END_FONT")) + break; + /* treat extra lines as properties (for private extensions) */ + add_property(hbf, line); + } + + return TRUE; +} + +static FILE * +path_open(const char *path, const char *filename, char **fullp) +{ + if (LocalFileName(filename) && path != NULL) { +#ifdef PATH_DELIMITER + char *fullname; + FILE *f; + const char *p_next; + + for (;;) { + p_next = strchr(path, PATH_DELIMITER); + if (p_next == NULL) + p_next = path + strlen(path); + fullname = concat(path, p_next - path, filename); + if ((f = fopen(fullname, "r")) != NULL) { + *fullp = fullname; + return f; + } + free(fullname); + if (*p_next == '\0') + break; + path = p_next + 1; + } +#endif + return NULL; + } + else { + *fullp = strdup(filename); + return fopen(*fullp, "r"); + } +} + +static bool +real_open(const char *filename, reg HBF_STRUCT *hbf) +{ + FILE *f; + + f = path_open(getenv("HBFPATH"), filename, &(hbf->filename)); + if (f == NULL) { + eprintf("can't read file '%s'", filename); + return FALSE; + } + if (! parse_file(f, hbf)) { + fclose(f); + return FALSE; + } + fclose(f); + return TRUE; +} + +HBF * +hbfOpen(const char *filename) +{ +reg HBF_STRUCT *hbf; + + if ((hbf = NEW(HBF_STRUCT)) == NULL) { + eprintf("can't allocate HBF structure"); + return NULL; + } + clear_record(hbf); + if (real_open(filename, hbf)) + return &(hbf->public); + hbfClose(&(hbf->public)); + return NULL; +} + +int +HBF_OpenFont(const char *filename, HBF **ptrHandleStorage) +{ + return (*ptrHandleStorage = hbfOpen(filename)) == NULL ? -1 : 0; +} + +/* + * Close files, free everything associated with the HBF. + */ + +int +HBF_CloseFont(HBF *hbfFile) +{ +reg HBF_STRUCT *hbf; + PROPERTY *prop_ptr, *prop_next; + B2_RANGE *b2r_ptr, *b2r_next; + CODE_RANGE *code_ptr, *code_next; + BM_FILE *bmf_ptr, *bmf_next; + int status; + + status = 0; + hbf = (HBF_STRUCT *)hbfFile; + + if (hbf->filename != NULL) + free(hbf->filename); + if (hbf->bitmap_buffer != NULL) + free(hbf->bitmap_buffer); + + for (prop_ptr = hbf->property; + prop_ptr != NULL; + prop_ptr = prop_next) { + prop_next = prop_ptr->prop_next; + free(prop_ptr->prop_name); + free(prop_ptr->prop_value); + free((char *)prop_ptr); + } + + for (b2r_ptr = hbf->byte_2_range; + b2r_ptr != NULL; + b2r_ptr = b2r_next) { + b2r_next = b2r_ptr->b2r_next; + free((char *)b2r_ptr); + } + + for (code_ptr = hbf->code_range; + code_ptr != NULL; + code_ptr = code_next) { + code_next = code_ptr->code_next; + free((char *)code_ptr); + } + + for (bmf_ptr = hbf->bm_file; + bmf_ptr != NULL; + bmf_ptr = bmf_next) { + bmf_next = bmf_ptr->bmf_next; +#ifdef IN_MEMORY + free((char *)(bmf_ptr->bmf_contents)); +#else + if (bmf_ptr->bmf_file != NULL && + fclose(bmf_ptr->bmf_file) < 0) + status = -1; +#endif + free(bmf_ptr->bmf_name); + free((char *)bmf_ptr); + } + + free((char *)hbf); + + return status; +} + +void +hbfClose(HBF *hbfFile) +{ + (void)HBF_CloseFont(hbfFile); +} + +/* + * Fetch a bitmap + */ + +const byte * +hbfGetBitmap(HBF *hbf, HBF_CHAR code) +{ + return get_bitmap((HBF_STRUCT *)hbf, code, (byte *)NULL); +} + +int +HBF_GetBitmap(HBF *hbf, HBF_CHAR code, byte *buffer) +{ + return get_bitmap((HBF_STRUCT *)hbf, code, buffer) == NULL ? -1 : 0; +} + +/* + * Internal function to fetch a bitmap. + * If buffer is non-null, it must be used. + */ +static const byte * +get_bitmap(reg HBF_STRUCT *hbf, HBF_CHAR code, byte *buffer) +{ + CHAR_INDEX pos, b2pos; +reg CODE_RANGE *cp; + BM_FILE *bmf; + int bm_size; + long offset; + + if ((b2pos = b2_pos(hbf, code)) == BAD_CHAR_INDEX) + return NULL; + pos = hbf->b2_size*FirstByte(code) + b2pos; + for (cp = hbf->code_range; cp != NULL; cp = cp->code_next) + if (cp->code_start <= code && code <= cp->code_finish) { + bmf = cp->code_bm_file; + bm_size = FileBitmapSize(&(hbf->public), cp); + offset = cp->code_offset + + (long)(pos - cp->code_pos) * bm_size; +#ifdef IN_MEMORY + if (buffer == NULL && + ! cp->code_transposed && ! cp->code_inverted) + return bmf->bmf_contents + offset; +#endif /* IN_MEMORY */ + if (buffer == NULL && + ((buffer = local_buffer(hbf)) == NULL)) + return NULL; +#ifdef IN_MEMORY + if (cp->code_transposed) + copy_transposed(&(hbf->public), + buffer, + bmf->bmf_contents + offset); + else + memcpy((char *)buffer, + (char *)(bmf->bmf_contents + offset), + bm_size); +#else /* ! IN_MEMORY */ + if (fseek(bmf->bmf_file, offset, 0) != 0) { + eprintf("seek error on code 0x%04x", code); + return NULL; + } + if (cp->code_transposed ? + ! get_transposed(&(hbf->public), bmf->bmf_file, + buffer) : + fread((char *)buffer, + bm_size, 1, bmf->bmf_file) != 1) { + eprintf("read error on code 0x%04x", code); + return NULL; + } +#endif /* IN_MEMORY */ + if (cp->code_inverted) + invert(buffer, HBF_BitmapSize(&(hbf->public))); + return buffer; + } + eprintf("code 0x%04x out of range", code); + return NULL; +} + +static byte * +local_buffer(HBF_STRUCT *hbf) +{ + if (hbf->bitmap_buffer == NULL && + (hbf->bitmap_buffer = (byte *)malloc(HBF_BitmapSize(&(hbf->public)))) == NULL) { + eprintf("out of memory"); + return NULL; + } + return hbf->bitmap_buffer; +} + +static void +invert(byte *buffer, unsigned int length) +{ + for ( ; length > 0; length--) + *buffer++ ^= 0xff; +} + +#ifdef IN_MEMORY +static bool +copy_transposed(HBF *hbf, reg byte *bitmap, reg const byte *source) +{ +reg byte *pos; +reg byte *bm_end; + int x; + int width; +reg int row_size; +reg int c; +reg int imask, omask; + + width = hbfBitmapBBox(hbf)->hbf_width; + row_size = HBF_RowSize(hbf); + bm_end = bitmap + HBF_BitmapSize(hbf); + (void)memset((char *)bitmap, '\0', HBF_BitmapSize(hbf)); + for (x = 0; x < width; x++) { + pos = bitmap + x/8; + omask = Bit(x%8); + /* y = 0 */ + for (;;) { + c = *source++; + for (imask = Bit(0); imask != 0; imask >>= 1) { + /* + * At this point, + * + * imask == Bit(y%8) + * pos == bitmap + y*row_size + x/8 + * + * We examine bit y of row x of the input, + * setting bit x of row y of the output if + * required, by applying omask to *pos. + */ + if ((c & imask) != 0) + *pos |= omask; + /* if (++y > height) goto end_column */ + pos += row_size; + if (pos >= bm_end) + goto end_column; + } + } +end_column: + ; + } + return TRUE; +} +#else /* ! IN_MEMORY */ +static bool +get_transposed(HBF *hbf, FILE *f, reg byte *bitmap) +{ +reg byte *pos; +reg byte *bm_end; + int x; + int width; +reg int row_size; +reg int c; +reg int imask, omask; + + width = hbfBitmapBBox(hbf)->hbf_width; + row_size = HBF_RowSize(hbf); + bm_end = bitmap + HBF_BitmapSize(hbf); + (void)memset((char *)bitmap, '\0', HBF_BitmapSize(hbf)); + for (x = 0; x < width; x++) { + pos = bitmap + x/8; + omask = Bit(x%8); + /* y = 0 */ + for (;;) { + if ((c = getc(f)) == EOF) + return FALSE; + for (imask = Bit(0); imask != 0; imask >>= 1) { + /* + * At this point, + * + * imask == Bit(y%8) + * pos == bitmap + y*row_size + x/8 + * + * We examine bit y of row x of the input, + * setting bit x of row y of the output if + * required, by applying omask to *pos. + */ + if ((c & imask) != 0) + *pos |= omask; + /* if (++y > height) goto end_column */ + pos += row_size; + if (pos >= bm_end) + goto end_column; + } + } +end_column: + ; + } + return TRUE; +} +#endif /* ! IN_MEMORY */ + +/* + * Call function on each valid code in ascending order. + */ +void +hbfForEach(reg HBF *hbfFile, void (*func)(HBF *, HBF_CHAR)) +{ + HBF_STRUCT *hbf; + CODE_RANGE *cp; +reg B2_RANGE *b2r; +reg unsigned byte1, byte2; +reg unsigned finish; + + hbf = (HBF_STRUCT *)hbfFile; + for (cp = hbf->code_range; cp != NULL; cp = cp->code_next) { + byte1 = FirstByte(cp->code_start); + byte2 = SecondByte(cp->code_start); + while (MakeCode(byte1, byte2) <= cp->code_finish) { + for (b2r = hbf->byte_2_range; + b2r != NULL; + b2r = b2r->b2r_next) { + if (byte2 < b2r->b2r_start) + byte2 = b2r->b2r_start; + finish = b2r->b2r_finish; + if (byte1 == FirstByte(cp->code_finish) && + finish > SecondByte(cp->code_finish)) + finish = SecondByte(cp->code_finish); + while (byte2 <= finish) { + (*func)(hbfFile, + MakeCode(byte1, byte2)); + byte2++; + } + } + byte1++; + byte2 = 0; + } + } +} + +const char * +hbfFileName(HBF *hbf) +{ + return ((HBF_STRUCT *)hbf)->filename; +} + +long +hbfChars(HBF *hbfFile) +{ + HBF_STRUCT *hbf; + CODE_RANGE *cp; + long num_chars; + + hbf = (HBF_STRUCT *)hbfFile; + num_chars = 0; + for (cp = hbf->code_range; cp != NULL; cp = cp->code_next) + num_chars += + hbf->b2_size*FirstByte(cp->code_finish) + + b2_pos(hbf, cp->code_finish) - + (hbf->b2_size*FirstByte(cp->code_start) + + b2_pos(hbf, cp->code_start)) + 1; + return num_chars; +} + +/* + * Functions also implemented as macros + */ + +#ifdef hbfBitmapBBox +#undef hbfBitmapBBox +#endif + +HBF_BBOX * +hbfBitmapBBox(HBF *hbf) +{ + return &(hbf->hbf_bitmap_bbox); +} + +#ifdef hbfFontBBox +#undef hbfFontBBox +#endif + +HBF_BBOX * +hbfFontBBox(HBF *hbf) +{ + return &(hbf->hbf_font_bbox); +} + +const void * +hbfGetByte2Range(HBF *hbfFile, const void *b2r_pointer, + byte *startp, byte *finishp) +{ + HBF_STRUCT *hbf; + const B2_RANGE *b2r; + + hbf = (HBF_STRUCT *)hbfFile; + if (b2r_pointer == NULL) + b2r = hbf->byte_2_range; + else + b2r = ((const B2_RANGE *)b2r_pointer)->b2r_next; + if(b2r == NULL) + return NULL; + *startp = b2r->b2r_start; + *finishp = b2r->b2r_finish; + return (const void *)b2r; +} + +const void * +hbfGetCodeRange(HBF *hbfFile, const void *code_pointer, + HBF_CHAR *startp, HBF_CHAR *finishp) +{ + HBF_STRUCT *hbf; + const CODE_RANGE *cp; + + hbf = (HBF_STRUCT *)hbfFile; + if (code_pointer == NULL) + cp = hbf->code_range; + else + cp = ((const CODE_RANGE *)code_pointer)->code_next; + if(cp == NULL) + return NULL; + *startp = cp->code_start; + *finishp = cp->code_finish; + return (const void *)cp; +} |