1 /*
2 * Copyright 1993,1994,1995,2005 by Ross Paterson
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote
14 * products derived from this software without specific prior written
15 * permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 *
30 * Ross Paterson <ross@soi.city.ac.uk>
31 * 17 October 1995
32 *
33 * The following people have supplied bug fixes:
34 *
35 * Simon Chow <khsc@synoptics.com>
36 * Fung Fung Lee <lee@simd.stanford.edu>
37 * Man-Chi Pong <mcpong@cs.ust.hk>
38 * Steven Simpson <simpson@math.psu.edu>
39 * Charles Wang <charles.wang@infores.com>
40 * Werner Lemberg <wl@gnu.org>
41 *
42 * Ross no longer maintains this code. Please send bug reports to
43 * Werner Lemberg <wl@gnu.org>.
44 *
45 */
46
47 /*
48 * Two C interfaces to HBF files.
49 *
50 * The multiple interfaces make this code rather messy; I intend
51 * to clean it up as experience is gained on what is really needed.
52 *
53 * There are also two modes of operation:
54 * - the default is to read each bitmap from its file as demanded
55 * - if IN_MEMORY is defined, the whole bitmap file is held in memory.
56 * In this case, if running under Unix, the bitmap files may be gzipped
57 * (but the filename used in the HBF file should be the name of the
58 * file before it was gzipped).
59 */
60 #include <stddef.h>
61 #include <stdlib.h>
62 #include <stdio.h>
63 #include <ctype.h>
64 #include <string.h>
65 #include "hbf.h"
66
67 #ifdef __MSDOS__
68 #define msdos
69 #endif
70
71 /*
72 * if the linker complains about an unresolved identifier '_strdup',
73 * uncomment the following definition.
74 */
75 /* #define NO_STRDUP */
76
77 #ifdef __STDC__
78 # define _(x) x
79 #else
80 # define _(x) ()
81 #endif
82
83 #define reg register
84
85 typedef int bool;
86 #define TRUE 1
87 #define FALSE 0
88
89 #define Bit(n) (1<<(7 - (n)))
90
91 /*
92 * Messy file system issues
93 */
94
95 #ifdef unix
96 #define PATH_DELIMITER ':'
97 #define RelativeFileName(fn) ((fn)[0] != '/')
98 #define LocalFileName(fn) (strchr(fn, '/') == NULL)
99 #endif /* unix */
100 #ifdef msdos
101 #define PATH_DELIMITER ';'
102 #define HasDrive(fn) (isalpha((fn)[0]) && (fn)[1] == ':')
103 #ifdef __EMX__
104 #define RelativeFileName(fn) (! HasDrive(fn) && \
105 !((fn)[0] == '\\' || (fn)[0] == '/'))
106 #define LocalFileName(fn) (! HasDrive(fn) && \
107 strchr(fn, '\\') == NULL && \
108 strchr(fn, '/') == NULL)
109 #else
110 #define RelativeFileName(fn) (! HasDrive(fn) && (fn)[0] != '\\')
111 #define LocalFileName(fn) (! HasDrive(fn) && strchr(fn, '\\') == NULL)
112 #endif /* __EMX__ */
113 #define READ_BINARY "rb"
114 #endif /* msdos */
115 #ifdef vms
116 #define PATH_DELIMITER ','
117 #define RelativeFileName(fn) (strchr(fn, ':') == NULL && ((fn)[0] != '[' || (fn)[1] == '.' || (fn)[1] == '-'))
118 #define LocalFileName(fn) (strchr(fn, ':') == NULL && strchr(fn, ']') == NULL)
119 #endif
120
121 #ifndef RelativeFileName
122 #define RelativeFileName(fn) FALSE
123 #endif
124
125 #ifndef LocalFileName
126 #define LocalFileName(fn) FALSE
127 #endif
128
129 #ifndef READ_BINARY
130 #define READ_BINARY "r"
131 #endif
132
133 #define MAX_FILENAME 1024
134
135 /*
136 * Internal structures
137 */
138
139 typedef unsigned char byte;
140
141 #define PROPERTY struct _PROPERTY
142 #define BM_FILE struct _BM_FILE
143 #define B2_RANGE struct _B2_RANGE
144 #define CODE_RANGE struct _CODE_RANGE
145
146 PROPERTY {
147 char *prop_name;
148 char *prop_value;
149 PROPERTY *prop_next;
150 };
151
152 BM_FILE {
153 char *bmf_name;
154 #ifdef IN_MEMORY
155 byte *bmf_contents;
156 #else
157 FILE *bmf_file;
158 #endif
159 long bmf_size;
160 BM_FILE *bmf_next;
161 };
162
163 B2_RANGE {
164 byte b2r_start;
165 byte b2r_finish;
166 B2_RANGE *b2r_next;
167 };
168
169 typedef unsigned short CHAR;
170 typedef unsigned int CHAR_INDEX; /* character index in file */
171 #define BAD_CHAR_INDEX 0xffff
172
173 CODE_RANGE {
174 CHAR code_start;
175 CHAR code_finish;
176 BM_FILE *code_bm_file;
177 long code_offset;
178 CHAR_INDEX code_pos;
179 bool code_transposed;
180 bool code_inverted;
181 CODE_RANGE *code_next;
182 };
183
184 /*
185 * Extended internal version of HBF
186 */
187
188 typedef struct {
189 /* fields corresponding to the definition */
190 HBF public;
191 /* plus internal stuff */
192 char *filename;
193 byte *bitmap_buffer;
194 unsigned int b2_size; /* number of legal byte-2's */
195 PROPERTY *property;
196 B2_RANGE *byte_2_range;
197 CODE_RANGE *code_range;
198 BM_FILE *bm_file;
199 } HBF_STRUCT;
200
201 #define FirstByte(code) ((code)>>8)
202 #define SecondByte(code) ((code)&0xff)
203 #define MakeCode(byte1,byte2) (((byte1)<<8)|(byte2))
204
205 /* size of a bitmap in the file (may be affected by transposition) */
206 #define FileBitmapSize(hbfFile,cp) \
207 ((cp)->code_transposed ? \
208 (hbfBitmapBBox(hbfFile)->hbf_height + 7)/8 * \
209 hbfBitmapBBox(hbfFile)->hbf_width : \
210 HBF_BitmapSize(hbfFile))
211
212 #define NEW(type) ((type *)malloc((unsigned)(sizeof(type))))
213
214 #define QUOTE '"'
215
216 #define MAXLINE 1024
217
218 #ifdef WIN32
219 #define strdup(x) _strdup(x)
220 #else
221 extern char *strdup _((const char *s));
222 #endif
223
224 static void add_b2r _((B2_RANGE **last_b2r, int start, int finish));
225 static bool add_code_range _((HBF_STRUCT *hbf, const char *line));
226 static void add_property _((HBF_STRUCT *hbf, const char *lp));
227 static CHAR_INDEX b2_pos _((HBF_STRUCT *hbf, HBF_CHAR code));
228 static int b2_size _((B2_RANGE *b2r));
229 static void clear_bbox _((HBF_BBOX *bbox));
230 static void clear_record _((HBF_STRUCT *hbf));
231 static char *concat _((const char *dir, int dirlen, const char *stem));
232 static char *expand_filename _((const char *name, const char *filename));
233 static const byte *get_bitmap
234 _((HBF_STRUCT *hbf, HBF_CHAR code, byte *buffer));
235 static byte *local_buffer _((HBF_STRUCT *hbf));
236 static void invert _((byte *buffer, unsigned length));
237 #ifdef IN_MEMORY
238 static bool read_bitmap_file _((BM_FILE *bmf, FILE *f));
239 static bool copy_transposed
240 _((HBF *hbf, byte *bitmap, const byte *source));
241 #else
242 static bool get_transposed _((HBF *hbf, FILE *f, byte *bitmap));
243 #endif
244 static bool match _((const char *lp, const char *sp));
245 static bool parse_file _((FILE *f, HBF_STRUCT *hbf));
246 static FILE *path_open
247 _((const char *path, const char *filename, char **fullp));
248 static bool real_open _((const char *filename, HBF_STRUCT *hbf));
249
250 /* Error reporting */
251
252 int hbfDebug; /* set this for error reporting */
253
254 #ifdef __STDC__
255 #include <stdarg.h>
256
257 static void
eprintf(const char * fmt,...)258 eprintf(const char *fmt, ...)
259 {
260 if (hbfDebug) {
261 va_list args;
262
263 (void)fprintf(stderr, "HBF: ");
264 va_start(args, fmt);
265 (void)vfprintf(stderr, fmt, args);
266 va_end(args);
267 (void)fprintf(stderr, "\n");
268 }
269 }
270 #else /* ! __STDC__ */
271 /* poor man's variable-length argument list */
272 static void
eprintf(fmt,x1,x2,x3,x4,x5,x6,x7,x8,x9)273 eprintf(fmt, x1, x2, x3, x4, x5, x6, x7, x8, x9)
274 const char *fmt;
275 int x1, x2, x3, x4, x5, x6, x7, x8, x9;
276 {
277 if (hbfDebug) {
278 (void)fprintf(stderr, "HBF: ");
279 (void)fprintf(stderr, fmt, x1, x2, x3, x4, x5, x6, x7, x8, x9);
280 (void)fprintf(stderr, "\n");
281 }
282 }
283 #endif /* __STDC__ */
284
285 static void
clear_bbox(bbox)286 clear_bbox(bbox)
287 HBF_BBOX *bbox;
288 {
289 bbox->hbf_width = bbox->hbf_height = 0;
290 bbox->hbf_xDisplacement = bbox->hbf_yDisplacement = 0;
291 }
292
293 static void
clear_record(hbf)294 clear_record(hbf)
295 HBF_STRUCT *hbf;
296 {
297 clear_bbox(&(hbf->public.hbf_bitmap_bbox));
298 clear_bbox(&(hbf->public.hbf_font_bbox));
299 hbf->property = NULL;
300 hbf->filename = NULL;
301 hbf->bitmap_buffer = NULL;
302 hbf->byte_2_range = NULL;
303 hbf->code_range = NULL;
304 hbf->bm_file = NULL;
305 }
306
307 /*
308 * Byte-2 ranges
309 */
310
311 static void
add_b2r(last_b2r,start,finish)312 add_b2r(last_b2r, start, finish)
313 reg B2_RANGE **last_b2r;
314 int start;
315 int finish;
316 {
317 reg B2_RANGE *b2r;
318
319 b2r = NEW(B2_RANGE);
320 while (*last_b2r != NULL && (*last_b2r)->b2r_start < start)
321 last_b2r = &((*last_b2r)->b2r_next);
322 b2r->b2r_next = *last_b2r;
323 b2r->b2r_start = start;
324 b2r->b2r_finish = finish;
325 *last_b2r = b2r;
326 }
327
328 static CHAR_INDEX
b2_pos(hbf,code)329 b2_pos(hbf, code)
330 HBF_STRUCT *hbf;
331 HBF_CHAR code;
332 {
333 reg B2_RANGE *b2r;
334 reg unsigned c;
335 reg CHAR_INDEX pos;
336
337 c = SecondByte(code);
338 pos = 0;
339 for (b2r = hbf->byte_2_range; b2r != NULL; b2r = b2r->b2r_next)
340 if (b2r->b2r_start <= c && c <= b2r->b2r_finish)
341 return pos + c - b2r->b2r_start;
342 else
343 pos += b2r->b2r_finish - b2r->b2r_start + 1;
344 return BAD_CHAR_INDEX;
345 }
346
347 static int
b2_size(b2r)348 b2_size(b2r)
349 reg B2_RANGE *b2r;
350 {
351 reg int size;
352
353 size = 0;
354 for ( ; b2r != NULL; b2r = b2r->b2r_next)
355 size += b2r->b2r_finish - b2r->b2r_start + 1;
356 return size;
357 }
358
359 /* map a position to a character code */
360 static long
code_of(hbf,pos)361 code_of(hbf, pos)
362 HBF_STRUCT *hbf;
363 long pos;
364 {
365 long code;
366 int residue;
367 reg B2_RANGE *b2r;
368
369 code = pos / hbf->b2_size * 256;
370 residue = pos % hbf->b2_size;
371 for (b2r = hbf->byte_2_range; b2r != NULL; b2r = b2r->b2r_next)
372 if (b2r->b2r_start + residue <= b2r->b2r_finish)
373 return code + b2r->b2r_start + residue;
374 else
375 residue -= b2r->b2r_finish - b2r->b2r_start + 1;
376 /* should never get here */
377 return 0L;
378 }
379
380 /*
381 * String stuff
382 */
383
384 static bool
match(lp,sp)385 match(lp, sp)
386 reg const char *lp;
387 reg const char *sp;
388 {
389 while (*lp == *sp && *sp != '\0') {
390 lp++;
391 sp++;
392 }
393 return (*lp == '\0' || isspace(*lp)) && *sp == '\0';
394 }
395
396 #ifdef NO_STRDUP
397 char *
strdup(s)398 strdup(s)
399 const char *s;
400 {
401 char *new_s;
402
403 new_s = malloc((unsigned)strlen(s) + 1);
404 strcpy(new_s, s);
405 return new_s;
406 }
407 #endif
408
409 /*
410 * Properties
411 */
412
413 static void
add_property(hbf,lp)414 add_property(hbf, lp)
415 reg HBF_STRUCT *hbf;
416 reg const char *lp;
417 {
418 reg PROPERTY *prop;
419 char tmp[MAXLINE];
420 reg char *tp;
421
422 prop = NEW(PROPERTY);
423
424 tp = tmp;
425 while (*lp != '\0' && ! isspace(*lp))
426 *tp++ = *lp++;
427 *tp = '\0';
428 prop->prop_name = strdup(tmp);
429
430 while (*lp != '\0' && isspace(*lp))
431 lp++;
432
433 tp = tmp;
434 if (*lp == QUOTE) {
435 lp++;
436 while (*lp != '\0' && ! (*lp == QUOTE && *++lp != QUOTE))
437 *tp++ = *lp++;
438 }
439 else
440 for (;;) {
441 while (*lp != '\0' && ! isspace(*lp))
442 *tp++ = *lp++;
443 while (*lp != '\0' && isspace(*lp))
444 lp++;
445 if (*lp == '\0')
446 break;
447 *tp++ = ' ';
448 }
449 *tp = '\0';
450 prop->prop_value = strdup(tmp);
451
452 prop->prop_next = hbf->property;
453 hbf->property = prop;
454 }
455
456 const char *
hbfProperty(hbfFile,propName)457 hbfProperty(hbfFile, propName)
458 HBF *hbfFile;
459 const char *propName;
460 {
461 reg HBF_STRUCT *hbf;
462 reg PROPERTY *prop;
463
464 hbf = (HBF_STRUCT *)hbfFile;
465 for (prop = hbf->property; prop != NULL; prop = prop->prop_next)
466 if (strcmp(prop->prop_name, propName) == 0)
467 return prop->prop_value;
468 return NULL;
469 }
470
471 /*
472 * Compatability routines
473 */
474
475 const char *
HBF_GetProperty(handle,propertyName)476 HBF_GetProperty(handle, propertyName)
477 HBF *handle;
478 const char *propertyName;
479 {
480 return hbfProperty(handle, propertyName);
481 }
482
483 int
HBF_GetFontBoundingBox(handle,width,height,xDisplacement,yDisplacement)484 HBF_GetFontBoundingBox(handle, width, height, xDisplacement, yDisplacement)
485 HBF_Handle handle;
486 unsigned int *width;
487 unsigned int *height;
488 int *xDisplacement;
489 int *yDisplacement;
490 {
491 if (width != NULL)
492 *width = hbfFontBBox(handle)->hbf_width;
493 if (height != NULL)
494 *height = hbfFontBBox(handle)->hbf_height;
495 if (xDisplacement != NULL)
496 *xDisplacement = hbfFontBBox(handle)->hbf_xDisplacement;
497 if (yDisplacement != NULL)
498 *yDisplacement = hbfFontBBox(handle)->hbf_yDisplacement;
499 return 0;
500 }
501
502 int
HBF_GetBitmapBoundingBox(handle,width,height,xDisplacement,yDisplacement)503 HBF_GetBitmapBoundingBox(handle, width, height, xDisplacement, yDisplacement)
504 HBF_Handle handle;
505 unsigned int *width;
506 unsigned int *height;
507 int *xDisplacement;
508 int *yDisplacement;
509 {
510 if (width != NULL)
511 *width = hbfBitmapBBox(handle)->hbf_width;
512 if (height != NULL)
513 *height = hbfBitmapBBox(handle)->hbf_height;
514 if (xDisplacement != NULL)
515 *xDisplacement = hbfBitmapBBox(handle)->hbf_xDisplacement;
516 if (yDisplacement != NULL)
517 *yDisplacement = hbfBitmapBBox(handle)->hbf_yDisplacement;
518 return 0;
519 }
520
521 /*
522 * Prepend a directory to a relative filename.
523 */
524 static char *
concat(dir,dirlen,stem)525 concat(dir, dirlen, stem)
526 const char *dir; /* not necessarily null-terminated */
527 int dirlen; /* number of significant chars in dir */
528 const char *stem; /* relative filename */
529 {
530 char *fullname;
531
532 if (dirlen == 0) /* null: current directory */
533 return strdup(stem);
534 #ifdef unix
535 fullname = malloc(dirlen + strlen(stem) + 2);
536 (void)sprintf(fullname, "%.*s/%s", dirlen, dir, stem);
537 #else
538 #ifdef msdos
539 fullname = malloc(dirlen + strlen(stem) + 2);
540 (void)sprintf(fullname, "%.*s\\%s", dirlen, dir, stem);
541 #else
542 #ifdef vms
543 if (dir[dirlen-1] == ']' && stem[0] == '[' && stem[1] == '-') {
544 dirlen--;
545 stem++;
546 fullname = malloc(dirlen + strlen(stem) + 2);
547 (void)sprintf(fullname, "%.*s.%s", dirlen, dir, stem);
548 }
549 else {
550 if (dir[dirlen-1] == ']' && stem[0] == '[' && stem[1] == '.') {
551 dirlen--;
552 stem++;
553 }
554 fullname = malloc(dirlen + strlen(stem) + 1);
555 (void)sprintf(fullname, "%.*s%s", dirlen, dir, stem);
556 }
557 #else
558 fullname = strdup(stem);
559 #endif /* vms */
560 #endif /* msdos */
561 #endif /* unix */
562 return fullname;
563 }
564
565 /*
566 * Bitmap files
567 *
568 * If the host operating system has a heirarchical file system and
569 * the bitmap file name is relative, it is relative to the directory
570 * containing the HBF file.
571 */
572 static char *
expand_filename(name,hbf_name)573 expand_filename(name, hbf_name)
574 const char *name;
575 const char *hbf_name;
576 {
577 #ifdef unix
578 reg char *s;
579 reg int size;
580
581 size = name[0] != '/' && (s = strrchr(hbf_name, '/')) != NULL ?
582 s - hbf_name + 1 : 0;
583 s = malloc((unsigned)size + strlen(name) + 1);
584 (void)sprintf(s, "%.*s%s", size, hbf_name, name);
585 return s;
586 #else
587 #ifdef msdos
588 reg char *s;
589 reg int size;
590
591 #ifdef __EMX__
592 s = (unsigned char *)hbf_name + strlen((unsigned char *)hbf_name) - 1;
593 for(;;) {
594 if (*s == '\\' || *s == '/')
595 break;
596 if (s == hbf_name) {
597 s = NULL;
598 break;
599 }
600 s--;
601 }
602
603 size = HasDrive(name) ? 0 :
604 (name[0] == '\\' || name[0] == '/') ?
605 (HasDrive(hbf_name) ? 2 : 0) :
606 s != NULL ? s - hbf_name + 1 : 0;
607 #else
608 size = HasDrive(name) ? 0 :
609 name[0] == '\\' ? (HasDrive(hbf_name) ? 2 : 0) :
610 (s = strrchr(hbf_name, '\\')) != NULL ?
611 s - hbf_name + 1 : 0;
612 #endif /* __EMX__ */
613 s = malloc((unsigned)size + strlen(name) + 1);
614 (void)sprintf(s, "%.*s%s", size, hbf_name, name);
615 return s;
616 #else
617 #ifdef vms
618 reg char *s;
619 reg const char *copyto;
620 reg int size;
621
622 if ((s = strchr(hbf_name, ']')) != NULL && RelativeFileName(name))
623 return concat(hbf_name, (s - hbf_name) + 1, name);
624
625 copyto = hbf_name;
626 if ((s = strstr(copyto, "::")) != NULL && strstr(name, "::") == NULL)
627 copyto = s+2;
628 if ((s = strchr(copyto, ':')) != NULL && strchr(name, ':') == NULL)
629 copyto = s+1;
630 size = copyto - hbf_name;
631 s = malloc((unsigned)size + strlen(name) + 1);
632 (void)sprintf(s, "%.*s%s", size, hbf_name, name);
633 return s;
634 #else
635 return strdup(name);
636 #endif /* vms */
637 #endif /* msdos */
638 #endif /* unix */
639 }
640
641 static BM_FILE *
find_file(hbf,filename)642 find_file(hbf, filename)
643 HBF_STRUCT *hbf;
644 const char *filename;
645 {
646 BM_FILE **fp;
647 reg BM_FILE *file;
648 FILE *f;
649 char *bmfname;
650 #ifdef IN_MEMORY
651 #ifdef unix
652 bool from_pipe;
653 #endif
654 #endif
655
656 for (fp = &(hbf->bm_file); *fp != NULL; fp = &((*fp)->bmf_next)) {
657 bmfname = strrchr((*fp)->bmf_name, '/');
658 bmfname = (bmfname) ? bmfname + 1 : (*fp)->bmf_name;
659 if (strcmp(bmfname, filename) == 0)
660 return *fp;
661 }
662
663 file = NEW(BM_FILE);
664 if (file == NULL) {
665 eprintf("out of memory");
666 return NULL;
667 }
668 file->bmf_name = expand_filename(filename, hbf->filename);
669 if (file->bmf_name == NULL) {
670 free((char *)file);
671 return NULL;
672 }
673 f = fopen(file->bmf_name, READ_BINARY);
674 #ifdef IN_MEMORY
675 #ifdef unix
676 from_pipe = FALSE;
677 if (f == NULL) {
678 char tmp[400];
679
680 sprintf(tmp, "%s.gz", file->bmf_name);
681 if ((f = fopen(tmp, "r")) != NULL) {
682 fclose(f);
683 sprintf(tmp, "gzcat %s.gz", file->bmf_name);
684 if ((f = popen(tmp, "r")) != NULL)
685 from_pipe = TRUE;
686 }
687 }
688 #endif /* unix */
689 #endif /* IN_MEMORY */
690 if (f == NULL) {
691 eprintf("can't open bitmap file '%s'", file->bmf_name);
692 free(file->bmf_name);
693 free((char *)file);
694 return NULL;
695 }
696 #ifdef IN_MEMORY
697 if (! read_bitmap_file(file, f)) {
698 free(file->bmf_name);
699 free((char *)file);
700 return NULL;
701 }
702 #ifdef unix
703 if (from_pipe)
704 pclose(f);
705 else
706 fclose(f);
707 #else /* ! unix */
708 fclose(f);
709 #endif /* ! unix */
710 #else /* ! IN_MEMORY */
711 file->bmf_file = f;
712 fseek(f, 0L, 2);
713 file->bmf_size = ftell(f);
714 #endif /* ! IN_MEMORY */
715 file->bmf_next = NULL;
716 *fp = file;
717 return file;
718 }
719
720 #ifdef IN_MEMORY
721 #define GRAIN_SIZE 512
722
723 static bool
read_bitmap_file(bmf,f)724 read_bitmap_file(bmf, f)
725 BM_FILE *bmf;
726 FILE *f;
727 {
728 byte *contents, *cp;
729 long size;
730 int c;
731
732 size = 0;
733 cp = contents = (byte *)malloc((unsigned)GRAIN_SIZE);
734 if (contents == NULL) {
735 eprintf("not enough space for bitmap file");
736 return NULL;
737 }
738 while ((c = getc(f)) != EOF) {
739 if (size%GRAIN_SIZE == 0) {
740 contents = (byte *)realloc((char *)contents,
741 (unsigned)(size + GRAIN_SIZE));
742 if (contents == NULL) {
743 eprintf("not enough space for bitmap file");
744 return NULL;
745 }
746 cp = contents + size;
747 }
748 *cp++ = c;
749 size++;
750 }
751 bmf->bmf_size = size;
752 bmf->bmf_contents = (byte *)realloc((char *)contents, (unsigned)size);
753 return TRUE;
754 }
755 #endif /* IN_MEMORY */
756
757 /*
758 * Code ranges
759 */
760
761 /* check that a code range fits within its bitmap file */
762 static bool
too_short(hbf,cp)763 too_short(hbf, cp)
764 HBF_STRUCT *hbf;
765 CODE_RANGE *cp;
766 {
767 int bm_size;
768 long offset, end_offset;
769 BM_FILE *bmf;
770 long start, finish;
771
772 bm_size = FileBitmapSize(&(hbf->public), cp);
773 offset = cp->code_offset;
774 start = cp->code_start;
775 finish = cp->code_finish;
776 end_offset = offset + bm_size *
777 (hbf->b2_size*(long)FirstByte(finish) +
778 b2_pos(hbf, finish) - cp->code_pos + 1);
779 bmf = cp->code_bm_file;
780 if (end_offset <= bmf->bmf_size)
781 return FALSE;
782 /* bitmap file is too short: produce a specific error message */
783 if (offset > bmf->bmf_size)
784 eprintf("bitmap file '%s' is shorter than offset 0x%04lx",
785 bmf->bmf_name, offset);
786 else if (offset + bm_size > bmf->bmf_size)
787 eprintf("bitmap file '%s' too short: no room for any bitmaps at offset 0x%04lx",
788 bmf->bmf_name, offset);
789 else
790 eprintf("bitmap file '%s' is too short - code range appears to be 0x%04lx-0x%04lx",
791 bmf->bmf_name,
792 start,
793 code_of(hbf, cp->code_pos +
794 (bmf->bmf_size - offset)/bm_size) - 1);
795 return TRUE;
796 }
797
798 static const char *
skip_word(n,s)799 skip_word(n, s)
800 int n;
801 const char *s;
802 {
803 for ( ; n > 0; n--) {
804 while (*s != '\0' && ! isspace(*s))
805 s++;
806 while (*s != '\0' && isspace(*s))
807 s++;
808 }
809 return s;
810 }
811
812 /* optional keywords at the end of a CODE_RANGE line */
813 static void
parse_keywords(cp,s)814 parse_keywords(cp, s)
815 CODE_RANGE *cp;
816 const char *s;
817 {
818 for (s = skip_word(4, s) ; *s != '\0'; s = skip_word(1, s)) {
819 switch (*s) {
820 case 's': case 'S': case 't': case 'T':
821 /* keyword "sideways" or "transposed" */
822 cp->code_transposed = TRUE;
823 break;
824 case 'i': case 'I':
825 /* keyword "inverted" */
826 cp->code_inverted = TRUE;
827 }
828 }
829 }
830
831 static bool
add_code_range(hbf,line)832 add_code_range(hbf, line)
833 HBF_STRUCT *hbf;
834 const char *line;
835 {
836 CODE_RANGE *cp;
837 CODE_RANGE **cpp;
838 long start, finish;
839 long offset;
840 char filename[MAXLINE];
841 BM_FILE *bmf;
842 CHAR_INDEX b2pos;
843
844 if (sscanf(line, "HBF_CODE_RANGE %li-%li %s %li",
845 &start, &finish, filename, &offset) != 4) {
846 eprintf("syntax error in HBF_CODE_RANGE");
847 return FALSE;
848 }
849 /* code ranges are checked in real_open() */
850 if ((bmf = find_file(hbf, filename)) == NULL)
851 return FALSE;
852 if ((cp = NEW(CODE_RANGE)) == NULL) {
853 eprintf("out of memory");
854 return FALSE;
855 }
856
857 cp->code_start = (CHAR)start;
858 cp->code_finish = (CHAR)finish;
859 cp->code_bm_file = bmf;
860 cp->code_offset = offset;
861 cp->code_transposed = cp->code_inverted = FALSE;
862 parse_keywords(cp, line);
863 /* insert it in order */
864 for (cpp = &hbf->code_range;
865 *cpp != NULL && (*cpp)->code_finish < start;
866 cpp = &((*cpp)->code_next))
867 ;
868 if (*cpp != NULL && (*cpp)->code_start <= finish) {
869 eprintf("code ranges overlap");
870 return FALSE;
871 }
872 cp->code_next = *cpp;
873 *cpp = cp;
874
875 /* set code_pos, and check range */
876 if (start > finish) {
877 eprintf("illegal code range 0x%04lx-0x%04lx", start, finish);
878 return FALSE;
879 }
880 if ((b2pos = b2_pos(hbf, start)) == BAD_CHAR_INDEX) {
881 eprintf("illegal start code 0x%04lx", start);
882 return FALSE;
883 }
884 cp->code_pos = hbf->b2_size*(long)FirstByte(start) + b2pos;
885 if ((b2pos = b2_pos(hbf, finish)) == BAD_CHAR_INDEX) {
886 eprintf("illegal finish code 0x%04lx", finish);
887 return FALSE;
888 }
889 /* check that the bitmap file has enough bitmaps */
890 return ! too_short(hbf, cp);
891 }
892
893 /*
894 * Reading and parsing of an HBF file
895 */
896
897 /* get line, truncating to len, and trimming trailing spaces */
898 static bool
get_line(buf,len,f)899 get_line(buf, len, f)
900 char *buf;
901 int len;
902 FILE *f;
903 {
904 int c;
905 char *bp;
906
907 bp = buf;
908 for (;;) {
909 if ((c = getc(f)) == EOF) {
910 eprintf("unexpected end of file");
911 return FALSE;
912 }
913 if (c == '\n' || c == '\r') {
914 /* trim trailing space */
915 while (bp > buf && isspace(*(bp-1)))
916 bp--;
917 *bp = '\0';
918 return TRUE;
919 }
920 if (len > 0) {
921 *bp++ = c;
922 len--;
923 }
924 }
925 }
926
927 /* get next non-COMMENT line */
928 static bool
get_text_line(buf,len,f)929 get_text_line(buf, len, f)
930 char *buf;
931 int len;
932 FILE *f;
933 {
934 while (get_line(buf, len, f))
935 if (*buf != '\0' && ! match(buf, "COMMENT"))
936 return TRUE;
937 return FALSE;
938 }
939
940 static bool
get_property(line,keyword,hbf)941 get_property(line, keyword, hbf)
942 const char *line;
943 const char *keyword;
944 HBF_STRUCT *hbf;
945 {
946 if (! match(line, keyword)) {
947 eprintf("%s expected", keyword);
948 return FALSE;
949 }
950 add_property(hbf, line);
951 return TRUE;
952 }
953
954 static bool
get_bbox(line,keyword,bbox)955 get_bbox(line, keyword, bbox)
956 const char *line;
957 const char *keyword;
958 HBF_BBOX *bbox;
959 {
960 int w, h, xd, yd;
961
962 if (! match(line, keyword) ||
963 sscanf(line + strlen(keyword), "%i %i %i %i",
964 &w, &h, &xd, &yd) != 4) {
965 eprintf("%s expected", keyword);
966 return FALSE;
967 }
968 if (w <= 0 || h <= 0) {
969 eprintf("illegal %s dimensions %dx%d", keyword, w, h);
970 return FALSE;
971 }
972 bbox->hbf_width = w;
973 bbox->hbf_height = h;
974 bbox->hbf_xDisplacement = xd;
975 bbox->hbf_yDisplacement = yd;
976 return TRUE;
977 }
978
979 /*
980 * HBFHeaderFile ::=
981 * 'HBF_START_FONT' version EOLN
982 * 'HBF_CODE_SCHEME' word ... EOLN
983 * 'FONT' fontName EOLN
984 * 'SIZE' ptsize xres yres EOLN
985 * 'HBF_BITMAP_BOUNDING_BOX' w h xd yd EOLN
986 * 'FONTBOUNDINGBOX' w h xd yd EOLN
987 * X11R5FontPropertySection
988 * 'CHARS' n EOLN
989 * HBFByte2RangeSection
990 * HBFCodeRangeSection
991 * 'HBF_END_FONT' EOLN .
992 *
993 * This implementation allows extra lines before HBF_END_FONT.
994 * Anything after HBF_END_FONT is ignored.
995 */
996
997 static bool
parse_file(f,hbf)998 parse_file(f, hbf)
999 FILE *f;
1000 reg HBF_STRUCT *hbf;
1001 {
1002 char line[MAXLINE];
1003 int start, finish;
1004
1005 if (! get_text_line(line, MAXLINE, f) ||
1006 ! get_property(line, "HBF_START_FONT", hbf))
1007 return FALSE;
1008
1009 if (! get_text_line(line, MAXLINE, f) ||
1010 ! get_property(line, "HBF_CODE_SCHEME", hbf))
1011 return FALSE;
1012
1013 if (! get_text_line(line, MAXLINE, f) ||
1014 ! get_property(line, "FONT", hbf))
1015 return FALSE;
1016
1017 if (! get_text_line(line, MAXLINE, f) ||
1018 ! get_property(line, "SIZE", hbf))
1019 return FALSE;
1020
1021 if (! get_text_line(line, MAXLINE, f) ||
1022 ! get_bbox(line, "HBF_BITMAP_BOUNDING_BOX",
1023 &(hbf->public.hbf_bitmap_bbox)))
1024 return FALSE;
1025
1026 if (! get_text_line(line, MAXLINE, f) ||
1027 ! get_bbox(line, "FONTBOUNDINGBOX", &(hbf->public.hbf_font_bbox)))
1028 return FALSE;
1029
1030 if (! get_text_line(line, MAXLINE, f))
1031 return FALSE;
1032 if (match(line, "STARTPROPERTIES")) {
1033 for (;;) {
1034 if (! get_text_line(line, MAXLINE, f))
1035 return FALSE;
1036 if (match(line, "ENDPROPERTIES"))
1037 break;
1038 add_property(hbf, line);
1039 }
1040 if (! get_text_line(line, MAXLINE, f))
1041 return FALSE;
1042 }
1043
1044 if (match(line, "CHARS"))
1045 if (! get_text_line(line, MAXLINE, f))
1046 return FALSE;
1047
1048 if (match(line, "HBF_START_BYTE_2_RANGES")) {
1049 for (;;) {
1050 if (! get_text_line(line, MAXLINE, f))
1051 return FALSE;
1052 if (match(line, "HBF_END_BYTE_2_RANGES"))
1053 break;
1054 if (sscanf(line, "HBF_BYTE_2_RANGE %i-%i",
1055 &start, &finish) != 2) {
1056 eprintf("HBF_BYTE_2_RANGE expected");
1057 return FALSE;
1058 }
1059 add_b2r(&(hbf->byte_2_range), start, finish);
1060 }
1061 if (! get_text_line(line, MAXLINE, f))
1062 return FALSE;
1063 }
1064 else
1065 add_b2r(&(hbf->byte_2_range), 0, 0xff);
1066 hbf->b2_size = b2_size(hbf->byte_2_range);
1067
1068 if (! match(line, "HBF_START_CODE_RANGES")) {
1069 eprintf("HBF_START_CODE_RANGES expected");
1070 return FALSE;
1071 }
1072 for (;;) {
1073 if (! get_text_line(line, MAXLINE, f))
1074 return FALSE;
1075 if (match(line, "HBF_END_CODE_RANGES"))
1076 break;
1077 if (! add_code_range(hbf, line))
1078 return FALSE;
1079 }
1080
1081 for (;;) {
1082 if (! get_text_line(line, MAXLINE, f))
1083 return FALSE;
1084 if (match(line, "HBF_END_FONT"))
1085 break;
1086 /* treat extra lines as properties (for private extensions) */
1087 add_property(hbf, line);
1088 }
1089
1090 return TRUE;
1091 }
1092
1093 static FILE *
path_open(path,filename,fullp)1094 path_open(path, filename, fullp)
1095 const char *path;
1096 const char *filename;
1097 char **fullp;
1098 {
1099 if (LocalFileName(filename) && path != NULL) {
1100 #ifdef PATH_DELIMITER
1101 int len;
1102 char *fullname;
1103 FILE *f;
1104 const char *p_next;
1105
1106 len = strlen(filename);
1107 for (;;) {
1108 p_next = strchr(path, PATH_DELIMITER);
1109 if (p_next == NULL)
1110 p_next = path + strlen(path);
1111 fullname = concat(path, p_next - path, filename);
1112 if ((f = fopen(fullname, "r")) != NULL) {
1113 *fullp = fullname;
1114 return f;
1115 }
1116 free(fullname);
1117 if (*p_next == '\0')
1118 break;
1119 path = p_next + 1;
1120 }
1121 #endif
1122 return NULL;
1123 }
1124 else {
1125 *fullp = strdup(filename);
1126 return fopen(*fullp, "r");
1127 }
1128 }
1129
1130 static bool
real_open(filename,hbf)1131 real_open(filename, hbf)
1132 const char *filename;
1133 reg HBF_STRUCT *hbf;
1134 {
1135 FILE *f;
1136
1137 f = path_open(getenv("HBFPATH"), filename, &(hbf->filename));
1138 if (f == NULL) {
1139 eprintf("can't read file '%s'", filename);
1140 return FALSE;
1141 }
1142 if (! parse_file(f, hbf)) {
1143 fclose(f);
1144 return FALSE;
1145 }
1146 fclose(f);
1147 return TRUE;
1148 }
1149
1150 HBF *
hbfOpen(filename)1151 hbfOpen(filename)
1152 const char *filename;
1153 {
1154 reg HBF_STRUCT *hbf;
1155
1156 if ((hbf = NEW(HBF_STRUCT)) == NULL) {
1157 eprintf("can't allocate HBF structure");
1158 return NULL;
1159 }
1160 clear_record(hbf);
1161 if (real_open(filename, hbf))
1162 return &(hbf->public);
1163 hbfClose(&(hbf->public));
1164 return NULL;
1165 }
1166
1167 int
HBF_OpenFont(filename,ptrHandleStorage)1168 HBF_OpenFont(filename, ptrHandleStorage)
1169 const char *filename;
1170 HBF **ptrHandleStorage;
1171 {
1172 return (*ptrHandleStorage = hbfOpen(filename)) == NULL ? -1 : 0;
1173 }
1174
1175 /*
1176 * Close files, free everything associated with the HBF.
1177 */
1178
1179 int
HBF_CloseFont(hbfFile)1180 HBF_CloseFont(hbfFile)
1181 HBF *hbfFile;
1182 {
1183 reg HBF_STRUCT *hbf;
1184 PROPERTY *prop_ptr, *prop_next;
1185 B2_RANGE *b2r_ptr, *b2r_next;
1186 CODE_RANGE *code_ptr, *code_next;
1187 BM_FILE *bmf_ptr, *bmf_next;
1188 int status;
1189
1190 status = 0;
1191 hbf = (HBF_STRUCT *)hbfFile;
1192
1193 if (hbf->filename != NULL)
1194 free(hbf->filename);
1195 if (hbf->bitmap_buffer != NULL)
1196 free(hbf->bitmap_buffer);
1197
1198 for (prop_ptr = hbf->property;
1199 prop_ptr != NULL;
1200 prop_ptr = prop_next) {
1201 prop_next = prop_ptr->prop_next;
1202 free(prop_ptr->prop_name);
1203 free(prop_ptr->prop_value);
1204 free((char *)prop_ptr);
1205 }
1206
1207 for (b2r_ptr = hbf->byte_2_range;
1208 b2r_ptr != NULL;
1209 b2r_ptr = b2r_next) {
1210 b2r_next = b2r_ptr->b2r_next;
1211 free((char *)b2r_ptr);
1212 }
1213
1214 for (code_ptr = hbf->code_range;
1215 code_ptr != NULL;
1216 code_ptr = code_next) {
1217 code_next = code_ptr->code_next;
1218 free((char *)code_ptr);
1219 }
1220
1221 for (bmf_ptr = hbf->bm_file;
1222 bmf_ptr != NULL;
1223 bmf_ptr = bmf_next) {
1224 bmf_next = bmf_ptr->bmf_next;
1225 #ifdef IN_MEMORY
1226 free((char *)(bmf_ptr->bmf_contents));
1227 #else
1228 if (bmf_ptr->bmf_file != NULL &&
1229 fclose(bmf_ptr->bmf_file) < 0)
1230 status = -1;
1231 #endif
1232 free(bmf_ptr->bmf_name);
1233 free((char *)bmf_ptr);
1234 }
1235
1236 free((char *)hbf);
1237
1238 return status;
1239 }
1240
1241 void
hbfClose(hbfFile)1242 hbfClose(hbfFile)
1243 HBF *hbfFile;
1244 {
1245 (void)HBF_CloseFont(hbfFile);
1246 }
1247
1248 /*
1249 * Fetch a bitmap
1250 */
1251
1252 const byte *
hbfGetBitmap(hbf,code)1253 hbfGetBitmap(hbf, code)
1254 HBF *hbf;
1255 HBF_CHAR code;
1256 {
1257 return get_bitmap((HBF_STRUCT *)hbf, code, (byte *)NULL);
1258 }
1259
1260 int
HBF_GetBitmap(hbf,code,buffer)1261 HBF_GetBitmap(hbf, code, buffer)
1262 HBF *hbf;
1263 HBF_CHAR code;
1264 byte *buffer;
1265 {
1266 return get_bitmap((HBF_STRUCT *)hbf, code, buffer) == NULL ? -1 : 0;
1267 }
1268
1269 /*
1270 * Internal function to fetch a bitmap.
1271 * If buffer is non-null, it must be used.
1272 */
1273 static const byte *
get_bitmap(hbf,code,buffer)1274 get_bitmap(hbf, code, buffer)
1275 reg HBF_STRUCT *hbf;
1276 HBF_CHAR code;
1277 byte *buffer;
1278 {
1279 CHAR_INDEX pos, b2pos;
1280 reg CODE_RANGE *cp;
1281 BM_FILE *bmf;
1282 int bm_size;
1283 long offset;
1284
1285 if ((b2pos = b2_pos(hbf, code)) == BAD_CHAR_INDEX)
1286 return NULL;
1287 pos = hbf->b2_size*FirstByte(code) + b2pos;
1288 for (cp = hbf->code_range; cp != NULL; cp = cp->code_next)
1289 if (cp->code_start <= code && code <= cp->code_finish) {
1290 bmf = cp->code_bm_file;
1291 bm_size = FileBitmapSize(&(hbf->public), cp);
1292 offset = cp->code_offset +
1293 (long)(pos - cp->code_pos) * bm_size;
1294 #ifdef IN_MEMORY
1295 if (buffer == NULL &&
1296 ! cp->code_transposed && ! cp->code_inverted)
1297 return bmf->bmf_contents + offset;
1298 #endif /* IN_MEMORY */
1299 if (buffer == NULL &&
1300 ((buffer = local_buffer(hbf)) == NULL))
1301 return NULL;
1302 #ifdef IN_MEMORY
1303 if (cp->code_transposed)
1304 copy_transposed(&(hbf->public),
1305 buffer,
1306 bmf->bmf_contents + offset);
1307 else
1308 memcpy((char *)buffer,
1309 (char *)(bmf->bmf_contents + offset),
1310 bm_size);
1311 #else /* ! IN_MEMORY */
1312 if (fseek(bmf->bmf_file, offset, 0) != 0) {
1313 eprintf("seek error on code 0x%04x", code);
1314 return NULL;
1315 }
1316 if (cp->code_transposed ?
1317 ! get_transposed(&(hbf->public), bmf->bmf_file,
1318 buffer) :
1319 fread((char *)buffer,
1320 bm_size, 1, bmf->bmf_file) != 1) {
1321 eprintf("read error on code 0x%04x", code);
1322 return NULL;
1323 }
1324 #endif /* IN_MEMORY */
1325 if (cp->code_inverted)
1326 invert(buffer, HBF_BitmapSize(&(hbf->public)));
1327 return buffer;
1328 }
1329 eprintf("code 0x%04x out of range", code);
1330 return NULL;
1331 }
1332
1333 static byte *
local_buffer(hbf)1334 local_buffer(hbf)
1335 HBF_STRUCT *hbf;
1336 {
1337 if (hbf->bitmap_buffer == NULL &&
1338 (hbf->bitmap_buffer = (byte *)malloc(HBF_BitmapSize(&(hbf->public)))) == NULL) {
1339 eprintf("out of memory");
1340 return NULL;
1341 }
1342 return hbf->bitmap_buffer;
1343 }
1344
1345 static void
invert(buffer,length)1346 invert(buffer, length)
1347 byte *buffer;
1348 unsigned int length;
1349 {
1350 for ( ; length > 0; length--)
1351 *buffer++ ^= 0xff;
1352 }
1353
1354 #ifdef IN_MEMORY
1355 static bool
copy_transposed(hbf,bitmap,source)1356 copy_transposed(hbf, bitmap, source)
1357 HBF *hbf;
1358 reg byte *bitmap;
1359 reg const byte *source;
1360 {
1361 reg byte *pos;
1362 reg byte *bm_end;
1363 int x;
1364 int width;
1365 reg int row_size;
1366 reg int c;
1367 reg int imask, omask;
1368
1369 width = hbfBitmapBBox(hbf)->hbf_width;
1370 row_size = HBF_RowSize(hbf);
1371 bm_end = bitmap + HBF_BitmapSize(hbf);
1372 (void)memset((char *)bitmap, '\0', HBF_BitmapSize(hbf));
1373 for (x = 0; x < width; x++) {
1374 pos = bitmap + x/8;
1375 omask = Bit(x%8);
1376 /* y = 0 */
1377 for (;;) {
1378 c = *source++;
1379 for (imask = Bit(0); imask != 0; imask >>= 1) {
1380 /*
1381 * At this point,
1382 *
1383 * imask == Bit(y%8)
1384 * pos == bitmap + y*row_size + x/8
1385 *
1386 * We examine bit y of row x of the input,
1387 * setting bit x of row y of the output if
1388 * required, by applying omask to *pos.
1389 */
1390 if ((c & imask) != 0)
1391 *pos |= omask;
1392 /* if (++y > height) goto end_column */
1393 pos += row_size;
1394 if (pos >= bm_end)
1395 goto end_column;
1396 }
1397 }
1398 end_column:
1399 ;
1400 }
1401 return TRUE;
1402 }
1403 #else /* ! IN_MEMORY */
1404 static bool
get_transposed(hbf,f,bitmap)1405 get_transposed(hbf, f, bitmap)
1406 HBF *hbf;
1407 FILE *f;
1408 reg byte *bitmap;
1409 {
1410 reg byte *pos;
1411 reg byte *bm_end;
1412 int x;
1413 int width;
1414 reg int row_size;
1415 reg int c;
1416 reg int imask, omask;
1417
1418 width = hbfBitmapBBox(hbf)->hbf_width;
1419 row_size = HBF_RowSize(hbf);
1420 bm_end = bitmap + HBF_BitmapSize(hbf);
1421 (void)memset((char *)bitmap, '\0', HBF_BitmapSize(hbf));
1422 for (x = 0; x < width; x++) {
1423 pos = bitmap + x/8;
1424 omask = Bit(x%8);
1425 /* y = 0 */
1426 for (;;) {
1427 if ((c = getc(f)) == EOF)
1428 return FALSE;
1429 for (imask = Bit(0); imask != 0; imask >>= 1) {
1430 /*
1431 * At this point,
1432 *
1433 * imask == Bit(y%8)
1434 * pos == bitmap + y*row_size + x/8
1435 *
1436 * We examine bit y of row x of the input,
1437 * setting bit x of row y of the output if
1438 * required, by applying omask to *pos.
1439 */
1440 if ((c & imask) != 0)
1441 *pos |= omask;
1442 /* if (++y > height) goto end_column */
1443 pos += row_size;
1444 if (pos >= bm_end)
1445 goto end_column;
1446 }
1447 }
1448 end_column:
1449 ;
1450 }
1451 return TRUE;
1452 }
1453 #endif /* ! IN_MEMORY */
1454
1455 /*
1456 * Call function on each valid code in ascending order.
1457 */
1458 void
hbfForEach(hbfFile,func,data)1459 hbfForEach(hbfFile, func, data)
1460 reg HBF *hbfFile;
1461 reg void (*func)_((HBF *sameHbfFile, HBF_CHAR code, void *data));
1462 reg void *data;
1463 {
1464 HBF_STRUCT *hbf;
1465 CODE_RANGE *cp;
1466 reg B2_RANGE *b2r;
1467 reg unsigned byte1, byte2;
1468 reg unsigned finish;
1469
1470 hbf = (HBF_STRUCT *)hbfFile;
1471 for (cp = hbf->code_range; cp != NULL; cp = cp->code_next) {
1472 byte1 = FirstByte(cp->code_start);
1473 byte2 = SecondByte(cp->code_start);
1474 while (MakeCode(byte1, byte2) <= cp->code_finish) {
1475 for (b2r = hbf->byte_2_range;
1476 b2r != NULL;
1477 b2r = b2r->b2r_next) {
1478 if (byte2 < b2r->b2r_start)
1479 byte2 = b2r->b2r_start;
1480 finish = b2r->b2r_finish;
1481 if (byte1 == FirstByte(cp->code_finish) &&
1482 finish > SecondByte(cp->code_finish))
1483 finish = SecondByte(cp->code_finish);
1484 while (byte2 <= finish) {
1485 (*func)(hbfFile,
1486 MakeCode(byte1, byte2), data);
1487 byte2++;
1488 }
1489 }
1490 byte1++;
1491 byte2 = 0;
1492 }
1493 }
1494 }
1495
1496 const char *
hbfFileName(hbf)1497 hbfFileName(hbf)
1498 HBF *hbf;
1499 {
1500 return ((HBF_STRUCT *)hbf)->filename;
1501 }
1502
1503 long
hbfChars(hbfFile)1504 hbfChars(hbfFile)
1505 HBF *hbfFile;
1506 {
1507 HBF_STRUCT *hbf;
1508 CODE_RANGE *cp;
1509 long num_chars;
1510
1511 hbf = (HBF_STRUCT *)hbfFile;
1512 num_chars = 0;
1513 for (cp = hbf->code_range; cp != NULL; cp = cp->code_next)
1514 num_chars +=
1515 hbf->b2_size*FirstByte(cp->code_finish) +
1516 b2_pos(hbf, cp->code_finish) -
1517 (hbf->b2_size*FirstByte(cp->code_start) +
1518 b2_pos(hbf, cp->code_start)) + 1;
1519 return num_chars;
1520 }
1521
1522 /*
1523 * Functions also implemented as macros
1524 */
1525
1526 #ifdef hbfBitmapBBox
1527 #undef hbfBitmapBBox
1528 #endif
1529
1530 HBF_BBOX *
hbfBitmapBBox(hbf)1531 hbfBitmapBBox(hbf)
1532 HBF *hbf;
1533 {
1534 return &(hbf->hbf_bitmap_bbox);
1535 }
1536
1537 #ifdef hbfFontBBox
1538 #undef hbfFontBBox
1539 #endif
1540
1541 HBF_BBOX *
hbfFontBBox(hbf)1542 hbfFontBBox(hbf)
1543 HBF *hbf;
1544 {
1545 return &(hbf->hbf_font_bbox);
1546 }
1547
1548 const void *
hbfGetByte2Range(hbfFile,b2r_pointer,startp,finishp)1549 hbfGetByte2Range(hbfFile, b2r_pointer, startp, finishp)
1550 HBF *hbfFile;
1551 const void *b2r_pointer;
1552 byte *startp;
1553 byte *finishp;
1554 {
1555 HBF_STRUCT *hbf;
1556 B2_RANGE *b2r;
1557
1558 hbf = (HBF_STRUCT *)hbfFile;
1559 if (b2r_pointer == NULL)
1560 b2r = hbf->byte_2_range;
1561 else
1562 b2r = ((B2_RANGE *)b2r_pointer)->b2r_next;
1563 if(b2r == NULL)
1564 return NULL;
1565 *startp = b2r->b2r_start;
1566 *finishp = b2r->b2r_finish;
1567 return (void *)b2r;
1568 }
1569
1570 const void *
hbfGetCodeRange(hbfFile,code_pointer,startp,finishp)1571 hbfGetCodeRange(hbfFile, code_pointer, startp, finishp)
1572 HBF *hbfFile;
1573 const void *code_pointer;
1574 HBF_CHAR *startp;
1575 HBF_CHAR *finishp;
1576 {
1577 HBF_STRUCT *hbf;
1578 CODE_RANGE *cp;
1579
1580 hbf = (HBF_STRUCT *)hbfFile;
1581 if (code_pointer == NULL)
1582 cp = hbf->code_range;
1583 else
1584 cp = ((CODE_RANGE *)code_pointer)->code_next;
1585 if(cp == NULL)
1586 return NULL;
1587 *startp = cp->code_start;
1588 *finishp = cp->code_finish;
1589 return (void *)cp;
1590 }
1591