1 /* Hey EMACS -*- linux-c -*- */
2 /* $Id: typesxx.c 912 2005-03-30 20:49:06Z roms $ */
3 
4 /*  libtifiles - file format library, a part of the TiLP project
5  *  Copyright (C) 1999-2005  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 #include <ctype.h>
23 #include <glib/gstdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "gettext.h"
28 #include "tifiles.h"
29 #include "logging.h"
30 #include "internal.h"
31 #include "typesxx.h"
32 #include "error.h"
33 #include "rwfile.h"
34 
35 // Whether to enable strict file extension checking.
36 #define CHECK_FILE_EXTENSIONS
37 
38 /****************/
39 /* Global types */
40 /****************/
41 
42 static const char GROUP_FILE_EXT[CALC_MAX + 1][4] =
43 {
44 	"",
45 	"73g", "82g", "83g", "8Xg", "8Xg", "85g", "86g",
46 	"89g", "89g", "92g", "9Xg", "V2g", "8Xg", "89g",
47 	"",    "",    "8Xg", "8Xg", "8Xg", "8Xg", "8Xg",
48 	"8xg",
49 	""
50 };
51 
52 static const char BACKUP_FILE_EXT[CALC_MAX + 1][4] =
53 {
54 	"",
55 	"73b", "82b", "83b", "8Xb", "8Xb", "85b", "86b",
56 	"89g", "89g", "92b", "9Xg", "V2g", "8Xg", "89g",
57 	"",    "",    "8Cb", "8Cb", "",    "",    "8Xb",
58 	"8Xb",
59 	""
60 };
61 
62 /*******************/
63 /* File extensions */
64 /*******************/
65 
66 /**
67  * tifiles_fext_of_group:
68  * @model: a calculator model.
69  *
70  * Returns file extension of a group file.
71  *
72  * Return value: a file extension as string (like "83g").
73  **/
tifiles_fext_of_group(CalcModel model)74 TIEXPORT2 const char * TICALL tifiles_fext_of_group (CalcModel model)
75 {
76 	switch (model)
77 	{
78 		case CALC_NONE:
79 			return NULL;
80 		case CALC_TI73:
81 			return "73g";
82 		case CALC_TI80:
83 			return NULL;
84 		case CALC_TI82:
85 			return "82g";
86 		case CALC_TI83:
87 			return "83g";
88 		case CALC_TI83P:
89 		case CALC_TI84P:
90 		case CALC_TI84PC:
91 		case CALC_TI84P_USB:
92 		case CALC_TI84PC_USB:
93 		case CALC_TI83PCE_USB:
94 		case CALC_TI84PCE_USB:
95 		case CALC_TI82A_USB:
96 		case CALC_TI84PT_USB:
97 			return "8Xg"; // There's also 8Cg.
98 		case CALC_TI85:
99 			return "85g";
100 		case CALC_TI86:
101 			return "86g";
102 		case CALC_TI89:
103 		case CALC_TI89T:
104 		case CALC_TI89T_USB:
105 			return "89g";
106 		case CALC_TI92:
107 			return "92g";
108 		case CALC_TI92P:
109 			return "9Xg";
110 		case CALC_V200:
111 			return "V2g";
112 		case CALC_NSPIRE:
113 			return NULL;
114 		default:
115 			tifiles_critical("%s: invalid model argument", __FUNCTION__);
116 			break;
117 	}
118 
119 	return NULL;
120 }
121 
122 /**
123  * tifiles_fext_of_backup:
124  * @model: a calculator model.
125  *
126  * Returns file extension of a backup file.
127  *
128  * Return value: a file extension as string (like "83b").
129  **/
tifiles_fext_of_backup(CalcModel model)130 TIEXPORT2 const char * TICALL tifiles_fext_of_backup (CalcModel model)
131 {
132 	switch (model)
133 	{
134 		case CALC_NONE:
135 			return "??b";
136 		case CALC_TI73:
137 			return "73b";
138 		case CALC_TI80:
139 			return NULL;
140 		case CALC_TI82:
141 			return "82b";
142 		case CALC_TI83:
143 			return "83b";
144 		case CALC_TI83P:
145 		case CALC_TI84P:
146 		case CALC_TI84P_USB:
147 		case CALC_TI82A_USB:
148 		case CALC_TI84PT_USB:
149 			return "8Xb";
150 		case CALC_TI84PC:
151 		case CALC_TI84PC_USB:
152 			return "8Cb";
153 		case CALC_TI83PCE_USB:
154 		case CALC_TI84PCE_USB:
155 			return NULL;
156 		case CALC_TI85:
157 			return "85b";
158 		case CALC_TI86:
159 			return "86b";
160 		case CALC_TI89:
161 		case CALC_TI89T:
162 		case CALC_TI89T_USB:
163 			return "89g";
164 		case CALC_TI92:
165 			return "92b";
166 		case CALC_TI92P:
167 			return "9Xg";
168 		case CALC_V200:
169 			return "V2g";
170 		case CALC_NSPIRE:
171 			return NULL;
172 		default:
173 			tifiles_critical("%s: invalid model argument", __FUNCTION__);
174 			break;
175 	}
176 
177 	return NULL;
178 }
179 
180 /**
181  * tifiles_fext_of_flash_app:
182  * @model: a calculator model.
183  *
184  * Returns file extension of a FLASH application file.
185  *
186  * Return value: a file extension as string (like "89k").
187  **/
tifiles_fext_of_flash_app(CalcModel model)188 TIEXPORT2 const char * TICALL tifiles_fext_of_flash_app (CalcModel model)
189 {
190 	switch (model)
191 	{
192 		case CALC_NONE:
193 			return "??k";
194 		case CALC_TI73:
195 			return "73k";
196 		case CALC_TI80:
197 			return NULL;
198 		case CALC_TI82:
199 			return NULL;
200 		case CALC_TI83:
201 			return NULL;
202 		case CALC_TI83P:
203 		case CALC_TI84P:
204 		case CALC_TI84P_USB:
205 			return "8Xk";
206 		case CALC_TI84PC:
207 		case CALC_TI84PC_USB:
208 			return "8Ck";
209 		case CALC_TI83PCE_USB:
210 			return "8Ek";
211 		case CALC_TI84PCE_USB:
212 			return "8Ek";
213 		case CALC_TI82A_USB:
214 		case CALC_TI84PT_USB:
215 			return NULL;
216 		case CALC_TI85:
217 			return NULL;
218 		case CALC_TI86:
219 			return NULL;
220 		case CALC_TI89:
221 		case CALC_TI89T:
222 		case CALC_TI89T_USB:
223 			return "89k";
224 		case CALC_TI92:
225 			return NULL;
226 		case CALC_TI92P:
227 			return "9Xk";
228 		case CALC_V200:
229 			return "V2k";
230 		case CALC_NSPIRE:
231 			return NULL;
232 		default:
233 			tifiles_critical("%s: invalid model argument", __FUNCTION__);
234 			break;
235 	}
236 
237 	return NULL;
238 }
239 
240 /**
241  * tifiles_fext_of_flash_os:
242  * @model: a calculator model.
243  *
244  * Returns file extension of a FLASH Operating System file.
245  *
246  * Return value: a file extension as string (like "89u").
247  **/
tifiles_fext_of_flash_os(CalcModel model)248 TIEXPORT2 const char * TICALL tifiles_fext_of_flash_os(CalcModel model)
249 {
250 	switch (model)
251 	{
252 		case CALC_NONE:
253 			return NULL;
254 		case CALC_TI73:
255 			return "73u";
256 		case CALC_TI80:
257 			return NULL;
258 		case CALC_TI82:
259 			return NULL;
260 		case CALC_TI83:
261 			return NULL;
262 		case CALC_TI83P:
263 		case CALC_TI84P:
264 		case CALC_TI84P_USB:
265 			return "8Xu";
266 		case CALC_TI84PC:
267 		case CALC_TI84PC_USB:
268 			return "8Cu";
269 		case CALC_TI83PCE_USB:
270 			return "8Pu";
271 		case CALC_TI84PCE_USB:
272 			return "8Eu";
273 		case CALC_TI82A_USB:
274 			return "82u";
275 		case CALC_TI84PT_USB:
276 			return "8Xu";
277 		case CALC_TI85:
278 			return NULL;
279 		case CALC_TI86:
280 			return NULL;
281 		case CALC_TI89:
282 		case CALC_TI89T:
283 		case CALC_TI89T_USB:
284 			return "89u";
285 		case CALC_TI92:
286 			return NULL;
287 		case CALC_TI92P:
288 			return "9Xu";
289 		case CALC_V200:
290 			return "V2u";
291 		case CALC_NSPIRE:
292 			return "tno"; // Actually, it depends on the sub-model...
293 		default:
294 			tifiles_critical("%s: invalid model argument", __FUNCTION__);
295 			break;
296 	}
297 
298 	return NULL;
299 }
300 
301 /**
302  * tifiles_fext_of_certif:
303  * @model: a calculator model.
304  *
305  * Returns file extension of certificate file.
306  *
307  * Return value: a file extension as string (like "89q").
308  **/
tifiles_fext_of_certif(CalcModel model)309 TIEXPORT2 const char * TICALL tifiles_fext_of_certif(CalcModel model)
310 {
311 	switch (model)
312 	{
313 		case CALC_NONE:
314 			return "??q";
315 		case CALC_TI73:
316 			return "73q";
317 		case CALC_TI80:
318 			return NULL;
319 		case CALC_TI82:
320 			return NULL;
321 		case CALC_TI83:
322 			return NULL;
323 		case CALC_TI83P:
324 		case CALC_TI84P:
325 		case CALC_TI84P_USB:
326 			return "8Xq";
327 		case CALC_TI84PC:
328 		case CALC_TI84PC_USB:
329 			return "8Cq";
330 		case CALC_TI83PCE_USB:
331 			return "8Pq";
332 		case CALC_TI84PCE_USB:
333 			return "8Eq";
334 		case CALC_TI82A_USB:
335 		case CALC_TI84PT_USB:
336 			return NULL;
337 		case CALC_TI85:
338 			return NULL;
339 		case CALC_TI86:
340 			return NULL;
341 		case CALC_TI89:
342 		case CALC_TI89T:
343 		case CALC_TI89T_USB:
344 			return "89q";
345 		case CALC_TI92:
346 			return NULL;
347 		case CALC_TI92P:
348 			return "9Xq";
349 		case CALC_V200:
350 			return "V2q";
351 		case CALC_NSPIRE:
352 			return NULL;
353 		default:
354 			tifiles_critical("%s: invalid calc_type argument", __FUNCTION__);
355 			break;
356 	}
357 
358 	return NULL;
359 }
360 
361 /**
362  * tifiles_fext_get:
363  * @filename: a filename as string.
364  *
365  * Returns file extension part.
366  *
367  * Return value: a file extension without dot as string (like "89g").
368  **/
tifiles_fext_get(const char * filename)369 TIEXPORT2 char * TICALL tifiles_fext_get(const char *filename)
370 {
371 	if (filename != NULL)
372 	{
373 		char * d = strrchr(filename, '.');
374 		if (d != NULL)
375 		{
376 			return (++d);
377 		}
378 	}
379 	else
380 	{
381 		tifiles_critical("%s(NULL)", __FUNCTION__);
382 	}
383 
384 	return (char *)"";
385 }
386 
387 /**
388  * tifiles_fext_dup:
389  * @filename: a filename as string.
390  *
391  * Returns a copy of file extension part.
392  *
393  * Return value: a file extension without dot as string (like "89g").
394  * Needs to be freed with tifiles_fext_free() when no longer needed.
395  **/
tifiles_fext_dup(const char * filename)396 TIEXPORT2 char * TICALL tifiles_fext_dup(const char *filename)
397 {
398 	return g_strdup(tifiles_fext_get(filename));
399 }
400 
401 /**
402  * tifiles_fext_free:
403  * @filename: a filename as string.
404  *
405  * Frees a file extension part previously allocated with tifiles_fext_dup().
406  **/
tifiles_fext_free(char * filename)407 TIEXPORT2 void TICALL tifiles_fext_free(char *filename)
408 {
409 	g_free(filename);
410 }
411 
412 /**********************/
413 /* Signature checking */
414 /**********************/
415 
416 /**
417  * tifiles_file_has_ti_header:
418  * @filename: a filename as string.
419  *
420  * Check whether file has a TI magic number in the header.
421  *
422  * Return value: a boolean value.
423  **/
tifiles_file_has_ti_header(const char * filename)424 TIEXPORT2 int TICALL tifiles_file_has_ti_header(const char *filename)
425 {
426 	FILE *f;
427 	char buf[9];
428 	char *p;
429 	int ret = 0;
430 
431 	if (filename != NULL)
432 	{
433 		f = g_fopen(filename, "rb");
434 		if (f != NULL)
435 		{
436 			memset(buf, 0, sizeof(buf));
437 			if (fread_8_chars(f, buf) == 0)
438 			{
439 				for (p = buf; *p != '\0'; p++)
440 				{
441 					*p = toupper(*p);
442 				}
443 
444 				if (!strcmp(buf, "**TI73**") || !strcmp(buf, "**TI82**") ||
445 				    !strcmp(buf, "**TI83**") || !strcmp(buf, "**TI83F*") ||
446 				    !strcmp(buf, "**TI85**") || !strcmp(buf, "**TI86**") ||
447 				    !strcmp(buf, "**TI89**") || !strcmp(buf, "**TI92**") ||
448 				    !strcmp(buf, "**TI92P*") || !strcmp(buf, "**V200**") ||
449 				    !strcmp(buf, "**TIFL**") ||
450 				    !strncmp(buf, "*TI", 3))
451 				{
452 					ret = !0;
453 				}
454 			}
455 			fclose(f);
456 		}
457 	}
458 
459 	return ret;
460 }
461 
462 #define TIB_SIGNATURE	"Advanced Mathematics Software"
463 
464 /**
465  * tifiles_file_has_tib_header:
466  * @filename: a filename as string.
467  *
468  * Check whether file has a TIB magic number in the header.
469  *
470  * Return value: a boolean value.
471  **/
tifiles_file_has_tib_header(const char * filename)472 TIEXPORT2 int TICALL tifiles_file_has_tib_header(const char *filename)
473 {
474 	FILE *f;
475 	char str[64];
476 	int ret = 0;
477 
478 	if (filename != NULL)
479 	{
480 #ifdef CHECK_FILE_EXTENSIONS
481 		char *e = tifiles_fext_get(filename);
482 
483 		if (   e[0] == 0
484 		    || g_ascii_strcasecmp(e, "tib"))
485 		{
486 			return 0;
487 		}
488 #endif
489 
490 		f = g_fopen(filename, "rb");
491 		if (f != NULL)
492 		{
493 			if (fread_n_chars(f, 22 + sizeof(TIB_SIGNATURE) + 1, str) == 0)
494 			{
495 				str[22 + sizeof(TIB_SIGNATURE) + 1] = '\0';
496 				if (!strcmp(str + 22, TIB_SIGNATURE))
497 				{
498 					ret = !0;
499 				}
500 			}
501 			fclose(f);
502 		}
503 	}
504 
505 	return ret;
506 }
507 
508 #define TIG_SIGNATURE	"PK\x03\x04"	// 0x04034b50
509 #define TIG_SIGNATURE2	"PK\x05\x06"	// 0x06054b50
510 
511 /**
512  * tifiles_file_has_tig_header:
513  * @filename: a filename as string.
514  *
515  * Check whether file has a ZIP file header.
516  *
517  * Return value: a boolean value.
518  **/
tifiles_file_has_tig_header(const char * filename)519 TIEXPORT2 int TICALL tifiles_file_has_tig_header(const char *filename)
520 {
521 	FILE *f;
522 	char str[5];
523 	int ret = 0;
524 
525 	if (filename != NULL)
526 	{
527 #ifdef CHECK_FILE_EXTENSIONS
528 		char *e = tifiles_fext_get(filename);
529 
530 		if (   e[0] == 0
531 		    || g_ascii_strcasecmp(e, "tig"))
532 		{
533 			return 0;
534 		}
535 #endif
536 
537 		f = g_fopen(filename, "rb");
538 		if (f != NULL)
539 		{
540 			if (fread_n_chars(f, strlen(TIG_SIGNATURE), str) == 0)
541 			{
542 				str[strlen(TIG_SIGNATURE)] = '\0';
543 				if (!strcmp(str, TIG_SIGNATURE) || !strcmp(str, TIG_SIGNATURE2))
544 				{
545 					ret = !0;
546 				}
547 			}
548 			fclose(f);
549 		}
550 	}
551 
552 	return ret;
553 }
554 
555 /**
556  * tifiles_file_has_tifl_header:
557  * @filename: a filename as string.
558  *
559  * Check whether file has a TI Flash file magic number in the header, and
560  * fill device type and data type for the last entry in the file.
561  *
562  * Return value: a boolean value.
563  **/
tifiles_file_has_tifl_header(const char * filename,uint8_t * dev_type,uint8_t * data_type)564 TIEXPORT2 int TICALL tifiles_file_has_tifl_header(const char *filename, uint8_t *dev_type, uint8_t *data_type)
565 {
566 	FILE *f;
567 	uint8_t buf[78];
568 	uint32_t len;
569 	int ret = 0;
570 
571 	if (filename != NULL)
572 	{
573 		f = g_fopen(filename, "rb");
574 		if (f != NULL)
575 		{
576 			while (fread(buf, 1, 78, f) == 78)
577 			{
578 				if (strncmp((char *) buf, "**TIFL**", 8))
579 				{
580 					break;
581 				}
582 
583 				ret = 1;
584 
585 				/* if there are multiple entries (old OS files with license
586 				   agreement, old app files with certificate), return the type
587 				   of the last entry */
588 				if (dev_type != NULL)
589 				{
590 					*dev_type = buf[48];
591 				}
592 				if (data_type != NULL)
593 				{
594 					*data_type = buf[49];
595 				}
596 
597 				len = buf[74] | (((uint32_t)buf[75]) << 8) | (((uint32_t)buf[76]) << 16) | (((uint32_t)buf[77]) << 24);
598 				if (fseek(f, len, SEEK_CUR))
599 				{
600 					break;
601 				}
602 			}
603 
604 			fclose(f);
605 		}
606 	}
607 
608 	return ret;
609 }
610 
611 #define TNO_SIGNATURE           "TI-Nspire.tno "
612 #define TNO_NOSAMPLES_SIGNATURE "TI-Nspire.nosamples.tno "
613 #define TNC_SIGNATURE           "TI-Nspire.tnc "
614 #define TCO_SIGNATURE           "TI-Nspire.tco "
615 #define TCC_SIGNATURE           "TI-Nspire.tcc "
616 #define TMO_SIGNATURE           "TI-Nspire.tmo "
617 #define TMC_SIGNATURE           "TI-Nspire.tmc "
618 #define OSEXT1_SIGNATURE        "__OSEXT__1 "
619 
620 /**
621  * tifiles_file_has_tno_header:
622  * @filename: a filename as string.
623  *
624  * Check whether file has a Nspire OS / OS extension file header.
625  *
626  * Return value: a boolean value.
627  **/
tifiles_file_has_tno_header(const char * filename)628 TIEXPORT2 int TICALL tifiles_file_has_tno_header(const char *filename)
629 {
630 	FILE *f;
631 	char str[128];
632 	int ret = 0;
633 
634 	if (filename != NULL)
635 	{
636 #ifdef CHECK_FILE_EXTENSIONS
637 		char *e = tifiles_fext_get(filename);
638 
639 		if (   e[0] == 0
640 		    || (   g_ascii_strcasecmp(e, "tno") && g_ascii_strcasecmp(e, "tnc")
641 			&& g_ascii_strcasecmp(e, "tco") && g_ascii_strcasecmp(e, "tcc")
642 			&& g_ascii_strcasecmp(e, "tmo") && g_ascii_strcasecmp(e, "tmc")
643 		       )
644 		   )
645 		{
646 			return 0;
647 		}
648 #endif
649 
650 		f = g_fopen(filename, "rb");
651 		if (f != NULL)
652 		{
653 			if (fread_n_chars(f, 63, str) == 0)
654 			{
655 				if (   !strncmp(str, TNO_SIGNATURE, 14)
656 				    || !strncmp(str, TNC_SIGNATURE, 14)
657 				    || !strncmp(str, TNO_NOSAMPLES_SIGNATURE, 24)
658 				    || !strncmp(str, TCO_SIGNATURE, 14)
659 				    || !strncmp(str, TCC_SIGNATURE, 14)
660 				    || !strncmp(str, TMO_SIGNATURE, 14)
661 				    || !strncmp(str, TMC_SIGNATURE, 14)
662 				    || !strncmp(str, OSEXT1_SIGNATURE, 11)
663 				   )
664 				{
665 					ret = !0;
666 				}
667 			}
668 
669 			fclose(f);
670 		}
671 	}
672 
673 	return ret;
674 }
675 
676 /**
677  * tifiles_model_to_dev_type:
678  * @model: a calculator model
679  *
680  * Converts the calculator model to FlashApp DeviceType.
681  *
682  * Return value: FlashApp DeviceType if that calculator model supports FlashApps, -1 otherwise.
683  **/
tifiles_model_to_dev_type(CalcModel model)684 TIEXPORT2 int TICALL tifiles_model_to_dev_type(CalcModel model)
685 {
686 	switch (model) {
687 	case CALC_TI73:
688 		return DEVICE_TYPE_73;
689 
690 	case CALC_TI83P:
691 	case CALC_TI84P:
692 	case CALC_TI84P_USB:
693 	case CALC_TI84PC:
694 	case CALC_TI84PC_USB:
695 	case CALC_TI83PCE_USB:
696 	case CALC_TI84PCE_USB:
697 	case CALC_TI82A_USB:
698 	case CALC_TI84PT_USB:
699 		return DEVICE_TYPE_83P;
700 
701 	case CALC_TI89:
702 	case CALC_TI89T:
703 	case CALC_TI89T_USB:
704 		return DEVICE_TYPE_89;
705 
706 	case CALC_TI92P:
707 	case CALC_V200:
708 		return DEVICE_TYPE_92P;
709 
710 	default:
711 		return -1;
712 	}
713 }
714 
715 
716 /**************/
717 /* File types */
718 /**************/
719 
720 #ifndef __WIN32__
721 #include <sys/types.h>
722 #include <sys/stat.h>
723 #include <unistd.h>
724 #endif
725 
is_regfile(const char * filename)726 static int is_regfile(const char *filename)
727 {
728 #ifndef __WIN32__
729 	struct stat buf;
730 
731 	if (stat(filename, &buf) < 0)
732 	{
733 		return 0;
734 	}
735 
736 	if (S_ISREG(buf.st_mode))
737 	{
738 		return !0;
739 	}
740 	else
741 	{
742 		return 0;
743 	}
744 #else
745 	return !0;
746 #endif
747 }
748 
749 /**
750  * tifiles_file_is_ti:
751  * @filename: a filename as string.
752  *
753  * Check whether file is a TI file by checking the signature.
754  *
755  * Return value: a boolean value.
756  **/
tifiles_file_is_ti(const char * filename)757 TIEXPORT2 int TICALL tifiles_file_is_ti(const char *filename)
758 {
759 	char *e;
760 
761 	if (filename != NULL)
762 	{
763 		// bug: check that file is not a FIFO
764 		if (!is_regfile(filename))
765 		{
766 			return 0;
767 		}
768 
769 		if (   tifiles_file_has_ti_header(filename)
770 		    || tifiles_file_has_tib_header(filename)
771 		    || tifiles_file_has_tig_header(filename)
772 		    || tifiles_file_has_tifl_header(filename, NULL, NULL)
773 		    || tifiles_file_has_tno_header(filename))
774 		{
775 			return !0;
776 		}
777 
778 		e = tifiles_fext_get(filename);
779 
780 #ifdef CHECK_FILE_EXTENSIONS
781 		if (e[0] == 0)
782 		{
783 			return 0;
784 		}
785 #endif
786 
787 		if (!g_ascii_strcasecmp(e, "tns"))
788 		{
789 			return !0;
790 		}
791 	}
792 	else
793 	{
794 		tifiles_critical("%s(NULL)", __FUNCTION__);
795 	}
796 
797 	return 0;
798 }
799 
800 /**
801  * tifiles_file_is_single:
802  * @filename: a filename as string.
803  *
804  * Check whether file is a single TI file (like program, function, ...).
805  *
806  * Return value: a boolean value.
807  **/
tifiles_file_is_single(const char * filename)808 TIEXPORT2 int TICALL tifiles_file_is_single(const char *filename)
809 {
810 	if (!tifiles_file_is_ti(filename))
811 	{
812 		return 0;
813 	}
814 
815 	if (!tifiles_file_is_group(filename) &&
816 	    !tifiles_file_is_backup(filename) &&
817 	    !tifiles_file_is_flash(filename) &&
818 	    !tifiles_file_is_tigroup(filename))
819 	{
820 		return !0;
821 	}
822 
823 	return 0;
824 }
825 
826 /**
827  * tifiles_file_is_group:
828  * @filename: a filename as string.
829  *
830  * Check whether file is a group file.
831  *
832  * Return value: a boolean value.
833  **/
tifiles_file_is_group(const char * filename)834 TIEXPORT2 int TICALL tifiles_file_is_group(const char *filename)
835 {
836 	int i;
837 	char *e = tifiles_fext_get(filename);
838 
839 #ifdef CHECK_FILE_EXTENSIONS
840 	if (e[0] == 0)
841 	{
842 		return 0;
843 	}
844 #endif
845 	if (!tifiles_file_is_ti(filename))
846 	{
847 		return 0;
848 	}
849 
850 	for (i = 1; i < CALC_MAX + 1; i++)
851 	{
852 		if (GROUP_FILE_EXT[i][0] != 0 && !g_ascii_strcasecmp(e, GROUP_FILE_EXT[i]))
853 		{
854 			return !0;
855 		}
856 	}
857 
858 	return 0;
859 }
860 
861 /**
862  * tifiles_file_is_regular:
863  * @filename: a filename as string.
864  *
865  * Check whether file is a single or group file.
866  *
867  * Return value: a boolean value.
868  **/
tifiles_file_is_regular(const char * filename)869 TIEXPORT2 int TICALL tifiles_file_is_regular(const char *filename)
870 {
871 	if (!tifiles_file_is_ti(filename))
872 	{
873 		return 0;
874 	}
875 
876 	return (tifiles_file_is_single(filename) || tifiles_file_is_group(filename));
877 }
878 
879 /**
880  * tifiles_file_is_backup:
881  * @filename: a filename as string.
882  *
883  * Check whether file is a backup file.
884  *
885  * Return value: a boolean value.
886  **/
tifiles_file_is_backup(const char * filename)887 TIEXPORT2 int TICALL tifiles_file_is_backup(const char *filename)
888 {
889 	int i;
890 	char *e = tifiles_fext_get(filename);
891 
892 #ifdef CHECK_FILE_EXTENSIONS
893 	if (e[0] == 0)
894 	{
895 		return 0;
896 	}
897 #endif
898 	if (!tifiles_file_is_ti(filename))
899 	{
900 		return 0;
901 	}
902 
903 	for (i = 1; i < CALC_MAX + 1; i++)
904 	{
905 		if (BACKUP_FILE_EXT[i][0] != 0 && !g_ascii_strcasecmp(e, BACKUP_FILE_EXT[i]))
906 		{
907 			return !0;
908 		}
909 	}
910 
911 	return 0;
912 }
913 
914 /**
915  * tifiles_file_is_os:
916  * @filename: a filename as string.
917  *
918  * Check whether file is a FLASH OS file (tib or XXu)
919  *
920  * Return value: a boolean value.
921  **/
tifiles_file_is_os(const char * filename)922 TIEXPORT2 int TICALL tifiles_file_is_os(const char *filename)
923 {
924 	uint8_t type;
925 
926 	if (!tifiles_file_is_ti(filename))
927 	{
928 		return 0;
929 	}
930 
931 	if (   tifiles_file_is_tib(filename)
932 	    || tifiles_file_is_tno(filename)
933 	    || (tifiles_file_has_tifl_header(filename, NULL, &type) && type == TI83p_AMS))
934 	{
935 		return !0;
936 	}
937 
938 	return 0;
939 }
940 
941 /**
942  * tifiles_file_is_app:
943  * @filename: a filename as string.
944  *
945  * Check whether file is a FLASH app file
946  *
947  * Return value: a boolean value.
948  **/
tifiles_file_is_app(const char * filename)949 TIEXPORT2 int TICALL tifiles_file_is_app(const char *filename)
950 {
951 	uint8_t type;
952 
953 	if (!tifiles_file_is_ti(filename))
954 	{
955 		return 0;
956 	}
957 
958 	if (tifiles_file_has_tifl_header(filename, NULL, &type) && type == TI83p_APPL)
959 	{
960 		return !0;
961 	}
962 
963 	return 0;
964 }
965 
966 /**
967  * tifiles_file_is_flash:
968  * @filename: a filename as string.
969  *
970  * Check whether file is a FLASH file (os or app).
971  *
972  * Return value: a boolean value.
973  **/
tifiles_file_is_flash(const char * filename)974 TIEXPORT2 int TICALL tifiles_file_is_flash(const char *filename)
975 {
976 	return (tifiles_file_is_tib(filename) ||
977 	        tifiles_file_is_tno(filename) ||
978 	        tifiles_file_has_tifl_header(filename, NULL, NULL));
979 }
980 
981 /**
982  * tifiles_file_is_tib:
983  * @filename: a filename as string.
984  *
985  * Check whether file is a TIB formatted file.
986  *
987  * Return value: a boolean value.
988  **/
tifiles_file_is_tib(const char * filename)989 TIEXPORT2 int TICALL tifiles_file_is_tib(const char *filename)
990 {
991 	return tifiles_file_has_tib_header(filename);
992 }
993 
994 /**
995  * tifiles_file_is_tigroup:
996  * @filename: a filename as string.
997  *
998  * Check whether file is a TiGroup formatted file.
999  *
1000  * Return value: a boolean value.
1001  **/
tifiles_file_is_tigroup(const char * filename)1002 TIEXPORT2 int TICALL tifiles_file_is_tigroup(const char *filename)
1003 {
1004 	return tifiles_file_has_tig_header(filename);
1005 }
1006 
1007 /**
1008  * tifiles_file_is_tno:
1009  * @filename: a filename as string.
1010  *
1011  * Check whether file is a TNO formatted file.
1012  *
1013  * Return value: a boolean value.
1014  **/
tifiles_file_is_tno(const char * filename)1015 TIEXPORT2 int TICALL tifiles_file_is_tno(const char *filename)
1016 {
1017 	return tifiles_file_has_tno_header(filename);
1018 }
1019 
1020 /**
1021  * tifiles_file_test:
1022  * @filename: a filename as string.
1023  * @type: type to check
1024  * @target: hand-held model or CALC_NONE for no filtering
1025  *
1026  * Check whether #filename is a TI file of type #type useable on a #target model.
1027  * This function is a generic one which overwrap and extends the tifiles_file_is_*
1028  * functions.
1029  *
1030  * This is a powerful function which allows checking of a specific file type for
1031  * a given target.
1032  *
1033  * Return value: a boolean value.
1034  **/
tifiles_file_test(const char * filename,FileClass type,CalcModel target)1035 TIEXPORT2 int TICALL tifiles_file_test(const char *filename, FileClass type, CalcModel target)
1036 {
1037 	char *e = tifiles_fext_get(filename);
1038 	uint8_t ctype, dtype;
1039 
1040 #ifdef CHECK_FILE_EXTENSIONS
1041 	if (e[0] == 0)
1042 	{
1043 		return 0;
1044 	}
1045 #endif
1046 
1047 	if (target > CALC_MAX)
1048 	{
1049 		tifiles_critical("%s: invalid target argument", __FUNCTION__);
1050 		return 0;
1051 	}
1052 
1053 	if (!tifiles_file_is_ti(filename))
1054 	{
1055 		return 0;
1056 	}
1057 
1058 	if (type & TIFILE_SINGLE)
1059 	{
1060 		if (GROUP_FILE_EXT[target][0] != 0 && !g_ascii_strncasecmp(e, GROUP_FILE_EXT[target], 2))
1061 		{
1062 			return !0;
1063 		}
1064 		else
1065 		{
1066 			return tifiles_file_is_single(filename);
1067 		}
1068 	}
1069 
1070 	if (type & TIFILE_GROUP)
1071 	{
1072 		if (GROUP_FILE_EXT[target][0] != 0 && !g_ascii_strcasecmp(e, GROUP_FILE_EXT[target]))
1073 		{
1074 			return !0;
1075 		}
1076 		else
1077 		{
1078 			return tifiles_file_is_group(filename);
1079 		}
1080 	}
1081 
1082 	if (type & TIFILE_REGULAR)
1083 	{
1084 		return tifiles_file_test(filename, TIFILE_SINGLE, target) || tifiles_file_test(filename, TIFILE_GROUP, target);
1085 	}
1086 
1087 	if (type & TIFILE_BACKUP)
1088 	{
1089 		if (BACKUP_FILE_EXT[target][0] != 0 && !g_ascii_strcasecmp(e, BACKUP_FILE_EXT[target]))
1090 		{
1091 			return !0;
1092 		}
1093 		else
1094 		{
1095 			return tifiles_file_is_backup(filename);
1096 		}
1097 	}
1098 
1099 	if (type & TIFILE_OS)
1100 	{
1101 		if (target && tifiles_file_has_tifl_header(filename, &ctype, &dtype))
1102 		{
1103 			return (ctype == tifiles_model_to_dev_type(target) && dtype == TI83p_AMS);
1104 		}
1105 		else if (target && tifiles_file_is_tib(filename))
1106 		{
1107 			FILE *f;
1108 			uint8_t data[16];
1109 
1110 			f = g_fopen(filename, "rb");
1111 			if (f == NULL)
1112 			{
1113 				return 0;
1114 			}
1115 
1116 			fread_n_chars(f, 16, (char *)data);
1117 			fclose(f);
1118 
1119 			switch(data[8])
1120 			{
1121 				case 1:
1122 				{
1123 					if (target != CALC_TI92P)
1124 					{
1125 						return 0;
1126 					}
1127 					break;
1128 				}
1129 				case 3:
1130 				{
1131 					if (target != CALC_TI89)
1132 					{
1133 						return 0;
1134 					}
1135 					break;
1136 				}
1137 				case 8:
1138 				{
1139 					if (target != CALC_V200)
1140 					{
1141 						return 0;
1142 					}
1143 					break;
1144 				}
1145 				case 9:
1146 				{
1147 					if (target != CALC_TI89T)
1148 					{
1149 						return 0;
1150 					}
1151 					break;
1152 				}
1153 				default:
1154 					return 0;
1155 			}
1156 
1157 			return !0;
1158 		}
1159 		else
1160 		{
1161 			return tifiles_file_is_os(filename);
1162 		}
1163 	}
1164 
1165 	if (type & TIFILE_APP)
1166 	{
1167 		if(target && tifiles_file_has_tifl_header(filename, &ctype, &dtype))
1168 		{
1169 			return (ctype == tifiles_model_to_dev_type(target) && dtype == TI83p_APPL);
1170 		}
1171 		else
1172 		{
1173 			return tifiles_file_is_app(filename);
1174 		}
1175 	}
1176 
1177 	if (type & TIFILE_FLASH)
1178 	{
1179 		return tifiles_file_test(filename, TIFILE_OS, target) || tifiles_file_test(filename, TIFILE_APP, target);
1180 	}
1181 
1182 	if (type & TIFILE_TIGROUP)
1183 	{
1184 		if (target)
1185 		{
1186 			// No easy/light way for this part: we have to load the whole file
1187 			// and to parse the TigEntry structures.
1188 			TigContent *content;
1189 			int ret, ok=0;
1190 			unsigned int k;
1191 
1192 			if (!tifiles_file_has_tig_header(filename))
1193 			{
1194 				return 0;
1195 			}
1196 
1197 			content = tifiles_content_create_tigroup(CALC_NONE, 0);
1198 			ret = tifiles_file_read_tigroup(filename, content);
1199 			if (ret)
1200 			{
1201 				tifiles_content_delete_tigroup(content);
1202 				return 0;
1203 			}
1204 
1205 			for (k = 0; k < content->n_apps; k++)
1206 			{
1207 				TigEntry *te = content->app_entries[k];
1208 
1209 				if(tifiles_calc_are_compat(te->content.regular->model, target))
1210 				{
1211 					ok++;
1212 				}
1213 			}
1214 
1215 			for (k = 0; k < content->n_vars; k++)
1216 			{
1217 				TigEntry *te = content->var_entries[k];
1218 
1219 				if(tifiles_calc_are_compat(te->content.regular->model, target))
1220 				{
1221 					ok++;
1222 				}
1223 			}
1224 
1225 			tifiles_content_delete_tigroup(content);
1226 			return ok;
1227 		}
1228 		else
1229 		{
1230 			return tifiles_file_is_tigroup(filename);
1231 		}
1232 	}
1233 
1234 	return 0;
1235 }
1236 
1237 /********/
1238 /* Misc */
1239 /********/
1240 
1241 /**
1242  * tifiles_fext_to_model:
1243  * @filename: a file extension.
1244  *
1245  * Returns the calculator model corresponding best to this file extension.
1246  *
1247  * Return value: a model taken in #CalcModel.
1248  **/
tifiles_fext_to_model(const char * ext)1249 TIEXPORT2 CalcModel TICALL tifiles_fext_to_model(const char *ext)
1250 {
1251 	int type = CALC_NONE;
1252 
1253 	if (ext == NULL)
1254 	{
1255 		tifiles_critical("%s(NULL)", __FUNCTION__);
1256 		return CALC_NONE;
1257 	}
1258 
1259 	if (ext[0] != 0 && ext[1] != 0 && ext[2] != 0)
1260 	{
1261 		char c1 = g_ascii_tolower(ext[0]);
1262 		char c2 = g_ascii_tolower(ext[1]);
1263 		char c3 = g_ascii_tolower(ext[2]);
1264 
1265 		if (c1 == '7' && c2 == '3')
1266 		{
1267 			type = CALC_TI73;
1268 		}
1269 		else if (c1 == '8')
1270 		{
1271 			if (c2 == '2')
1272 			{
1273 				if (c3 == 'u')
1274 				{
1275 					type = CALC_TI82A_USB;
1276 				}
1277 				else
1278 				{
1279 					type = CALC_TI82;
1280 				}
1281 			}
1282 			else if (c2 == '3')
1283 			{
1284 				type = CALC_TI83;
1285 			}
1286 			else if (c2 == 'x')
1287 			{
1288 				type = CALC_TI83P;
1289 			}
1290 			else if (c2 == 'c')
1291 			{
1292 				type = CALC_TI84PC;
1293 			}
1294 			else if (c2 == 'p')
1295 			{
1296 				type = CALC_TI83PCE_USB;
1297 			}
1298 			else if (c2 == 'e')
1299 			{
1300 				type = CALC_TI84PCE_USB;
1301 			}
1302 			else if (c2 == '5')
1303 			{
1304 				type = CALC_TI85;
1305 			}
1306 			else if (c2 == '6')
1307 			{
1308 				type = CALC_TI86;
1309 			}
1310 			else if (c2 == '9')
1311 			{
1312 				type = CALC_TI89;
1313 			}
1314 			// else fall through.
1315 		}
1316 		else if (c1 == '9')
1317 		{
1318 			if (c2 == '2')
1319 			{
1320 				type = CALC_TI92;
1321 			}
1322 			else if (c2 == 'x')
1323 			{
1324 				type = CALC_TI92P;
1325 			}
1326 			// else fall through.
1327 		}
1328 		else if (c1 == 'v' && c2 == '2')
1329 		{
1330 			type = CALC_V200;
1331 		}
1332 		//else if (!g_ascii_strcasecmp(str, "tib"))
1333 			//type = CALC_TI89;	// consider .tib as TI89
1334 		else if (c1 == 't')
1335 		{
1336 			if (c2 == 'n' || c2 == 'c' || c2 == 'm')
1337 			{
1338 				if (c3 == 's' || c3 == 'c' || c3 == 'o')
1339 				{
1340 					type = CALC_NSPIRE;
1341 				}
1342 				// else fall through.
1343 			}
1344 			// else fall through.
1345 		}
1346 		// else fall through.
1347 	}
1348 
1349 	return type;
1350 }
1351 
1352 /* Note: a better way should be to open the file and read the signature */
1353 /**
1354  * tifiles_file_get_model:
1355  * @filename: a filename as string.
1356  *
1357  * Returns the calculator model targeted by this file.
1358  *
1359  * Return value: a model taken in #CalcModel.
1360  **/
tifiles_file_get_model(const char * filename)1361 TIEXPORT2 CalcModel TICALL tifiles_file_get_model(const char *filename)
1362 {
1363 	char *e = tifiles_fext_get(filename);
1364 	return tifiles_fext_to_model(e);
1365 }
1366 
1367 /**
1368  * tifiles_file_get_class:
1369  * @filename: a filename as string.
1370  *
1371  * Returns the file class (single, group, backup, flash, tigroup).
1372  *
1373  * Return value: a value in #FileClass.
1374  **/
tifiles_file_get_class(const char * filename)1375 TIEXPORT2 FileClass TICALL tifiles_file_get_class(const char *filename)
1376 {
1377 	if (tifiles_file_is_single(filename))
1378 	{
1379 		return TIFILE_SINGLE;
1380 	}
1381 	else if (tifiles_file_is_group(filename))
1382 	{
1383 		return TIFILE_GROUP;
1384 	}
1385 	else if (tifiles_file_is_backup(filename))
1386 	{
1387 		return TIFILE_BACKUP;
1388 	}
1389 	else if (tifiles_file_is_flash(filename))
1390 	{
1391 		return TIFILE_FLASH;
1392 	}
1393 	else if (tifiles_file_is_tigroup(filename))
1394 	{
1395 		return TIFILE_TIGROUP;
1396 	}
1397 	else
1398 	{
1399 		return 0;
1400 	}
1401 }
1402 
1403 /**
1404  * tifiles_file_get_type:
1405  * @filename: a filename as string.
1406  *
1407  * Returns the type of file (function, program, ...).
1408  *
1409  * Return value: a string like "Assembly Program" (localized).
1410  **/
tifiles_file_get_type(const char * filename)1411 TIEXPORT2 const char *TICALL tifiles_file_get_type(const char *filename)
1412 {
1413 	char *e = tifiles_fext_get(filename);
1414 #ifdef CHECK_FILE_EXTENSIONS
1415 	if (e[0] == 0)
1416 	{
1417 		return "";
1418 	}
1419 #endif
1420 	if (   !g_ascii_strcasecmp(e, "tib")
1421 	    || !g_ascii_strcasecmp(e, "tno") || !g_ascii_strcasecmp(e, "tnc")
1422 	    || !g_ascii_strcasecmp(e, "tco") || !g_ascii_strcasecmp(e, "tcc")
1423 	    || !g_ascii_strcasecmp(e, "tmo") || !g_ascii_strcasecmp(e, "tmc")
1424 	  )
1425 	{
1426 		return _("OS upgrade");
1427 	}
1428 
1429 	if (!tifiles_file_is_ti(filename))
1430 	{
1431 		return "";
1432 	}
1433 
1434 	if (tifiles_file_is_tigroup(filename))
1435 	{
1436 		return _("TIGroup");
1437 	}
1438 
1439 	if (tifiles_file_is_group(filename))
1440 	{
1441 		switch (tifiles_file_get_model(filename))
1442 		{
1443 			case CALC_TI89:
1444 			case CALC_TI89T:
1445 			case CALC_TI89T_USB:
1446 			case CALC_TI92P:
1447 			case CALC_V200:
1448 				return _("Group/Backup");
1449 			default:
1450 				return _("Group");
1451 		}
1452 	}
1453 
1454 	switch (tifiles_file_get_model(filename))
1455 	{
1456 #ifndef DISABLE_TI8X
1457 		case CALC_TI73:
1458 			return tixx_byte2desc(TI73_CONST, TI73_MAXTYPES, tixx_fext2byte(TI73_CONST, TI73_MAXTYPES, e));
1459 		case CALC_TI82:
1460 			return tixx_byte2desc(TI82_CONST, TI82_MAXTYPES, tixx_fext2byte(TI82_CONST, TI82_MAXTYPES, e));
1461 		case CALC_TI83:
1462 			return tixx_byte2desc(TI83_CONST, TI83_MAXTYPES, tixx_fext2byte(TI83_CONST, TI83_MAXTYPES, e));
1463 		case CALC_TI83P:
1464 			return ti83p_byte2desc(ti83p_fext2byte(e));
1465 		case CALC_TI84P:
1466 		case CALC_TI84P_USB:
1467 			return ti84p_byte2desc(ti84p_fext2byte(e));
1468 		case CALC_TI82A_USB:
1469 			return ti82a_byte2desc(ti82a_fext2byte(e));
1470 		case CALC_TI84PT_USB:
1471 			return ti84pt_byte2desc(ti84pt_fext2byte(e));
1472 		case CALC_TI84PC:
1473 		case CALC_TI84PC_USB:
1474 			return ti84pc_byte2desc(ti84pc_fext2byte(e));
1475 		case CALC_TI83PCE_USB:
1476 			return ti83pce_byte2desc(ti83pce_fext2byte(e));
1477 		case CALC_TI84PCE_USB:
1478 			return ti84pce_byte2desc(ti84pce_fext2byte(e));
1479 		case CALC_TI85:
1480 			return tixx_byte2desc(TI85_CONST, TI85_MAXTYPES, tixx_fext2byte(TI85_CONST, TI85_MAXTYPES, e));
1481 		case CALC_TI86:
1482 			return tixx_byte2desc(TI86_CONST, TI86_MAXTYPES, tixx_fext2byte(TI86_CONST, TI86_MAXTYPES, e));
1483 #endif
1484 #ifndef DISABLE_TI9X
1485 		case CALC_TI89:
1486 			return ti89_byte2desc(ti89_fext2byte(e));
1487 		case CALC_TI89T:
1488 		case CALC_TI89T_USB:
1489 			return ti89t_byte2desc(ti89_fext2byte(e));
1490 		case CALC_TI92:
1491 			return ti92_byte2desc(ti92_fext2byte(e));
1492 		case CALC_TI92P:
1493 			return ti92p_byte2desc(ti92p_fext2byte(e));
1494 		case CALC_V200:
1495 			return v200_byte2desc(v200_fext2byte(e));
1496 #endif
1497 		case CALC_NSPIRE:
1498 			return tixx_byte2desc(NSP_CONST, NSP_MAXTYPES, tixx_fext2byte(NSP_CONST, NSP_MAXTYPES, e));
1499 		case CALC_NONE:
1500 		default:
1501 			return "";
1502 	}
1503 
1504 	return "";
1505 }
1506 
1507 /**
1508  * tifiles_file_get_icon:
1509  * @filename: a filename as string.
1510  *
1511  * Returns the type of file (function, program, ...).
1512  *
1513  * Return value: a string like "Assembly Program" (non localized).
1514  **/
tifiles_file_get_icon(const char * filename)1515 TIEXPORT2 const char *TICALL tifiles_file_get_icon(const char *filename)
1516 {
1517 	char *e = tifiles_fext_get(filename);
1518 #ifdef CHECK_FILE_EXTENSIONS
1519 	if (e[0] == 0)
1520 	{
1521 		return "";
1522 	}
1523 #endif
1524 	if (   !g_ascii_strcasecmp(e, "tib")
1525 	    || !g_ascii_strcasecmp(e, "tno") || !g_ascii_strcasecmp(e, "tnc")
1526 	    || !g_ascii_strcasecmp(e, "tco") || !g_ascii_strcasecmp(e, "tcc")
1527 	    || !g_ascii_strcasecmp(e, "tmo") || !g_ascii_strcasecmp(e, "tmc")
1528 	   )
1529 	{
1530 		return _("OS upgrade");
1531 	}
1532 
1533 	if (!tifiles_file_is_ti(filename))
1534 	{
1535 		return "";
1536 	}
1537 
1538 	if (tifiles_file_is_tigroup(filename))
1539 	{
1540 		return _("TIGroup");
1541 	}
1542 
1543 	if (tifiles_file_is_group(filename))
1544 	{
1545 		switch (tifiles_file_get_model(filename))
1546 		{
1547 			case CALC_TI89:
1548 			case CALC_TI89T:
1549 			case CALC_TI89T_USB:
1550 			case CALC_TI92P:
1551 			case CALC_V200:
1552 				return _("Group/Backup");
1553 			default:
1554 				return _("Group");
1555 		}
1556 	}
1557 
1558 	switch (tifiles_file_get_model(filename))
1559 	{
1560 #ifndef DISABLE_TI8X
1561 		case CALC_TI73:
1562 			return tixx_byte2icon(TI73_CONST, TI73_MAXTYPES, tixx_fext2byte(TI73_CONST, TI73_MAXTYPES, e));
1563 		case CALC_TI82:
1564 			return tixx_byte2icon(TI82_CONST, TI82_MAXTYPES, tixx_fext2byte(TI82_CONST, TI82_MAXTYPES, e));
1565 		case CALC_TI83:
1566 			return tixx_byte2icon(TI83_CONST, TI83_MAXTYPES, tixx_fext2byte(TI83_CONST, TI83_MAXTYPES, e));
1567 		case CALC_TI83P:
1568 			return ti83p_byte2icon(ti83p_fext2byte(e));
1569 		case CALC_TI84P:
1570 		case CALC_TI84P_USB:
1571 			return ti84p_byte2icon(ti83p_fext2byte(e));
1572 		case CALC_TI82A_USB:
1573 			return ti82a_byte2icon(ti82a_fext2byte(e));
1574 		case CALC_TI84PT_USB:
1575 			return ti84pt_byte2icon(ti84pt_fext2byte(e));
1576 		case CALC_TI84PC:
1577 		case CALC_TI84PC_USB:
1578 			return ti84pc_byte2icon(ti84pc_fext2byte(e));
1579 		case CALC_TI83PCE_USB:
1580 			return ti83pce_byte2icon(ti83pce_fext2byte(e));
1581 		case CALC_TI84PCE_USB:
1582 			return ti84pce_byte2icon(ti84pce_fext2byte(e));
1583 		case CALC_TI85:
1584 			return tixx_byte2icon(TI85_CONST, TI85_MAXTYPES, tixx_fext2byte(TI85_CONST, TI85_MAXTYPES, e));
1585 		case CALC_TI86:
1586 			return tixx_byte2icon(TI86_CONST, TI86_MAXTYPES, tixx_fext2byte(TI86_CONST, TI86_MAXTYPES, e));
1587 #endif
1588 #ifndef DISABLE_TI9X
1589 		case CALC_TI89:
1590 			return ti89_byte2icon(ti89_fext2byte(e));
1591 		case CALC_TI89T:
1592 		case CALC_TI89T_USB:
1593 			return ti89t_byte2icon(ti89_fext2byte(e));
1594 		case CALC_TI92:
1595 			return ti92_byte2icon(ti92_fext2byte(e));
1596 		case CALC_TI92P:
1597 			return ti92p_byte2icon(ti92p_fext2byte(e));
1598 		case CALC_V200:
1599 			return v200_byte2icon(v200_fext2byte(e));
1600 #endif
1601 		case CALC_NSPIRE:
1602 			return tixx_byte2icon(NSP_CONST, NSP_MAXTYPES, tixx_fext2byte(NSP_CONST, NSP_MAXTYPES, e));
1603 		case CALC_NONE:
1604 		default:
1605 			return "";
1606 	}
1607 
1608 	return "";
1609 }
1610