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(HBF_BBOX * bbox)286 clear_bbox(HBF_BBOX *bbox)
287 {
288 	bbox->hbf_width = bbox->hbf_height = 0;
289 	bbox->hbf_xDisplacement = bbox->hbf_yDisplacement = 0;
290 }
291 
292 static void
clear_record(HBF_STRUCT * hbf)293 clear_record(HBF_STRUCT *hbf)
294 {
295 	clear_bbox(&(hbf->public.hbf_bitmap_bbox));
296 	clear_bbox(&(hbf->public.hbf_font_bbox));
297 	hbf->property = NULL;
298 	hbf->filename = NULL;
299 	hbf->bitmap_buffer = NULL;
300 	hbf->byte_2_range = NULL;
301 	hbf->code_range = NULL;
302 	hbf->bm_file = NULL;
303 }
304 
305 /*
306  *	Byte-2 ranges
307  */
308 
309 static void
add_b2r(reg B2_RANGE ** last_b2r,int start,int finish)310 add_b2r(reg B2_RANGE **last_b2r, int start, int finish)
311 {
312 reg	B2_RANGE *b2r;
313 
314 	b2r = NEW(B2_RANGE);
315 	while (*last_b2r != NULL && (*last_b2r)->b2r_start < start)
316 		last_b2r = &((*last_b2r)->b2r_next);
317 	b2r->b2r_next = *last_b2r;
318 	b2r->b2r_start = start;
319 	b2r->b2r_finish = finish;
320 	*last_b2r = b2r;
321 }
322 
323 static CHAR_INDEX
b2_pos(HBF_STRUCT * hbf,HBF_CHAR code)324 b2_pos(HBF_STRUCT *hbf, HBF_CHAR code)
325 {
326 reg	B2_RANGE *b2r;
327 reg	unsigned c;
328 reg	CHAR_INDEX	pos;
329 
330 	c = SecondByte(code);
331 	pos = 0;
332 	for (b2r = hbf->byte_2_range; b2r != NULL; b2r = b2r->b2r_next)
333 		if (b2r->b2r_start <= c && c <= b2r->b2r_finish)
334 			return pos + c - b2r->b2r_start;
335 		else
336 			pos += b2r->b2r_finish - b2r->b2r_start + 1;
337 	return BAD_CHAR_INDEX;
338 }
339 
340 static int
b2_size(reg B2_RANGE * b2r)341 b2_size(reg B2_RANGE *b2r)
342 {
343 reg	int	size;
344 
345 	size = 0;
346 	for ( ; b2r != NULL; b2r = b2r->b2r_next)
347 		size += b2r->b2r_finish - b2r->b2r_start + 1;
348 	return size;
349 }
350 
351 /* map a position to a character code */
352 static long
code_of(HBF_STRUCT * hbf,long pos)353 code_of(HBF_STRUCT *hbf, long pos)
354 {
355 	long	code;
356 	int	residue;
357 reg	B2_RANGE *b2r;
358 
359 	code = pos / hbf->b2_size * 256;
360 	residue = pos % hbf->b2_size;
361 	for (b2r = hbf->byte_2_range; b2r != NULL; b2r = b2r->b2r_next)
362 		if (b2r->b2r_start + residue <= b2r->b2r_finish)
363 			return code + b2r->b2r_start + residue;
364 		else
365 			residue -= b2r->b2r_finish - b2r->b2r_start + 1;
366 	/* should never get here */
367 	return 0L;
368 }
369 
370 /*
371  *	String stuff
372  */
373 
374 static bool
match(reg const char * lp,reg const char * sp)375 match(reg const char *lp, reg const char *sp)
376 {
377 	while (*lp == *sp && *sp != '\0') {
378 		lp++;
379 		sp++;
380 	}
381 	return (*lp == '\0' || isspace((unsigned char)*lp)) && *sp == '\0';
382 }
383 
384 #ifdef NO_STRDUP
385 char *
strdup(const char * s)386 strdup(const char *s)
387 {
388 	char	*new_s;
389 
390 	new_s = malloc((unsigned)strlen(s) + 1);
391 	strcpy(new_s, s);
392 	return new_s;
393 }
394 #endif
395 
396 /*
397  *	Properties
398  */
399 
400 static void
add_property(reg HBF_STRUCT * hbf,const char * lp)401 add_property(reg HBF_STRUCT *hbf, const char *lp)
402 {
403 reg	PROPERTY	*prop;
404 	char	tmp[MAXLINE];
405 reg	char	*tp;
406 
407 	prop = NEW(PROPERTY);
408 
409 	tp = tmp;
410 	while (*lp != '\0' && ! isspace((unsigned char)*lp))
411 		*tp++ = *lp++;
412 	*tp = '\0';
413 	prop->prop_name = strdup(tmp);
414 
415 	while (*lp != '\0' && isspace((unsigned char)*lp))
416 		lp++;
417 
418 	tp = tmp;
419 	if (*lp == QUOTE) {
420 		lp++;
421 		while (*lp != '\0' && ! (*lp == QUOTE && *++lp != QUOTE))
422 			*tp++ = *lp++;
423 	}
424 	else
425 		for (;;) {
426 			while (*lp != '\0' && ! isspace((unsigned char)*lp))
427 				*tp++ = *lp++;
428 			while (*lp != '\0' && isspace((unsigned char)*lp))
429 				lp++;
430 			if (*lp == '\0')
431 				break;
432 			*tp++ = ' ';
433 		}
434 	*tp = '\0';
435 	prop->prop_value = strdup(tmp);
436 
437 	prop->prop_next = hbf->property;
438 	hbf->property = prop;
439 }
440 
441 const char *
hbfProperty(HBF * hbfFile,const char * propName)442 hbfProperty(HBF *hbfFile, const char *propName)
443 {
444 reg	HBF_STRUCT	*hbf;
445 reg	PROPERTY	*prop;
446 
447 	hbf = (HBF_STRUCT *)hbfFile;
448 	for (prop = hbf->property; prop != NULL; prop = prop->prop_next)
449 		if (strcmp(prop->prop_name, propName) == 0)
450 			return prop->prop_value;
451 	return NULL;
452 }
453 
454 /*
455  *	Compatability routines
456  */
457 
458 const char *
HBF_GetProperty(HBF * handle,const char * propertyName)459 HBF_GetProperty(HBF *handle, const char *propertyName)
460 {
461 	return hbfProperty(handle, propertyName);
462 }
463 
464 int
HBF_GetFontBoundingBox(HBF_Handle handle,unsigned int * width,unsigned int * height,int * xDisplacement,int * yDisplacement)465 HBF_GetFontBoundingBox(HBF_Handle handle,
466 		       unsigned int *width, unsigned int *height,
467 		       int *xDisplacement, int *yDisplacement)
468 {
469 	if (width != NULL)
470 		*width = hbfFontBBox(handle)->hbf_width;
471 	if (height != NULL)
472 		*height = hbfFontBBox(handle)->hbf_height;
473 	if (xDisplacement != NULL)
474 		*xDisplacement = hbfFontBBox(handle)->hbf_xDisplacement;
475 	if (yDisplacement != NULL)
476 		*yDisplacement = hbfFontBBox(handle)->hbf_yDisplacement;
477 	return 0;
478 }
479 
480 int
HBF_GetBitmapBoundingBox(HBF_Handle handle,unsigned int * width,unsigned int * height,int * xDisplacement,int * yDisplacement)481 HBF_GetBitmapBoundingBox(HBF_Handle handle,
482 			 unsigned int *width, unsigned int *height,
483 			 int *xDisplacement, int *yDisplacement)
484 {
485 	if (width != NULL)
486 		*width = hbfBitmapBBox(handle)->hbf_width;
487 	if (height != NULL)
488 		*height = hbfBitmapBBox(handle)->hbf_height;
489 	if (xDisplacement != NULL)
490 		*xDisplacement = hbfBitmapBBox(handle)->hbf_xDisplacement;
491 	if (yDisplacement != NULL)
492 		*yDisplacement = hbfBitmapBBox(handle)->hbf_yDisplacement;
493 	return 0;
494 }
495 
496 /*
497  * Prepend a directory to a relative filename.
498  */
499 static char *
concat(const char * dir,int dirlen,const char * stem)500 concat(const char *dir,		/* not necessarily null-terminated */
501        int dirlen,		/* number of significant chars in dir */
502        const char *stem)	/* relative filename */
503 {
504 	char	*fullname;
505 
506 	if (dirlen == 0)	/* null: current directory */
507 		return strdup(stem);
508 #ifdef unix
509 	fullname = malloc(dirlen + strlen(stem) + 2);
510 	(void)sprintf(fullname, "%.*s/%s", dirlen, dir, stem);
511 #else
512 #ifdef msdos
513 	fullname = malloc(dirlen + strlen(stem) + 2);
514 	(void)sprintf(fullname, "%.*s\\%s", dirlen, dir, stem);
515 #else
516 #ifdef vms
517 	if (dir[dirlen-1] == ']' && stem[0] == '[' && stem[1] == '-') {
518 		dirlen--;
519 		stem++;
520 		fullname = malloc(dirlen + strlen(stem) + 2);
521 		(void)sprintf(fullname, "%.*s.%s", dirlen, dir, stem);
522 	}
523 	else {
524 		if (dir[dirlen-1] == ']' && stem[0] == '[' && stem[1] == '.') {
525 			dirlen--;
526 			stem++;
527 		}
528 		fullname = malloc(dirlen + strlen(stem) + 1);
529 		(void)sprintf(fullname, "%.*s%s", dirlen, dir, stem);
530 	}
531 #else
532 	fullname = strdup(stem);
533 #endif /* vms */
534 #endif /* msdos */
535 #endif /* unix */
536 	return fullname;
537 }
538 
539 /*
540  *	Bitmap files
541  *
542  *	If the host operating system has a heirarchical file system and
543  *	the bitmap file name is relative, it is relative to the directory
544  *	containing the HBF file.
545  */
546 static char *
expand_filename(const char * name,const char * hbf_name)547 expand_filename(const char *name, const char *hbf_name)
548 {
549 #ifdef unix
550 reg	char	*s;
551 reg	int	size;
552 
553 	size = name[0] != '/' && (s = strrchr(hbf_name, '/')) != NULL ?
554 		s - hbf_name + 1 : 0;
555 	s = malloc((unsigned)size + strlen(name) + 1);
556 	(void)sprintf(s, "%.*s%s", size, hbf_name, name);
557 	return s;
558 #else
559 #ifdef msdos
560 reg	char	*s;
561 reg	int	size;
562 
563 #ifdef __EMX__
564 	s = (unsigned char *)hbf_name + strlen((unsigned char *)hbf_name) - 1;
565 	for(;;) {
566 		if (*s == '\\' || *s == '/')
567 			break;
568 		if (s == hbf_name) {
569 			s = NULL;
570 			break;
571 		}
572 		s--;
573 	}
574 
575 	size = HasDrive(name) ? 0 :
576 		(name[0] == '\\' || name[0] == '/') ?
577 			(HasDrive(hbf_name) ? 2 : 0) :
578 		s != NULL ? s - hbf_name + 1 : 0;
579 #else
580 	size = HasDrive(name) ? 0 :
581 		name[0] == '\\' ? (HasDrive(hbf_name) ? 2 : 0) :
582 		(s = strrchr(hbf_name, '\\')) != NULL ?
583 			s - hbf_name + 1 : 0;
584 #endif /* __EMX__ */
585 	s = malloc((unsigned)size + strlen(name) + 1);
586 	(void)sprintf(s, "%.*s%s", size, hbf_name, name);
587 	return s;
588 #else
589 #ifdef vms
590 reg	char	*s;
591 reg	const	char	*copyto;
592 reg	int	size;
593 
594 	if ((s = strchr(hbf_name, ']')) != NULL && RelativeFileName(name))
595 		return concat(hbf_name, (s - hbf_name) + 1, name);
596 
597 	copyto = hbf_name;
598 	if ((s = strstr(copyto, "::")) != NULL && strstr(name, "::") == NULL)
599 		copyto = s+2;
600 	if ((s = strchr(copyto, ':')) != NULL && strchr(name, ':') == NULL)
601 		copyto = s+1;
602 	size = copyto - hbf_name;
603 	s = malloc((unsigned)size + strlen(name) + 1);
604 	(void)sprintf(s, "%.*s%s", size, hbf_name, name);
605 	return s;
606 #else
607 	return strdup(name);
608 #endif /* vms */
609 #endif /* msdos */
610 #endif /* unix */
611 }
612 
613 static BM_FILE *
find_file(HBF_STRUCT * hbf,const char * filename)614 find_file(HBF_STRUCT *hbf, const char *filename)
615 {
616 	BM_FILE	**fp;
617 reg	BM_FILE	*file;
618 	FILE	*f;
619 	char	*bmfname;
620 #ifdef IN_MEMORY
621 #ifdef unix
622 	bool	from_pipe;
623 #endif
624 #endif
625 
626 	for (fp = &(hbf->bm_file); *fp != NULL; fp = &((*fp)->bmf_next)) {
627 		bmfname = strrchr((*fp)->bmf_name, '/');
628 		bmfname = (bmfname) ? bmfname + 1 : (*fp)->bmf_name;
629 		if (strcmp(bmfname, filename) == 0)
630 			return *fp;
631 	}
632 
633 	file = NEW(BM_FILE);
634 	if (file == NULL) {
635 		eprintf("out of memory");
636 		return NULL;
637 	}
638 	file->bmf_name = expand_filename(filename, hbf->filename);
639 	if (file->bmf_name == NULL) {
640 		free((char *)file);
641 		return NULL;
642 	}
643 	f = fopen(file->bmf_name, READ_BINARY);
644 #ifdef IN_MEMORY
645 #ifdef unix
646 	from_pipe = FALSE;
647 	if (f == NULL) {
648 		char	tmp[400];
649 
650 		sprintf(tmp, "%s.gz", file->bmf_name);
651 		if ((f = fopen(tmp, "r")) != NULL) {
652 			fclose(f);
653 			sprintf(tmp, "gzcat %s.gz", file->bmf_name);
654 			if ((f = popen(tmp, "r")) != NULL)
655 				from_pipe = TRUE;
656 		}
657 	}
658 #endif /* unix */
659 #endif /* IN_MEMORY */
660 	if (f == NULL) {
661 		eprintf("can't open bitmap file '%s'", file->bmf_name);
662 		free(file->bmf_name);
663 		free((char *)file);
664 		return NULL;
665 	}
666 #ifdef IN_MEMORY
667 	if (! read_bitmap_file(file, f)) {
668 		free(file->bmf_name);
669 		free((char *)file);
670 		return NULL;
671 	}
672 #ifdef unix
673 	if (from_pipe)
674 		pclose(f);
675 	else
676 		fclose(f);
677 #else /* ! unix */
678 	fclose(f);
679 #endif /* ! unix */
680 #else /* ! IN_MEMORY */
681 	file->bmf_file = f;
682 	fseek(f, 0L, 2);
683 	file->bmf_size = ftell(f);
684 #endif /* ! IN_MEMORY */
685 	file->bmf_next = NULL;
686 	*fp = file;
687 	return file;
688 }
689 
690 #ifdef IN_MEMORY
691 #define	GRAIN_SIZE	512
692 
693 static bool
read_bitmap_file(BM_FILE * bmf,FILE * f)694 read_bitmap_file(BM_FILE *bmf, FILE *f)
695 {
696 	byte	*contents, *cp;
697 	long	size;
698 	int	c;
699 
700 	size = 0;
701 	cp = contents = (byte *)malloc((unsigned)GRAIN_SIZE);
702 	if (contents == NULL) {
703 		eprintf("not enough space for bitmap file");
704 		return NULL;
705 	}
706 	while ((c = getc(f)) != EOF) {
707 		if (size%GRAIN_SIZE == 0) {
708 			contents = (byte *)realloc((char *)contents,
709 					(unsigned)(size + GRAIN_SIZE));
710 			if (contents == NULL) {
711 				eprintf("not enough space for bitmap file");
712 				return NULL;
713 			}
714 			cp = contents + size;
715 		}
716 		*cp++ = c;
717 		size++;
718 	}
719 	bmf->bmf_size = size;
720 	bmf->bmf_contents = (byte *)realloc((char *)contents, (unsigned)size);
721 	return TRUE;
722 }
723 #endif /* IN_MEMORY */
724 
725 /*
726  *	Code ranges
727  */
728 
729 /* check that a code range fits within its bitmap file */
730 static bool
too_short(HBF_STRUCT * hbf,CODE_RANGE * cp)731 too_short(HBF_STRUCT *hbf, CODE_RANGE *cp)
732 {
733 	int	bm_size;
734 	long	offset, end_offset;
735 	BM_FILE	*bmf;
736 	long	start, finish;
737 
738 	bm_size = FileBitmapSize(&(hbf->public), cp);
739 	offset = cp->code_offset;
740 	start = cp->code_start;
741 	finish = cp->code_finish;
742 	end_offset = offset + bm_size *
743 			(hbf->b2_size*(long)FirstByte(finish) +
744 				b2_pos(hbf, finish) - cp->code_pos + 1);
745 	bmf = cp->code_bm_file;
746 	if (end_offset <= bmf->bmf_size)
747 		return FALSE;
748 	/* bitmap file is too short: produce a specific error message */
749 	if (offset > bmf->bmf_size)
750 		eprintf("bitmap file '%s' is shorter than offset 0x%04lx",
751 			bmf->bmf_name, offset);
752 	else if (offset + bm_size > bmf->bmf_size)
753 		eprintf("bitmap file '%s' too short: no room for any bitmaps at offset 0x%04lx",
754 			bmf->bmf_name, offset);
755 	else
756 		eprintf("bitmap file '%s' is too short - code range appears to be 0x%04lx-0x%04lx",
757 			bmf->bmf_name,
758 			start,
759 			code_of(hbf, cp->code_pos +
760 					(bmf->bmf_size - offset)/bm_size) - 1);
761 	return TRUE;
762 }
763 
764 static const char *
skip_word(int n,const char * s)765 skip_word(int n, const char *s)
766 {
767 	for ( ; n > 0; n--) {
768 		while (*s != '\0' && ! isspace((unsigned char)*s))
769 			s++;
770 		while (*s != '\0' && isspace((unsigned char)*s))
771 			s++;
772 	}
773 	return s;
774 }
775 
776 /* optional keywords at the end of a CODE_RANGE line */
777 static void
parse_keywords(CODE_RANGE * cp,const char * s)778 parse_keywords(CODE_RANGE *cp, const char *s)
779 {
780 	for (s = skip_word(4, s) ; *s != '\0'; s = skip_word(1, s)) {
781 		switch (*s) {
782 		case 's': case 'S': case 't': case 'T':
783 			/* keyword "sideways" or "transposed" */
784 			cp->code_transposed = TRUE;
785 			break;
786 		case 'i': case 'I':
787 			/* keyword "inverted" */
788 			cp->code_inverted = TRUE;
789 		}
790 	}
791 }
792 
793 static bool
add_code_range(HBF_STRUCT * hbf,const char * line)794 add_code_range(HBF_STRUCT *hbf, const char *line)
795 {
796 	CODE_RANGE *cp;
797 	CODE_RANGE **cpp;
798 	long	start, finish;
799 	long	offset;
800 	char	filename[MAXLINE];
801 	BM_FILE	*bmf;
802 	CHAR_INDEX b2pos;
803 
804 	if (sscanf(line, "HBF_CODE_RANGE %li-%li %s %li",
805 			   &start, &finish, filename, &offset) != 4) {
806 		eprintf("syntax error in HBF_CODE_RANGE");
807 		return FALSE;
808 	}
809 	/* code ranges are checked in real_open() */
810 	if ((bmf = find_file(hbf, filename)) == NULL)
811 		return FALSE;
812 	if ((cp = NEW(CODE_RANGE)) == NULL) {
813 		eprintf("out of memory");
814 		return FALSE;
815 	}
816 
817 	cp->code_start = (CHAR)start;
818 	cp->code_finish = (CHAR)finish;
819 	cp->code_bm_file = bmf;
820 	cp->code_offset = offset;
821 	cp->code_transposed = cp->code_inverted = FALSE;
822 	parse_keywords(cp, line);
823 	/* insert it in order */
824 	for (cpp = &hbf->code_range;
825 	     *cpp != NULL && (*cpp)->code_finish < start;
826 	     cpp = &((*cpp)->code_next))
827 		;
828 	if (*cpp != NULL && (*cpp)->code_start <= finish) {
829 		eprintf("code ranges overlap");
830 		return FALSE;
831 	}
832 	cp->code_next = *cpp;
833 	*cpp = cp;
834 
835 	/* set code_pos, and check range */
836 	if (start > finish) {
837 		eprintf("illegal code range 0x%04lx-0x%04lx", start, finish);
838 		return FALSE;
839 	}
840 	if ((b2pos = b2_pos(hbf, start)) == BAD_CHAR_INDEX) {
841 		eprintf("illegal start code 0x%04lx", start);
842 		return FALSE;
843 	}
844 	cp->code_pos = hbf->b2_size*(long)FirstByte(start) + b2pos;
845 	if ((b2pos = b2_pos(hbf, finish)) == BAD_CHAR_INDEX) {
846 		eprintf("illegal finish code 0x%04lx", finish);
847 		return FALSE;
848 	}
849 	/* check that the bitmap file has enough bitmaps */
850 	return ! too_short(hbf, cp);
851 }
852 
853 /*
854  *	Reading and parsing of an HBF file
855  */
856 
857 /* get line, truncating to len, and trimming trailing spaces */
858 static bool
get_line(char * buf,int len,FILE * f)859 get_line(char *buf, int len, FILE *f)
860 {
861 	int	c;
862 	char	*bp;
863 
864 	bp = buf;
865 	for (;;) {
866 		if ((c = getc(f)) == EOF) {
867 			eprintf("unexpected end of file");
868 			return FALSE;
869 		}
870 		if (c == '\n' || c == '\r') {
871 			/* trim trailing space */
872 			while (bp > buf && isspace((unsigned char)*(bp-1)))
873 				bp--;
874 			*bp = '\0';
875 			return TRUE;
876 		}
877 		if (len > 0) {
878 			*bp++ = c;
879 			len--;
880 		}
881 	}
882 }
883 
884 /* get next non-COMMENT line */
885 static bool
get_text_line(char * buf,int len,FILE * f)886 get_text_line(char *buf, int len, FILE *f)
887 {
888 	while (get_line(buf, len, f))
889 		if (*buf != '\0' && ! match(buf, "COMMENT"))
890 			return TRUE;
891 	return FALSE;
892 }
893 
894 static bool
get_property(const char * line,const char * keyword,HBF_STRUCT * hbf)895 get_property(const char *line, const char *keyword, HBF_STRUCT *hbf)
896 {
897 	if (! match(line, keyword)) {
898 		eprintf("%s expected", keyword);
899 		return FALSE;
900 	}
901 	add_property(hbf, line);
902 	return TRUE;
903 }
904 
905 static bool
get_bbox(const char * line,const char * keyword,HBF_BBOX * bbox)906 get_bbox(const char *line, const char *keyword, HBF_BBOX *bbox)
907 {
908 	int	w, h, xd, yd;
909 
910 	if (! match(line, keyword) ||
911 	    sscanf(line + strlen(keyword), "%i %i %i %i",
912 			&w, &h, &xd, &yd) != 4) {
913 		eprintf("%s expected", keyword);
914 		return FALSE;
915 	}
916 	if (w <= 0 || h <= 0) {
917 		eprintf("illegal %s dimensions %dx%d", keyword, w, h);
918 		return FALSE;
919 	}
920 	bbox->hbf_width = w;
921 	bbox->hbf_height = h;
922 	bbox->hbf_xDisplacement = xd;
923 	bbox->hbf_yDisplacement = yd;
924 	return TRUE;
925 }
926 
927 /*
928  *  HBFHeaderFile ::=
929  * 	'HBF_START_FONT'		version			EOLN
930  * 	'HBF_CODE_SCHEME'		word ...		EOLN
931  * 	'FONT'				fontName		EOLN
932  * 	'SIZE'				ptsize xres yres	EOLN
933  * 	'HBF_BITMAP_BOUNDING_BOX'	w h xd yd		EOLN
934  * 	'FONTBOUNDINGBOX'		w h xd yd		EOLN
935  * 	X11R5FontPropertySection
936  * 	'CHARS'				n			EOLN
937  * 	HBFByte2RangeSection
938  * 	HBFCodeRangeSection
939  * 	'HBF_END_FONT'			EOLN .
940  *
941  * This implementation allows extra lines before HBF_END_FONT.
942  * Anything after HBF_END_FONT is ignored.
943  */
944 
945 static bool
parse_file(FILE * f,reg HBF_STRUCT * hbf)946 parse_file(FILE *f, reg HBF_STRUCT *hbf)
947 {
948 	char	line[MAXLINE];
949 	int	start, finish;
950 
951 	if (! get_text_line(line, MAXLINE, f) ||
952 	    ! get_property(line, "HBF_START_FONT", hbf))
953 		return FALSE;
954 
955 	if (! get_text_line(line, MAXLINE, f) ||
956 	    ! get_property(line, "HBF_CODE_SCHEME", hbf))
957 		return FALSE;
958 
959 	if (! get_text_line(line, MAXLINE, f) ||
960 	    ! get_property(line, "FONT", hbf))
961 		return FALSE;
962 
963 	if (! get_text_line(line, MAXLINE, f) ||
964 	    ! get_property(line, "SIZE", hbf))
965 		return FALSE;
966 
967 	if (! get_text_line(line, MAXLINE, f) ||
968 	    ! get_bbox(line, "HBF_BITMAP_BOUNDING_BOX",
969 			&(hbf->public.hbf_bitmap_bbox)))
970 		return FALSE;
971 
972 	if (! get_text_line(line, MAXLINE, f) ||
973 	    ! get_bbox(line, "FONTBOUNDINGBOX", &(hbf->public.hbf_font_bbox)))
974 		return FALSE;
975 
976 	if (! get_text_line(line, MAXLINE, f))
977 		return FALSE;
978 	if (match(line, "STARTPROPERTIES")) {
979 		for (;;) {
980 			if (! get_text_line(line, MAXLINE, f))
981 				return FALSE;
982 			if (match(line, "ENDPROPERTIES"))
983 				break;
984 			add_property(hbf, line);
985 		}
986 		if (! get_text_line(line, MAXLINE, f))
987 			return FALSE;
988 	}
989 
990 	if (match(line, "CHARS"))
991 		if (! get_text_line(line, MAXLINE, f))
992 			return FALSE;
993 
994 	if (match(line, "HBF_START_BYTE_2_RANGES")) {
995 		for (;;) {
996 			if (! get_text_line(line, MAXLINE, f))
997 				return FALSE;
998 			if (match(line, "HBF_END_BYTE_2_RANGES"))
999 				break;
1000 			if (sscanf(line, "HBF_BYTE_2_RANGE %i-%i",
1001 					&start, &finish) != 2) {
1002 				eprintf("HBF_BYTE_2_RANGE expected");
1003 				return FALSE;
1004 			}
1005 			add_b2r(&(hbf->byte_2_range), start, finish);
1006 		}
1007 		if (! get_text_line(line, MAXLINE, f))
1008 			return FALSE;
1009 	}
1010 	else
1011 		add_b2r(&(hbf->byte_2_range), 0, 0xff);
1012 	hbf->b2_size = b2_size(hbf->byte_2_range);
1013 
1014 	if (! match(line, "HBF_START_CODE_RANGES")) {
1015 		eprintf("HBF_START_CODE_RANGES expected");
1016 		return FALSE;
1017 	}
1018 	for (;;) {
1019 		if (! get_text_line(line, MAXLINE, f))
1020 			return FALSE;
1021 		if (match(line, "HBF_END_CODE_RANGES"))
1022 			break;
1023 		if (! add_code_range(hbf, line))
1024 			return FALSE;
1025 	}
1026 
1027 	for (;;) {
1028 		if (! get_text_line(line, MAXLINE, f))
1029 			return FALSE;
1030 		if (match(line, "HBF_END_FONT"))
1031 			break;
1032 		/* treat extra lines as properties (for private extensions) */
1033 		add_property(hbf, line);
1034 	}
1035 
1036 	return TRUE;
1037 }
1038 
1039 static FILE *
path_open(const char * path,const char * filename,char ** fullp)1040 path_open(const char *path, const char *filename, char **fullp)
1041 {
1042 	if (LocalFileName(filename) && path != NULL) {
1043 #ifdef PATH_DELIMITER
1044 		char	*fullname;
1045 		FILE	*f;
1046 		const	char	*p_next;
1047 
1048 		for (;;) {
1049 			p_next = strchr(path, PATH_DELIMITER);
1050 			if (p_next == NULL)
1051 				p_next = path + strlen(path);
1052 			fullname = concat(path, p_next - path, filename);
1053 			if ((f = fopen(fullname, "r")) != NULL) {
1054 				*fullp = fullname;
1055 				return f;
1056 			}
1057 			free(fullname);
1058 			if (*p_next == '\0')
1059 				break;
1060 			path = p_next + 1;
1061 		}
1062 #endif
1063 		return NULL;
1064 	}
1065 	else {
1066 		*fullp = strdup(filename);
1067 		return fopen(*fullp, "r");
1068 	}
1069 }
1070 
1071 static bool
real_open(const char * filename,reg HBF_STRUCT * hbf)1072 real_open(const char *filename, reg HBF_STRUCT *hbf)
1073 {
1074 	FILE	*f;
1075 
1076 	f = path_open(getenv("HBFPATH"), filename, &(hbf->filename));
1077 	if (f == NULL) {
1078 		eprintf("can't read file '%s'", filename);
1079 		return FALSE;
1080 	}
1081 	if (! parse_file(f, hbf)) {
1082 		fclose(f);
1083 		return FALSE;
1084 	}
1085 	fclose(f);
1086 	return TRUE;
1087 }
1088 
1089 HBF *
hbfOpen(const char * filename)1090 hbfOpen(const char *filename)
1091 {
1092 reg	HBF_STRUCT *hbf;
1093 
1094 	if ((hbf = NEW(HBF_STRUCT)) == NULL) {
1095 		eprintf("can't allocate HBF structure");
1096 		return NULL;
1097 	}
1098 	clear_record(hbf);
1099 	if (real_open(filename, hbf))
1100 		return &(hbf->public);
1101 	hbfClose(&(hbf->public));
1102 	return NULL;
1103 }
1104 
1105 int
HBF_OpenFont(const char * filename,HBF ** ptrHandleStorage)1106 HBF_OpenFont(const char *filename, HBF **ptrHandleStorage)
1107 {
1108 	return (*ptrHandleStorage = hbfOpen(filename)) == NULL ? -1 : 0;
1109 }
1110 
1111 /*
1112  *	Close files, free everything associated with the HBF.
1113  */
1114 
1115 int
HBF_CloseFont(HBF * hbfFile)1116 HBF_CloseFont(HBF *hbfFile)
1117 {
1118 reg	HBF_STRUCT	*hbf;
1119 	PROPERTY	*prop_ptr, *prop_next;
1120 	B2_RANGE	*b2r_ptr, *b2r_next;
1121 	CODE_RANGE	*code_ptr, *code_next;
1122 	BM_FILE		*bmf_ptr, *bmf_next;
1123 	int		status;
1124 
1125 	status = 0;
1126 	hbf = (HBF_STRUCT *)hbfFile;
1127 
1128 	if (hbf->filename != NULL)
1129 		free(hbf->filename);
1130 	if (hbf->bitmap_buffer != NULL)
1131 		free(hbf->bitmap_buffer);
1132 
1133 	for (prop_ptr = hbf->property;
1134 	     prop_ptr != NULL;
1135 	     prop_ptr = prop_next) {
1136 		prop_next = prop_ptr->prop_next;
1137 		free(prop_ptr->prop_name);
1138 		free(prop_ptr->prop_value);
1139 		free((char *)prop_ptr);
1140 	}
1141 
1142 	for (b2r_ptr = hbf->byte_2_range;
1143 	     b2r_ptr != NULL;
1144 	     b2r_ptr = b2r_next) {
1145 		b2r_next = b2r_ptr->b2r_next;
1146 		free((char *)b2r_ptr);
1147 	}
1148 
1149 	for (code_ptr = hbf->code_range;
1150 	     code_ptr != NULL;
1151 	     code_ptr = code_next) {
1152 		code_next = code_ptr->code_next;
1153 		free((char *)code_ptr);
1154 	}
1155 
1156 	for (bmf_ptr = hbf->bm_file;
1157 	     bmf_ptr != NULL;
1158 	     bmf_ptr = bmf_next) {
1159 		bmf_next = bmf_ptr->bmf_next;
1160 #ifdef IN_MEMORY
1161 		free((char *)(bmf_ptr->bmf_contents));
1162 #else
1163 		if (bmf_ptr->bmf_file != NULL &&
1164 		    fclose(bmf_ptr->bmf_file) < 0)
1165 			status = -1;
1166 #endif
1167 		free(bmf_ptr->bmf_name);
1168 		free((char *)bmf_ptr);
1169 	}
1170 
1171 	free((char *)hbf);
1172 
1173 	return status;
1174 }
1175 
1176 void
hbfClose(HBF * hbfFile)1177 hbfClose(HBF *hbfFile)
1178 {
1179 	(void)HBF_CloseFont(hbfFile);
1180 }
1181 
1182 /*
1183  *	Fetch a bitmap
1184  */
1185 
1186 const byte *
hbfGetBitmap(HBF * hbf,HBF_CHAR code)1187 hbfGetBitmap(HBF *hbf, HBF_CHAR code)
1188 {
1189 	return get_bitmap((HBF_STRUCT *)hbf, code, (byte *)NULL);
1190 }
1191 
1192 int
HBF_GetBitmap(HBF * hbf,HBF_CHAR code,byte * buffer)1193 HBF_GetBitmap(HBF *hbf, HBF_CHAR code, byte *buffer)
1194 {
1195 	return get_bitmap((HBF_STRUCT *)hbf, code, buffer) == NULL ? -1 : 0;
1196 }
1197 
1198 /*
1199  * Internal function to fetch a bitmap.
1200  * If buffer is non-null, it must be used.
1201  */
1202 static const byte *
get_bitmap(reg HBF_STRUCT * hbf,HBF_CHAR code,byte * buffer)1203 get_bitmap(reg HBF_STRUCT *hbf, HBF_CHAR code, byte *buffer)
1204 {
1205 	CHAR_INDEX	pos, b2pos;
1206 reg	CODE_RANGE	*cp;
1207 	BM_FILE		*bmf;
1208 	int		bm_size;
1209 	long		offset;
1210 
1211 	if ((b2pos = b2_pos(hbf, code)) == BAD_CHAR_INDEX)
1212 		return NULL;
1213 	pos = hbf->b2_size*FirstByte(code) + b2pos;
1214 	for (cp = hbf->code_range; cp != NULL; cp = cp->code_next)
1215 		if (cp->code_start <= code && code <= cp->code_finish) {
1216 			bmf = cp->code_bm_file;
1217 			bm_size = FileBitmapSize(&(hbf->public), cp);
1218 			offset = cp->code_offset +
1219 				   (long)(pos - cp->code_pos) * bm_size;
1220 #ifdef IN_MEMORY
1221 			if (buffer == NULL &&
1222 			    ! cp->code_transposed && ! cp->code_inverted)
1223 				return bmf->bmf_contents + offset;
1224 #endif /* IN_MEMORY */
1225 			if (buffer == NULL &&
1226 			    ((buffer = local_buffer(hbf)) == NULL))
1227 				return NULL;
1228 #ifdef IN_MEMORY
1229 			if (cp->code_transposed)
1230 				copy_transposed(&(hbf->public),
1231 						buffer,
1232 						bmf->bmf_contents + offset);
1233 			else
1234 				memcpy((char *)buffer,
1235 				       (char *)(bmf->bmf_contents + offset),
1236 				       bm_size);
1237 #else /* ! IN_MEMORY */
1238 			if (fseek(bmf->bmf_file, offset, 0) != 0) {
1239 				eprintf("seek error on code 0x%04x", code);
1240 				return NULL;
1241 			}
1242 			if (cp->code_transposed ?
1243 			    ! get_transposed(&(hbf->public), bmf->bmf_file,
1244 						buffer) :
1245 			    fread((char *)buffer,
1246 					bm_size, 1, bmf->bmf_file) != 1) {
1247 				eprintf("read error on code 0x%04x", code);
1248 				return NULL;
1249 			}
1250 #endif /* IN_MEMORY */
1251 			if (cp->code_inverted)
1252 				invert(buffer, HBF_BitmapSize(&(hbf->public)));
1253 			return buffer;
1254 		}
1255 	eprintf("code 0x%04x out of range", code);
1256 	return NULL;
1257 }
1258 
1259 static byte *
local_buffer(HBF_STRUCT * hbf)1260 local_buffer(HBF_STRUCT *hbf)
1261 {
1262 	if (hbf->bitmap_buffer == NULL &&
1263 	    (hbf->bitmap_buffer = (byte *)malloc(HBF_BitmapSize(&(hbf->public)))) == NULL) {
1264 		eprintf("out of memory");
1265 		return NULL;
1266 	}
1267 	return hbf->bitmap_buffer;
1268 }
1269 
1270 static void
invert(byte * buffer,unsigned int length)1271 invert(byte *buffer, unsigned int length)
1272 {
1273 	for ( ; length > 0; length--)
1274 		*buffer++ ^= 0xff;
1275 }
1276 
1277 #ifdef IN_MEMORY
1278 static bool
copy_transposed(HBF * hbf,reg byte * bitmap,reg const byte * source)1279 copy_transposed(HBF *hbf, reg byte *bitmap, reg const byte *source)
1280 {
1281 reg	byte	*pos;
1282 reg	byte	*bm_end;
1283 	int	x;
1284 	int	width;
1285 reg	int	row_size;
1286 reg	int	c;
1287 reg	int	imask, omask;
1288 
1289 	width = hbfBitmapBBox(hbf)->hbf_width;
1290 	row_size = HBF_RowSize(hbf);
1291 	bm_end = bitmap + HBF_BitmapSize(hbf);
1292 	(void)memset((char *)bitmap, '\0', HBF_BitmapSize(hbf));
1293 	for (x = 0; x < width; x++) {
1294 		pos = bitmap + x/8;
1295 		omask = Bit(x%8);
1296 		/* y = 0 */
1297 		for (;;) {
1298 			c = *source++;
1299 			for (imask = Bit(0); imask != 0; imask >>= 1) {
1300 				/*
1301 				 * At this point,
1302 				 *
1303 				 *	imask == Bit(y%8)
1304 				 *	pos == bitmap + y*row_size + x/8
1305 				 *
1306 				 * We examine bit y of row x of the input,
1307 				 * setting bit x of row y of the output if
1308 				 * required, by applying omask to *pos.
1309 				 */
1310 				if ((c & imask) != 0)
1311 					*pos |= omask;
1312 				/* if (++y > height) goto end_column */
1313 				pos += row_size;
1314 				if (pos >= bm_end)
1315 					goto end_column;
1316 			}
1317 		}
1318 end_column:
1319 		;
1320 	}
1321 	return TRUE;
1322 }
1323 #else /* ! IN_MEMORY */
1324 static bool
get_transposed(HBF * hbf,FILE * f,reg byte * bitmap)1325 get_transposed(HBF *hbf, FILE *f, reg byte *bitmap)
1326 {
1327 reg	byte	*pos;
1328 reg	byte	*bm_end;
1329 	int	x;
1330 	int	width;
1331 reg	int	row_size;
1332 reg	int	c;
1333 reg	int	imask, omask;
1334 
1335 	width = hbfBitmapBBox(hbf)->hbf_width;
1336 	row_size = HBF_RowSize(hbf);
1337 	bm_end = bitmap + HBF_BitmapSize(hbf);
1338 	(void)memset((char *)bitmap, '\0', HBF_BitmapSize(hbf));
1339 	for (x = 0; x < width; x++) {
1340 		pos = bitmap + x/8;
1341 		omask = Bit(x%8);
1342 		/* y = 0 */
1343 		for (;;) {
1344 			if ((c = getc(f)) == EOF)
1345 				return FALSE;
1346 			for (imask = Bit(0); imask != 0; imask >>= 1) {
1347 				/*
1348 				 * At this point,
1349 				 *
1350 				 *	imask == Bit(y%8)
1351 				 *	pos == bitmap + y*row_size + x/8
1352 				 *
1353 				 * We examine bit y of row x of the input,
1354 				 * setting bit x of row y of the output if
1355 				 * required, by applying omask to *pos.
1356 				 */
1357 				if ((c & imask) != 0)
1358 					*pos |= omask;
1359 				/* if (++y > height) goto end_column */
1360 				pos += row_size;
1361 				if (pos >= bm_end)
1362 					goto end_column;
1363 			}
1364 		}
1365 end_column:
1366 		;
1367 	}
1368 	return TRUE;
1369 }
1370 #endif /* ! IN_MEMORY */
1371 
1372 /*
1373  * Call function on each valid code in ascending order.
1374  */
1375 void
hbfForEach(reg HBF * hbfFile,void (* func)(HBF *,HBF_CHAR))1376 hbfForEach(reg HBF *hbfFile, void (*func)(HBF *, HBF_CHAR))
1377 {
1378 	HBF_STRUCT	*hbf;
1379 	CODE_RANGE	*cp;
1380 reg	B2_RANGE	*b2r;
1381 reg	unsigned	byte1, byte2;
1382 reg	unsigned	finish;
1383 
1384 	hbf = (HBF_STRUCT *)hbfFile;
1385 	for (cp = hbf->code_range; cp != NULL; cp = cp->code_next) {
1386 		byte1 = FirstByte(cp->code_start);
1387 		byte2 = SecondByte(cp->code_start);
1388 		while (MakeCode(byte1, byte2) <= cp->code_finish) {
1389 			for (b2r = hbf->byte_2_range;
1390 			     b2r != NULL;
1391 			     b2r = b2r->b2r_next) {
1392 				if (byte2 < b2r->b2r_start)
1393 					byte2 = b2r->b2r_start;
1394 				finish = b2r->b2r_finish;
1395 				if (byte1 == FirstByte(cp->code_finish) &&
1396 				    finish > SecondByte(cp->code_finish))
1397 					finish = SecondByte(cp->code_finish);
1398 				while (byte2 <= finish) {
1399 					(*func)(hbfFile,
1400 						MakeCode(byte1, byte2));
1401 					byte2++;
1402 				}
1403 			}
1404 			byte1++;
1405 			byte2 = 0;
1406 		}
1407 	}
1408 }
1409 
1410 const char *
hbfFileName(HBF * hbf)1411 hbfFileName(HBF *hbf)
1412 {
1413 	return ((HBF_STRUCT *)hbf)->filename;
1414 }
1415 
1416 long
hbfChars(HBF * hbfFile)1417 hbfChars(HBF *hbfFile)
1418 {
1419 	HBF_STRUCT	*hbf;
1420 	CODE_RANGE	*cp;
1421 	long		num_chars;
1422 
1423 	hbf = (HBF_STRUCT *)hbfFile;
1424 	num_chars = 0;
1425 	for (cp = hbf->code_range; cp != NULL; cp = cp->code_next)
1426 		num_chars +=
1427 			hbf->b2_size*FirstByte(cp->code_finish) +
1428 			b2_pos(hbf, cp->code_finish) -
1429 			(hbf->b2_size*FirstByte(cp->code_start) +
1430 			b2_pos(hbf, cp->code_start)) + 1;
1431 	return num_chars;
1432 }
1433 
1434 /*
1435  *	Functions also implemented as macros
1436  */
1437 
1438 #ifdef hbfBitmapBBox
1439 #undef hbfBitmapBBox
1440 #endif
1441 
1442 HBF_BBOX *
hbfBitmapBBox(HBF * hbf)1443 hbfBitmapBBox(HBF *hbf)
1444 {
1445 	return &(hbf->hbf_bitmap_bbox);
1446 }
1447 
1448 #ifdef hbfFontBBox
1449 #undef hbfFontBBox
1450 #endif
1451 
1452 HBF_BBOX *
hbfFontBBox(HBF * hbf)1453 hbfFontBBox(HBF *hbf)
1454 {
1455 	return &(hbf->hbf_font_bbox);
1456 }
1457 
1458 const void *
hbfGetByte2Range(HBF * hbfFile,const void * b2r_pointer,byte * startp,byte * finishp)1459 hbfGetByte2Range(HBF *hbfFile, const void *b2r_pointer,
1460 		 byte *startp, byte *finishp)
1461 {
1462 	HBF_STRUCT	*hbf;
1463 	const B2_RANGE	*b2r;
1464 
1465 	hbf = (HBF_STRUCT *)hbfFile;
1466 	if (b2r_pointer == NULL)
1467 		b2r = hbf->byte_2_range;
1468 	else
1469 		b2r = ((const B2_RANGE *)b2r_pointer)->b2r_next;
1470 	if(b2r == NULL)
1471 		return NULL;
1472 	*startp = b2r->b2r_start;
1473 	*finishp = b2r->b2r_finish;
1474 	return (const void *)b2r;
1475 }
1476 
1477 const void *
hbfGetCodeRange(HBF * hbfFile,const void * code_pointer,HBF_CHAR * startp,HBF_CHAR * finishp)1478 hbfGetCodeRange(HBF *hbfFile, const void *code_pointer,
1479 		HBF_CHAR *startp, HBF_CHAR *finishp)
1480 {
1481 	HBF_STRUCT	*hbf;
1482 	const CODE_RANGE	*cp;
1483 
1484 	hbf = (HBF_STRUCT *)hbfFile;
1485 	if (code_pointer == NULL)
1486 		cp = hbf->code_range;
1487 	else
1488 		cp = ((const CODE_RANGE *)code_pointer)->code_next;
1489 	if(cp == NULL)
1490 		return NULL;
1491 	*startp = cp->code_start;
1492 	*finishp = cp->code_finish;
1493 	return (const void *)cp;
1494 }
1495