1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 #include <deark-config.h>
6 #include <deark-private.h>
7 DE_DECLARE_MODULE(de_module_tivariable
);
9 typedef struct localctx_struct
{
14 typedef void (*ti_decoder_fn
)(deark
*c
, lctx
*d
);
16 static void do_ti83(deark
*c
, lctx
*d
);
17 static void do_ti85(deark
*c
, lctx
*d
);
18 static void do_ti92(deark
*c
, lctx
*d
);
22 const char *description
;
23 ti_decoder_fn decoder_fn
;
25 // The format IDs are the indices of the items in this array.
26 static const struct ti_ver_info ti_ver_info_arr
[] = {
27 #define DE_FMT_NOT_TI 0
29 #define DE_FMT_UNKNOWN_TI 1
32 { "**TI73**", "TI73 variable file", do_ti83
},
34 { "**TI82**", "TI82 variable file", do_ti83
},
36 { "**TI83**", "TI83 variable file", do_ti83
},
37 #define DE_FMT_TI83F 5
38 { "**TI83F*", "TI83F variable file", do_ti83
},
40 { "**TI85**", "TI85 variable file", do_ti85
},
42 { "**TI86**", "TI86 variable file", do_ti85
},
44 { "**TI89**", "TI89 variable file", do_ti92
},
46 { "**TI92**", "TI92 variable file", do_ti92
},
47 #define DE_FMT_TI92P 10
48 { "**TI92P*", "TI92P variable file", do_ti92
}
49 #define DE_FMT_COUNT 11
52 static int identify_internal(deark
*c
)
59 if(de_memcmp(buf
, "**TI", 4)) return DE_FMT_NOT_TI
;
61 for(i
=2; i
<DE_FMT_COUNT
; i
++) {
62 if(!de_memcmp(buf
, ti_ver_info_arr
[i
].sig
, 8)) {
66 return DE_FMT_UNKNOWN_TI
;
69 static int do_bitmap(deark
*c
, lctx
*d
, i64 pos
)
74 de_dbg_dimensions(c
, d
->w
, d
->h
);
77 if(pos
+rowspan
*d
->h
> c
->infile
->len
) {
78 de_err(c
, "Unexpected end of file");
82 de_convert_and_write_image_bilevel(c
->infile
, pos
, d
->w
, d
->h
, rowspan
,
83 DE_CVTF_WHITEISZERO
, NULL
, 0);
89 static int do_bitmap_8ca(deark
*c
, lctx
*d
, i64 pos
)
91 de_bitmap
*img
= NULL
;
99 de_dbg_dimensions(c
, d
->w
, d
->h
);
101 rowspan
= (((d
->w
* 16)+31)/32)*4; // Uses 4-byte alignment, apparently
103 if(pos
+rowspan
*d
->h
> c
->infile
->len
) {
104 de_err(c
, "Unexpected end of file");
107 if(!de_good_image_dimensions(c
, d
->w
, d
->h
)) goto done
;
109 img
= de_bitmap_create(c
, d
->w
, d
->h
, 3);
111 for(j
=0; j
<d
->h
; j
++) {
112 for(i
=0; i
<d
->w
; i
++) {
113 b0
= de_getbyte(pos
+ j
*rowspan
+ i
*2);
114 b1
= de_getbyte(pos
+ j
*rowspan
+ i
*2 + 1);
115 clr
= (((u32
)b1
)<<8) | b0
;
116 clr
= de_rgb565_to_888(clr
);
117 de_bitmap_setpixel_rgb(img
, i
, j
, clr
);
122 de_bitmap_write_to_file(img
, NULL
, DE_CREATEFLAG_FLIP_IMAGE
);
125 de_bitmap_destroy(img
);
129 static int do_bitmap_8ci(deark
*c
, lctx
*d
, i64 pos
)
131 de_bitmap
*img
= NULL
;
138 de_dbg_dimensions(c
, d
->w
, d
->h
);
140 rowspan
= (d
->w
+ 1) / 2;
142 if(pos
+rowspan
*d
->h
> c
->infile
->len
) {
143 de_err(c
, "Unexpected end of file");
146 if(!de_good_image_dimensions(c
, d
->w
, d
->h
)) goto done
;
148 // This a 4 bits/pixel format, but I don't even know if it's grayscale or color.
149 img
= de_bitmap_create(c
, d
->w
, d
->h
, 1);
151 for(j
=0; j
<d
->h
; j
++) {
152 for(i
=0; i
<d
->w
; i
++) {
153 b0
= de_getbyte(pos
+ j
*rowspan
+ i
/2);
159 de_bitmap_setpixel_gray(img
, i
, j
, b0
* 17);
164 de_bitmap_write_to_file(img
, NULL
, 0);
167 de_bitmap_destroy(img
);
171 static int do_ti83_picture_var(deark
*c
, lctx
*d
, i64 pos
)
175 de_dbg(c
, "picture at %d", (int)pos
);
176 picture_size
= de_getu16le(pos
);
177 de_dbg(c
, "picture size: %d", (int)picture_size
);
179 if(picture_size
==21945) {
182 return do_bitmap_8ci(c
, d
, pos
+2);
187 return do_bitmap(c
, d
, pos
+2);
190 static int do_ti83c_picture_var(deark
*c
, lctx
*d
, i64 pos
)
192 // Try to support a type of color image (.8ca).
193 // This code may not be correct.
194 de_dbg(c
, "picture at %d", (int)pos
);
197 return do_bitmap_8ca(c
, d
, pos
+3);
200 static int do_ti85_picture_var(deark
*c
, lctx
*d
, i64 pos
)
204 de_dbg(c
, "picture at %d", (int)pos
);
205 x
= de_getu16le(pos
);
206 de_dbg(c
, "picture size: %d", (int)x
);
209 return do_bitmap(c
, d
, pos
+2);
212 static int do_ti92_picture_var(deark
*c
, lctx
*d
, i64 pos
)
216 de_dbg(c
, "picture at %d", (int)pos
);
219 x
= de_getu16be(pos
);
220 de_dbg(c
, "picture size: %d", (int)x
);
221 d
->h
= de_getu16be(pos
+2);
222 d
->w
= de_getu16be(pos
+4);
223 return do_bitmap(c
, d
, pos
+6);
226 static void do_ti92_var_table_entry(deark
*c
, lctx
*d
, i64 pos
)
231 de_dbg(c
, "var table entry at %d", (int)pos
);
232 data_offset
= de_getu32le(pos
);
234 type_id
= de_getbyte(pos
+12);
235 de_dbg(c
, "var type: 0x%02x", (unsigned int)type_id
);
240 de_dbg(c
, "data offset: %d", (int)data_offset
);
241 do_ti92_picture_var(c
, d
, data_offset
);
244 static void do_ti83(deark
*c
, lctx
*d
)
247 i64 data_section_size
;
248 i64 data_section_end
;
253 // 8-10: 0x1a 0x0a 0x00
256 data_section_size
= de_getu16le(53);
257 de_dbg(c
, "data section size: %d", (int)data_section_size
);
258 data_section_end
= 55+data_section_size
;
259 if(data_section_end
> c
->infile
->len
) {
260 de_err(c
, "Data section goes beyond end of file");
264 // Read the variables
266 while(pos
< data_section_end
) {
267 var_data_size
= de_getu16le(pos
+2);
268 type_id
= de_getbyte(pos
+4);
270 if(d
->fmt
==DE_FMT_TI83F
)
272 de_dbg(c
, "var type=0x%02x pos=%d len=%d", (unsigned int)type_id
,
273 (int)pos
, (int)var_data_size
);
275 if(type_id
==0x07) { // guess
276 do_ti83_picture_var(c
, d
, pos
);
278 else if(type_id
==0x1a) {
279 do_ti83c_picture_var(c
, d
, pos
);
282 pos
+= var_data_size
;
289 static void do_ti85(deark
*c
, lctx
*d
)
292 i64 data_section_size
;
293 i64 data_section_end
;
295 i64 name_len_reported
;
302 // 8-10: 0x1a 0x0a 0x00
305 data_section_size
= de_getu16le(53);
306 de_dbg(c
, "data section size: %d", (int)data_section_size
);
307 data_section_end
= 55+data_section_size
;
308 if(data_section_end
> c
->infile
->len
) {
309 de_err(c
, "Data section goes beyond end of file");
313 // Read the variables
315 while(pos
< data_section_end
) {
316 if(data_section_end
- pos
< 8) {
317 de_warn(c
, "Invalid variable entry size. This file may not have been processed correctly.");
321 var_data_size
= de_getu16le(pos
+2);
322 type_id
= de_getbyte(pos
+4);
323 name_len_reported
= (i64
)de_getbyte(pos
+5);
324 de_dbg(c
, "reported var name length: %d", (int)name_len_reported
);
325 if(d
->fmt
==DE_FMT_TI86
) {
326 name_field_len
= 8; // Initial default
328 // The TI86 name field length *should* always be 8, but some files do not
330 if(name_len_reported
!=8) {
331 // There are two "variable data length" fields that should contain the
332 // same value. Although this is bad design, we can exploit it to help
333 // guess the correct length of the variable name field.
335 x1
= de_getu16le(pos
+14);
336 x2
= de_getu16le(pos
+6+name_len_reported
);
337 if(x1
!=var_data_size
&& x2
==var_data_size
) {
339 de_warn(c
, "This TI86 file appears to use TI85 variable name format "
340 "instead of TI86 format. Trying to continue.");
343 name_field_len
= name_len_reported
;
349 name_field_len
= name_len_reported
;
352 pos
+= 6+name_field_len
;
354 x1
= de_getu16le(pos
);
355 if(x1
!=var_data_size
) {
356 de_warn(c
, "Inconsistent variable-data-length fields. "
357 "This file may not be processed correctly.");
361 de_dbg(c
, "var type=0x%02x pos=%d len=%d", (unsigned int)type_id
,
362 (int)pos
, (int)var_data_size
);
364 if(type_id
==0x11) { // guess
365 do_ti85_picture_var(c
, d
, pos
);
368 pos
+= var_data_size
;
375 static void do_ti92(deark
*c
, lctx
*d
)
384 // 10-17: default folder name
387 numvars
= de_getu16le(58);
388 de_dbg(c
, "number of variables/folders: %d", (int)numvars
);
389 if(!de_good_image_count(c
, numvars
)) goto done
;
392 for(i
=0; i
<numvars
; i
++) {
393 do_ti92_var_table_entry(c
, d
, pos
);
398 x
= de_getu32le(pos
);
399 de_dbg(c
, "reported file size: %d", (int)x
);
405 static void de_run_tivariable(deark
*c
, de_module_params
*mparams
)
409 d
= de_malloc(c
, sizeof(lctx
));
410 d
->fmt
= identify_internal(c
);
412 if(!ti_ver_info_arr
[d
->fmt
].decoder_fn
) {
413 de_err(c
, "Unknown or unsupported TI variable file version");
417 de_declare_fmt(c
, ti_ver_info_arr
[d
->fmt
].description
);
418 ti_ver_info_arr
[d
->fmt
].decoder_fn(c
, d
);
424 static int de_identify_tivariable(deark
*c
)
427 fmt
= identify_internal(c
);
428 if(fmt
==DE_FMT_NOT_TI
) return 0;
429 if(fmt
==DE_FMT_UNKNOWN_TI
) return 10;
433 void de_module_tivariable(deark
*c
, struct deark_module_info
*mi
)
435 mi
->id
= "tivariable";
436 mi
->desc
= "TI calculator variable or picture file";
437 mi
->run_fn
= de_run_tivariable
;
438 mi
->identify_fn
= de_identify_tivariable
;