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) {
200 fi
->filetype
= TYPE1
;
205 error(err_pfnoafm
, &tf
->pos
, fontname
);
210 * PostScript white space characters; PLRM3 table 3.1
212 static int pf_isspace(int c
) {
213 return c
== 000 || c
== 011 || c
== 012 || c
== 014 || c
== 015 ||
218 * PostScript special characters; PLRM3 page 27
220 static int pf_isspecial(int c
) {
221 return c
== '(' || c
== ')' || c
== '<' || c
== '>' || c
== '[' ||
222 c
== ']' || c
== '{' || c
== '}' || c
== '/' || c
== '%';
225 static size_t pf_findtoken(t1_font
*tf
, size_t off
, char const *needle
) {
227 pfstate pfs
, *pf
= &pfs
;
232 tok
= pf_read_token(pf
);
234 if (pf
->offset
== 0 && pf
->curblock
->type
== PFB_BINARY
)
235 pf
->curblock
= pf
->curblock
->next
;
239 if (strcmp(tok
, needle
) == 0) {
248 static size_t pf_length1(t1_font
*tf
) {
251 ret
= pf_findtoken(tf
, 0, "eexec");
252 if (ret
== (size_t)-1) {
253 error(err_pfeof
, &tf
->pos
);
259 static size_t pf_length2(t1_font
*tf
) {
262 if (tf
->length1
== 0)
263 tf
->length1
= pf_length1(tf
);
264 ret
= pf_findtoken(tf
, tf
->length1
, "cleartomark");
265 if (ret
== (size_t)-1) {
266 error(err_pfeof
, &tf
->pos
);
269 return ret
- 12 - tf
->length1
; /* backspace over "cleartomark\n" */
272 static void pf_getascii(t1_font
*tf
, size_t off
, size_t len
,
273 char **bufp
, size_t *lenp
) {
274 t1_data
*td
= tf
->data
;
278 while (td
&& off
>= td
->length
) {
285 blk
= len
< td
->length ? len
: td
->length
;
286 if (td
->type
== PFB_ASCII
) {
287 *bufp
= sresize(*bufp
, *lenp
+ blk
, char);
288 memcpy(*bufp
+ *lenp
, td
->data
+ off
, blk
);
291 *bufp
= sresize(*bufp
, *lenp
+ blk
* 2 + blk
/ 39 + 3, char);
293 for (i
= 0; i
< blk
; i
++) {
294 if (i
% 39 == 0) p
+= sprintf(p
, "\n");
295 p
+= sprintf(p
, "%02x", td
->data
[off
+ i
]);
297 p
+= sprintf(p
, "\n");
306 void pf_writeps(font_info
const *fi
, FILE *ofp
) {
310 pf_getascii(fi
->fontfile
, 0, INT_MAX
, &buf
, &len
);
311 fwrite(buf
, 1, len
, ofp
);
315 static int hexval(char c
) {
316 if (c
>= '0' && c
<= '9') return c
- '0';
317 if (c
>= 'A' && c
<= 'F') return c
- 'A' + 0xA;
318 if (c
>= 'a' && c
<= 'f') return c
- 'a' + 0xa;
322 static void pf_getbinary(t1_font
*tf
, size_t off
, size_t len
,
323 char **bufp
, size_t *lenp
) {
324 t1_data
*td
= tf
->data
;
329 while (td
&& off
>= td
->length
) {
336 blk
= len
< td
->length ? len
: td
->length
;
337 if (td
->type
== PFB_BINARY
) {
338 *bufp
= sresize(*bufp
, *lenp
+ blk
, char);
339 memcpy(*bufp
+ *lenp
, td
->data
+ off
, blk
);
342 *bufp
= sresize(*bufp
, *lenp
+ blk
/ 2 + 1, char);
344 for (i
= 0; i
< blk
; i
++) {
345 if (pf_isspace(td
->data
[off
+ i
])) continue;
347 nybble
= hexval(td
->data
[off
+i
]);
349 *p
++ = (nybble
<< 4) | hexval(td
->data
[off
+i
]);
350 havenybble
= !havenybble
;
362 * Return the initial, unencrypted, part of a font.
364 void pf_part1(font_info
*fi
, char **bufp
, size_t *lenp
) {
365 t1_font
*tf
= fi
->fontfile
;
367 if (tf
->length1
== 0)
368 tf
->length1
= pf_length1(tf
);
369 pf_getascii(tf
, 0, tf
->length1
, bufp
, lenp
);
373 * Return the middle, encrypted, part of a font.
375 void pf_part2(font_info
*fi
, char **bufp
, size_t *lenp
) {
376 t1_font
*tf
= fi
->fontfile
;
378 if (tf
->length2
== 0)
379 tf
->length2
= pf_length2(tf
);
380 pf_getbinary(tf
, tf
->length1
, tf
->length2
, bufp
, lenp
);
385 static char *pf_read_litstring(pfstate
*pf
) {
386 rdstringc rsc
= { 0, 0, NULL
};
403 if (c
!= EOF
) rdaddc(&rsc
, c
);
404 } while (depth
> 0 && c
!= EOF
);
408 static char *pf_read_hexstring(pfstate
*pf
) {
409 rdstringc rsc
= { 0, 0, NULL
};
415 if (c
!= EOF
) rdaddc(&rsc
, c
);
416 } while (c
!= '>' && c
!= EOF
);
420 static char *pf_read_word(pfstate
*pf
, int c
) {
421 rdstringc rsc
= { 0, 0, NULL
};
424 if (c
== '{' || c
== '}' || c
== '[' || c
== ']')
428 if (pf_isspecial(c
) || pf_isspace(c
) || c
== EOF
) break;
431 if (pf_isspecial(c
)) pf_ungetc(c
, pf
);
435 static char *pf_read_token(pfstate
*pf
) {
440 } while (pf_isspace(c
));
441 if (c
== EOF
) return NULL
;
445 } while (c
!= 012 && c
!= 015);
446 return pf_read_token(pf
);
448 if (c
== '(') return pf_read_litstring(pf
);
449 if (c
== '<') return pf_read_hexstring(pf
);
450 return pf_read_word(pf
, c
);