1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
7 #include <deark-config.h>
8 #include <deark-private.h>
9 #include <deark-fmtutil.h>
10 DE_DECLARE_MODULE(de_module_pff2
);
12 typedef struct localctx_struct
{
13 struct de_bitmap_font
*font
;
17 #define CODE_ASCE 0x41534345U
18 #define CODE_CHIX 0x43484958U
19 #define CODE_DATA 0x44415441U
20 #define CODE_DESC 0x44455343U
21 #define CODE_FAMI 0x46414d49U
22 #define CODE_FILE 0x46494c45U
23 #define CODE_MAXH 0x4d415848U
24 #define CODE_MAXW 0x4d415857U
25 #define CODE_NAME 0x4e414d45U
26 #define CODE_PTSZ 0x5054535aU
27 #define CODE_SLAN 0x534c414eU
28 #define CODE_WEIG 0x57454947U
30 struct pff2_sectiontype_info
;
32 typedef void (*pff2_section_handler_fn
)(deark
*c
, lctx
*d
,
33 const struct pff2_sectiontype_info
*si
, i64 pos
, i64 len
);
35 struct pff2_sectiontype_info
{
37 // 0x1=ASCII, 0x2=uint16be
40 pff2_section_handler_fn hfn
;
43 static void do_char(deark
*c
, lctx
*d
, i64 char_idx
, i32 codepoint
, i64 pos
)
45 struct de_bitmap_font_char
*ch
;
51 ch
= &d
->font
->char_array
[char_idx
];
53 ch
->codepoint_unicode
= codepoint
;
55 ch
->width
= (int)de_getu16be(pos
);
56 ch
->height
= (int)de_getu16be(pos
+2);
57 if(ch
->width
> d
->font
->nominal_width
) d
->font
->nominal_width
= ch
->width
;
58 if(ch
->height
> d
->font
->nominal_height
) d
->font
->nominal_height
= ch
->height
;
61 de_dbg2(c
, "%d"DE_CHAR_TIMES
"%d, bitmap at %d", (int)ch
->width
, (int)ch
->height
, (int)bitmap_pos
);
62 ch
->rowspan
= (ch
->width
+7)/8;
64 srcbitmapsize
= (ch
->width
* ch
->height
+ 7)/8;
65 srcbitmap
= de_malloc(c
, srcbitmapsize
);
66 de_read(srcbitmap
, bitmap_pos
, srcbitmapsize
);
68 ch
->bitmap
= de_malloc(c
, ch
->rowspan
* ch
->height
);
69 for(j
=0; j
<ch
->height
; j
++) {
70 // The source bitmap's rows are not byte aligned (except the first row).
71 de_copy_bits(srcbitmap
, j
*ch
->width
, ch
->bitmap
, j
*ch
->rowspan
*8, ch
->width
);
74 de_free(c
, srcbitmap
);
77 static void do_code_chix(deark
*c
, lctx
*d
, const struct pff2_sectiontype_info
*si
,
84 unsigned int storage_flags
;
86 if(d
->found_CHIX_chunk
) goto done
;
87 d
->found_CHIX_chunk
= 1;
89 d
->font
->num_chars
= len
/9;
90 de_dbg(c
, "number of characters: %d", (int)d
->font
->num_chars
);
92 d
->font
->char_array
= de_mallocarray(c
, d
->font
->num_chars
, sizeof(struct de_bitmap_font_char
));
94 for(i
=0; i
<d
->font
->num_chars
; i
++) {
96 codepoint
= (i32
)de_getu32be(pos
);
97 storage_flags
= (unsigned int)de_getbyte(pos
+4);
98 defpos
= de_getu32be(pos
+5);
99 de_dbg2(c
, "code point U+%04X, index at %d, definition at %d",
100 (unsigned int)codepoint
, (int)pos
, (int)defpos
);
101 if((storage_flags
&0x07)!=0) {
102 de_err(c
, "Compressed PFF2 format is not supported");
106 do_char(c
, d
, i
, codepoint
, defpos
);
107 de_dbg_indent(c
, -1);
110 de_font_bitmap_font_to_image(c
, d
->font
, NULL
, 0);
115 static const struct pff2_sectiontype_info pff2_sectiontype_info_arr
[] = {
116 { CODE_ASCE
, 0x00000002, "ascent, in pixels", NULL
},
117 { CODE_CHIX
, 0x00000000, "character index", do_code_chix
},
118 { CODE_DATA
, 0x00000000, "character data", NULL
},
119 { CODE_DESC
, 0x00000002, "descent, in pixels", NULL
},
120 { CODE_FAMI
, 0x00000001, "font family name", NULL
},
121 { CODE_FILE
, 0x00000001, "file type ID", NULL
},
122 { CODE_MAXH
, 0x00000002, "max char height, in pixels", NULL
},
123 { CODE_MAXW
, 0x00000002, "max char width, in pixels", NULL
},
124 { CODE_NAME
, 0x00000001, "font name", NULL
},
125 { CODE_PTSZ
, 0x00000002, "font point size", NULL
},
126 { CODE_SLAN
, 0x00000001, "font slant", NULL
},
127 { CODE_WEIG
, 0x00000001, "font weight", NULL
}
130 static const struct pff2_sectiontype_info
*find_pffs_sectiontype_info(u32 id
)
134 for(i
=0; i
<DE_ARRAYCOUNT(pff2_sectiontype_info_arr
); i
++) {
135 if(pff2_sectiontype_info_arr
[i
].id
== id
) {
136 return &pff2_sectiontype_info_arr
[i
];
142 static int my_pff2_chunk_handler(struct de_iffctx
*ictx
)
145 lctx
*d
= (lctx
*)ictx
->userdata
;
146 const struct pff2_sectiontype_info
*si
;
148 si
= find_pffs_sectiontype_info(ictx
->chunkctx
->chunk4cc
.id
);
152 // Default value decoders:
155 str
= ucstring_create(c
);
156 dbuf_read_to_ucstring_n(ictx
->f
,
157 ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
,
158 DE_DBG_MAX_STRLEN
, str
, 0, DE_ENCODING_ASCII
);
159 de_dbg(c
, "value: \"%s\"", ucstring_getpsz_d(str
));
160 ucstring_destroy(str
);
162 else if(si
->flags
&0x2) {
164 n
= dbuf_getu16be(ictx
->f
, ictx
->chunkctx
->dpos
);
165 de_dbg(c
, "value: %d", (int)n
);
169 si
->hfn(c
, d
, si
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
176 static int my_preprocess_pff2_chunk_fn(struct de_iffctx
*ictx
)
178 const struct pff2_sectiontype_info
*si
;
180 si
= find_pffs_sectiontype_info(ictx
->chunkctx
->chunk4cc
.id
);
182 ictx
->chunkctx
->chunk_name
= si
->name
;
185 if(ictx
->chunkctx
->dlen
==0xffffffffU
) {
186 // The 'DATA' chunk's length is usually set to the special value 0xffffffff.
187 // We are allowed to adjust ictx->chunkctx->dlen here.
188 ictx
->chunkctx
->dlen
= ictx
->f
->len
- ictx
->chunkctx
->dpos
;
193 static void de_run_pff2(deark
*c
, de_module_params
*mparams
)
196 struct de_iffctx
*ictx
= NULL
;
199 d
= de_malloc(c
, sizeof(lctx
));
200 ictx
= fmtutil_create_iff_decoder(c
);
202 ictx
->userdata
= (void*)d
;
204 ictx
->preprocess_chunk_fn
= my_preprocess_pff2_chunk_fn
;
205 ictx
->handle_chunk_fn
= my_pff2_chunk_handler
;
208 d
->font
= de_create_bitmap_font(c
);
209 d
->font
->has_nonunicode_codepoints
= 0;
210 d
->font
->has_unicode_codepoints
= 1;
211 d
->font
->prefer_unicode
= 1;
213 fmtutil_read_iff_format(ictx
, 0, c
->infile
->len
);
216 if(d
->font
->char_array
) {
217 for(i
=0; i
<d
->font
->num_chars
; i
++) {
218 de_free(c
, d
->font
->char_array
[i
].bitmap
);
220 de_free(c
, d
->font
->char_array
);
222 de_destroy_bitmap_font(c
, d
->font
);
225 fmtutil_destroy_iff_decoder(ictx
);
229 static int de_identify_pff2(deark
*c
)
231 if(!dbuf_memcmp(c
->infile
, 0, "FILE\x00\x00\x00\x04PFF2", 12))
236 void de_module_pff2(deark
*c
, struct deark_module_info
*mi
)
239 mi
->desc
= "PFF2 font";
240 mi
->run_fn
= de_run_pff2
;
241 mi
->identify_fn
= de_identify_pff2
;