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 DE_DECLARE_MODULE(de_module_gemfont
);
11 typedef struct localctx_struct
{
12 struct de_bitmap_font
*font
;
14 i64 first_index
, last_index
;
15 i64 max_char_cell_width
;
16 i64 char_offset_table_pos
;
19 i64 form_height_pixels
;
24 static int do_characters(deark
*c
, lctx
*d
)
29 struct de_bitmap_font_char
*ch
;
35 de_dbg(c
, "reading characters");
38 form_nbytes
= d
->form_width_bytes
* d
->form_height_pixels
;
39 if(d
->font_data_pos
+ form_nbytes
> c
->infile
->len
) {
40 de_err(c
, "Font data goes beyond end of file");
43 font_data
= de_malloc(c
, form_nbytes
);
44 de_read(font_data
, d
->font_data_pos
, form_nbytes
);
46 for(i
=0; i
<d
->font
->num_chars
; i
++) {
47 ch
= &d
->font
->char_array
[i
];
48 char_startpos
= de_getu16le(d
->char_offset_table_pos
+ 2*i
);
49 n
= de_getu16le(d
->char_offset_table_pos
+ 2*(i
+1));
50 ch
->width
= (int)(n
- char_startpos
);
51 ch
->height
= d
->font
->nominal_height
;
52 ch
->codepoint_nonunicode
= (i32
)(d
->first_index
+i
);
53 de_dbg2(c
, "char[%d] #%d offset=%d width=%d", (int)i
, (int)ch
->codepoint_nonunicode
,
54 (int)char_startpos
, ch
->width
);
55 if(ch
->width
<1 || ch
->width
>d
->max_char_cell_width
|| ch
->width
>512) continue;
57 ch
->rowspan
= (ch
->width
+7)/8;
58 ch
->bitmap
= de_malloc(c
, ch
->height
* ch
->rowspan
);
60 for(row
=0; row
<ch
->height
; row
++) {
61 de_copy_bits(font_data
+ row
*d
->form_width_bytes
, char_startpos
,
62 ch
->bitmap
+ row
*ch
->rowspan
, 0, (i64
)ch
->width
);
65 if(ch
->width
> d
->font
->nominal_width
) {
66 // Track the maximum character width.
67 d
->font
->nominal_width
= ch
->width
;
74 de_free(c
, font_data
);
78 static void do_face_name(deark
*c
, lctx
*d
)
80 de_ucstring
*name
= NULL
;
82 name
= ucstring_create(c
);
83 dbuf_read_to_ucstring(c
->infile
, 4, 32, name
, DE_CONVFLAG_STOP_AT_NUL
,
85 de_dbg(c
, "face name: \"%s\"", ucstring_getpsz_d(name
));
86 if(!c
->filenames_from_file
) goto done
;
88 ucstring_strip_trailing_spaces(name
);
89 ucstring_printf(name
, DE_ENCODING_LATIN1
, "-%d", (int)d
->face_size
);
90 d
->fi
= de_finfo_create(c
);
91 de_finfo_set_name_from_ucstring(c
, d
->fi
, name
, 0);
94 ucstring_destroy(name
);
97 static int do_header(deark
*c
, lctx
*d
)
99 unsigned int font_flags
;
103 de_dbg(c
, "header at %d", 0);
107 de_dbg(c
, "face ID: %d", (int)n
);
109 d
->face_size
= de_getu16le(2);
110 de_dbg(c
, "point size: %d", (int)d
->face_size
);
112 do_face_name(c
, d
); // Offset 4-35
114 d
->first_index
= de_getu16le(36);
115 d
->last_index
= de_getu16le(38);
116 de_dbg(c
, "first char: %d, last char: %d", (int)d
->first_index
, (int)d
->last_index
);
117 d
->font
->num_chars
= d
->last_index
- d
->first_index
+ 1;
119 max_char_width
= de_getu16le(50);
120 d
->max_char_cell_width
= de_getu16le(52);
121 de_dbg(c
, "max char width: %d, max char cell width: %d", (int)max_char_width
,
122 (int)d
->max_char_cell_width
);
125 de_dbg(c
, "left offset: %d", (int)n
);
127 de_dbg(c
, "right offset: %d", (int)n
);
130 de_dbg(c
, "lightening mask: 0x%04x", (unsigned int)n
);
132 font_flags
= (unsigned int)de_getu16le(66);
133 d
->byte_swap_flag
= (font_flags
& 0x04) ? 1 : 0;
135 de_dbg(c
, "byte swap flag: %d", (int)d
->byte_swap_flag
);
136 if(d
->byte_swap_flag
) {
137 de_warn(c
, "This font uses an unsupported byte-swap option, and might not be "
138 "decoded correctly.");
142 de_dbg(c
, "horiz. offset table offset: %u", (unsigned int)n
);
144 d
->char_offset_table_pos
= de_getu32le(72);
145 d
->font_data_pos
= de_getu32le(76);
146 de_dbg(c
, "char. offset table offset: %d", (int)d
->char_offset_table_pos
);
147 de_dbg(c
, "font data offset: %d", (int)d
->font_data_pos
);
149 d
->form_width_bytes
= de_getu16le(80);
150 d
->form_height_pixels
= de_getu16le(82);
151 de_dbg(c
, "form width: %d bytes", (int)d
->form_width_bytes
);
152 de_dbg(c
, "form height: %d pixels", (int)d
->form_height_pixels
);
154 de_dbg_indent(c
, -1);
158 static void de_run_gemfont(deark
*c
, de_module_params
*mparams
)
162 int saved_indent_level
;
164 de_dbg_indent_save(c
, &saved_indent_level
);
165 d
= de_malloc(c
, sizeof(lctx
));
166 d
->font
= de_create_bitmap_font(c
);
167 d
->font
->has_nonunicode_codepoints
= 1;
169 if(!do_header(c
, d
)) goto done
;
171 d
->font
->nominal_width
= 1; // This will be calculated later
172 d
->font
->nominal_height
= (int)d
->form_height_pixels
;
173 if(d
->font
->nominal_height
<1 || d
->font
->nominal_height
>512) goto done
;
175 if(d
->font
->num_chars
<1) goto done
;
176 d
->font
->char_array
= de_mallocarray(c
, d
->font
->num_chars
, sizeof(struct de_bitmap_font_char
));
178 if(!do_characters(c
, d
)) goto done
;
180 de_font_bitmap_font_to_image(c
, d
->font
, d
->fi
, 0);
183 de_dbg_indent_restore(c
, saved_indent_level
);
185 if(d
->font
->char_array
) {
186 for(i
=0; i
<d
->font
->num_chars
; i
++) {
187 de_free(c
, d
->font
->char_array
[i
].bitmap
);
189 de_free(c
, d
->font
->char_array
);
191 de_destroy_bitmap_font(c
, d
->font
);
193 de_finfo_destroy(c
, d
->fi
);
197 // This is a difficult format to reliably identify.
198 static int de_identify_gemfont(deark
*c
)
201 i64 fdoffs
, fwidth
, fheight
, eofd
;
203 if(!de_input_file_has_ext(c
, "fnt") &&
204 !de_input_file_has_ext(c
, "gft"))
209 has_usual_lm
= !dbuf_memcmp(c
->infile
, 62, "UUUU", 4);
210 fdoffs
= de_getu32le(76);
211 if(fdoffs
<88) return 0;
212 fwidth
= de_getu16le(80);
213 fheight
= de_getu16le(82);
214 if(fwidth
<1 || fheight
<1) return 0;
215 eofd
= fdoffs
+ fwidth
*fheight
; // end of font data
216 if(eofd
> c
->infile
->len
) return 0;
217 if(eofd
==c
->infile
->len
&& has_usual_lm
) return 100;
218 if(eofd
==c
->infile
->len
) return 70;
219 if(has_usual_lm
) return 25;
223 void de_module_gemfont(deark
*c
, struct deark_module_info
*mi
)
226 mi
->desc
= "GEM bitmap font";
227 mi
->run_fn
= de_run_gemfont
;
228 mi
->identify_fn
= de_identify_gemfont
;