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