bmp: Rewrote the RLE decompressor
[deark.git] / modules / pff2.c
blob490d2b6518bdbf23e41917fcffd24965230affde
1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // PFF2 font (.pf2)
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;
14 u8 found_CHIX_chunk;
15 } lctx;
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 {
36 u32 id;
37 // 0x1=ASCII, 0x2=uint16be
38 u32 flags;
39 const char *name;
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;
46 i64 bitmap_pos;
47 u8 *srcbitmap = NULL;
48 i64 srcbitmapsize;
49 i64 j;
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;
60 bitmap_pos = pos+10;
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,
78 i64 pos1, i64 len)
80 i64 i;
81 i64 pos;
82 i64 defpos;
83 i32 codepoint;
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++) {
95 pos = pos1 + 9*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");
103 goto done;
105 de_dbg_indent(c, 1);
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);
112 done: ;
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)
132 size_t i;
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];
139 return NULL;
142 static int my_pff2_chunk_handler(struct de_iffctx *ictx)
144 deark *c = ictx->c;
145 lctx *d = (lctx*)ictx->userdata;
146 const struct pff2_sectiontype_info *si;
148 si = find_pffs_sectiontype_info(ictx->chunkctx->chunk4cc.id);
149 if(!si) goto done;
150 ictx->handled = 1;
152 // Default value decoders:
153 if(si->flags&0x1) {
154 de_ucstring *str;
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) {
163 i64 n;
164 n = dbuf_getu16be(ictx->f, ictx->chunkctx->dpos);
165 de_dbg(c, "value: %d", (int)n);
168 if(si->hfn) {
169 si->hfn(c, d, si, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
172 done:
173 return 1;
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);
181 if(si) {
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;
190 return 1;
193 static void de_run_pff2(deark *c, de_module_params *mparams)
195 lctx *d = NULL;
196 struct de_iffctx *ictx = NULL;
197 i64 i;
199 d = de_malloc(c, sizeof(lctx));
200 ictx = fmtutil_create_iff_decoder(c);
202 ictx->userdata = (void*)d;
203 ictx->alignment = 1;
204 ictx->preprocess_chunk_fn = my_preprocess_pff2_chunk_fn;
205 ictx->handle_chunk_fn = my_pff2_chunk_handler;
206 ictx->f = c->infile;
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);
215 if(d->font) {
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);
226 de_free(c, d);
229 static int de_identify_pff2(deark *c)
231 if(!dbuf_memcmp(c->infile, 0, "FILE\x00\x00\x00\x04PFF2", 12))
232 return 100;
233 return 0;
236 void de_module_pff2(deark *c, struct deark_module_info *mi)
238 mi->id = "pff2";
239 mi->desc = "PFF2 font";
240 mi->run_fn = de_run_pff2;
241 mi->identify_fn = de_identify_pff2;