nrg: Improved support for v2
[deark.git] / modules / pcf.c
blob9094df3da41e3b6e74f08e189192f94e6868c3e4
1 // This file is part of Deark.
2 // Copyright (C) 2018 Jason Summers
3 // See the file COPYING for terms of use.
5 // PCF font
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
19 struct table_entry;
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);
25 struct char_info {
26 unsigned int bitmap_offset;
27 i32 codepoint;
28 int width_raw, height_raw; // Dimensions of the bitmap stored in the file
29 int ascent;
30 i16 extraspace_l, extraspace_r;
33 struct format_struct {
34 u32 raw_format;
35 unsigned int gross_format; // GFMT_*
36 unsigned int glyph_padding_code;
37 unsigned int glyph_padding_value;
38 int is_le;
39 int msbit_first;
40 unsigned int scan_unit_code;
41 unsigned int scan_unit_value;
44 struct table_entry {
45 struct format_struct fmt;
46 u32 type;
47 i64 size;
48 i64 offset;
50 const char *type_name;
51 table_entry_handler_fn handler_fn;
54 struct localctx_struct {
55 i64 table_count;
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.)
63 i64 num_chars;
64 struct char_info *chars;
66 i64 bitmaps_data_len;
67 u8 *bitmaps_data;
69 struct format_struct bitmaps_fmt;
71 u8 has_encodings_table;
72 u8 is_unicode;
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)
83 const char *name;
85 fmt->raw_format = (unsigned int)de_getu32le(pos);
86 de_dbg(c, "format: 0x%08x", fmt->raw_format);
87 de_dbg_indent(c, 1);
89 fmt->gross_format = fmt->raw_format&0xffffff00U;
90 if(fmt->gross_format==GFMT_DEFAULT) {
91 name="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) {
100 name="INKBOUNDS";
102 else {
103 name="?";
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)
125 u32 format;
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");
131 return 0;
133 return 1;
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));
145 return srd;
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)
151 i64 pos = pos1;
152 u8 isstringprop;
153 i64 name_offset;
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);
158 de_dbg_indent(c, 1);
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);
163 pos += 4;
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);
169 if(isstringprop) {
170 i64 value_offset;
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));
184 else {
185 i64 value;
187 value = dbuf_geti32x(c->infile, pos, te->fmt.is_le);
188 de_dbg(c, "value: %"I64_FMT, value);
190 pos += 4;
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;
200 i64 nprops;
201 int saved_indent_level;
202 i64 props_idx_pos;
203 i64 props_idx_size_padded;
204 i64 string_data_area_pos;
205 i64 string_data_area_size;
206 i64 k;
208 de_dbg(c, "properties table at %"I64_FMT, pos);
209 de_dbg_indent_save(c, &saved_indent_level);
210 de_dbg_indent(c, 1);
212 if(!read_and_check_format_field(c, d, te, pos)) goto done;
213 pos += 4;
215 nprops = dbuf_getu32x(c->infile, pos, te->fmt.is_le);
216 pos += 4;
217 de_dbg(c, "nprops: %d", (int)nprops);
219 props_idx_pos = pos;
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);
226 pos += 4;
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
232 pos = props_idx_pos;
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);
236 pos += 9;
239 done:
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;
247 i64 nmetrics;
248 i64 k;
250 de_dbg_indent_save(c, &saved_indent_level);
251 de_dbg(c, "metrics table at %"I64_FMT, pos);
252 de_dbg_indent(c, 1);
254 if(!read_and_check_format_field(c, d, te, pos)) goto done;
255 pos += 4;
257 nmetrics = dbuf_getu16x(c->infile, pos, te->fmt.is_le);
258 pos += 2;
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++) {
270 int leftsb, rightsb;
271 int char_width;
272 int char_desc;
273 unsigned int char_attr;
274 struct char_info *ci;
276 de_dbg2(c, "char[%d]", (int)k);
277 de_dbg_indent(c, 1);
278 ci = &d->chars[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;
286 char_attr = 0;
288 else {
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);
319 done:
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;
332 i64 ncodepoints;
333 i64 k;
335 de_dbg_indent_save(c, &saved_indent_level);
336 de_dbg(c, "BDF encodings table at %"I64_FMT, pos);
337 de_dbg_indent(c, 1);
339 if(!read_and_check_format_field(c, d, te, pos)) goto done;
340 pos += 4;
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);
345 pos += 2;
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);
348 pos += 2;
349 min_byte1 = (unsigned int)dbuf_getu16x(c->infile, pos, te->fmt.is_le);
350 de_dbg(c, "min_byte1: %u", min_byte1);
351 pos += 2;
352 max_byte1 = (unsigned int)dbuf_getu16x(c->infile, pos, te->fmt.is_le);
353 de_dbg(c, "max_byte1: %u", max_byte1);
354 pos += 2;
355 default_char = (unsigned int)dbuf_getu16x(c->infile, pos, te->fmt.is_le);
356 de_dbg(c, "default_char: %u", default_char);
357 pos += 2;
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;
374 i32 codepoint;
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;
382 else {
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) |
387 (min_byte1+tmp_lo));
390 if(glyph_number!=0xffff && glyph_number<d->num_chars) {
391 d->chars[glyph_number].codepoint = codepoint;
394 if(c->debug_level>=2) {
395 char gstr[40];
396 if(glyph_number==0xffff) {
397 de_strlcpy(gstr, "no char", sizeof(gstr));
399 else {
400 de_snprintf(gstr, sizeof(gstr), "char[%u]", glyph_number);
402 de_dbg2(c, "[%d]: codepoint %d = %s", (int)k, (int)codepoint, gstr);
405 pos += 2;
408 done:
409 de_dbg_indent_restore(c, saved_indent_level);
412 static void reverse_bit_order(u8 *m, i64 m_len)
414 i64 k;
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;
427 i64 nglyphs;
428 i64 k;
429 int saved_indent_level;
431 de_dbg_indent_save(c, &saved_indent_level);
432 de_dbg(c, "bitmap table at %"I64_FMT, pos);
433 de_dbg_indent(c, 1);
435 if(!read_and_check_format_field(c, d, te, pos)) goto done;
436 pos += 4;
437 d->bitmaps_fmt = te->fmt; // struct copy
439 nglyphs = dbuf_getu32x(c->infile, pos, te->fmt.is_le);
440 pos += 4;
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);
452 pos += 4;
453 if(c->debug_level>=2)
454 de_dbg2(c, "char[%d] glyph offset: %u", (int)k, d->chars[k].bitmap_offset);
457 for(k=0; k<4; k++) {
458 i64 bitmapsize;
459 int use_this_one;
461 bitmapsize = dbuf_getu32x(c->infile, pos, te->fmt.is_le);
462 pos += 4;
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?" *":"");
466 if(use_this_one) {
467 d->bitmaps_data_len = bitmapsize;
471 if(pos + d->bitmaps_data_len > te->offset+te->size) {
472 // error
473 d->bitmaps_data_len = 0;
474 goto done;
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");
480 goto done;
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);
490 done:
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)
498 switch(te->type) {
499 case TBLTYPE_PROPERTIES:
500 te->type_name = "properties";
501 te->handler_fn = handler_properties;
502 break;
503 case 0x2:
504 te->type_name = "accelerators";
505 break;
506 case TBLTYPE_METRICS:
507 te->type_name = "metrics";
508 te->handler_fn = handler_metrics;
509 break;
510 case TBLTYPE_BITMAPS:
511 te->type_name = "bitmaps";
512 te->handler_fn = handler_bitmaps;
513 break;
514 case 0x10:
515 te->type_name = "ink metrics";
516 break;
517 case TBLTYPE_BDF_ENCODINGS:
518 te->type_name = "BDF encodings";
519 te->handler_fn = handler_bdf_encodings;
520 break;
521 case 0x40:
522 te->type_name = "swidths";
523 break;
524 case 0x80:
525 te->type_name = "glyph names";
526 break;
527 case 0x100:
528 te->type_name = "BDF accelerators";
529 break;
530 default:
531 te->type_name = "?";
535 static int do_read_table_entry(deark *c, lctx *d, struct table_entry *te, i64 pos1)
537 int retval = 0;
538 i64 pos = 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);
547 pos += 4;
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) {
557 goto done;
560 retval = 1;
562 done:
563 return retval;
566 static void do_make_font_image(deark *c, lctx *d)
568 struct de_bitmap_font *font = NULL;
569 i64 k;
570 int max_full_width = 1;
571 int max_ascent = 0;
572 int max_descent = 0;
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];
594 int full_width;
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];
611 i64 bitmap_len;
613 if(ci->codepoint == DE_CODEPOINT_INVALID) continue;
614 ch->codepoint_nonunicode = ci->codepoint;
615 if(d->is_unicode) {
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];
635 else {
636 continue;
640 de_font_bitmap_font_to_image(c, font, NULL, 0);
642 done:
643 if(font) {
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)
653 i64 k;
654 struct table_entry *te;
656 for(k=0; k<d->table_count; k++) {
657 te = &d->tables[k];
658 if(te->type == tbltype) {
659 if(te->handler_fn) {
660 te->handler_fn(c, d, te);
662 return 1;
665 return 0;
668 static void de_run_pcf(deark *c, de_module_params *mparams)
670 lctx *d = NULL;
671 i64 pos;
672 i64 k;
673 int saved_indent_level;
675 de_dbg_indent_save(c, &saved_indent_level);
676 d = de_malloc(c, sizeof(lctx));
678 pos = 0;
679 de_dbg(c, "header at %d", (int)pos);
680 de_dbg_indent(c, 1);
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);
694 de_dbg_indent(c, 1);
695 if(!do_read_table_entry(c, d, &d->tables[k], pos)) goto done;
696 de_dbg_indent(c, -1);
697 pos += 16;
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")) {
705 d->is_unicode = 1;
707 else if(!de_strcmp(d->charset_registry, "ISO8859")) {
708 if(!de_strcmp(d->charset_encoding, "1")) {
709 d->is_unicode = 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");
719 goto done;
722 process_table_by_type(c, d, TBLTYPE_BDF_ENCODINGS);
724 if(!d->has_encodings_table) {
725 d->is_unicode = 0;
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");
734 goto done;
737 do_make_font_image(c, d);
739 done:
740 if(d) {
741 de_free(c, d->tables);
742 de_free(c, d->chars);
743 de_free(c, d->bitmaps_data);
744 de_free(c, d);
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))
752 return 100;
753 return 0;
756 void de_module_pcf(deark *c, struct deark_module_info *mi)
758 mi->id = "pcf";
759 mi->desc = "PCF font";
760 mi->run_fn = de_run_pcf;
761 mi->identify_fn = de_identify_pcf;