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();
77 static t1_data
*load_pfa_file(FILE *fp
, filepos
*pos
) {
78 t1_data
*ret
= snew(t1_data
);
79 size_t off
= 0, len
, got
;
82 ret
->type
= PFB_ASCII
;
84 ret
->data
= snewn(len
, unsigned char);
86 got
= fread(ret
->data
+ off
, 1, len
- off
, fp
);
88 if (off
!= len
) break;
90 ret
->data
= sresize(ret
->data
, len
, unsigned char);
92 ret
->data
= sresize(ret
->data
, off
, unsigned char);
98 void read_pfa_file(input
*in
) {
99 t1_font
*tf
= snew(t1_font
);
101 tf
->data
= load_pfa_file(in
->currfp
, &in
->pos
);
103 tf
->length1
= tf
->length2
= 0;
108 void read_pfb_file(input
*in
) {
109 t1_font
*tf
= snew(t1_font
);
111 tf
->data
= load_pfb_file(in
->currfp
, &in
->pos
);
113 tf
->length1
= tf
->length2
= 0;
117 static char *pf_read_token(pfstate
*);
120 * Read a character from the initial plaintext part of a Type 1 font
122 static int pf_getc(pfstate
*pf
) {
123 if (pf
->offset
== pf
->curblock
->length
) {
124 if (pf
->curblock
->next
== NULL
) return EOF
;
125 pf
->curblock
= pf
->curblock
->next
;
128 if (pf
->curblock
->type
!= PFB_ASCII
) return EOF
;
129 return pf
->curblock
->data
[pf
->offset
++];
132 static void pf_ungetc(int c
, pfstate
*pf
) {
133 assert(pf
->offset
> 0);
135 assert(c
== pf
->curblock
->data
[pf
->offset
]);
138 static void pf_rewind(pfstate
*pf
) {
139 pf
->curblock
= pf
->data
;
143 static void pf_seek(pfstate
*pf
, size_t off
) {
144 t1_data
*td
= pf
->data
;
146 while (td
->length
< off
) {
154 static size_t pf_tell(pfstate
*pf
) {
155 t1_data
*td
= pf
->data
;
158 while (td
!= pf
->curblock
) {
162 return o
+ pf
->offset
;
165 static void pf_identify(t1_font
*tf
) {
166 rdstringc rsc
= { 0, 0, NULL
};
172 pfstate pfs
, *pf
= &pfs
;
180 error(err_pfeof
, &tf
->pos
);
184 } while (c
!= 012 && c
!= 015);
186 if ((p
= strchr(p
, ':')) == NULL
) {
188 error(err_pfhead
, &tf
->pos
);
192 p
+= strspn(p
, " \t");
193 len
= strcspn(p
, " \t");
194 fontname
= snewn(len
+ 1, char);
195 memcpy(fontname
, p
, len
);
199 for (fi
= all_fonts
; fi
; fi
= fi
->next
) {
200 if (strcmp(fi
->name
, fontname
) == 0) {
202 fi
->filetype
= TYPE1
;
207 error(err_pfnoafm
, &tf
->pos
, fontname
);
212 * PostScript white space characters; PLRM3 table 3.1
214 static int pf_isspace(int c
) {
215 return c
== 000 || c
== 011 || c
== 012 || c
== 014 || c
== 015 ||
220 * PostScript special characters; PLRM3 page 27
222 static int pf_isspecial(int c
) {
223 return c
== '(' || c
== ')' || c
== '<' || c
== '>' || c
== '[' ||
224 c
== ']' || c
== '{' || c
== '}' || c
== '/' || c
== '%';
227 static size_t pf_findtoken(t1_font
*tf
, size_t off
, char const *needle
) {
229 pfstate pfs
, *pf
= &pfs
;
234 tok
= pf_read_token(pf
);
236 if (pf
->offset
== 0 && pf
->curblock
->type
== PFB_BINARY
)
237 pf
->curblock
= pf
->curblock
->next
;
241 if (strcmp(tok
, needle
) == 0) {
250 static size_t pf_length1(t1_font
*tf
) {
253 ret
= pf_findtoken(tf
, 0, "eexec");
254 if (ret
== (size_t)-1) {
255 error(err_pfeof
, &tf
->pos
);
261 static size_t pf_length2(t1_font
*tf
) {
264 if (tf
->length1
== 0)
265 tf
->length1
= pf_length1(tf
);
266 ret
= pf_findtoken(tf
, tf
->length1
, "cleartomark");
267 if (ret
== (size_t)-1) {
268 error(err_pfeof
, &tf
->pos
);
271 return ret
- 12 - tf
->length1
; /* backspace over "cleartomark\n" */
274 static void pf_getascii(t1_font
*tf
, size_t off
, size_t len
,
275 char **bufp
, size_t *lenp
) {
276 t1_data
*td
= tf
->data
;
280 while (td
&& off
>= td
->length
) {
287 blk
= len
< td
->length ? len
: td
->length
;
288 if (td
->type
== PFB_ASCII
) {
289 *bufp
= sresize(*bufp
, *lenp
+ blk
, char);
290 memcpy(*bufp
+ *lenp
, td
->data
+ off
, blk
);
293 *bufp
= sresize(*bufp
, *lenp
+ blk
* 2 + blk
/ 39 + 3, char);
295 for (i
= 0; i
< blk
; i
++) {
296 if (i
% 39 == 0) p
+= sprintf(p
, "\n");
297 p
+= sprintf(p
, "%02x", td
->data
[off
+ i
]);
299 p
+= sprintf(p
, "\n");
308 void pf_writeps(font_info
const *fi
, FILE *ofp
) {
312 pf_getascii(fi
->fontfile
, 0, INT_MAX
, &buf
, &len
);
313 fwrite(buf
, 1, len
, ofp
);
317 static int hexval(char c
) {
318 if (c
>= '0' && c
<= '9') return c
- '0';
319 if (c
>= 'A' && c
<= 'F') return c
- 'A' + 0xA;
320 if (c
>= 'a' && c
<= 'f') return c
- 'a' + 0xa;
324 static void pf_getbinary(t1_font
*tf
, size_t off
, size_t len
,
325 char **bufp
, size_t *lenp
) {
326 t1_data
*td
= tf
->data
;
331 while (td
&& off
>= td
->length
) {
338 blk
= len
< td
->length ? len
: td
->length
;
339 if (td
->type
== PFB_BINARY
) {
340 *bufp
= sresize(*bufp
, *lenp
+ blk
, char);
341 memcpy(*bufp
+ *lenp
, td
->data
+ off
, blk
);
344 *bufp
= sresize(*bufp
, *lenp
+ blk
/ 2 + 1, char);
346 for (i
= 0; i
< blk
; i
++) {
347 if (pf_isspace(td
->data
[off
+ i
])) continue;
349 nybble
= hexval(td
->data
[off
+i
]);
351 *p
++ = (nybble
<< 4) | hexval(td
->data
[off
+i
]);
352 havenybble
= !havenybble
;
364 * Return the initial, unencrypted, part of a font.
366 void pf_part1(font_info
*fi
, char **bufp
, size_t *lenp
) {
367 t1_font
*tf
= fi
->fontfile
;
369 if (tf
->length1
== 0)
370 tf
->length1
= pf_length1(tf
);
371 pf_getascii(tf
, 0, tf
->length1
, bufp
, lenp
);
375 * Return the middle, encrypted, part of a font.
377 void pf_part2(font_info
*fi
, char **bufp
, size_t *lenp
) {
378 t1_font
*tf
= fi
->fontfile
;
380 if (tf
->length2
== 0)
381 tf
->length2
= pf_length2(tf
);
382 pf_getbinary(tf
, tf
->length1
, tf
->length2
, bufp
, lenp
);
387 static char *pf_read_litstring(pfstate
*pf
) {
388 rdstringc rsc
= { 0, 0, NULL
};
405 if (c
!= EOF
) rdaddc(&rsc
, c
);
406 } while (depth
> 0 && c
!= EOF
);
410 static char *pf_read_hexstring(pfstate
*pf
) {
411 rdstringc rsc
= { 0, 0, NULL
};
417 if (c
!= EOF
) rdaddc(&rsc
, c
);
418 } while (c
!= '>' && c
!= EOF
);
422 static char *pf_read_word(pfstate
*pf
, int c
) {
423 rdstringc rsc
= { 0, 0, NULL
};
426 if (c
== '{' || c
== '}' || c
== '[' || c
== ']')
430 if (pf_isspecial(c
) || pf_isspace(c
) || c
== EOF
) break;
433 if (pf_isspecial(c
)) pf_ungetc(c
, pf
);
437 static char *pf_read_token(pfstate
*pf
) {
442 } while (pf_isspace(c
));
443 if (c
== EOF
) return NULL
;
447 } while (c
!= 012 && c
!= 015);
448 return pf_read_token(pf
);
450 if (c
== '(') return pf_read_litstring(pf
);
451 if (c
== '<') return pf_read_hexstring(pf
);
452 return pf_read_word(pf
, c
);