1 /* Hey EMACS -*- linux-c -*- */
2 /* $Id$ */
3
4 /* libtifiles - file format library, a part of the TiLP project
5 * Copyright (C) 1999-2006 Romain Lievin
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 /*
23 This unit contains a TI file independent API
24 */
25
26 #include <glib.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <time.h>
31
32 #include "tifiles.h"
33 #include "error.h"
34 #include "files8x.h"
35 #include "files9x.h"
36 #include "filesnsp.h"
37 #include "logging.h"
38
39 // Whether to print detailed information about FileContent, BackupContent, FlashContent instances throughout their lifecycle.
40 //#define TRACE_CONTENT_INSTANCES
41
42 /**
43 * tifiles_content_create_regular:
44 * @model: a calculator model (required).
45 *
46 * Allocates a #FileContent structure.
47 *
48 * Return value: the allocated block.
49 **/
tifiles_content_create_regular(CalcModel model)50 TIEXPORT2 FileContent* TICALL tifiles_content_create_regular(CalcModel model)
51 {
52 FileContent* content = g_malloc0(sizeof(FileContent));
53
54 if (content != NULL)
55 {
56 if ((unsigned int)model >= CALC_MAX)
57 {
58 tifiles_warning("Invalid calculator model");
59 }
60 content->model = content->model_dst = model;
61 strncpy(content->comment, tifiles_comment_set_single(), sizeof(content->comment) - 1);
62 content->comment[sizeof(content->comment) - 1] = 0;
63 }
64
65 #ifdef TRACE_CONTENT_INSTANCES
66 tifiles_info("tifiles_content_create_regular: %p", content);
67 tifiles_file_display_regular(content);
68 #endif
69
70 return content;
71 }
72
73 /**
74 * tifiles_content_delete_regular:
75 *
76 * Free the whole content of a #FileContent structure.
77 *
78 * Return value: 0.
79 **/
tifiles_content_delete_regular(FileContent * content)80 TIEXPORT2 int TICALL tifiles_content_delete_regular(FileContent *content)
81 {
82 unsigned int i;
83
84 #ifdef TRACE_CONTENT_INSTANCES
85 tifiles_info("tifiles_content_delete_regular: %p", content);
86 tifiles_file_display_regular(content);
87 #endif
88
89 if (content != NULL)
90 {
91 for (i = 0; i < content->num_entries; i++)
92 {
93 VarEntry *entry = content->entries[i];
94
95 if (entry != NULL)
96 {
97 g_free(entry->data);
98 g_free(entry);
99 }
100 else
101 {
102 tifiles_critical("tifiles_content_delete_regular(content with NULL entry)");
103 }
104 }
105
106 g_free(content->entries);
107 g_free(content);
108 }
109 else
110 {
111 tifiles_critical("%s(NULL)", __FUNCTION__);
112 }
113
114 return 0;
115 }
116
117 /**
118 * tifiles_content_dup_regular:
119 *
120 * Allocates and copies a new #FileContent structure.
121 *
122 * Return value: none.
123 **/
tifiles_content_dup_regular(FileContent * content)124 TIEXPORT2 FileContent* TICALL tifiles_content_dup_regular(FileContent *content)
125 {
126 FileContent *dup = NULL;
127 unsigned int i;
128
129 if (content != NULL)
130 {
131 dup = tifiles_content_create_regular(content->model);
132 if (dup != NULL)
133 {
134 memcpy(dup, content, sizeof(FileContent));
135 dup->entries = tifiles_ve_create_array(content->num_entries);
136
137 if (dup->entries != NULL)
138 {
139 for (i = 0; i < content->num_entries; i++)
140 {
141 dup->entries[i] = tifiles_ve_dup(content->entries[i]);
142 if (dup->entries[i] == NULL)
143 {
144 tifiles_content_delete_regular(dup);
145 dup = NULL;
146 break;
147 }
148 }
149 }
150 else
151 {
152 dup->num_entries = 0;
153 tifiles_content_delete_regular(dup);
154 dup = NULL;
155 }
156 }
157 }
158 else
159 {
160 tifiles_critical("%s(NULL)", __FUNCTION__);
161 }
162
163 #ifdef TRACE_CONTENT_INSTANCES
164 tifiles_info("tifiles_content_dup_regular: %p", dup);
165 tifiles_file_display_regular(dup);
166 #endif
167
168 return dup;
169 }
170
171 /**
172 * tifiles_file_read_regular:
173 * @filename: name of single/group file to open.
174 * @content: where to store the file content.
175 *
176 * Load the single/group file into a FileContent structure.
177 *
178 * Structure content must be freed with #tifiles_content_delete_regular when
179 * no longer used. If an error occurs, the structure content is released for you.
180 *
181 * Return value: an error code, 0 otherwise.
182 **/
tifiles_file_read_regular(const char * filename,FileContent * content)183 TIEXPORT2 int tifiles_file_read_regular(const char *filename, FileContent *content)
184 {
185 if (filename == NULL || content == NULL)
186 {
187 tifiles_critical("%s: an argument is NULL", __FUNCTION__);
188 return ERR_INVALID_FILE;
189 }
190
191 #if !defined(DISABLE_TI8X)
192 if (tifiles_calc_is_ti8x(tifiles_file_get_model(filename)))
193 {
194 return ti8x_file_read_regular(filename, (Ti8xRegular *)content);
195 }
196 else
197 #endif
198 #if !defined(DISABLE_TI9X)
199 if (tifiles_calc_is_ti9x(tifiles_file_get_model(filename)))
200 {
201 return ti9x_file_read_regular(filename, (Ti9xRegular *)content);
202 }
203 else
204 #endif
205 if (content->model == CALC_NSPIRE)
206 {
207 return tnsp_file_read_regular(filename, (FileContent *)content);
208 }
209 else
210 {
211 return ERR_BAD_CALC;
212 }
213 }
214
215 /**
216 * tifiles_file_write_regular:
217 * @filename: name of single/group file where to write or NULL.
218 * @content: the file content to write.
219 * @real_fname: pointer address or NULL. Must be freed if needed when no longer needed.
220 *
221 * Write one (or several) variable(s) into a single (group) file. If filename is set to NULL,
222 * the function build a filename from varname and allocates resulting filename in %real_fname.
223 * %filename and %real_filename can be NULL but not both !
224 *
225 * %real_filename must be freed when no longer used.
226 *
227 * Return value: an error code, 0 otherwise.
228 **/
tifiles_file_write_regular(const char * filename,FileContent * content,char ** real_fname)229 TIEXPORT2 int tifiles_file_write_regular(const char *filename, FileContent *content, char **real_fname)
230 {
231 if (content == NULL || (filename == NULL && real_fname == NULL))
232 {
233 tifiles_critical("%s: an argument is NULL", __FUNCTION__);
234 return ERR_INVALID_FILE;
235 }
236
237 #if !defined(DISABLE_TI8X)
238 if (tifiles_calc_is_ti8x(content->model))
239 {
240 return ti8x_file_write_regular(filename, (Ti8xRegular *)content, real_fname);
241 }
242 else
243 #endif
244 #if !defined(DISABLE_TI9X)
245 if (tifiles_calc_is_ti9x(content->model))
246 {
247 return ti9x_file_write_regular(filename, (Ti9xRegular *)content, real_fname);
248 }
249 else
250 #endif
251 if (content->model == CALC_NSPIRE)
252 {
253 return tnsp_file_write_regular(filename, (FileContent *)content, real_fname);
254 }
255 else
256 {
257 return ERR_BAD_CALC;
258 }
259 }
260
261 /**
262 * tifiles_file_display_regular:
263 * @content: the file content to show, a FileContent pointer.
264 *
265 * Display file content information contained in a FileContent structure.
266 *
267 * Return value: an error code, 0 otherwise.
268 **/
tifiles_file_display_regular(FileContent * content)269 TIEXPORT2 int TICALL tifiles_file_display_regular(FileContent *content)
270 {
271 unsigned int i;
272 char trans[257];
273 int model_supports_folder = 1;
274
275 if (content == NULL)
276 {
277 tifiles_critical("%s(NULL)", __FUNCTION__);
278 return ERR_INVALID_FILE;
279 }
280
281 #if !defined(DISABLE_TI8X)
282 if (tifiles_calc_is_ti8x(content->model))
283 {
284 tifiles_info("FileContent for TI-8x: %p", content);
285 model_supports_folder = 0;
286 }
287 else
288 #endif
289 #if !defined(DISABLE_TI9X)
290 if (tifiles_calc_is_ti9x(content->model))
291 {
292 tifiles_info("FileContent for TI-9x: %p", content);
293 }
294 else
295 #endif
296 if (content->model == CALC_NSPIRE)
297 {
298 tifiles_info("FileContent for TI-Nspire: %p", content);
299 }
300 else
301 {
302 return ERR_BAD_CALC;
303 }
304
305 tifiles_info("Model: %02X (%u)", content->model, content->model);
306 tifiles_info("Signature: %s", tifiles_calctype2signature(content->model));
307 tifiles_info("Comment: %s", content->comment);
308 if (model_supports_folder)
309 {
310 tifiles_info("Default folder: %s", content->default_folder);
311 }
312 tifiles_info("Number of entries: %u", content->num_entries);
313 tifiles_info("Entries: %p", content->entries);
314
315 if (content->entries != NULL)
316 {
317 for (i = 0; i < content->num_entries; i++)
318 {
319 VarEntry * ve = content->entries[i];
320 if (ve != NULL)
321 {
322 tifiles_info("Entry #%u %p", i, ve);
323 if (model_supports_folder)
324 {
325 tifiles_info(" folder: %s", ve->folder);
326 }
327 tifiles_info(" name: %s", ticonv_varname_to_utf8_sn(content->model, ve->name, trans, sizeof(trans), ve->type));
328 tifiles_info(" type: %02X (%s)", ve->type, tifiles_vartype2string(content->model, ve->type));
329 tifiles_info(" attr: %s", tifiles_attribute_to_string(ve->attr));
330 tifiles_info(" version: %02X (%u)", ve->version, ve->version);
331 tifiles_info(" length: %04X (%u)", ve->size, ve->size);
332 tifiles_info(" data: %p", ve->data);
333 }
334 else
335 {
336 tifiles_critical("%s: an entry in content is NULL", __FUNCTION__);
337 }
338 }
339 }
340
341 tifiles_info("Checksum: %04X (%u)", content->checksum, content->checksum);
342 tifiles_info("Dest model: %02X (%u)", content->model_dst, content->model_dst);
343
344 return 0;
345 }
346
347 /**
348 * tifiles_content_create_backup:
349 * @model: a calculator model or CALC_NONE.
350 *
351 * Allocates a BackupContent structure.
352 *
353 * Return value: the allocated block.
354 **/
tifiles_content_create_backup(CalcModel model)355 TIEXPORT2 BackupContent* TICALL tifiles_content_create_backup(CalcModel model)
356 {
357 BackupContent* content = g_malloc0(sizeof(BackupContent));
358
359 if (content != NULL)
360 {
361 if ((unsigned int)model >= CALC_MAX)
362 {
363 tifiles_warning("Invalid calculator model");
364 }
365 content->model = model;
366 strncpy(content->comment, tifiles_comment_set_backup(), sizeof(content->comment) - 1);
367 content->comment[sizeof(content->comment) - 1] = 0;
368 }
369
370 #ifdef TRACE_CONTENT_INSTANCES
371 tifiles_info("tifiles_content_create_backup: %p", content);
372 tifiles_file_display_backup(content);
373 #endif
374
375 return content;
376 }
377
378 /**
379 * tifiles_content_delete_backup:
380 *
381 * Free the whole content of a BackupContent structure.
382 *
383 * Return value: none.
384 **/
tifiles_content_delete_backup(BackupContent * content)385 TIEXPORT2 int TICALL tifiles_content_delete_backup(BackupContent *content)
386 {
387 #ifdef TRACE_CONTENT_INSTANCES
388 tifiles_info("tifiles_content_delete_backup: %p", content);
389 tifiles_file_display_backup(content);
390 #endif
391
392 if (content != NULL)
393 {
394 if (tifiles_calc_is_ti9x(content->model))
395 {
396 g_free(content->data_part);
397 }
398 else if (tifiles_calc_is_ti8x(content->model))
399 {
400 g_free(content->data_part1);
401 g_free(content->data_part2);
402 g_free(content->data_part3);
403 g_free(content->data_part4);
404 }
405
406 g_free(content);
407 }
408 else
409 {
410 tifiles_critical("%s(NULL)", __FUNCTION__);
411 }
412
413 return 0;
414 }
415
416 /**
417 * tifiles_file_read_backup:
418 * @filename: name of backup file to open.
419 * @content: where to store the file content.
420 *
421 * Load the backup file into a BackupContent structure.
422 *
423 * Structure content must be freed with #tifiles_content_delete_backup when
424 * no longer used.
425 *
426 * Return value: an error code, 0 otherwise.
427 **/
tifiles_file_read_backup(const char * filename,BackupContent * content)428 TIEXPORT2 int tifiles_file_read_backup(const char *filename, BackupContent *content)
429 {
430 if (filename == NULL || content == NULL)
431 {
432 tifiles_critical("%s: an argument is NULL", __FUNCTION__);
433 return ERR_INVALID_FILE;
434 }
435
436 #if !defined(DISABLE_TI8X)
437 if (tifiles_calc_is_ti8x(tifiles_file_get_model(filename)))
438 {
439 return ti8x_file_read_backup(filename, content);
440 }
441 else
442 #endif
443 #if !defined(DISABLE_TI9X)
444 if (tifiles_calc_is_ti9x(tifiles_file_get_model(filename)))
445 {
446 return ti9x_file_read_backup(filename, content);
447 }
448 else
449 #endif
450 return ERR_BAD_CALC;
451 }
452
453 /**
454 * tifiles_file_write_backup:
455 * @filename: name of backup file where to write.
456 * @content: the file content to write.
457 *
458 * Write backup into file.
459 *
460 * Return value: an error code, 0 otherwise.
461 **/
tifiles_file_write_backup(const char * filename,BackupContent * content)462 TIEXPORT2 int tifiles_file_write_backup(const char *filename, BackupContent *content)
463 {
464 if (filename == NULL || content == NULL)
465 {
466 tifiles_critical("%s: an argument is NULL", __FUNCTION__);
467 return ERR_INVALID_FILE;
468 }
469
470 #if !defined(DISABLE_TI8X)
471 if (tifiles_calc_is_ti8x(content->model))
472 {
473 return ti8x_file_write_backup(filename, content);
474 }
475 else
476 #endif
477 #if !defined(DISABLE_TI9X)
478 if (tifiles_calc_is_ti9x(content->model))
479 {
480 return ti9x_file_write_backup(filename, content);
481 }
482 else
483 #endif
484 return ERR_BAD_CALC;
485 }
486
487 /**
488 * tifiles_file_display_backup:
489 * @content: the file content to show.
490 *
491 * Display file content information.
492 *
493 * Return value: an error code, 0 otherwise.
494 **/
tifiles_file_display_backup(BackupContent * content)495 TIEXPORT2 int TICALL tifiles_file_display_backup(BackupContent *content)
496 {
497 if (content == NULL)
498 {
499 tifiles_critical("%s(NULL)", __FUNCTION__);
500 return ERR_INVALID_FILE;
501 }
502
503 #if !defined(DISABLE_TI8X)
504 if (tifiles_calc_is_ti8x(content->model))
505 {
506 return ti8x_content_display_backup(content);
507 }
508 else
509 #endif
510 #if !defined(DISABLE_TI9X)
511 if (tifiles_calc_is_ti9x(content->model))
512 {
513 return ti9x_content_display_backup(content);
514 }
515 else
516 #endif
517 return ERR_BAD_CALC;
518 }
519
520 /**
521 * tifiles_content_create_flash:
522 * @model: a calculator model (compulsory).
523 *
524 * Allocates a #FlashContent structure.
525 *
526 * Return value: the allocated block.
527 **/
tifiles_content_create_flash(CalcModel model)528 TIEXPORT2 FlashContent* TICALL tifiles_content_create_flash(CalcModel model)
529 {
530 FlashContent* content = g_malloc0(sizeof(FlashContent));
531
532 if (content != NULL)
533 {
534 if ((unsigned int)model >= CALC_MAX)
535 {
536 tifiles_warning("Invalid calculator model");
537 }
538 content->model = content->model_dst = model;
539 if (tifiles_calc_is_ti9x(content->model))
540 {
541 time_t tt;
542 struct tm *lt;
543
544 time(&tt);
545 lt = localtime(&tt);
546 content->revision_major = 1;
547 content->revision_minor = 0;
548 content->flags = 0;
549 content->object_type = 0;
550 content->revision_day = lt->tm_mday;
551 content->revision_month = lt->tm_mon;
552 content->revision_year = lt->tm_year + 1900;
553 }
554 }
555
556 #ifdef TRACE_CONTENT_INSTANCES
557 tifiles_info("tifiles_content_create_flash: %p", content);
558 tifiles_file_display_flash(content);
559 #endif
560
561 return content;
562 }
563
564 /**
565 * tifiles_content_delete_flash:
566 *
567 * Free the whole content of a #FlashContent structure.
568 *
569 * Return value: always 0.
570 **/
tifiles_content_delete_flash(FlashContent * content)571 TIEXPORT2 int TICALL tifiles_content_delete_flash(FlashContent *content)
572 {
573 #ifdef TRACE_CONTENT_INSTANCES
574 tifiles_info("tifiles_content_delete_flash: %p", content);
575 tifiles_file_display_flash(content);
576 #endif
577
578 if (content != NULL)
579 {
580 #if !defined(DISABLE_TI8X) && !defined(DISABLE_TI9X)
581 FlashContent *ptr;
582 unsigned int i;
583
584 g_free(content->data_part);
585
586 ptr = content->next;
587 while (ptr != NULL)
588 {
589 FlashContent *next = ptr->next;
590
591 g_free(ptr->data_part);
592 g_free(ptr);
593
594 for (i = 0; i < content->num_pages; i++)
595 {
596 g_free(content->pages[i]->data);
597 g_free(content->pages[i]);
598 }
599 g_free(content->pages);
600
601 ptr = next;
602 }
603
604 g_free(content);
605 #else
606 return ERR_BAD_CALC;
607 #endif
608 }
609 else
610 {
611 tifiles_critical("%s(NULL)", __FUNCTION__);
612 }
613
614 return 0;
615 }
616
617 /**
618 * tifiles_content_dup_flash:
619 *
620 * Allocates and copies a new FlashContent structure.
621 *
622 * Return value: none.
623 **/
tifiles_content_dup_flash(FlashContent * content)624 TIEXPORT2 FlashContent* TICALL tifiles_content_dup_flash(FlashContent *content)
625 {
626 FlashContent *dup = NULL;
627 FlashContent *p, *q;
628
629 if (content != NULL)
630 {
631 dup = tifiles_content_create_flash(content->model);
632 if (dup != NULL)
633 {
634 for (p = content, q = dup; p; p = p->next, q = q->next)
635 {
636 memcpy(q, p, sizeof(FlashContent));
637
638 // TI-68k or TI-eZ80 part
639 if (tifiles_calc_is_ti9x(content->model) || ticonv_model_is_tiez80(content->model))
640 {
641 if (p->data_part)
642 {
643 q->data_part = (uint8_t *)g_malloc0(p->data_length+1);
644 memcpy(q->data_part, p->data_part, p->data_length+1);
645 }
646 }
647
648 // TI-Z80 part
649 if (tifiles_calc_is_ti8x(content->model))
650 {
651 unsigned int i;
652
653 // copy pages
654 q->pages = tifiles_fp_create_array(p->num_pages);
655 for (i = 0; i < content->num_pages; i++)
656 {
657 q->pages[i] = (FlashPage *)g_malloc0(sizeof(FlashPage));
658 memcpy(q->pages[i], p->pages[i], sizeof(FlashPage));
659
660 q->pages[i]->data = (uint8_t *) g_malloc0(p->pages[i]->size);
661 memcpy(q->pages[i]->data, p->pages[i]->data, p->pages[i]->size);
662 }
663 }
664
665 if (p->next)
666 {
667 q->next = tifiles_content_create_flash(p->model);
668 }
669 }
670 }
671 }
672 else
673 {
674 tifiles_critical("%s(NULL)", __FUNCTION__);
675 }
676
677 #ifdef TRACE_CONTENT_INSTANCES
678 tifiles_info("tifiles_content_dup_flash: %p", dup);
679 tifiles_file_display_flash(dup);
680 #endif
681
682 return dup;
683 }
684
685 /**
686 * tifiles_file_read_flash:
687 * @filename: name of FLASH file to open.
688 * @content: where to store the file content.
689 *
690 * Load the FLASH file into a FlashContent structure.
691 *
692 * Structure content must be freed with #tifiles_content_delete_flash when
693 * no longer used.
694 *
695 * Return value: an error code, 0 otherwise.
696 **/
tifiles_file_read_flash(const char * filename,FlashContent * content)697 TIEXPORT2 int tifiles_file_read_flash(const char *filename, FlashContent *content)
698 {
699 if (filename == NULL || content == NULL)
700 {
701 tifiles_critical("%s: an argument is NULL", __FUNCTION__);
702 return ERR_INVALID_FILE;
703 }
704
705 #if !defined(DISABLE_TI8X)
706 if (tifiles_calc_is_ti8x(tifiles_file_get_model(filename)))
707 {
708 return ti8x_file_read_flash(filename, content);
709 }
710 else
711 #endif
712 #if !defined(DISABLE_TI9X)
713 if (tifiles_calc_is_ti9x(tifiles_file_get_model(filename)) || tifiles_file_is_tib(filename))
714 {
715 return ti9x_file_read_flash(filename, content);
716 }
717 else
718 #endif
719 if (content->model == CALC_NSPIRE)
720 {
721 return tnsp_file_read_flash(filename, content);
722 }
723 else
724 {
725 return ERR_BAD_CALC;
726 }
727 }
728
729 /**
730 * tifiles_file_write_flash2:
731 * @filename: name of flash file where to write or NULL.
732 * @content: the file content to write.
733 * @real_fname: pointer address or NULL. Must be freed if needed when no longer needed.
734 *
735 * Write a FLASH content to a file. If filename is set to NULL, the function build a filename
736 * from appname and allocates resulting filename in %real_fname.
737 * %filename and %real_fname can be NULL but not both !
738 *
739 * %real_fname must be freed when no longer used.
740 *
741 * Return value: an error code, 0 otherwise.
742 **/
tifiles_file_write_flash2(const char * filename,FlashContent * content,char ** real_fname)743 TIEXPORT2 int tifiles_file_write_flash2(const char *filename, FlashContent *content, char **real_fname)
744 {
745 if (content == NULL || (filename == NULL && real_fname == NULL))
746 {
747 tifiles_critical("%s: an argument is NULL", __FUNCTION__);
748 return ERR_INVALID_FILE;
749 }
750
751 #if !defined(DISABLE_TI8X)
752 if (tifiles_calc_is_ti8x(content->model))
753 {
754 return ti8x_file_write_flash(filename, content, real_fname);
755 }
756 else
757 #endif
758 #if !defined(DISABLE_TI9X)
759 if (tifiles_calc_is_ti9x(content->model))
760 {
761 return ti9x_file_write_flash(filename, content, real_fname);
762 }
763 else
764 #endif
765 return ERR_BAD_CALC;
766 }
767
768 /**
769 * tifiles_file_write_flash:
770 * @filename: name of flash file where to write or NULL.
771 * @content: the file content to write.
772 *
773 * Write a FLASH content to a file. If filename is set to NULL, the function build a filename
774 * from appname.
775 *
776 * Return value: an error code, 0 otherwise.
777 **/
tifiles_file_write_flash(const char * filename,FlashContent * content)778 TIEXPORT2 int tifiles_file_write_flash(const char *filename, FlashContent *content)
779 {
780 return tifiles_file_write_flash2(filename, content, NULL);
781 }
782
783 /**
784 * tifiles_file_display_flash:
785 * @content: the file content to show.
786 *
787 * Display file content information.
788 *
789 * Return value: an error code, 0 otherwise.
790 **/
tifiles_file_display_flash(FlashContent * content)791 TIEXPORT2 int TICALL tifiles_file_display_flash(FlashContent *content)
792 {
793 if (content == NULL)
794 {
795 tifiles_critical("%s(NULL)", __FUNCTION__);
796 return ERR_INVALID_FILE;
797 }
798
799 #if !defined(DISABLE_TI8X)
800 if (tifiles_calc_is_ti8x(content->model))
801 {
802 return ti8x_content_display_flash(content);
803 }
804 else
805 #endif
806 #if !defined(DISABLE_TI9X)
807 if (tifiles_calc_is_ti9x(content->model))
808 {
809 return ti9x_content_display_flash(content);
810 }
811 else
812 #endif
813 return ERR_BAD_CALC;
814 }
815
816 /**
817 * tifiles_file_display:
818 * @filename: a TI file.
819 *
820 * Determine file class and display internal content.
821 *
822 * Return value: an error code, 0 otherwise.
823 **/
tifiles_file_display(const char * filename)824 TIEXPORT2 int TICALL tifiles_file_display(const char *filename)
825 {
826 if (tifiles_file_is_tigroup(filename))
827 {
828 return tifiles_file_display_tigroup(filename);
829 }
830 #if !defined(DISABLE_TI8X)
831 if (tifiles_calc_is_ti8x(tifiles_file_get_model(filename)))
832 {
833 return ti8x_file_display(filename);
834 }
835 else
836 #endif
837 #if !defined(DISABLE_TI9X)
838 if (tifiles_calc_is_ti9x(tifiles_file_get_model(filename)))
839 {
840 return ti9x_file_display(filename);
841 }
842 else
843 #endif
844 return ERR_BAD_CALC;
845 }
846
847 /*****************/
848 /* Miscellaneous */
849 /*****************/
850
851 /**
852 * tifiles_create_table_of_entries:
853 * @content: a TI file content structure.
854 * @nfolders: returns the number of folders in the file.
855 *
856 * The goal of this function is to parse the file content structure in order to build
857 * a table of entries so that it's easy to write it just after the header in a group
858 * file. Mainly used as an helper.
859 * The returned 'table' is an NULL-terminated array of int* pointers.
860 * Each pointers points on an integer array. Each cell are an index on the 'VarEntry*
861 * entries' array.
862 *
863 * In fact, this array represents a kind of tree. The array of pointer is the folder list
864 * and each pointer is the variable list for each folder.
865 * For accessing the entry, we use the index.
866 *
867 * This function may be difficult to understand but it avoids to use trees (and
868 * linked list) which will require an implementation.
869 *
870 * Return value: a 2-dimensions allocated integer array. Must be freed with tifiles_free_table_of_entries when
871 * no longer used.
872 **/
tifiles_create_table_of_entries(FileContent * content,unsigned int * nfolders)873 TIEXPORT2 int** tifiles_create_table_of_entries(FileContent *content, unsigned int *nfolders)
874 {
875 unsigned int num_folders = 0;
876 unsigned int i, j;
877 char **ptr, *folder_list[32768] = { 0 };
878 int **table;
879
880 if (content == NULL)
881 {
882 tifiles_critical("%s: an argument is NULL", __FUNCTION__);
883 return NULL;
884 }
885
886 if (content->entries != NULL)
887 {
888 // determine how many folders we have
889 for (i = 0; i < content->num_entries; i++)
890 {
891 VarEntry *entry = content->entries[i];
892
893 // scan for an existing folder entry
894 for (ptr = folder_list; *ptr != NULL; ptr++)
895 {
896 if (!strcmp(*ptr, entry->folder))
897 {
898 //printf("break: %s\n", entry->folder);
899 break;
900 }
901 }
902 if (*ptr == NULL)
903 { // add new folder entry
904 folder_list[num_folders] = (char *) g_malloc0(257);
905 //printf("%i: adding '%s'\n", num_folders, entry->folder);
906 strncpy(folder_list[num_folders], entry->folder, sizeof(folder_list[num_folders]) - 1);
907 folder_list[num_folders][sizeof(folder_list[num_folders]) - 1] = 0;
908 folder_list[num_folders + 1] = NULL;
909 num_folders++;
910 }
911 }
912 if (tifiles_calc_is_ti8x(content->model))
913 {
914 num_folders++;
915 }
916 }
917 if (nfolders != NULL)
918 {
919 *nfolders = num_folders;
920 }
921
922 // allocate the folder list
923 table = (int **) g_malloc0((num_folders + 1) * sizeof(int *));
924 table[num_folders] = NULL;
925
926 // for each folder, determine how many variables we have
927 // and allocate array with indexes
928 for (j = 0; j < num_folders; j++)
929 {
930 int k;
931
932 for (i = 0, k = 0; i < content->num_entries; i++)
933 {
934 VarEntry *entry = content->entries[i];
935
936 if (!strcmp(folder_list[j], entry->folder))
937 {
938 table[j] = (int *) g_realloc(table[j], (k + 2) * sizeof(int));
939 table[j][k] = i;
940 //printf("%i %i: adding %i\n", j, k, i);
941 table[j][k + 1] = -1;
942 k++;
943 }
944 }
945 }
946
947 // g_free( memory
948 for (j = 0; j < num_folders + 1; j++)
949 {
950 g_free(folder_list[j]);
951 }
952
953 return table;
954 }
955
tifiles_free_table_of_entries(int ** table)956 TIEXPORT2 void tifiles_free_table_of_entries(int ** table)
957 {
958 if (table != NULL)
959 {
960 int ** ptr = table;
961 while (*ptr != NULL)
962 {
963 g_free(*ptr);
964 ptr++;
965 }
966 g_free(table);
967 }
968 }
969