1 /* Hey EMACS -*- linux-c -*- */
2 /* $Id: files9x.c 3524 2007-06-26 13:31:26Z 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 /*
23 TI File Format handling routines
24 Calcs: TI-NSpire
25 */
26
27 #include <glib/gstdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <time.h>
31
32 #include <ticonv.h>
33 #include "tifiles.h"
34 #include "error.h"
35 #include "logging.h"
36 #include "macros.h"
37 #include "typesxx.h"
38 #include "filesnsp.h"
39 #include "rwfile.h"
40
41
42 /***********/
43 /* Reading */
44 /***********/
45
46 /**
47 * tnsp_file_read_regular:
48 * @filename: name of file to open.
49 * @content: where to store the file content.
50 *
51 * Load the file into a FileContent structure.
52 *
53 * Structure content must be freed with #tifiles_content_delete_regular when
54 * no longer used. If error occurs, the structure content is released for you.
55 *
56 * Return value: an error code, 0 otherwise.
57 **/
tnsp_file_read_regular(const char * filename,FileContent * content)58 int tnsp_file_read_regular(const char *filename, FileContent *content)
59 {
60 FILE *f;
61 int ret = ERR_FILE_IO;
62
63 if (content == NULL)
64 {
65 tifiles_critical("%s: an argument is NULL", __FUNCTION__);
66 return ERR_INVALID_FILE;
67 }
68
69 if (!tifiles_file_is_regular(filename))
70 {
71 ret = ERR_INVALID_FILE;
72 goto tfrr2;
73 }
74
75 f = g_fopen(filename, "rb");
76 if (f == NULL)
77 {
78 tifiles_info( "Unable to open this file: %s", filename);
79 ret = ERR_FILE_OPEN;
80 goto tfrr2;
81 }
82
83 content->model = CALC_NSPIRE;
84 content->model_dst = content->model;
85
86 content->entries = g_malloc0((content->num_entries + 1) * sizeof(VarEntry*));
87
88 {
89 long cur_pos;
90 VarEntry *entry = content->entries[0] = g_malloc0(sizeof(VarEntry));
91
92 gchar *basename = g_path_get_basename(filename);
93 gchar *ext = tifiles_fext_get(basename);
94
95 entry->type = tifiles_fext2vartype(content->model, ext);
96 if (ext && ext[0]) *(ext-1) = '\0';
97
98 entry->folder[0] = 0;
99 strncpy(entry->name, basename, sizeof(entry->name) - 1);
100 entry->name[sizeof(entry->name) - 1] = 0;
101 g_free(basename);
102
103 entry->attr = ATTRB_NONE;
104 if (fseek(f, 0, SEEK_END) < 0) goto tfrr;
105 cur_pos = ftell(f);
106 if (cur_pos < 0) goto tfrr;
107 if (fseek(f, 0, SEEK_SET) < 0) goto tfrr;
108
109 // The Nspire series' members have at best 128 MB of Flash (TODO: modify this code if this no longer holds).
110 // Regular files larger than that size are insane.
111 if (cur_pos >= (128L << 20))
112 {
113 ret = ERR_INVALID_FILE;
114 goto tfrr;
115 }
116 entry->size = (uint32_t)cur_pos;
117
118 entry->data = (uint8_t *)g_malloc0(entry->size);
119 if(fread(entry->data, 1, entry->size, f) < entry->size) goto tfrr;
120 }
121
122 content->num_entries++;
123
124 fclose(f);
125 return 0;
126
127 tfrr: // release on exit
128 tifiles_critical("%s: error reading / understanding file %s", __FUNCTION__, filename);
129 fclose(f);
130 tfrr2:
131 tifiles_content_delete_regular(content);
132 return ret;
133 }
134
135 /**
136 * tnsp_file_read_flash:
137 * @filename: name of flash file to open.
138 * @content: where to store the file content.
139 *
140 * Load the flash file into a #FlashContent structure.
141 *
142 * Structure content must be freed with #tifiles_content_delete_flash when
143 * no longer used. If error occurs, the structure content is released for you.
144 *
145 * Return value: an error code, 0 otherwise.
146 **/
tnsp_file_read_flash(const char * filename,FlashContent * content)147 int tnsp_file_read_flash(const char *filename, FlashContent *content)
148 {
149 FILE *f;
150 int c;
151 long cur_pos;
152 uint32_t file_size;
153 int ret = ERR_FILE_IO;
154
155 if (content == NULL)
156 {
157 tifiles_critical("%s: an argument is NULL", __FUNCTION__);
158 return ERR_INVALID_FILE;
159 }
160
161 if (!tifiles_file_is_tno(filename))
162 {
163 ret = ERR_INVALID_FILE;
164 goto tfrf2;
165 }
166
167 f = g_fopen(filename, "rb");
168 if (f == NULL)
169 {
170 tifiles_info("Unable to open this file: %s", filename);
171 ret = ERR_FILE_OPEN;
172 goto tfrf2;
173 }
174
175 if (fseek(f, 0, SEEK_END) < 0) goto tfrf;
176 cur_pos = ftell(f);
177 if (cur_pos < 0) goto tfrf;
178 if (fseek(f, 0, SEEK_SET) < 0) goto tfrf;
179 // The Nspire series' members have at best 128 MB of Flash (TODO: modify this code if this no longer holds).
180 // Flash files larger than that size are insane.
181 if (cur_pos >= (128L << 20))
182 {
183 ret = ERR_INVALID_FILE;
184 goto tfrf;
185 }
186 file_size = (uint32_t)cur_pos;
187
188 content->model = CALC_NSPIRE;
189
190 // Skip chars.
191 c = 0;
192 while (c != ' ')
193 {
194 c = fgetc(f);
195 if (c == EOF)
196 {
197 goto tfrf;
198 }
199 }
200
201 // Read revision major.
202 c = fgetc(f);
203 if (c == EOF)
204 {
205 goto tfrf;
206 }
207 content->revision_major = c;
208
209 // Skip char.
210 c = fgetc(f);
211 if (c == EOF)
212 {
213 goto tfrf;
214 }
215
216 // Read revision minor.
217 c = fgetc(f);
218 if (c == EOF)
219 {
220 goto tfrf;
221 }
222 content->revision_minor = c;
223
224 // Skip chars.
225 c = fgetc(f);
226 if (c == EOF)
227 {
228 goto tfrf;
229 }
230
231 c = 0;
232 while (c != ' ')
233 {
234 c = fgetc(f);
235 if (c == EOF)
236 {
237 goto tfrf;
238 }
239 }
240 if (fscanf(f, "%i", &(content->data_length)) < 1)
241 {
242 goto tfrf;
243 }
244 if (content->data_length > file_size)
245 {
246 ret = ERR_INVALID_FILE;
247 goto tfrf;
248 }
249 if (fseek(f, 0, SEEK_SET) < 0) goto tfrf;
250
251 content->data_part = (uint8_t *)g_malloc0(content->data_length);
252 if (content->data_part == NULL)
253 {
254 fclose(f);
255 tifiles_content_delete_flash(content);
256 return ERR_MALLOC;
257 }
258
259 content->next = NULL;
260 if(fread(content->data_part, 1, content->data_length, f) < content->data_length) goto tfrf;
261
262 fclose(f);
263 return 0;
264
265 tfrf: // release on exit
266 tifiles_critical("%s: error reading / understanding file %s", __FUNCTION__, filename);
267 fclose(f);
268 tfrf2:
269 tifiles_content_delete_flash(content);
270 return ret;
271 }
272
273 /***********/
274 /* Writing */
275 /***********/
276
277 /**
278 * tnsp_file_write_regular:
279 * @filename: name of file where to write or NULL.
280 * @content: the file content to write.
281 * @real_filename: pointer address or NULL. Must be freed if needed when no longer needed.
282 *
283 * Write one variable into a single file. If filename is set to NULL,
284 * the function build a filename from varname and allocates resulting filename in %real_fname.
285 * %filename and %real_filename can be NULL but not both !
286 *
287 * %real_filename must be freed when no longer used.
288 *
289 * Return value: an error code, 0 otherwise.
290 **/
tnsp_file_write_regular(const char * fname,FileContent * content,char ** real_fname)291 int tnsp_file_write_regular(const char *fname, FileContent *content, char **real_fname)
292 {
293 FILE *f;
294 char *filename = NULL;
295 VarEntry *entry;
296
297 if (content->entries == NULL || content->entries[0] == NULL)
298 {
299 tifiles_warning("%s: skipping content with NULL content->entries or content->entries[0]", __FUNCTION__);
300 return ERR_FILE_IO;
301 }
302
303 if (fname != NULL)
304 {
305 filename = g_strdup(fname);
306 if (filename == NULL)
307 {
308 return ERR_MALLOC;
309 }
310 }
311 else
312 {
313 filename = tifiles_build_filename(content->model_dst, content->entries[0]);
314 if (real_fname != NULL)
315 {
316 *real_fname = g_strdup(filename);
317 }
318 }
319
320 f = g_fopen(filename, "wb");
321 if (f == NULL)
322 {
323 tifiles_info( "Unable to open this file: %s", filename);
324 g_free(filename);
325 return ERR_FILE_OPEN;
326 }
327
328 entry = content->entries[0];
329 if(fwrite(entry->data, 1, entry->size, f) < entry->size)
330 {
331 goto tfwr;
332 }
333
334 g_free(filename);
335 fclose(f);
336 return 0;
337
338 tfwr: // release on exit
339 tifiles_critical("%s: error writing file %s", __FUNCTION__, filename);
340 g_free(filename);
341 fclose(f);
342 return ERR_FILE_IO;
343 }
344
345 /**************/
346 /* Displaying */
347 /**************/
348
349 /**
350 * tnsp_content_display_flash:
351 * @content: a FlashContent structure.
352 *
353 * Display fields of a FlashContent structure.
354 *
355 * Return value: an error code, 0 otherwise.
356 **/
tnsp_content_display_flash(FlashContent * content)357 int tnsp_content_display_flash(FlashContent *content)
358 {
359 FlashContent *ptr = content;
360
361 if (content == NULL)
362 {
363 tifiles_critical("%s(NULL)", __FUNCTION__);
364 return ERR_INVALID_FILE;
365 }
366
367 for (ptr = content; ptr != NULL; ptr = ptr->next)
368 {
369 tifiles_info("FlashContent for TI-Nspire: %p", ptr);
370 tifiles_info("Model: %02X (%u)", ptr->model, ptr->model);
371 tifiles_info("Signature: %s", tifiles_calctype2signature(ptr->model));
372 tifiles_info("model_dst: %02X (%u)", ptr->model_dst, ptr->model_dst);
373 tifiles_info("Revision: %u.%u", ptr->revision_major, ptr->revision_minor);
374 tifiles_info("Flags: %02X", ptr->flags);
375 tifiles_info("Object type: %02X", ptr->object_type);
376 tifiles_info("Date: %02X/%02X/%02X%02X", ptr->revision_day, ptr->revision_month, ptr->revision_year & 0xff, (ptr->revision_year & 0xff00) >> 8);
377 tifiles_info("Name: %s", ptr->name);
378 tifiles_info("Data type: OS data");
379 tifiles_info("Length: %08X (%i)", ptr->data_length, ptr->data_length);
380 tifiles_info("Data part: %p", ptr->data_part);
381 tifiles_info("Next: %p", ptr->next);
382 }
383
384 return 0;
385 }
386
387 /**
388 * tnsp_file_display:
389 * @filename: a TI file.
390 *
391 * Determine file class and display internal content.
392 *
393 * Return value: an error code, 0 otherwise.
394 **/
tnsp_file_display(const char * filename)395 int tnsp_file_display(const char *filename)
396 {
397 FileContent *content1;
398 FlashContent *content3;
399 int ret;
400
401 if (tifiles_file_is_os(filename))
402 {
403 content3 = tifiles_content_create_flash(CALC_NSPIRE);
404 ret = tnsp_file_read_flash(filename, content3);
405 if (!ret)
406 {
407 tnsp_content_display_flash(content3);
408 tifiles_content_delete_flash(content3);
409 }
410 }
411 else if (tifiles_file_is_regular(filename))
412 {
413 content1 = tifiles_content_create_regular(CALC_NSPIRE);
414 ret = tnsp_file_read_regular(filename, content1);
415 if (!ret)
416 {
417 tifiles_file_display_regular(content1);
418 tifiles_content_delete_regular(content1);
419 }
420 }
421 else
422 {
423 tifiles_info("Unknown file type !");
424 return ERR_BAD_FILE;
425 }
426
427 return ret;
428 }
429