1 /* $Id$ */
2
3 /* libtifiles - file format library, a part of the TiLP project
4 * Copyright (C) 1999-2005 Romain Lievin
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /*
22 TI File Format handling routines
23 Calcs: 73/82/83/83+/84+/85/86
24 */
25
26 /*
27 Thanks to Adrian Mettler <amettler@hmc.edu> for his patch which fixes
28 some TI85/86 file issues (padded, not padded).
29 */
30
31 #include <glib/gstdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include <ticonv.h>
36 #include "tifiles.h"
37 #include "error.h"
38 #include "logging.h"
39 #include "typesxx.h"
40 #include "files8x.h"
41 #include "rwfile.h"
42 #include "intelhex.h"
43
44 #ifndef DISABLE_TI8X
45
46 /********/
47 /* Misc */
48 /********/
49
50 static uint8_t fsignature85[3] = { 0x1A, 0x0C, 0x00 }; //TI85
51 static uint8_t fsignature8x[3] = { 0x1A, 0x0A, 0x00 }; //TI73, 82, 83, 86
52
53
is_ti8586(CalcModel model)54 static int is_ti8586(CalcModel model)
55 {
56 return ((model == CALC_TI85) || (model == CALC_TI86));
57 }
58
is_ti83p(CalcModel model)59 static int is_ti83p(CalcModel model)
60 {
61 return ((model == CALC_TI83P) || (model == CALC_TI84P) || (model == CALC_TI84P_USB)
62 || (model == CALC_TI84PC) || (model == CALC_TI84PC_USB)
63 || (model == CALC_TI83PCE_USB) || (model == CALC_TI84PCE_USB) || (model == CALC_TI82A_USB) || (model == CALC_TI84PT_USB));
64 }
65
compute_backup_sum(BackupContent * content,uint16_t header_size)66 static uint16_t compute_backup_sum(BackupContent* content, uint16_t header_size)
67 {
68 uint16_t sum= 0;
69
70 sum += header_size;
71 sum += tifiles_checksum((uint8_t *)&(content->data_length1), 2);
72 sum += content->type;
73 if (header_size >= 12)
74 {
75 sum += content->version;
76 }
77 sum += tifiles_checksum((uint8_t *)&(content->data_length2), 2);
78 sum += tifiles_checksum((uint8_t *)&(content->data_length3), 2);
79 if (content->model != CALC_TI86)
80 {
81 sum += tifiles_checksum((uint8_t *)&(content->mem_address), 2);
82 }
83 else
84 {
85 sum += tifiles_checksum((uint8_t *)&(content->data_length4), 2);
86 }
87
88 sum += tifiles_checksum((uint8_t *)&(content->data_length1), 2);
89 sum += tifiles_checksum(content->data_part1, content->data_length1);
90 sum += tifiles_checksum((uint8_t *)&(content->data_length2), 2);
91 sum += tifiles_checksum(content->data_part2, content->data_length2);
92 sum += tifiles_checksum((uint8_t *)&(content->data_length3), 2);
93 sum += tifiles_checksum(content->data_part3, content->data_length3);
94 sum += tifiles_checksum((uint8_t *)&(content->data_length4), 2);
95 sum += tifiles_checksum(content->data_part4, content->data_length4);
96
97 return sum;
98 }
99
100 /***********/
101 /* Reading */
102 /***********/
103
104 /**
105 * ti8x_file_read_regular:
106 * @filename: name of single/group file to open.
107 * @content: where to store the file content.
108 *
109 * Load the single/group file into a Ti8xRegular structure.
110 *
111 * Structure content must be freed with #tifiles_content_delete_regular when
112 * no longer used. If error occurs, the structure content is released for you.
113 *
114 * Return value: an error code, 0 otherwise.
115 **/
ti8x_file_read_regular(const char * filename,Ti8xRegular * content)116 int ti8x_file_read_regular(const char *filename, Ti8xRegular *content)
117 {
118 FILE *f;
119 uint16_t tmp = 0x000B;
120 long offset = 0;
121 unsigned int i, j;
122 int ti83p_flag = 0;
123 uint8_t name_length = 8; // ti85/86 only
124 uint16_t data_size, sum = 0;
125 long cur_pos;
126 uint32_t file_size;
127 char signature[9];
128 int padded86 = 0;
129 char varname[VARNAME_MAX];
130 int ret = ERR_FILE_IO;
131
132 if (content == NULL)
133 {
134 tifiles_critical("%s: an argument is NULL", __FUNCTION__);
135 return ERR_INVALID_FILE;
136 }
137
138 if (!tifiles_file_is_regular(filename))
139 {
140 ret = ERR_INVALID_FILE;
141 goto tfrr2;
142 }
143
144 f = g_fopen(filename, "rb");
145 if (f == NULL)
146 {
147 tifiles_warning("Unable to open this file: %s", filename);
148 ret = ERR_FILE_OPEN;
149 goto tfrr2;
150 }
151
152 // Get file size, then rewind.
153 if (fseek(f, 0, SEEK_END) < 0) goto tfrr;
154 cur_pos = ftell(f);
155 if (cur_pos < 0) goto tfrr;
156 if (fseek(f, 0, SEEK_SET) < 0) goto tfrr;
157
158 // The TI-Z80 and TI-eZ80 series' members have at best 4 MB of Flash (TODO: modify this code if this no longer holds).
159 // Regular / group files larger than that size are highly dubious, files larger than twice that size are insane.
160 if (cur_pos >= (8L << 20))
161 {
162 ret = ERR_INVALID_FILE;
163 goto tfrr;
164 }
165 file_size = (uint32_t)cur_pos;
166
167 if (fread_8_chars(f, signature) < 0) goto tfrr; // Offset 0
168 content->model = tifiles_signature2calctype(signature);
169 if (content->model == CALC_NONE)
170 {
171 ret = ERR_INVALID_FILE;
172 goto tfrr;
173 }
174 if (content->model_dst == CALC_NONE)
175 {
176 content->model_dst = content->model;
177 }
178 if (fskip(f, 3) < 0) goto tfrr; // Offset 0x8
179 if (fread_n_chars(f, 42, content->comment) < 0) goto tfrr; // Offset 0xB
180 if (fread_word(f, &data_size) < 0) goto tfrr; // Offset 0x35
181 if ((uint32_t)data_size > file_size)
182 {
183 ret = ERR_INVALID_FILE;
184 goto tfrr;
185 }
186
187 // search for the number of entries by parsing the whole file
188 offset = ftell(f); // Offset 0x37
189 if (offset == -1L) goto tfrr;
190
191 for (i = 0;; i++)
192 {
193 long current_offset = ftell(f);
194 /* We are done finding entries once we reach the end of the data segment
195 * as defined in the header. This works better than magic numbers, as
196 * as there exist files in the wild with incorrect magic numbers that
197 * transmit correctly with TI's software and with this code.
198 * Adrian Mettler
199 */
200 if (current_offset == -1L) goto tfrr;
201 if (current_offset >= offset + data_size)
202 {
203 break;
204 }
205
206 if (fread_word(f, &tmp) < 0) goto tfrr; // Offset N, 0x37 for the first entry
207 if (tmp == 0x0D)
208 {
209 ti83p_flag = !0; // true TI83+ file (2 extra bytes)
210 }
211
212 if (content->model == CALC_TI85)
213 {
214 // length & name with no padding
215 if (fskip(f, 3) < 0) goto tfrr; // Offset N+2, 0x39 for the first entry
216 if (fread_byte(f, &name_length) < 0) goto tfrr; // Offset N+5, 0x3C for the first entry
217 if (name_length > 8)
218 {
219 ret = ERR_INVALID_FILE;
220 goto tfrr;
221 }
222 if (fskip(f, name_length) < 0) goto tfrr; // Offset N+6+name_length, 0x3D for the first entry
223 }
224 else if (content->model == CALC_TI86)
225 {
226 /* name may follow one of four conventions: padded with SPC bytes
227 * (most correct, generated by TI's software), padded with NULL bytes,
228 * unpadded (like TI85) or partially padded (garbaged).
229 * TI's software accepts all four, so we should too.
230 */
231 padded86 = tmp < 0x0C ? 0 : !0; // TI-85 style file
232
233 if (fskip(f, 3) < 0) goto tfrr; // Offset N+2, 0x39 for the first entry
234 if (fread_byte(f, &name_length) < 0) goto tfrr; // Offset N+5, 0x3C for the first entry
235 if (name_length > 8)
236 {
237 ret = ERR_INVALID_FILE;
238 goto tfrr;
239 }
240 if (fskip(f, name_length) < 0) goto tfrr; // Offset N+6+name_length, 0x3D for the first entry
241
242 if (padded86)
243 {
244 if (fskip(f, 8 - name_length) < 0) goto tfrr;
245 }
246 }
247 else if (ti83p_flag)
248 {
249 if (fskip(f, 13) < 0) goto tfrr; // Offset N+2, 0x39 for the first entry.
250 }
251 else
252 {
253 if (fskip(f, 11) < 0) goto tfrr; // Offset N+2, 0x39 for the first entry.
254 }
255 if (fread_word(f, &tmp) < 0) goto tfrr; // Offset depends on model.
256 if (fskip(f, tmp) < 0) goto tfrr;
257 }
258
259 if (fseek(f, offset, SEEK_SET) < 0) goto tfrr; // Offset 0x37
260
261 content->num_entries = i;
262 content->entries = g_malloc0((content->num_entries + 1) * sizeof(VarEntry*));
263 if (content->entries == NULL)
264 {
265 ret = ERR_MALLOC;
266 goto tfrr;
267 }
268
269 for (i = 0; i < content->num_entries; i++)
270 {
271 VarEntry *entry = content->entries[i] = g_malloc0(sizeof(VarEntry));
272 uint16_t packet_length, entry_size;
273
274 if (fread_word(f, &packet_length) < 0) goto tfrr; // Offset 0x37
275 if ((uint32_t)packet_length > file_size)
276 {
277 ret = ERR_INVALID_FILE;
278 goto tfrr;
279 }
280 if (fread_word(f, &entry_size) < 0) goto tfrr; // Offset 0x39
281 if ((uint32_t)entry_size > file_size)
282 {
283 ret = ERR_INVALID_FILE;
284 goto tfrr;
285 }
286 entry->size = entry_size;
287 if (fread_byte(f, &(entry->type)) < 0) goto tfrr; // Offset 0x3B
288 if (is_ti8586(content->model))
289 {
290 if (fread_byte(f, &name_length) < 0) goto tfrr; // Offset 0x3C
291 }
292 if (fread_n_chars(f, name_length, varname) < 0) goto tfrr; // Offset up to 0x44
293 ticonv_varname_from_tifile_sn(content->model_dst, varname, entry->name, sizeof(entry->name), entry->type);
294 if ((content->model == CALC_TI86) && padded86)
295 {
296 for (j = 0; j < 8U - name_length; j++)
297 {
298 sum += fgetc(f);
299 }
300 }
301 if (ti83p_flag)
302 {
303 uint16_t attribute;
304 if (fread_word(f, &attribute) < 0) goto tfrr; // Offset 0x44
305 // Handle both the files created by TI-Connect and the files created by
306 // some broken versions of libtifiles.
307 if (attribute == 0x80)
308 {
309 entry->attr = ATTRB_ARCHIVED;
310 entry->version = 0;
311 }
312 else
313 {
314 entry->attr = ((attribute & 0x8000) ? ATTRB_ARCHIVED : ATTRB_NONE);
315 entry->version = attribute & 0xff;
316 }
317
318 // Handle broken 84+CSE Pic files created by older versions of libtifiles.
319 if (entry->type == TI84p_PIC && entry->size == 0x55bb && entry->version == 0)
320 {
321 entry->version = 10;
322 }
323
324 sum += MSB(attribute);
325 sum += LSB(attribute);
326 }
327 if (fread_word(f, NULL) < 0) goto tfrr;
328
329 entry->data = (uint8_t *) g_malloc0(entry->size);
330 if (entry->data == NULL)
331 {
332 ret = ERR_MALLOC;
333 goto tfrr;
334 }
335
336 if (fread(entry->data, 1, entry->size, f) < entry->size) goto tfrr;
337
338 sum += packet_length;
339 sum += tifiles_checksum((uint8_t *)&(entry->size), 2);
340 sum += entry->type;
341 if (is_ti8586(content->model))
342 {
343 sum += strlen(entry->name);
344 }
345 sum += tifiles_checksum((uint8_t *)varname, name_length);
346 sum += 0; // see above (file may be padded with garbage)
347 sum += tifiles_checksum((uint8_t *)&(entry->size), 2);
348 sum += tifiles_checksum(entry->data, entry->size);
349 }
350
351 if (fread_word(f, &(content->checksum)) < 0) goto tfrr;
352 #if defined(CHECKSUM_ENABLED)
353 if (sum != content->checksum)
354 {
355 ret = ERR_FILE_CHECKSUM;
356 goto tfrr;
357 }
358 #endif
359
360 fclose(f);
361 return 0;
362
363 tfrr: // release on exit
364 tifiles_critical("%s: error reading / understanding file %s", __FUNCTION__, filename);
365 fclose(f);
366 tfrr2:
367 tifiles_content_delete_regular(content);
368 return ret;
369 }
370
371 /**
372 * ti8x_file_read_backup:
373 * @filename: name of backup file to open.
374 * @content: where to store the file content.
375 *
376 * Load the backup file into a Ti8xBackup structure.
377 *
378 * Structure content must be freed with #tifiles_content_delete_backup when
379 * no longer used. If error occurs, the structure content is released for you.
380 *
381 * Return value: an error code, 0 otherwise.
382 **/
ti8x_file_read_backup(const char * filename,Ti8xBackup * content)383 int ti8x_file_read_backup(const char *filename, Ti8xBackup *content)
384 {
385 FILE *f;
386 long cur_pos = 0;
387 char signature[9];
388 uint16_t sum;
389 uint16_t file_size, header_size;
390 uint8_t extra_header[3] = { 0, 0, 0 };
391 int ret = ERR_FILE_IO;
392
393 if (content == NULL)
394 {
395 tifiles_critical("%s: an argument is NULL", __FUNCTION__);
396 return ERR_INVALID_FILE;
397 }
398
399 if (!tifiles_file_is_backup(filename))
400 {
401 ret = ERR_INVALID_FILE;
402 goto tfrb2;
403 }
404
405 f = g_fopen(filename, "rb");
406 if (f == NULL)
407 {
408 tifiles_info( "Unable to open this file: %s", filename);
409 ret = ERR_FILE_OPEN;
410 goto tfrb2;
411 }
412
413 // Get file size, then rewind.
414 if (fseek(f, 0, SEEK_END) < 0) goto tfrb;
415 cur_pos = ftell(f);
416 if (cur_pos < 0) goto tfrb;
417 if (fseek(f, 0, SEEK_SET) < 0) goto tfrb;
418
419 // The TI-Z80 backup format cannot handle more than 65535 bytes.
420 if (cur_pos >= 65536L)
421 {
422 ret = ERR_INVALID_FILE;
423 goto tfrb;
424 }
425 file_size = (uint16_t)cur_pos;
426
427 if (fread_8_chars(f, signature) < 0) goto tfrb;
428 content->model = tifiles_signature2calctype(signature);
429 if (content->model == CALC_NONE)
430 {
431 ret = ERR_INVALID_FILE;
432 goto tfrb;
433 }
434 if (fskip(f, 3) < 0) goto tfrb;
435 if (fread_n_chars(f, 42, content->comment) < 0) goto tfrb;
436 if (fread_word(f, NULL) < 0) goto tfrb;
437
438 if (fread_word(f, &header_size) < 0) goto tfrb;
439 if (header_size < 9 || header_size > 12)
440 {
441 ret = ERR_INVALID_FILE;
442 goto tfrb;
443 }
444
445 if (fread_word(f, &(content->data_length1)) < 0) goto tfrb;
446 if (content->data_length1 > file_size)
447 {
448 ret = ERR_INVALID_FILE;
449 goto tfrb;
450 }
451 if (fread_byte(f, &(content->type)) < 0) goto tfrb;
452 if (fread_word(f, &(content->data_length2)) < 0) goto tfrb;
453 if (content->data_length2 > file_size)
454 {
455 ret = ERR_INVALID_FILE;
456 goto tfrb;
457 }
458 if (fread_word(f, &(content->data_length3)) < 0) goto tfrb;
459 if (content->data_length3 > file_size)
460 {
461 ret = ERR_INVALID_FILE;
462 goto tfrb;
463 }
464 content->data_length4 = 0;
465 if (content->model != CALC_TI86)
466 {
467 if (fread_word(f, &(content->mem_address)) < 0) goto tfrb;
468 }
469 else
470 {
471 if (fread_word(f, &(content->data_length4)) < 0) goto tfrb;
472 }
473 if (content->data_length4 > file_size)
474 {
475 ret = ERR_INVALID_FILE;
476 goto tfrb;
477 }
478 if (header_size > 9)
479 {
480 if (fread(extra_header, 1, header_size - 9, f) < header_size - 9) goto tfrb;
481 }
482 content->version = extra_header[2];
483
484 if (fread_word(f, NULL) < 0) goto tfrb;
485 content->data_part1 = (uint8_t *)g_malloc0(content->data_length1);
486 if (content->data_part1 == NULL)
487 {
488 ret = ERR_MALLOC;
489 goto tfrb;
490 }
491 if (fread(content->data_part1, 1, content->data_length1, f) < content->data_length1) goto tfrb;
492
493 if (fread_word(f, NULL) < 0) goto tfrb;
494 content->data_part2 = (uint8_t *)g_malloc0(content->data_length2);
495 if (content->data_part2 == NULL)
496 {
497 ret = ERR_MALLOC;
498 goto tfrb;
499 }
500 if (fread(content->data_part2, 1, content->data_length2, f) < content->data_length2) goto tfrb;
501
502 if (content->data_length3) // can be 0000 on TI86
503 {
504 if (fread_word(f, NULL) < 0) goto tfrb;
505 content->data_part3 = (uint8_t *)g_malloc0(content->data_length3);
506 if (content->data_part3 == NULL)
507 {
508 ret = ERR_MALLOC;
509 goto tfrb;
510 }
511 if (fread(content->data_part3, 1, content->data_length3, f) < content->data_length3) goto tfrb;
512 }
513
514 if (content->model == CALC_TI86)
515 {
516 if (fread_word(f, NULL) < 0) goto tfrb;
517 content->data_part4 = (uint8_t *)g_malloc0(content->data_length4);
518 if (content->data_part4 == NULL)
519 {
520 ret = ERR_MALLOC;
521 goto tfrb;
522 }
523 if (fread(content->data_part4, 1, content->data_length4, f) < content->data_length4) goto tfrb;
524 }
525 else
526 {
527 content->data_length4 = 0;
528 content->data_part4 = NULL;
529 }
530
531 if (fread_word(f, &(content->checksum)) < 0) goto tfrb;
532 sum = compute_backup_sum(content, header_size);
533 #if defined(CHECKSUM_ENABLED)
534 if (sum != content->checksum)
535 {
536 ret = ERR_FILE_CHECKSUM;
537 goto tfrb;
538 }
539 #endif
540
541 fclose(f);
542 return 0;
543
544 tfrb: // release on exit
545 tifiles_critical("%s: error reading / understanding file %s", __FUNCTION__, filename);
546 fclose(f);
547 tfrb2:
548 tifiles_content_delete_backup(content);
549 return ret;
550 }
551
check_device_type(uint8_t id)552 static int check_device_type(uint8_t id)
553 {
554 static const uint8_t types[] = { 0, DEVICE_TYPE_73, DEVICE_TYPE_83P };
555 int i;
556
557 for (i = 1; i < (int)(sizeof(types)/sizeof(types[0])); i++)
558 {
559 if (types[i] == id)
560 {
561 return i;
562 }
563 }
564
565 return 0;
566 }
567
check_data_type(uint8_t id)568 static int check_data_type(uint8_t id)
569 {
570 static const uint8_t types[] = { 0, TI83p_AMS, TI83p_APPL, TI83p_CERT, TI83p_LICENSE };
571 int i;
572
573 for (i = 1; i < (int)(sizeof(types)/sizeof(types[0])); i++)
574 {
575 if (types[i] == id)
576 {
577 return i;
578 }
579 }
580
581 return 0;
582 }
583
get_native_app_name(const FlashContent * content,char * buffer,size_t buffer_size)584 static int get_native_app_name(const FlashContent *content, char *buffer, size_t buffer_size)
585 {
586 const uint8_t *data, *name;
587 uint16_t app_type;
588 uint32_t size, n;
589
590 if (content->num_pages > 0)
591 {
592 data = content->pages[0]->data;
593 size = content->pages[0]->size;
594 }
595 else
596 {
597 data = content->data_part;
598 size = content->data_length;
599 }
600
601 if (size >= 6 && (data[0] & 0xf0) == 0x80 && data[1] == 0x0f)
602 {
603 app_type = (uint16_t)(data[0]) << 8;
604 if (!tifiles_cert_field_find(data + 6, size - 6, app_type + 0x40, &name, &n))
605 {
606 if (n >= buffer_size)
607 {
608 n = buffer_size - 1;
609 }
610 memcpy(buffer, name, n);
611 buffer[n] = 0;
612 return 1;
613 }
614 }
615
616 return 0;
617 }
618
619 /**
620 * ti8x_file_read_flash:
621 * @filename: name of flash file to open.
622 * @content: where to store the file content.
623 *
624 * Load the flash file into a #FlashContent structure.
625 *
626 * Structure content must be freed with #tifiles_content_delete_flash when
627 * no longer used. If error occurs, the structure content is released for you.
628 *
629 * Return value: an error code, 0 otherwise.
630 **/
ti8x_file_read_flash(const char * filename,Ti8xFlash * head)631 int ti8x_file_read_flash(const char *filename, Ti8xFlash *head)
632 {
633 FILE *f;
634 Ti8xFlash *content = head;
635 int i;
636 char signature[9];
637 char varname[9];
638 int ret = ERR_FILE_IO;
639
640 if (head == NULL)
641 {
642 tifiles_critical("%s: an argument is NULL", __FUNCTION__);
643 return ERR_INVALID_FILE;
644 }
645
646 if (!tifiles_file_is_flash(filename))
647 {
648 ret = ERR_INVALID_FILE;
649 goto tfrf2;
650 }
651
652 f = g_fopen(filename, "rb");
653 if (f == NULL)
654 {
655 tifiles_info("Unable to open this file: %s", filename);
656 ret = ERR_FILE_OPEN;
657 goto tfrf2;
658 }
659
660 for (content = head;; content = content->next)
661 {
662 if (fread_8_chars(f, signature) < 0) goto tfrf;
663 content->model = tifiles_file_get_model(filename);
664 if (fread_byte(f, &(content->revision_major)) < 0) goto tfrf;
665 if (fread_byte(f, &(content->revision_minor)) < 0) goto tfrf;
666 if (fread_byte(f, &(content->flags)) < 0) goto tfrf;
667 if (fread_byte(f, &(content->object_type)) < 0) goto tfrf;
668 if (fread_byte(f, &(content->revision_day)) < 0) goto tfrf;
669 if (fread_byte(f, &(content->revision_month)) < 0) goto tfrf;
670 if (fread_word(f, &(content->revision_year)) < 0) goto tfrf;
671 if (fskip(f, 1) < 0) goto tfrf;
672 if (fread_8_chars(f, varname) < 0) goto tfrf;
673 if (fskip(f, 23) < 0) goto tfrf;
674 if (fread_byte(f, &(content->device_type)) < 0) goto tfrf;
675 if (fread_byte(f, &(content->data_type)) < 0) goto tfrf;
676 if (fskip(f, 23) < 0) goto tfrf;
677 if (fread_byte(f, &(content->hw_id)) < 0) goto tfrf;
678 if (fread_long(f, &content->data_length) < 0) goto tfrf;
679
680 if (!check_device_type(content->device_type))
681 {
682 ret = ERR_INVALID_FILE;
683 goto tfrf;
684 }
685 if (!check_data_type(content->data_type))
686 {
687 ret = ERR_INVALID_FILE;
688 goto tfrf;
689 }
690 // TODO: modify this code if TI ever makes a TI-eZ80 model with more than 4 MB of Flash memory...
691 if (content->data_length > 4U * 1024 * 1024 - 16384)
692 {
693 // Data length larger than Flash memory size - boot code sector size doesn't look right.
694 ret = ERR_INVALID_FILE;
695 goto tfrf;
696 }
697
698 if (content->data_type == TI83p_CERT || content->data_type == TI83p_LICENSE)
699 {
700 // get data like TI9X
701 content->data_part = (uint8_t *)g_malloc0(content->data_length + 256);
702 if (content->data_part == NULL)
703 {
704 ret = ERR_MALLOC;
705 goto tfrf;
706 }
707
708 memset(content->data_part, 0xff, content->data_length + 256);
709 if (fread(content->data_part, 1, content->data_length, f) < content->data_length) goto tfrf;
710
711 content->next = NULL;
712 }
713 else if (content->data_type == TI83p_AMS || content->data_type == TI83p_APPL)
714 {
715 if (content->hw_id == 0)
716 {
717 // This looks like a TI-Z80-style OS / FlashApp, let's try to parse Intel Hex format.
718
719 // reset/initialize block reader
720 hex_block_read(NULL, NULL, NULL, NULL, NULL, NULL);
721 content->pages = NULL;
722
723 // TODO: modify this code if TI ever makes a TI-Z80 model with more than 256 Flash pages...
724 content->pages = g_malloc0((256+1) * sizeof(Ti8xFlashPage *));
725 if (content->pages == NULL)
726 {
727 ret = ERR_MALLOC;
728 goto tfrf;
729 }
730
731 // read FLASH pages
732 content->data_length = 0;
733 for (i = 0, ret = 0; !ret; i++)
734 {
735 uint16_t size;
736 uint16_t addr;
737 uint16_t page;
738 uint8_t flag = 0x80;
739 uint8_t data[FLASH_PAGE_SIZE];
740 FlashPage* fp = content->pages[i] = g_malloc0(sizeof(FlashPage));
741
742 ret = hex_block_read(f, &size, &addr, &flag, data, &page);
743
744 fp->data = (uint8_t *) g_malloc0(FLASH_PAGE_SIZE);
745 memset(fp->data, 0xff, FLASH_PAGE_SIZE);
746 if (fp->data == NULL)
747 {
748 ret = ERR_MALLOC;
749 goto tfrf;
750 }
751
752 fp->addr = addr;
753 fp->page = page;
754 fp->flag = flag;
755 fp->size = size;
756 memcpy(fp->data, data, size);
757
758 content->data_length += size;
759 }
760 content->num_pages = i;
761 content->next = NULL;
762 }
763 else
764 {
765 // This looks like a TI-68k-style OS / FlashApp, containing flat data.
766
767 content->data_part = (uint8_t *)g_malloc0(content->data_length);
768 if (content->data_part == NULL)
769 {
770 ret = ERR_MALLOC;
771 goto tfrf;
772 }
773
774 if (fread(content->data_part, 1, content->data_length, f) < content->data_length) goto tfrf;
775 if ( (content->data_type == TI83p_AMS && content->data_part[0] != 0x80)
776 || (content->data_type == TI83p_APPL && content->data_part[0] != 0x81))
777 {
778 ret = ERR_INVALID_FILE;
779 goto tfrf;
780 }
781 content->next = NULL;
782 }
783 }
784
785 if (content->data_type == TI83p_APPL)
786 {
787 // Determine the app name from the internal header if possible.
788 if (!get_native_app_name(content, varname, sizeof(varname)))
789 {
790 tifiles_warning("unable to determine app name from header");
791 }
792 }
793
794 if (content->model_dst == CALC_NONE)
795 {
796 content->model_dst = content->model;
797 }
798 ticonv_varname_from_tifile_sn(content->model_dst, varname, content->name, sizeof(content->name), content->data_type);
799
800 // check for end of file
801 if (fread_8_chars(f, signature) < 0)
802 {
803 break;
804 }
805 if (strcmp(signature, "**TIFL**") || feof(f))
806 {
807 break;
808 }
809 if (fseek(f, -8, SEEK_CUR)) goto tfrf;
810
811 content->next = (Ti8xFlash *)g_malloc0(sizeof(Ti8xFlash));
812 if (content->next == NULL)
813 {
814 ret = ERR_MALLOC;
815 goto tfrf;
816 }
817 }
818
819 fclose(f);
820 return 0;
821
822 tfrf: // release on exit
823 tifiles_critical("%s: error reading / understanding file %s", __FUNCTION__, filename);
824 fclose(f);
825 tfrf2:
826 tifiles_content_delete_flash(content);
827 return ret;
828 }
829
830 /***********/
831 /* Writing */
832 /***********/
833
834 /**
835 * ti8x_file_write_regular:
836 * @filename: name of single/group file where to write or NULL.
837 * @content: the file content to write.
838 * @real_filename: pointer address or NULL. Must be freed if needed when no longer needed.
839 *
840 * Write one (or several) variable(s) into a single (group) file. If filename is set to NULL,
841 * the function build a filename from varname and allocates resulting filename in %real_fname.
842 * %filename and %real_filename can be NULL but not both !
843 *
844 * %real_filename must be freed when no longer used.
845 *
846 * Return value: an error code, 0 otherwise.
847 **/
ti8x_file_write_regular(const char * fname,Ti8xRegular * content,char ** real_fname)848 int ti8x_file_write_regular(const char *fname, Ti8xRegular *content, char **real_fname)
849 {
850 FILE *f;
851 unsigned int i;
852 uint16_t sum = 0;
853 char *filename = NULL;
854 uint32_t data_length;
855 uint16_t packet_length = 0x0B;
856 uint8_t name_length = 8;
857 uint16_t attr;
858
859 if (content->entries == NULL)
860 {
861 tifiles_warning("%s: skipping content with NULL content->entries", __FUNCTION__);
862 return 0;
863 }
864
865 // Compute data length now, so as to be able to bail out immediately if we know the data won't fit.
866 for (i = 0, data_length = 0; i < content->num_entries; i++)
867 {
868 VarEntry *entry = content->entries[i];
869 if (entry == NULL)
870 {
871 tifiles_warning("%s: skipping null content entry %d", __FUNCTION__, i);
872 continue;
873 }
874
875 if (content->model == CALC_TI82 || content->model == CALC_TI73)
876 {
877 data_length += entry->size + 15;
878 }
879 else if (content->model == CALC_TI83)
880 {
881 data_length += entry->size + 15;
882 }
883 else if (content->model == CALC_TI85)
884 {
885 data_length += entry->size + 8 + strlen(entry->name);
886 }
887 else if (content->model == CALC_TI86)
888 {
889 data_length += entry->size + 16;
890 }
891 else if (is_ti83p(content->model))
892 {
893 data_length += entry->size + 17;
894 }
895 }
896 if (data_length > 65535)
897 {
898 return ERR_GROUP_SIZE;
899 }
900
901 if (fname != NULL)
902 {
903 filename = g_strdup(fname);
904 if (filename == NULL)
905 {
906 return ERR_MALLOC;
907 }
908 }
909 else
910 {
911 if (content->entries[0])
912 {
913 filename = tifiles_build_filename(content->model_dst, content->entries[0]);
914 }
915 else
916 {
917 tifiles_warning("%s: asked to build a filename from null content->entries[0], bailing out", __FUNCTION__);
918 if (real_fname != NULL)
919 {
920 *real_fname = NULL;
921 }
922 return 0;
923 }
924 if (real_fname != NULL)
925 {
926 *real_fname = g_strdup(filename);
927 }
928 }
929
930 f = g_fopen(filename, "wb");
931 if (f == NULL)
932 {
933 tifiles_info( "Unable to open this file: %s", filename);
934 g_free(filename);
935 return ERR_FILE_OPEN;
936 }
937
938 // write header
939 if (fwrite_8_chars(f, tifiles_calctype2signature(content->model)) < 0) goto tfwr;
940 if (fwrite(content->model == CALC_TI85 ? fsignature85 : fsignature8x, 1, 3, f) < 3) goto tfwr;
941 if (fwrite_n_bytes(f, 42, (uint8_t *)content->comment) < 0) goto tfwr;
942
943 if (fwrite_word(f, (uint16_t) data_length) < 0) goto tfwr;
944
945 // write data section
946 for (i = 0, sum = 0; i < content->num_entries; i++)
947 {
948 VarEntry *entry = content->entries[i];
949 char varname[VARNAME_MAX];
950
951 if (content->model == CALC_TI85)
952 {
953 packet_length = 4 + strlen(entry->name); //offset to data length
954 }
955 else if (content->model == CALC_TI86)
956 {
957 packet_length = 0x0C;
958 }
959 else if (is_ti83p(content->model))
960 {
961 packet_length = 0x0D;
962 }
963 else
964 {
965 packet_length = 0x0B;
966 }
967
968 if (fwrite_word(f, packet_length) < 0) goto tfwr;
969 if (fwrite_word(f, (uint16_t)entry->size) < 0) goto tfwr;
970 if (fwrite_byte(f, entry->type) < 0) goto tfwr;
971 memset(varname, 0, sizeof(varname));
972 ticonv_varname_to_tifile_sn(content->model_dst, entry->name, varname, sizeof(varname), entry->type);
973 if (is_ti8586(content->model))
974 {
975 name_length = strlen(varname);
976 if (fwrite_byte(f, (uint8_t)name_length) < 0) goto tfwr;
977 if (content->model == CALC_TI85)
978 {
979 if (fwrite_n_chars(f, name_length, varname) < 0) goto tfwr;
980 }
981 else
982 {
983 if (fwrite_n_chars2(f, 8, varname) < 0) goto tfwr; // space padded
984 }
985 }
986 else
987 {
988 if (fwrite_n_chars(f, 8, varname) < 0) goto tfwr;
989 }
990 if (is_ti83p(content->model))
991 {
992 attr = (uint16_t)((entry->attr == ATTRB_ARCHIVED) ? 0x8000 : 0x00) + entry->version;
993 if (fwrite_word(f, attr) < 0) goto tfwr;
994 sum += MSB(attr);
995 sum += LSB(attr);
996 }
997 if (fwrite_word(f, (uint16_t)entry->size) < 0) goto tfwr;
998 if (fwrite(entry->data, 1, entry->size, f) < entry->size) goto tfwr;
999
1000 sum += packet_length;
1001 sum += MSB(entry->size);
1002 sum += LSB(entry->size);
1003 sum += entry->type;
1004 if (is_ti8586(content->model))
1005 {
1006 sum += strlen(entry->name);
1007 }
1008 sum += tifiles_checksum((uint8_t *)varname, name_length);
1009 if (content->model == CALC_TI86)
1010 {
1011 sum += (8 - name_length) * ' ';
1012 }
1013 sum += MSB(entry->size);
1014 sum += LSB(entry->size);
1015 sum += tifiles_checksum(entry->data, entry->size);
1016 }
1017
1018 //checksum is the sum of all bytes in the data section
1019 content->checksum = sum;
1020 if (fwrite_word(f, content->checksum) < 0) goto tfwr;
1021
1022 g_free(filename);
1023 fclose(f);
1024 return 0;
1025
1026 tfwr: // release on exit
1027 tifiles_critical("%s: error writing file %s", __FUNCTION__, filename);
1028 g_free(filename);
1029 fclose(f);
1030 return ERR_FILE_IO;
1031 }
1032
1033 /**
1034 * ti8x_file_write_backup:
1035 * @filename: name of backup file where to write.
1036 * @content: the file content to write.
1037 *
1038 * Write content to a backup file.
1039 *
1040 * Return value: an error code, 0 otherwise.
1041 **/
ti8x_file_write_backup(const char * filename,Ti8xBackup * content)1042 int ti8x_file_write_backup(const char *filename, Ti8xBackup *content)
1043 {
1044 FILE *f;
1045 uint16_t header_size;
1046 uint32_t data_length;
1047
1048 if (filename == NULL || content == NULL)
1049 {
1050 tifiles_critical("%s: an argument is NULL", __FUNCTION__);
1051 return ERR_INVALID_FILE;
1052 }
1053
1054 data_length = content->data_length1 + content->data_length2 + content->data_length3 + 17;
1055 if (content->model == CALC_TI86)
1056 {
1057 data_length += content->data_length4;
1058 }
1059
1060 if (data_length > 65535)
1061 {
1062 return ERR_GROUP_SIZE;
1063 }
1064
1065 f = g_fopen(filename, "wb");
1066 if (f == NULL)
1067 {
1068 tifiles_info( "Unable to open this file: %s", filename);
1069 return ERR_FILE_OPEN;
1070 }
1071 // write header
1072 if (fwrite_8_chars(f, tifiles_calctype2signature(content->model)) < 0) goto tfwb;
1073 if (fwrite(content->model == CALC_TI85 ? fsignature85 : fsignature8x, 1, 3, f) < 3) goto tfwb;
1074 if (fwrite_n_bytes(f, 42, (uint8_t *)content->comment) < 0) goto tfwb;
1075 if (fwrite_word(f, data_length) < 0) goto tfwb;
1076
1077 // Use the old-style header for versions 0 to 5 (84+ OS 2.48 and
1078 // earlier), for compatibility with older versions of libtifiles
1079 // that assume the header is always 9 bytes. Backups from newer
1080 // OSes (2.53 and later) are incompatible in both directions, so a
1081 // new format is needed for version 6 and above.
1082 if ((content->version & ~0x20) <= 0x05)
1083 {
1084 header_size = 9;
1085 }
1086 else
1087 {
1088 header_size = 12;
1089 }
1090
1091 // write backup header
1092 if (fwrite_word(f, header_size) < 0) goto tfwb;
1093 if (fwrite_word(f, content->data_length1) < 0) goto tfwb;
1094 if (fwrite_byte(f, content->type) < 0) goto tfwb;
1095 if (fwrite_word(f, content->data_length2) < 0) goto tfwb;
1096 if (fwrite_word(f, content->data_length3) < 0) goto tfwb;
1097 if (content->model != CALC_TI86)
1098 {
1099 if (fwrite_word(f, content->mem_address) < 0) goto tfwb;
1100 }
1101 else
1102 {
1103 if (fwrite_word(f, content->data_length4) < 0) goto tfwb;
1104 }
1105 if (header_size == 12)
1106 {
1107 if (fwrite_word(f, 0) < 0) goto tfwb;
1108 if (fwrite_byte(f, content->version) < 0) goto tfwb;
1109 }
1110
1111 // write data num_entries
1112 if (fwrite_word(f, content->data_length1) < 0) goto tfwb;
1113 if (fwrite(content->data_part1, 1, content->data_length1, f) < content->data_length1) goto tfwb;
1114 if (fwrite_word(f, content->data_length2) < 0) goto tfwb;
1115 if (fwrite(content->data_part2, 1, content->data_length2, f) < content->data_length2) goto tfwb;
1116 if (content->data_length3) // TI86: can be NULL
1117 {
1118 if (fwrite_word(f, content->data_length3) < 0) goto tfwb;
1119 }
1120 if (fwrite(content->data_part3, 1, content->data_length3, f) < content->data_length3) goto tfwb;
1121 if (content->model == CALC_TI86)
1122 {
1123 if (fwrite_word(f, content->data_length4) < 0) goto tfwb;
1124 if (fwrite(content->data_part4, 1, content->data_length4, f) < content->data_length4) goto tfwb;
1125 }
1126
1127 // checksum = sum of all bytes in bachup headers and data num_entries
1128 content->checksum = compute_backup_sum(content, header_size);
1129 if (fwrite_word(f, content->checksum) < 0) goto tfwb;
1130
1131 fclose(f);
1132 return 0;
1133
1134 tfwb: // release on exit
1135 tifiles_critical("%s: error writing file %s", __FUNCTION__, filename);
1136 fclose(f);
1137 return ERR_FILE_IO;
1138 }
1139
1140 /**
1141 * ti8x_file_write_flash:
1142 * @filename: name of flash file where to write.
1143 * @content: the file content to write.
1144 * @real_filename: pointer address or NULL. Must be freed if needed when no longer needed.
1145 *
1146 * Write content to a flash file (os or app).
1147 *
1148 * Return value: an error code, 0 otherwise.
1149 **/
ti8x_file_write_flash(const char * fname,Ti8xFlash * head,char ** real_fname)1150 int ti8x_file_write_flash(const char *fname, Ti8xFlash *head, char **real_fname)
1151 {
1152 FILE *f;
1153 Ti8xFlash *content = head;
1154 unsigned int i;
1155 int bytes_written = 0;
1156 long pos;
1157 char *filename;
1158 char varname[VARNAME_MAX];
1159
1160 if (head == NULL)
1161 {
1162 tifiles_critical("%s: head is NULL", __FUNCTION__);
1163 return ERR_INVALID_FILE;
1164 }
1165
1166 if (fname)
1167 {
1168 filename = g_strdup(fname);
1169 if (filename == NULL)
1170 {
1171 return ERR_MALLOC;
1172 }
1173 }
1174 else
1175 {
1176 VarEntry ve;
1177
1178 for (content = head; content != NULL; content = content->next)
1179 {
1180 if (content->data_type == TI83p_AMS || content->data_type == TI83p_APPL)
1181 {
1182 break;
1183 }
1184 }
1185 if (content == NULL)
1186 {
1187 tifiles_critical("%s: content is NULL", __FUNCTION__);
1188 return ERR_BAD_FILE;
1189 }
1190
1191 strncpy(ve.name, content->name, sizeof(ve.name) - 1);
1192 ve.name[sizeof(ve.name) - 1] = 0;
1193 ve.type = content->data_type;
1194
1195 filename = tifiles_build_filename(content->model_dst, &ve);
1196 if (real_fname != NULL)
1197 {
1198 *real_fname = g_strdup(filename);
1199 }
1200 }
1201
1202 f = g_fopen(filename, "wb");
1203 if (f == NULL)
1204 {
1205 tifiles_info("Unable to open this file: %s", filename);
1206 g_free(filename);
1207 return ERR_FILE_OPEN;
1208 }
1209
1210 for (content = head; content != NULL; content = content->next)
1211 {
1212 // header
1213 if (fwrite_8_chars(f, "**TIFL**") < 0) goto tfwf;
1214 if (fwrite_byte(f, content->revision_major) < 0) goto tfwf;
1215 if (fwrite_byte(f, content->revision_minor) < 0) goto tfwf;
1216 if (fwrite_byte(f, content->flags) < 0) goto tfwf;
1217 if (fwrite_byte(f, content->object_type) < 0) goto tfwf;
1218 if (fwrite_byte(f, content->revision_day) < 0) goto tfwf;
1219 if (fwrite_byte(f, content->revision_month) < 0) goto tfwf;
1220 if (fwrite_word(f, content->revision_year) < 0) goto tfwf;
1221
1222 memset(varname, 0, sizeof(varname));
1223 ticonv_varname_to_tifile_sn(content->model_dst, content->name, varname, sizeof(varname), content->data_type);
1224 if (content->data_type == TI83p_APPL)
1225 {
1226 // Determine the app name from the internal header if possible.
1227 get_native_app_name(content, varname, sizeof(varname));
1228 }
1229 if (fwrite_byte(f, (uint8_t) strlen(varname)) < 0) goto tfwf;
1230 if (fwrite_8_chars(f, varname) < 0) goto tfwf;
1231 for (i = 0; i < 23; i++)
1232 {
1233 if (fwrite_byte(f, 0) < 0) goto tfwf;
1234 }
1235 if (fwrite_byte(f, content->device_type) < 0) goto tfwf;
1236 if (fwrite_byte(f, content->data_type) < 0) goto tfwf;
1237 for (i = 0; i < 23; i++)
1238 {
1239 if (fwrite_byte(f, 0) < 0) goto tfwf;
1240 }
1241 if (fwrite_byte(f, content->hw_id) < 0) goto tfwf;
1242 pos = ftell(f);
1243 if (pos == -1L) goto tfwf;
1244 if (fwrite_long(f, content->data_length) < 0) goto tfwf;
1245
1246 // data
1247 if (content->data_type == TI83p_CERT || content->data_type == TI83p_LICENSE)
1248 {
1249 if (fwrite(content->data_part, 1, content->data_length, f) < content->data_length) goto tfwf;
1250 }
1251 else if (content->data_type == TI83p_AMS || content->data_type == TI83p_APPL)
1252 {
1253 // write
1254 if (content->hw_id == 0)
1255 {
1256 // TI-Z80-style OS / FlashApp, let's write Intel Hex format.
1257 for (i = 0; content->pages != NULL && i < content->num_pages; i++)
1258 {
1259 uint32_t app_length, page_length;
1260 int extra_bytes = 0;
1261
1262 page_length = content->pages[i]->size;
1263
1264 if ( content->data_type == TI83p_APPL && i == content->num_pages - 1
1265 && content->pages[0]->data[0] == 0x80 && content->pages[0]->data[1] == 0x0f)
1266 {
1267 /* Flash app signing programs will usually add some
1268 padding to the end of the app, and some programs
1269 seem to expect that padding to be there.
1270
1271 The following is designed to mimic the behavior
1272 of these programs, padding to 96 bytes beyond the
1273 end of the application proper. */
1274
1275 /* get actual app length */
1276 app_length = 6 + ( (((uint32_t)(content->pages[0]->data[2])) << 24)
1277 | (((uint32_t)(content->pages[0]->data[3])) << 16)
1278 | (((uint32_t)(content->pages[0]->data[4])) << 8)
1279 | ((uint32_t)(content->pages[0]->data[5])));
1280
1281 /* remove any existing padding */
1282 while (page_length > 0 && content->pages[i]->data[page_length - 1] == 0xff)
1283 {
1284 page_length--;
1285 }
1286
1287 extra_bytes = app_length + 96 - i * 0x4000 - page_length;
1288
1289 /* don't add padding beyond the end of the page */
1290 if (page_length + extra_bytes >= 0x3fff)
1291 {
1292 extra_bytes = 0x3fff - page_length;
1293 }
1294
1295 if (extra_bytes < 0)
1296 {
1297 extra_bytes = 0;
1298 }
1299 else if (extra_bytes > 96)
1300 {
1301 extra_bytes = 96;
1302 }
1303 }
1304
1305 bytes_written += hex_block_write(f,
1306 page_length, content->pages[i]->addr,
1307 content->pages[i]->flag, content->pages[i]->data,
1308 content->pages[i]->page, extra_bytes);
1309 }
1310
1311 // final block
1312 bytes_written += hex_block_write(f, 0, 0, 0, NULL, 0, 0);
1313 if (fseek(f, -bytes_written - 4, SEEK_CUR)) goto tfwf;
1314 if (fwrite_long(f, bytes_written) < 0) goto tfwf;
1315 if (fseek(f, SEEK_END, 0L) ) goto tfwf;
1316 }
1317 else
1318 {
1319 // This looks like a TI-68k-style OS / FlashApp, containing flat data.
1320 if (fwrite(content->data_part, 1, content->data_length, f) < content->data_length) goto tfwf;
1321 }
1322 }
1323 }
1324
1325 g_free(filename);
1326 fclose(f);
1327 return 0;
1328
1329 tfwf: // release on exit
1330 tifiles_critical("%s: error writing file %s", __FUNCTION__, filename);
1331 g_free(filename);
1332 fclose(f);
1333 return ERR_FILE_IO;
1334 }
1335
1336
1337 /**************/
1338 /* Displaying */
1339 /**************/
1340
1341 /**
1342 * ti8x_content_display_backup:
1343 * @content: a Ti8xBackup structure.
1344 *
1345 * Display fields of a Ti8xBackup structure.
1346 *
1347 * Return value: an error code, 0 otherwise.
1348 **/
ti8x_content_display_backup(Ti8xBackup * content)1349 int ti8x_content_display_backup(Ti8xBackup *content)
1350 {
1351 if (content == NULL)
1352 {
1353 tifiles_critical("%s(NULL)", __FUNCTION__);
1354 return ERR_INVALID_FILE;
1355 }
1356
1357 tifiles_info("BackupContent for TI-8x: %p", content);
1358 tifiles_info("Model: %02X (%u)", content->model, content->model);
1359 tifiles_info("Signature: %s", tifiles_calctype2signature(content->model));
1360 tifiles_info("Comment: %s", content->comment);
1361 tifiles_info("Type: %02X (%s)", content->type, tifiles_vartype2string(content->model, content->type));
1362 tifiles_info("Version: %02X (%u)", content->version, content->version);
1363 tifiles_info("Mem address: %04X (%u)", content->mem_address, content->mem_address);
1364
1365 tifiles_info("data_length1: %04X (%u)", content->data_length1, content->data_length1);
1366 tifiles_info("data_part1: %p", content->data_part1);
1367 tifiles_info("data_length2: %04X (%u)", content->data_length2, content->data_length2);
1368 tifiles_info("data_part2: %p", content->data_part2);
1369 tifiles_info("data_length3: %04X (%u)", content->data_length3, content->data_length3);
1370 tifiles_info("data_part3: %p", content->data_part3);
1371
1372 if (content->model == CALC_TI86)
1373 {
1374 tifiles_info("data_length4: %04X (%u)", content->data_length4, content->data_length4);
1375 tifiles_info("data_part4: %p", content->data_part4);
1376 }
1377
1378 tifiles_info("Checksum: %04X (%u)", content->checksum, content->checksum);
1379
1380 return 0;
1381 }
1382
1383 /**
1384 * ti8x_content_display_flash:
1385 * @content: a Ti8xFlash structure.
1386 *
1387 * Display fields of a Ti8xFlash structure.
1388 *
1389 * Return value: an error code, 0 otherwise.
1390 **/
ti8x_content_display_flash(Ti8xFlash * content)1391 int ti8x_content_display_flash(Ti8xFlash *content)
1392 {
1393 Ti8xFlash *ptr;
1394
1395 for (ptr = content; ptr != NULL; ptr = ptr->next)
1396 {
1397 tifiles_info("FlashContent for TI-8x: %p", ptr);
1398 tifiles_info("Model: %02X (%u)", ptr->model, ptr->model);
1399 tifiles_info("Signature: %s", tifiles_calctype2signature(ptr->model));
1400 tifiles_info("model_dst: %02X (%u)", ptr->model_dst, ptr->model_dst);
1401 tifiles_info("Revision: %u.%u", ptr->revision_major, ptr->revision_minor);
1402 tifiles_info("Flags: %02X", ptr->flags);
1403 tifiles_info("Object type: %02X", ptr->object_type);
1404 tifiles_info("Date: %02X/%02X/%02X%02X", ptr->revision_day, ptr->revision_month, ptr->revision_year & 0xff, (ptr->revision_year & 0xff00) >> 8);
1405 tifiles_info("Name: %s", ptr->name);
1406 tifiles_info("Device type: %s", ptr->device_type == DEVICE_TYPE_83P ? "ti83+" : "ti73");
1407 switch (ptr->data_type)
1408 {
1409 case 0x23:
1410 tifiles_info("Data type: OS data");
1411 break;
1412 case 0x24:
1413 tifiles_info("Data type: APP data");
1414 break;
1415 case 0x20:
1416 case 0x25:
1417 tifiles_info("Data type: certificate");
1418 break;
1419 case 0x3E:
1420 tifiles_info("Data type: license");
1421 break;
1422 default:
1423 tifiles_info("Data type: Unknown (send mail to tilp-users@lists.sf.net)");
1424 break;
1425 }
1426 tifiles_info("Hardware ID: %02X (%u)", ptr->hw_id, ptr->hw_id);
1427 tifiles_info("Length: %08X (%u)", ptr->data_length, ptr->data_length);
1428 tifiles_info("Data: %p", ptr->data_part);
1429 tifiles_info("Number of pages: %i", ptr->num_pages);
1430 tifiles_info("Pages: %p", ptr->pages);
1431 tifiles_info("Next: %p", ptr->next);
1432 }
1433
1434 return 0;
1435 }
1436
1437 /**
1438 * ti8x_file_display:
1439 * @filename: a TI file.
1440 *
1441 * Determine file class and display internal content.
1442 *
1443 * Return value: an error code, 0 otherwise.
1444 **/
ti8x_file_display(const char * filename)1445 int ti8x_file_display(const char *filename)
1446 {
1447 Ti8xRegular *content1;
1448 Ti8xBackup *content2;
1449 Ti8xFlash *content3;
1450 int ret;
1451
1452 if (tifiles_file_is_flash(filename))
1453 {
1454 content3 = tifiles_content_create_flash(CALC_TI83P);
1455 ret = ti8x_file_read_flash(filename, content3);
1456 if (!ret)
1457 {
1458 ti8x_content_display_flash(content3);
1459 tifiles_content_delete_flash(content3);
1460 }
1461 }
1462 else if (tifiles_file_is_regular(filename))
1463 {
1464 content1 = tifiles_content_create_regular(CALC_NONE);
1465 ret = ti8x_file_read_regular(filename, content1);
1466 if (!ret)
1467 {
1468 tifiles_file_display_regular(content1);
1469 tifiles_content_delete_regular(content1);
1470 }
1471 }
1472 else if (tifiles_file_is_backup(filename))
1473 {
1474 content2 = tifiles_content_create_backup(CALC_NONE);
1475 ret = ti8x_file_read_backup(filename, content2);
1476 if (!ret)
1477 {
1478 ti8x_content_display_backup(content2);
1479 tifiles_content_delete_backup(content2);
1480 }
1481 }
1482 else
1483 {
1484 tifiles_info("Unknown file type !");
1485 return ERR_BAD_FILE;
1486 }
1487
1488 return ret;
1489 }
1490
1491 #endif
1492