2 * PostScript Type 1 font file support for Halibut
5 * Type 1 font file formats are specified by Adobe Technical Note
6 * #5040: "Supporting Downloadable PostScript Language Fonts".
7 * Halibut supports hexadecimal format (section 3.1) and IBM PC format
8 * (section 3.3), commonly called PFA and PFB respectively.
22 typedef struct t1_font_Tag t1_font
;
23 typedef struct t1_data_Tag t1_data
;
39 typedef struct pfstate_Tag
{
45 static void pf_identify(t1_font
*tf
);
47 static t1_data
*load_pfb_file(FILE *fp
, filepos
*pos
) {
48 t1_data
*head
= NULL
, *tail
= NULL
;
54 if (fgetc(fp
) != 128) abort();
56 if (type
== PFB_EOF
) return head
;
58 tail
->next
= snew(t1_data
);
66 for (i
= 0; i
< 4; i
++) {
68 if (c
== EOF
) abort();
69 tail
->length
|= c
<< (8 * i
);
71 tail
->data
= snewn(tail
->length
, unsigned char);
72 if (fread(tail
->data
, 1, tail
->length
, fp
) != tail
->length
) abort();
76 static t1_data
*load_pfa_file(FILE *fp
, filepos
*pos
) {
77 t1_data
*ret
= snew(t1_data
);
78 size_t off
= 0, len
, got
;
81 ret
->type
= PFB_ASCII
;
83 ret
->data
= snewn(len
, unsigned char);
85 got
= fread(ret
->data
+ off
, 1, len
- off
, fp
);
87 if (off
!= len
) break;
89 ret
->data
= sresize(ret
->data
, len
, unsigned char);
91 ret
->data
= sresize(ret
->data
, off
, unsigned char);
96 void read_pfa_file(input
*in
) {
97 t1_font
*tf
= snew(t1_font
);
99 tf
->data
= load_pfa_file(in
->currfp
, &in
->pos
);
101 tf
->length1
= tf
->length2
= 0;
106 void read_pfb_file(input
*in
) {
107 t1_font
*tf
= snew(t1_font
);
109 tf
->data
= load_pfb_file(in
->currfp
, &in
->pos
);
111 tf
->length1
= tf
->length2
= 0;
115 static char *pf_read_token(pfstate
*);
118 * Read a character from the initial plaintext part of a Type 1 font
120 static int pf_getc(pfstate
*pf
) {
121 if (pf
->offset
== pf
->curblock
->length
) {
122 if (pf
->curblock
->next
== NULL
) return EOF
;
123 pf
->curblock
= pf
->curblock
->next
;
126 if (pf
->curblock
->type
!= PFB_ASCII
) return EOF
;
127 return pf
->curblock
->data
[pf
->offset
++];
130 static void pf_ungetc(int c
, pfstate
*pf
) {
131 assert(pf
->offset
> 0);
133 assert(c
== pf
->curblock
->data
[pf
->offset
]);
136 static void pf_rewind(pfstate
*pf
) {
137 pf
->curblock
= pf
->data
;
141 static void pf_seek(pfstate
*pf
, size_t off
) {
142 t1_data
*td
= pf
->data
;
144 while (td
->length
< off
) {
152 static size_t pf_tell(pfstate
*pf
) {
153 t1_data
*td
= pf
->data
;
156 while (td
!= pf
->curblock
) {
160 return o
+ pf
->offset
;
163 static void pf_identify(t1_font
*tf
) {
164 rdstringc rsc
= { 0, 0, NULL
};
170 pfstate pfs
, *pf
= &pfs
;
178 error(err_pfeof
, &tf
->pos
);
182 } while (c
!= 012 && c
!= 015);
184 if ((p
= strchr(p
, ':')) == NULL
) {
186 error(err_pfhead
, &tf
->pos
);
190 p
+= strspn(p
, " \t");
191 len
= strcspn(p
, " \t");
192 fontname
= snewn(len
+ 1, char);
193 memcpy(fontname
, p
, len
);
197 for (fi
= all_fonts
; fi
; fi
= fi
->next
) {
198 if (strcmp(fi
->name
, fontname
) == 0) {
204 error(err_pfnoafm
, &tf
->pos
, fontname
);
209 * PostScript white space characters; PLRM3 table 3.1
211 static int pf_isspace(int c
) {
212 return c
== 000 || c
== 011 || c
== 012 || c
== 014 || c
== 015 ||
217 * PostScript special characters; PLRM3 page 27
219 static int pf_isspecial(int c
) {
220 return c
== '(' || c
== ')' || c
== '<' || c
== '>' || c
== '[' ||
221 c
== ']' || c
== '{' || c
== '}' || c
== '/' || c
== '%';
224 static size_t pf_findtoken(t1_font
*tf
, size_t off
, char const *needle
) {
226 pfstate pfs
, *pf
= &pfs
;
231 tok
= pf_read_token(pf
);
233 if (pf
->offset
== 0 && pf
->curblock
->type
== PFB_BINARY
)
234 pf
->curblock
= pf
->curblock
->next
;
238 if (strcmp(tok
, needle
) == 0) {
247 static size_t pf_length1(t1_font
*tf
) {
250 ret
= pf_findtoken(tf
, 0, "eexec");
251 if (ret
== (size_t)-1) {
252 error(err_pfeof
, &tf
->pos
);
258 static size_t pf_length2(t1_font
*tf
) {
261 if (tf
->length1
== 0)
262 tf
->length1
= pf_length1(tf
);
263 ret
= pf_findtoken(tf
, tf
->length1
, "cleartomark");
264 if (ret
== (size_t)-1) {
265 error(err_pfeof
, &tf
->pos
);
268 return ret
- 12 - tf
->length1
; /* backspace over "cleartomark\n" */
271 static void pf_getascii(t1_font
*tf
, size_t off
, size_t len
,
272 char **bufp
, size_t *lenp
) {
273 t1_data
*td
= tf
->data
;
277 while (td
&& off
>= td
->length
) {
284 blk
= len
< td
->length ? len
: td
->length
;
285 if (td
->type
== PFB_ASCII
) {
286 *bufp
= sresize(*bufp
, *lenp
+ blk
, char);
287 memcpy(*bufp
+ *lenp
, td
->data
+ off
, blk
);
290 *bufp
= sresize(*bufp
, *lenp
+ blk
* 2 + blk
/ 39 + 3, char);
292 for (i
= 0; i
< blk
; i
++) {
293 if (i
% 39 == 0) p
+= sprintf(p
, "\n");
294 p
+= sprintf(p
, "%02x", td
->data
[off
+ i
]);
296 p
+= sprintf(p
, "\n");
305 void pf_writeps(font_info
const *fi
, FILE *ofp
) {
309 pf_getascii(fi
->fontfile
, 0, INT_MAX
, &buf
, &len
);
310 fwrite(buf
, 1, len
, ofp
);
314 static int hexval(char c
) {
315 if (c
>= '0' && c
<= '9') return c
- '0';
316 if (c
>= 'A' && c
<= 'F') return c
- 'A' + 0xA;
317 if (c
>= 'a' && c
<= 'f') return c
- 'a' + 0xa;
321 static void pf_getbinary(t1_font
*tf
, size_t off
, size_t len
,
322 char **bufp
, size_t *lenp
) {
323 t1_data
*td
= tf
->data
;
328 while (td
&& off
>= td
->length
) {
335 blk
= len
< td
->length ? len
: td
->length
;
336 if (td
->type
== PFB_BINARY
) {
337 *bufp
= sresize(*bufp
, *lenp
+ blk
, char);
338 memcpy(*bufp
+ *lenp
, td
->data
+ off
, blk
);
341 *bufp
= sresize(*bufp
, *lenp
+ blk
/ 2 + 1, char);
343 for (i
= 0; i
< blk
; i
++) {
344 if (pf_isspace(td
->data
[off
+ i
])) continue;
346 nybble
= hexval(td
->data
[off
+i
]);
348 *p
++ = (nybble
<< 4) | hexval(td
->data
[off
+i
]);
349 havenybble
= !havenybble
;
361 * Return the initial, unencrypted, part of a font.
363 void pf_part1(font_info
*fi
, char **bufp
, size_t *lenp
) {
364 t1_font
*tf
= fi
->fontfile
;
366 if (tf
->length1
== 0)
367 tf
->length1
= pf_length1(tf
);
368 pf_getascii(tf
, 0, tf
->length1
, bufp
, lenp
);
372 * Return the middle, encrypted, part of a font.
374 void pf_part2(font_info
*fi
, char **bufp
, size_t *lenp
) {
375 t1_font
*tf
= fi
->fontfile
;
377 if (tf
->length2
== 0)
378 tf
->length2
= pf_length2(tf
);
379 pf_getbinary(tf
, tf
->length1
, tf
->length2
, bufp
, lenp
);
384 static char *pf_read_litstring(pfstate
*pf
) {
385 rdstringc rsc
= { 0, 0, NULL
};
402 if (c
!= EOF
) rdaddc(&rsc
, c
);
403 } while (depth
> 0 && c
!= EOF
);
407 static char *pf_read_hexstring(pfstate
*pf
) {
408 rdstringc rsc
= { 0, 0, NULL
};
414 if (c
!= EOF
) rdaddc(&rsc
, c
);
415 } while (c
!= '>' && c
!= EOF
);
419 static char *pf_read_word(pfstate
*pf
, int c
) {
420 rdstringc rsc
= { 0, 0, NULL
};
423 if (c
== '{' || c
== '}' || c
== '[' || c
== ']')
427 if (pf_isspecial(c
) || pf_isspace(c
) || c
== EOF
) break;
430 if (pf_isspecial(c
)) pf_ungetc(c
, pf
);
434 static char *pf_read_token(pfstate
*pf
) {
439 } while (pf_isspace(c
));
440 if (c
== EOF
) return NULL
;
444 } while (c
!= 012 && c
!= 015);
445 return pf_read_token(pf
);
447 if (c
== '(') return pf_read_litstring(pf
);
448 if (c
== '<') return pf_read_hexstring(pf
);
449 return pf_read_word(pf
, c
);