1 // This file is part of Deark.
2 // Copyright (C) 2018 Jason Summers
3 // See the file COPYING for terms of use.
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_pcf
);
11 #define TBLTYPE_PROPERTIES 0x1
12 #define TBLTYPE_METRICS 0x4
13 #define TBLTYPE_BITMAPS 0x8
14 #define TBLTYPE_BDF_ENCODINGS 0x20
16 #define GFMT_DEFAULT 0
17 #define GFMT_COMPRESSED_METRICS 0x00000100
20 struct localctx_struct
;
21 typedef struct localctx_struct lctx
;
23 typedef void (*table_entry_handler_fn
)(deark
*c
, lctx
*d
, struct table_entry
*te
);
26 unsigned int bitmap_offset
;
28 int width_raw
, height_raw
; // Dimensions of the bitmap stored in the file
30 i16 extraspace_l
, extraspace_r
;
33 struct format_struct
{
35 unsigned int gross_format
; // GFMT_*
36 unsigned int glyph_padding_code
;
37 unsigned int glyph_padding_value
;
40 unsigned int scan_unit_code
;
41 unsigned int scan_unit_value
;
45 struct format_struct fmt
;
50 const char *type_name
;
51 table_entry_handler_fn handler_fn
;
54 struct localctx_struct
{
56 struct table_entry
*tables
;
58 // AFAICT: In a PCF file, each "character" has a natural index, implicitly
59 // used by the metrics table, bitmaps table, glyph names table, etc.
60 // This chars[] array is indexed in the same way. It is allocated when we
61 // read the metrics table.
62 // (The encodings table is different: It maps codepoints to these indices.)
64 struct char_info
*chars
;
69 struct format_struct bitmaps_fmt
;
71 u8 has_encodings_table
;
73 u8 can_translate_to_unicode
;
74 int src_encoding
; // Used if(can_translate_to_unicode)
75 char charset_registry
[40];
76 char charset_encoding
[40];
79 // Read a 'format' field, populate caller-supplied 'fmt'.
80 static void read_format_field(deark
*c
, lctx
*d
, struct table_entry
*te
,
81 i64 pos
, struct format_struct
*fmt
)
85 fmt
->raw_format
= (unsigned int)de_getu32le(pos
);
86 de_dbg(c
, "format: 0x%08x", fmt
->raw_format
);
89 fmt
->gross_format
= fmt
->raw_format
&0xffffff00U
;
90 if(fmt
->gross_format
==GFMT_DEFAULT
) {
93 else if(fmt
->gross_format
==0x100 && (te
->type
==0x02 || te
->type
==0x100)) {
94 name
="ACCEL_W_INKBOUNDS";
96 else if(fmt
->gross_format
==0x100 && (te
->type
==0x04 || te
->type
==0x10)) {
97 name
="COMPRESSED_METRICS";
99 else if(fmt
->gross_format
==0x200) {
105 de_dbg(c
, "gross format: 0x%08x (%s)", fmt
->gross_format
, name
);
107 fmt
->glyph_padding_code
= fmt
->raw_format
&0x03;
108 fmt
->glyph_padding_value
= 1U<<(fmt
->glyph_padding_code
);
109 de_dbg(c
, "glyph padding: %u (= to %u-byte boundary)",fmt
->glyph_padding_code
,
110 fmt
->glyph_padding_value
);
111 fmt
->is_le
= !((fmt
->raw_format
>>2)&0x1);
112 de_dbg(c
, "byte order: %s", fmt
->is_le
?"LE":"BE");
113 fmt
->msbit_first
= ((fmt
->raw_format
>>3)&0x1)?1:0;
114 de_dbg(c
, "bit order: %s first", fmt
->msbit_first
?"msb":"lsb");
116 fmt
->scan_unit_code
= (fmt
->raw_format
>>4)&0x03;
117 fmt
->scan_unit_value
= 1U<<fmt
->scan_unit_code
;
118 de_dbg(c
, "scan unit: %u (= %u-byte units)", fmt
->scan_unit_code
,
119 fmt
->scan_unit_value
);
120 de_dbg_indent(c
, -1);
123 static int read_and_check_format_field(deark
*c
, lctx
*d
, struct table_entry
*te
, i64 pos
)
127 format
= (u32
)de_getu32le_p(&pos
);
128 de_dbg(c
, "format: 0x%08x", (unsigned int)format
);
129 if(format
!= te
->fmt
.raw_format
) {
130 de_err(c
, "Can't handle conflicting \"format\" fields");
136 // Read and return a property name or string value
137 static struct de_stringreaderdata
*read_prop_string(deark
*c
, lctx
*d
,
138 struct table_entry
*te
, i64 pos
, const char *name
)
140 struct de_stringreaderdata
*srd
= NULL
;
142 srd
= dbuf_read_string(c
->infile
, pos
, te
->offset
+te
->size
-pos
, 256,
143 DE_CONVFLAG_STOP_AT_NUL
|DE_CONVFLAG_WANT_UTF8
, DE_ENCODING_ASCII
);
144 de_dbg(c
, "%s: \"%s\"", name
, ucstring_getpsz_d(srd
->str
));
148 static void read_one_property(deark
*c
, lctx
*d
, struct table_entry
*te
,
149 i64 pos1
, i64 prop_idx
, i64 string_data_area_pos
)
154 struct de_stringreaderdata
*srd_name
= NULL
;
155 struct de_stringreaderdata
*srd_strval
= NULL
;
157 de_dbg(c
, "property[%d] index entry at %"I64_FMT
, (int)prop_idx
, pos
);
160 name_offset
= dbuf_getu32x(c
->infile
, pos
, te
->fmt
.is_le
);
161 de_dbg(c
, "name offset: %"I64_FMT
" (abs=%"I64_FMT
")", name_offset
,
162 string_data_area_pos
+name_offset
);
164 srd_name
= read_prop_string(c
, d
, te
, string_data_area_pos
+name_offset
, "name");
166 isstringprop
= de_getbyte_p(&pos
);
167 de_dbg(c
, "isStringProp: %u", (unsigned int)isstringprop
);
172 value_offset
= dbuf_getu32x(c
->infile
, pos
, te
->fmt
.is_le
);
173 de_dbg(c
, "value offset: %"I64_FMT
" (abs=%"I64_FMT
")", value_offset
,
174 string_data_area_pos
+value_offset
);
175 srd_strval
= read_prop_string(c
, d
, te
, string_data_area_pos
+value_offset
, "value");
177 if(!de_strcmp(srd_name
->sz_utf8
, "CHARSET_REGISTRY")) {
178 de_strlcpy(d
->charset_registry
, srd_strval
->sz_utf8
, sizeof(d
->charset_registry
));
180 else if(!de_strcmp(srd_name
->sz_utf8
, "CHARSET_ENCODING")) {
181 de_strlcpy(d
->charset_encoding
, srd_strval
->sz_utf8
, sizeof(d
->charset_encoding
));
187 value
= dbuf_geti32x(c
->infile
, pos
, te
->fmt
.is_le
);
188 de_dbg(c
, "value: %"I64_FMT
, value
);
192 de_dbg_indent(c
, -1);
193 de_destroy_stringreaderdata(c
, srd_name
);
194 de_destroy_stringreaderdata(c
, srd_strval
);
197 static void handler_properties(deark
*c
, lctx
*d
, struct table_entry
*te
)
199 i64 pos
= te
->offset
;
201 int saved_indent_level
;
203 i64 props_idx_size_padded
;
204 i64 string_data_area_pos
;
205 i64 string_data_area_size
;
208 de_dbg(c
, "properties table at %"I64_FMT
, pos
);
209 de_dbg_indent_save(c
, &saved_indent_level
);
212 if(!read_and_check_format_field(c
, d
, te
, pos
)) goto done
;
215 nprops
= dbuf_getu32x(c
->infile
, pos
, te
->fmt
.is_le
);
217 de_dbg(c
, "nprops: %d", (int)nprops
);
220 props_idx_size_padded
= de_pad_to_4(nprops
*9);
221 de_dbg(c
, "properties index at %"I64_FMT
, props_idx_pos
);
223 pos
+= props_idx_size_padded
;
225 string_data_area_size
= dbuf_getu32x(c
->infile
, pos
, te
->fmt
.is_le
);
227 string_data_area_pos
= pos
;
228 de_dbg(c
, "string data area at %"I64_FMT
", len=%d", string_data_area_pos
,
229 (int)string_data_area_size
);
231 // Go back and read the properties table
233 for(k
=0; k
<nprops
; k
++) {
234 if(pos
+9 > te
->offset
+ te
->size
) break;
235 read_one_property(c
, d
, te
, pos
, k
, string_data_area_pos
);
240 de_dbg_indent_restore(c
, saved_indent_level
);
243 static void handler_metrics(deark
*c
, lctx
*d
, struct table_entry
*te
)
245 i64 pos
= te
->offset
;
246 int saved_indent_level
;
250 de_dbg_indent_save(c
, &saved_indent_level
);
251 de_dbg(c
, "metrics table at %"I64_FMT
, pos
);
254 if(!read_and_check_format_field(c
, d
, te
, pos
)) goto done
;
257 nmetrics
= dbuf_getu16x(c
->infile
, pos
, te
->fmt
.is_le
);
259 de_dbg(c
, "number of metrics: %d", (int)nmetrics
);
261 d
->num_chars
= nmetrics
;
263 // Allocate chars array, and set defaults
264 d
->chars
= de_mallocarray(c
, d
->num_chars
, sizeof(struct char_info
));
265 for(k
=0; k
<d
->num_chars
; k
++) {
266 d
->chars
[k
].codepoint
= DE_CODEPOINT_INVALID
;
269 for(k
=0; k
<d
->num_chars
; k
++) {
273 unsigned int char_attr
;
274 struct char_info
*ci
;
276 de_dbg2(c
, "char[%d]", (int)k
);
280 if(te
->fmt
.gross_format
==GFMT_COMPRESSED_METRICS
) {
281 leftsb
= (int)de_getbyte_p(&pos
) - 0x80;
282 rightsb
= (int)de_getbyte_p(&pos
) - 0x80;
283 char_width
= (int)de_getbyte_p(&pos
) - 0x80;
284 ci
->ascent
= (int)de_getbyte_p(&pos
) - 0x80;
285 char_desc
= (int)de_getbyte_p(&pos
) - 0x80;
289 leftsb
= (int)dbuf_geti16x(c
->infile
, pos
, te
->fmt
.is_le
); pos
+= 2;
290 rightsb
= (int)dbuf_geti16x(c
->infile
, pos
, te
->fmt
.is_le
); pos
+= 2;
291 char_width
= (int)dbuf_geti16x(c
->infile
, pos
, te
->fmt
.is_le
); pos
+= 2;
292 ci
->ascent
= (int)dbuf_geti16x(c
->infile
, pos
, te
->fmt
.is_le
); pos
+= 2;
293 char_desc
= (int)dbuf_geti16x(c
->infile
, pos
, te
->fmt
.is_le
); pos
+= 2;
294 char_attr
= (int)dbuf_getu16x(c
->infile
, pos
, te
->fmt
.is_le
); pos
+= 2;
297 if(c
->debug_level
>=2) {
298 de_dbg2(c
, "bearing (l, r): %d, %d", leftsb
, rightsb
);
299 de_dbg2(c
, "width: %d", char_width
);
300 de_dbg2(c
, "ascent, descent: %d, %d", ci
->ascent
, char_desc
);
301 de_dbg2(c
, "attributes: %u", char_attr
);
303 ci
->width_raw
= rightsb
- leftsb
;
304 ci
->height_raw
= ci
->ascent
+ char_desc
;
305 if(c
->debug_level
>=2) {
306 de_dbg(c
, "raw bitmap dimensions: %d"DE_CHAR_TIMES
"%d",
307 ci
->width_raw
, ci
->height_raw
);
310 // TODO: Are these calculations correct?
311 ci
->extraspace_l
= (i16
)leftsb
;
312 if(ci
->extraspace_l
<0) ci
->extraspace_l
=0;
313 ci
->extraspace_r
= (i16
)(char_width
- ci
->width_raw
- (int)ci
->extraspace_l
);
314 if(ci
->extraspace_r
<0) ci
->extraspace_r
=0;
316 de_dbg_indent(c
, -1);
320 de_dbg_indent_restore(c
, saved_indent_level
);
323 static void handler_bdf_encodings(deark
*c
, lctx
*d
, struct table_entry
*te
)
325 i64 pos
= te
->offset
;
326 int saved_indent_level
;
327 unsigned int min_char_or_byte2
, max_char_or_byte2
;
328 unsigned int min_byte1
, max_byte1
;
329 unsigned int default_char
;
330 unsigned int byte1_count
, byte2_count
;
331 int is_singlebyte_encoding
;
335 de_dbg_indent_save(c
, &saved_indent_level
);
336 de_dbg(c
, "BDF encodings table at %"I64_FMT
, pos
);
339 if(!read_and_check_format_field(c
, d
, te
, pos
)) goto done
;
341 if(te
->fmt
.gross_format
!= GFMT_DEFAULT
) goto done
;
343 min_char_or_byte2
= (unsigned int)dbuf_getu16x(c
->infile
, pos
, te
->fmt
.is_le
);
344 de_dbg(c
, "min_char_or_byte2: %u", min_char_or_byte2
);
346 max_char_or_byte2
= (unsigned int)dbuf_getu16x(c
->infile
, pos
, te
->fmt
.is_le
);
347 de_dbg(c
, "max_char_or_byte2: %u", max_char_or_byte2
);
349 min_byte1
= (unsigned int)dbuf_getu16x(c
->infile
, pos
, te
->fmt
.is_le
);
350 de_dbg(c
, "min_byte1: %u", min_byte1
);
352 max_byte1
= (unsigned int)dbuf_getu16x(c
->infile
, pos
, te
->fmt
.is_le
);
353 de_dbg(c
, "max_byte1: %u", max_byte1
);
355 default_char
= (unsigned int)dbuf_getu16x(c
->infile
, pos
, te
->fmt
.is_le
);
356 de_dbg(c
, "default_char: %u", default_char
);
359 if(min_char_or_byte2
>max_char_or_byte2
) goto done
;
360 if(min_byte1
>max_byte1
) goto done
;
362 is_singlebyte_encoding
= (min_byte1
==0 && max_byte1
==0);
363 de_dbg(c
, "encoding type: %s", is_singlebyte_encoding
?"single byte":"double byte");
365 byte1_count
= max_byte1
-min_byte1
+1;
366 byte2_count
= max_char_or_byte2
-min_char_or_byte2
+1;
367 ncodepoints
= (i64
)byte1_count
* (i64
)byte2_count
;
368 de_dbg(c
, "number of codepoints in table: %"I64_FMT
, ncodepoints
);
370 d
->has_encodings_table
= 1;
372 for(k
=0; k
<ncodepoints
; k
++) {
373 unsigned int glyph_number
;
376 if(pos
+2 > te
->offset
+te
->size
) break;
377 glyph_number
= (unsigned int)dbuf_getu16x(c
->infile
, pos
, te
->fmt
.is_le
);
379 if(is_singlebyte_encoding
) {
380 codepoint
= (i32
)k
+ (i32
)min_char_or_byte2
;
383 unsigned int tmp_hi
, tmp_lo
;
384 tmp_hi
= ((unsigned int)k
)/byte2_count
;
385 tmp_lo
= ((unsigned int)k
)%byte2_count
;
386 codepoint
= (i32
)(((min_char_or_byte2
+tmp_hi
)<<8) |
390 if(glyph_number
!=0xffff && glyph_number
<d
->num_chars
) {
391 d
->chars
[glyph_number
].codepoint
= codepoint
;
394 if(c
->debug_level
>=2) {
396 if(glyph_number
==0xffff) {
397 de_strlcpy(gstr
, "no char", sizeof(gstr
));
400 de_snprintf(gstr
, sizeof(gstr
), "char[%u]", glyph_number
);
402 de_dbg2(c
, "[%d]: codepoint %d = %s", (int)k
, (int)codepoint
, gstr
);
409 de_dbg_indent_restore(c
, saved_indent_level
);
412 static void reverse_bit_order(u8
*m
, i64 m_len
)
415 static const u8 tbl
[16] = {
416 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
417 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf };
419 for(k
=0; k
<m_len
; k
++) {
420 m
[k
] = (tbl
[m
[k
]&0x0f]<<4) | tbl
[(m
[k
]&0xf0)>>4];
424 static void handler_bitmaps(deark
*c
, lctx
*d
, struct table_entry
*te
)
426 i64 pos
= te
->offset
;
429 int saved_indent_level
;
431 de_dbg_indent_save(c
, &saved_indent_level
);
432 de_dbg(c
, "bitmap table at %"I64_FMT
, pos
);
435 if(!read_and_check_format_field(c
, d
, te
, pos
)) goto done
;
437 d
->bitmaps_fmt
= te
->fmt
; // struct copy
439 nglyphs
= dbuf_getu32x(c
->infile
, pos
, te
->fmt
.is_le
);
441 de_dbg(c
, "glyph count: %d", (int)nglyphs
);
443 if(nglyphs
!= d
->num_chars
) {
444 de_warn(c
, "Expected %d bitmaps, found %d", (int)d
->num_chars
, (int)nglyphs
);
446 if(nglyphs
< d
->num_chars
) {
447 d
->num_chars
= nglyphs
;
450 for(k
=0; k
<d
->num_chars
; k
++) {
451 d
->chars
[k
].bitmap_offset
= (unsigned int)dbuf_getu32x(c
->infile
, pos
, te
->fmt
.is_le
);
453 if(c
->debug_level
>=2)
454 de_dbg2(c
, "char[%d] glyph offset: %u", (int)k
, d
->chars
[k
].bitmap_offset
);
461 bitmapsize
= dbuf_getu32x(c
->infile
, pos
, te
->fmt
.is_le
);
463 use_this_one
= (((unsigned int)k
)==te
->fmt
.glyph_padding_code
);
464 de_dbg(c
, "bitmapsize[if padding=%d]: %u%s", (int)k
, (unsigned int)bitmapsize
,
465 use_this_one
?" *":"");
467 d
->bitmaps_data_len
= bitmapsize
;
471 if(pos
+ d
->bitmaps_data_len
> te
->offset
+te
->size
) {
473 d
->bitmaps_data_len
= 0;
477 if(te
->fmt
.is_le
&& te
->fmt
.scan_unit_value
>1) {
478 // TODO: Support this
479 de_err(c
, "Little-endian byte order is not supported");
483 de_dbg(c
, "bitmaps data at %"I64_FMT
", len=%"I64_FMT
, pos
, d
->bitmaps_data_len
);
484 d
->bitmaps_data
= de_malloc(c
, d
->bitmaps_data_len
);
485 de_read(d
->bitmaps_data
, pos
, d
->bitmaps_data_len
);
486 if(!te
->fmt
.msbit_first
) {
487 reverse_bit_order(d
->bitmaps_data
, d
->bitmaps_data_len
);
491 de_dbg_indent_restore(c
, saved_indent_level
);
494 // Caller sets te->type.
495 // This function sets: ->type_name, ->handler_fn
496 static void lookup_table_entry_type_info(deark
*c
, lctx
*d
, struct table_entry
*te
)
499 case TBLTYPE_PROPERTIES
:
500 te
->type_name
= "properties";
501 te
->handler_fn
= handler_properties
;
504 te
->type_name
= "accelerators";
506 case TBLTYPE_METRICS
:
507 te
->type_name
= "metrics";
508 te
->handler_fn
= handler_metrics
;
510 case TBLTYPE_BITMAPS
:
511 te
->type_name
= "bitmaps";
512 te
->handler_fn
= handler_bitmaps
;
515 te
->type_name
= "ink metrics";
517 case TBLTYPE_BDF_ENCODINGS
:
518 te
->type_name
= "BDF encodings";
519 te
->handler_fn
= handler_bdf_encodings
;
522 te
->type_name
= "swidths";
525 te
->type_name
= "glyph names";
528 te
->type_name
= "BDF accelerators";
535 static int do_read_table_entry(deark
*c
, lctx
*d
, struct table_entry
*te
, i64 pos1
)
540 if(pos1
+16 > c
->infile
->len
) goto done
;
542 te
->type
= (unsigned int)de_getu32le_p(&pos
);
543 lookup_table_entry_type_info(c
, d
, te
);
544 de_dbg(c
, "type: 0x%08x (%s)", te
->type
, te
->type_name
);
546 read_format_field(c
, d
, te
, pos
, &te
->fmt
);
549 te
->size
= de_getu32le_p(&pos
);
550 te
->offset
= de_getu32le_p(&pos
);
551 de_dbg(c
, "offset: %"I64_FMT
", size: %"I64_FMT
, te
->offset
, te
->size
);
552 if(te
->offset
+te
->size
> c
->infile
->len
) {
553 de_warn(c
, "Table entry goes beyond end of file (type=%s, at %"I64_FMT
554 ", size=%"I64_FMT
")", te
->type_name
, te
->offset
, te
->size
);
556 if(te
->offset
> c
->infile
->len
) {
566 static void do_make_font_image(deark
*c
, lctx
*d
)
568 struct de_bitmap_font
*font
= NULL
;
570 int max_full_width
= 1;
573 struct de_encconv_state es
;
575 if(!d
->chars
) goto done
;
576 if(!d
->bitmaps_data
) goto done
;
578 font
= de_create_bitmap_font(c
);
580 font
->num_chars
= d
->num_chars
;
582 font
->has_nonunicode_codepoints
= 1;
583 if(d
->is_unicode
|| d
->can_translate_to_unicode
) {
584 font
->has_unicode_codepoints
= 1;
585 font
->prefer_unicode
= 1;
588 font
->char_array
= de_mallocarray(c
, d
->num_chars
, sizeof(struct de_bitmap_font_char
));
589 de_encconv_init(&es
, d
->src_encoding
); // 'es' might not get used, but that's ok.
591 // First, scan the characters
592 for(k
=0; k
<font
->num_chars
; k
++) {
593 struct char_info
*ci
= &d
->chars
[k
];
596 if(ci
->codepoint
== DE_CODEPOINT_INVALID
) continue;
598 full_width
= (int)ci
->extraspace_l
+ ci
->width_raw
+ (int)ci
->extraspace_r
;
599 if(full_width
> max_full_width
) max_full_width
= full_width
;
600 if(ci
->ascent
> max_ascent
) max_ascent
= ci
->ascent
;
601 if(ci
->height_raw
- ci
->ascent
> max_descent
) max_descent
= ci
->height_raw
- ci
->ascent
;
604 font
->nominal_width
= max_full_width
;
605 font
->nominal_height
= max_ascent
+ max_descent
;
606 if(font
->nominal_height
<1) font
->nominal_height
= 1;
608 for(k
=0; k
<font
->num_chars
; k
++) {
609 struct de_bitmap_font_char
*ch
= &font
->char_array
[k
];
610 struct char_info
*ci
= &d
->chars
[k
];
613 if(ci
->codepoint
== DE_CODEPOINT_INVALID
) continue;
614 ch
->codepoint_nonunicode
= ci
->codepoint
;
616 ch
->codepoint_unicode
= ci
->codepoint
;
618 else if(d
->can_translate_to_unicode
) {
619 ch
->codepoint_unicode
= de_char_to_unicode_ex(ci
->codepoint
, &es
);
622 ch
->width
= ci
->width_raw
;
623 ch
->height
= ci
->height_raw
;
624 if(ch
->width
<1) ch
->width
=1;
625 if(ch
->height
<1) ch
->height
=1;
626 ch
->v_offset
= max_ascent
- ci
->ascent
;
627 ch
->extraspace_l
= ci
->extraspace_l
;
628 ch
->extraspace_r
= ci
->extraspace_r
;
630 ch
->rowspan
= de_pad_to_n((i64
)((ci
->width_raw
+7)/8), (i64
)d
->bitmaps_fmt
.glyph_padding_value
);
631 bitmap_len
= ch
->rowspan
* ci
->height_raw
;
632 if(ci
->bitmap_offset
+ bitmap_len
<= d
->bitmaps_data_len
) {
633 ch
->bitmap
= &d
->bitmaps_data
[ci
->bitmap_offset
];
640 de_font_bitmap_font_to_image(c
, font
, NULL
, 0);
644 de_free(c
, font
->char_array
);
645 de_destroy_bitmap_font(c
, font
);
649 // If a table of type tbltype exists in d->tables[], process it.
650 // Processes at most one table.
651 static int process_table_by_type(deark
*c
, lctx
*d
, u32 tbltype
)
654 struct table_entry
*te
;
656 for(k
=0; k
<d
->table_count
; k
++) {
658 if(te
->type
== tbltype
) {
660 te
->handler_fn(c
, d
, te
);
668 static void de_run_pcf(deark
*c
, de_module_params
*mparams
)
673 int saved_indent_level
;
675 de_dbg_indent_save(c
, &saved_indent_level
);
676 d
= de_malloc(c
, sizeof(lctx
));
679 de_dbg(c
, "header at %d", (int)pos
);
682 pos
+= 4; // signature
684 d
->table_count
= de_getu32le_p(&pos
);
685 de_dbg(c
, "table count: %u", (unsigned int)d
->table_count
);
686 if(d
->table_count
>256) goto done
;
688 // We don't necessarily want to process the tables in the order they are
689 // listed in the index, so first read the tables index into memory.
690 d
->tables
= de_mallocarray(c
, d
->table_count
, sizeof(struct table_entry
));
692 for(k
=0; k
<d
->table_count
; k
++) {
693 de_dbg(c
, "table entry[%d] at %"I64_FMT
, (int)k
, pos
);
695 if(!do_read_table_entry(c
, d
, &d
->tables
[k
], pos
)) goto done
;
696 de_dbg_indent(c
, -1);
700 // Now process the tables in the order we choose.
702 process_table_by_type(c
, d
, TBLTYPE_PROPERTIES
);
704 if(!de_strcmp(d
->charset_registry
, "ISO10646")) {
707 else if(!de_strcmp(d
->charset_registry
, "ISO8859")) {
708 if(!de_strcmp(d
->charset_encoding
, "1")) {
711 else if(!de_strcmp(d
->charset_encoding
, "2")) {
712 d
->can_translate_to_unicode
= 1;
713 d
->src_encoding
= DE_ENCODING_LATIN2
;
717 if(!process_table_by_type(c
, d
, TBLTYPE_METRICS
)) {
718 de_err(c
, "Missing metrics table");
722 process_table_by_type(c
, d
, TBLTYPE_BDF_ENCODINGS
);
724 if(!d
->has_encodings_table
) {
726 d
->can_translate_to_unicode
= 0;
727 for(k
=0; k
<d
->num_chars
; k
++) {
728 d
->chars
[k
].codepoint
= (i32
)k
;
732 if(!process_table_by_type(c
, d
, TBLTYPE_BITMAPS
)) {
733 de_err(c
, "Missing bitmaps table");
737 do_make_font_image(c
, d
);
741 de_free(c
, d
->tables
);
742 de_free(c
, d
->chars
);
743 de_free(c
, d
->bitmaps_data
);
746 de_dbg_indent_restore(c
, saved_indent_level
);
749 static int de_identify_pcf(deark
*c
)
751 if(!dbuf_memcmp(c
->infile
, 0, "\x01" "fcp", 4))
756 void de_module_pcf(deark
*c
, struct deark_module_info
*mi
)
759 mi
->desc
= "PCF font";
760 mi
->run_fn
= de_run_pcf
;
761 mi
->identify_fn
= de_identify_pcf
;