1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // GRASP GL animation format
8 #include <deark-config.h>
9 #include <deark-private.h>
10 DE_DECLARE_MODULE(de_module_graspgl
);
11 DE_DECLARE_MODULE(de_module_graspfont
);
13 typedef struct localctx_struct
{
14 de_encoding input_encoding
;
21 // Returns 0 if there are no more files.
22 static int do_extract_file(deark
*c
, lctx
*d
, i64 fnum
)
29 de_ucstring
*fname
= NULL
;
30 int saved_indent_level
;
34 de_dbg_indent_save(c
, &saved_indent_level
);
35 index_entry_pos
= d
->index_pos
+17*fnum
;
36 data_block_pos
= dbuf_getu32x(c
->infile
, index_entry_pos
, d
->is_le
);
38 // The last "file" is usually not a file, but a "NULL terminator" with an
39 // offset of 0. Not very useful, since we already know how long the list is.
40 if(data_block_pos
==0) {
41 de_dbg(c
, "end-of-file-list marker found");
45 de_dbg(c
, "file #%d", (int)fnum
);
47 de_dbg(c
, "index entry pos: %"I64_FMT
, index_entry_pos
);
48 de_dbg(c
, "data block pos: %"I64_FMT
, data_block_pos
);
50 if(data_block_pos
< d
->index_size
) {
55 if(de_getbyte(index_entry_pos
+4)==0x00) {
56 need_errmsg
= 1; // missing file name?
60 fi
= de_finfo_create(c
);
61 fname
= ucstring_create(c
);
63 // Filenames are 13 bytes, NUL-padded.
64 dbuf_read_to_ucstring(c
->infile
, index_entry_pos
+4, 13, fname
, DE_CONVFLAG_STOP_AT_NUL
,
66 de_finfo_set_name_from_ucstring(c
, fi
, fname
, 0);
67 fi
->original_filename_flag
= 1;
68 de_dbg(c
, "file name: \"%s\"", ucstring_getpsz_d(fname
));
70 dlen
= dbuf_getu32x(c
->infile
, data_block_pos
, d
->is_le
);
71 dpos
= data_block_pos
+4;
72 de_dbg(c
, "file data at %"I64_FMT
", len=%"I64_FMT
, dpos
, dlen
);
73 if(dpos
+dlen
> c
->infile
->len
) {
78 dbuf_create_file_from_slice(c
->infile
, dpos
, dlen
, NULL
, fi
, 0);
83 de_err(c
, "Bad file entry (#%d)", (int)fnum
);
85 de_finfo_destroy(c
, fi
);
86 ucstring_destroy(fname
);
87 de_dbg_indent_restore(c
, saved_indent_level
);
91 static void de_run_graspgl(deark
*c
, de_module_params
*mparams
)
98 d
= de_malloc(c
, sizeof(lctx
));
100 if((UI
)de_getu32be(0)==0x41470100U
) {
101 // Ref: Aminet : gl2p1.lzh
106 de_declare_fmt(c
, "Amiga GRASP GL");
110 de_declare_fmt(c
, "GRASP GL");
114 d
->input_encoding
= de_get_input_encoding(c
, NULL
,
115 (d
->is_amiga
? DE_ENCODING_LATIN1
: DE_ENCODING_CP437
));
117 d
->index_size
= dbuf_getu16x(c
->infile
, pos
, d
->is_le
);
121 de_dbg(c
, "index size: %"I64_FMT
, d
->index_size
);
123 // 17 bytes per file entry
124 num_files
= (d
->index_size
+16)/17;
125 de_dbg(c
, "max number of files: %d", (int)num_files
);
127 for(i
=0; i
<num_files
; i
++) {
128 if(!do_extract_file(c
, d
, i
))
135 static int de_identify_graspgl(deark
*c
)
143 index_size
= de_getu16le(0);
144 if(index_size
==0x4741) {
145 if((UI
)de_getu16be(2)==0x0100U
) {
146 is_le
= 0; // Amiga GL?
147 index_size
= de_getu16be(4);
151 // Header should be a nonzero multiple of 17 bytes.
152 if(index_size
==0 || (index_size
%17 != 0)) return 0;
153 index_pos
= is_le
? 2 : 6;
154 if(index_pos
+index_size
>c
->infile
->len
) return 0;
156 gl_ext
= de_input_file_has_ext(c
, "gl");
158 // Most likely, the first embedded file immediately follows
159 // the header. If so, it's pretty good evidence this is a
161 first_offset
= dbuf_getu32x(c
->infile
, index_pos
, is_le
);
163 if(first_offset
>c
->infile
->len
|| first_offset
<index_pos
+index_size
) return 0;
164 if(first_offset
== index_pos
+index_size
)
165 return gl_ext
? 100 : 70;
172 void de_module_graspgl(deark
*c
, struct deark_module_info
*mi
)
175 mi
->desc
= "GRASP GL animation";
176 mi
->run_fn
= de_run_graspgl
;
177 mi
->identify_fn
= de_identify_graspgl
;
180 // **************************************************************************
181 // GRASP font (.set/.fnt)
182 // **************************************************************************
184 static void de_run_graspfont_oldfmt(deark
*c
)
186 i64 reported_filesize
;
188 struct de_bitmap_font
*font
= NULL
;
192 u8
*font_data
= NULL
;
194 struct de_encconv_state es
;
196 font
= de_create_bitmap_font(c
);
198 reported_filesize
= de_getu16le(0);
199 de_dbg(c
, "reported file size: %d", (int)reported_filesize
);
201 font
->has_nonunicode_codepoints
= 1;
202 font
->has_unicode_codepoints
= 1;
203 font
->num_chars
= (i64
)de_getbyte(2);
204 if(font
->num_chars
==0) font
->num_chars
=256;
205 first_codepoint
= (i32
)de_getbyte(3);
206 font
->nominal_width
= (int)de_getbyte(4);
207 font
->nominal_height
= (int)de_getbyte(5);
208 bytes_per_glyph
= (i64
)de_getbyte(6);
210 de_dbg(c
, "number of glyphs: %d, first codepoint: %d", (int)font
->num_chars
, (int)first_codepoint
);
211 de_dbg(c
, "glyph dimensions: %d"DE_CHAR_TIMES
"%d, size in bytes: %d", font
->nominal_width
,
212 font
->nominal_height
, (int)bytes_per_glyph
);
214 glyph_rowspan
= (font
->nominal_width
+7)/8;
215 if(bytes_per_glyph
< glyph_rowspan
*font
->nominal_height
||
216 font
->nominal_width
<1 || font
->nominal_height
<1)
218 de_err(c
, "Bad font metrics");
222 font
->char_array
= de_mallocarray(c
, font
->num_chars
, sizeof(struct de_bitmap_font_char
));
223 font_data_size
= bytes_per_glyph
* font
->num_chars
;
224 font_data
= de_malloc(c
, font_data_size
);
226 // There's no way to tell what encoding a GRASP font uses, but CP437 is
227 // a reasonable guess.
228 de_encconv_init(&es
, DE_ENCODING_CP437_G
);
230 de_read(font_data
, 7, font_data_size
);
232 for(i
=0; i
<font
->num_chars
; i
++) {
233 font
->char_array
[i
].width
= font
->nominal_width
;
234 font
->char_array
[i
].height
= font
->nominal_height
;
235 font
->char_array
[i
].rowspan
= glyph_rowspan
;
237 font
->char_array
[i
].codepoint_nonunicode
= first_codepoint
+ (i32
)i
;
239 font
->char_array
[i
].codepoint_unicode
=
240 de_char_to_unicode_ex(first_codepoint
+ (i32
)i
, &es
);
242 font
->char_array
[i
].bitmap
= &font_data
[i
*bytes_per_glyph
];
245 de_font_bitmap_font_to_image(c
, font
, NULL
, 0);
249 if(font
->char_array
) {
250 de_free(c
, font
->char_array
);
252 de_destroy_bitmap_font(c
, font
);
254 de_free(c
, font_data
);
257 // Caution: This code is not based on any official specifications.
258 static void de_run_graspfont_newfmt(deark
*c
)
260 struct de_bitmap_font
*font
= NULL
;
261 de_ucstring
*fontname
= NULL
;
263 i64 glyph_offsets_table_pos
;
264 i64 widths_table_pos
;
267 int ch_max_width
= 0;
269 de_dbg(c
, "header at %d", 0);
272 font
= de_create_bitmap_font(c
);
273 font
->has_nonunicode_codepoints
= 1;
275 fontname
= ucstring_create(c
);
276 dbuf_read_to_ucstring(c
->infile
, 1, 13, fontname
, DE_CONVFLAG_STOP_AT_NUL
, DE_ENCODING_ASCII
);
277 de_dbg(c
, "name: \"%s\"", ucstring_getpsz(fontname
));
279 font
->num_chars
= (i64
)de_getbyte(16);
280 de_dbg(c
, "number of glyphs: %d", (int)font
->num_chars
);
282 tmp_width
= (int)de_getbyte(19);
283 de_dbg(c
, "font width: %d", tmp_width
);
284 font
->nominal_height
= (int)de_getbyte(20);
285 de_dbg(c
, "font height: %d", font
->nominal_height
);
287 glyph_rowspan
= (i64
)de_getbyte(21);
289 de_dbg_indent(c
, -1);
291 glyph_offsets_table_pos
= 59;
292 widths_table_pos
= glyph_offsets_table_pos
+2*font
->num_chars
;
293 if(widths_table_pos
<249)
294 widths_table_pos
= 249;
295 de_dbg(c
, "glyph offsets table at %d, width table at %d", (int)glyph_offsets_table_pos
,
296 (int)widths_table_pos
);
299 font
->char_array
= de_mallocarray(c
, font
->num_chars
, sizeof(struct de_bitmap_font_char
));
301 for(k
=0; k
<font
->num_chars
; k
++) {
304 struct de_bitmap_font_char
*ch
= &font
->char_array
[k
];
306 ch
->codepoint_nonunicode
= (i32
)(33 + k
);
308 ch_offset
= de_getu16le(glyph_offsets_table_pos
+ 2 + 2*k
);
310 ch
->width
= (int)de_getbyte(widths_table_pos
+ 1 + k
);
311 de_dbg2(c
, "ch[%d]: codepoint=%d, width=%d, glyph_offs=%d", (int)k
,
312 (int)ch
->codepoint_nonunicode
,
313 (int)ch
->width
, (int)ch_offset
);
315 if(ch
->width
<1) continue;
317 if(ch
->width
> ch_max_width
) ch_max_width
= ch
->width
;
318 ch
->height
= font
->nominal_height
;
319 ch
->rowspan
= glyph_rowspan
;
320 bitmapsize
= ch
->rowspan
* ch
->height
;
321 ch
->bitmap
= de_malloc(c
, bitmapsize
);
322 de_read(ch
->bitmap
, ch_offset
, bitmapsize
);
325 de_dbg_indent(c
, -1);
327 de_dbg(c
, "calculated maximum width: %d", (int)ch_max_width
);
328 font
->nominal_width
= ch_max_width
;
330 de_font_bitmap_font_to_image(c
, font
, NULL
, 0);
333 if(font
->char_array
) {
334 for(k
=0; k
<font
->num_chars
; k
++) {
335 de_free(c
, font
->char_array
[k
].bitmap
);
337 de_free(c
, font
->char_array
);
339 de_destroy_bitmap_font(c
, font
);
342 ucstring_destroy(fontname
);
345 static int gfont_is_new_format(deark
*c
)
347 i64 reported_filesize
;
349 if(de_getbyte(0)==0x10) {
350 reported_filesize
= de_getu16le(25);
351 if(reported_filesize
== c
->infile
->len
) {
358 static void de_run_graspfont(deark
*c
, de_module_params
*mparams
)
360 if(gfont_is_new_format(c
)) {
361 de_declare_fmt(c
, "GRASP font (new)");
362 de_run_graspfont_newfmt(c
);
365 de_declare_fmt(c
, "GRASP font (old)");
366 de_run_graspfont_oldfmt(c
);
370 static int de_identify_graspfont(deark
*c
)
372 i64 reported_filesize
;
376 if(!de_input_file_has_ext(c
, "set") && !de_input_file_has_ext(c
, "fnt"))
379 if(gfont_is_new_format(c
)) {
383 reported_filesize
= de_getu16le(0);
384 if(reported_filesize
!= c
->infile
->len
) return 0;
385 num_chars
= (i64
)de_getbyte(2);
386 if(num_chars
==0) num_chars
=256;
387 bytes_per_glyph
= (i64
)de_getbyte(6);
388 if(7+num_chars
*bytes_per_glyph
== reported_filesize
)
393 void de_module_graspfont(deark
*c
, struct deark_module_info
*mi
)
395 mi
->id
= "graspfont";
396 mi
->desc
= "GRASP font";
397 mi
->run_fn
= de_run_graspfont
;
398 mi
->identify_fn
= de_identify_graspfont
;