/* Hey EMACS -*- linux-c -*- */ /* libcalcfiles - file format library, a part of the CalcForge project * Copyright (C) 1999-2006 Romain Lievin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This unit contains a TI file independant API */ #include #include #include #include #include #include #include "calcfiles.h" #include "error.h" #include "files8x.h" #include "files9x.h" #include "filesnsp.h" /** * calcfiles_content_create_regular: * @model: a calculator model (required). * * Allocates a #FileContent structure. * * Return value: the allocated block. **/ CALCFILES_EXPORT FileContent* CALCFORGE_CALL calcfiles_content_create_regular(CalcModel model) { FileContent* content = g_malloc0(sizeof(FileContent)); content->model = content->model_dst = model; strcpy(content->comment, calcfiles_comment_set_single()); return content; } /** * calcfiles_content_delete_regular: * * Free the whole content of a #FileContent structure. * * Return value: none. **/ CALCFILES_EXPORT int CALCFORGE_CALL calcfiles_content_delete_regular(FileContent *content) { int i; assert(content != NULL); for (i = 0; i < content->num_entries; i++) { VarEntry *entry = content->entries[i]; assert(entry != NULL); g_free(entry->data); g_free(entry); } g_free(content->entries); g_free(content); return 0; } /** * calcfiles_content_dup_regular: * * Allocates and copies a new #FileContent structure. * * Return value: none. **/ CALCFILES_EXPORT FileContent* CALCFORGE_CALL calcfiles_content_dup_regular(FileContent *content) { FileContent *dup; int i; assert(content != NULL); dup = calcfiles_content_create_regular(content->model); memcpy(dup, content, sizeof(FileContent)); dup->entries = calcfiles_ve_create_array(content->num_entries); for (i = 0; i < content->num_entries; i++) dup->entries[i] = calcfiles_ve_dup(content->entries[i]); return dup; } /** * calcfiles_file_read_regular: * @filename: name of single/group file to open. * @content: where to store the file content. * * Load the single/group file into a FileContent structure. * * Structure content must be freed with #calcfiles_content_delete_regular when * no longer used. * * Return value: an error code, 0 otherwise. **/ CALCFILES_EXPORT int calcfiles_file_read_regular(const char *filename, FileContent *content) { #if !defined(DISABLE_TI8X) if (calcfiles_calc_is_ti8x(calcfiles_file_get_model(filename))) return ti8x_file_read_regular(filename, (Ti8xRegular *)content); else #endif #if !defined(DISABLE_TI9X) if (calcfiles_calc_is_ti9x(calcfiles_file_get_model(filename))) return ti9x_file_read_regular(filename, (Ti9xRegular *)content); else #endif if(content->model == CALC_NSPIRE) return tnsp_file_read_regular(filename, (FileContent *)content); else return ERR_BAD_CALC; return 0; } /** * calcfiles_file_write_regular: * @filename: name of single/group file where to write or NULL. * @content: the file content to write. * @real_fname: pointer address or NULL. Must be freed if needed when no longer needed. * * Write one (or several) variable(s) into a single (group) file. If filename is set to NULL, * the function build a filename from varname and allocates resulting filename in %real_fname. * %filename and %real_filename can be NULL but not both ! * * %real_filename must be freed when no longer used. * * Return value: an error code, 0 otherwise. **/ CALCFILES_EXPORT int calcfiles_file_write_regular(const char *filename, FileContent *content, char **real_fname) { #if !defined(DISABLE_TI8X) if (calcfiles_calc_is_ti8x(content->model)) return ti8x_file_write_regular(filename, (Ti8xRegular *)content, real_fname); else #endif #if !defined(DISABLE_TI9X) if (calcfiles_calc_is_ti9x(content->model)) return ti9x_file_write_regular(filename, (Ti9xRegular *)content, real_fname); else #endif if(content->model == CALC_NSPIRE) return tnsp_file_write_regular(filename, (FileContent *)content, real_fname); else return ERR_BAD_CALC; return 0; } /** * calcfiles_file_display_regular: * @content: the file content to show. * * Display file content informations. * * Return value: an error code, 0 otherwise. **/ CALCFILES_EXPORT int CALCFORGE_CALL calcfiles_file_display_regular(FileContent *content) { #if !defined(DISABLE_TI8X) if (calcfiles_calc_is_ti8x(content->model)) return ti8x_content_display_regular(content); else #endif #if !defined(DISABLE_TI9X) if (calcfiles_calc_is_ti9x(content->model)) return ti9x_content_display_regular(content); else #endif if(content->model == CALC_NSPIRE) return tnsp_content_display_regular(content); else return ERR_BAD_CALC; return 0; } /** * calcfiles_content_create_backup: * @model: a calculator model or CALC_NONE. * * Allocates a BackupContent structure. * * Return value: the allocated block. **/ CALCFILES_EXPORT BackupContent* CALCFORGE_CALL calcfiles_content_create_backup(CalcModel model) { BackupContent* content = g_malloc0(sizeof(BackupContent)); content->model = model; strcpy(content->comment, calcfiles_comment_set_backup()); return content; } /** * calcfiles_content_delete_backup: * * Free the whole content of a BackupContent structure. * * Return value: none. **/ CALCFILES_EXPORT int CALCFORGE_CALL calcfiles_content_delete_backup(BackupContent *content) { assert(content != NULL); if (calcfiles_calc_is_ti9x(content->model)) g_free(content->data_part); else if (calcfiles_calc_is_ti8x(content->model)) { g_free(content->data_part1); g_free(content->data_part2); g_free(content->data_part3); g_free(content->data_part4); } g_free(content); return 0; } /** * calcfiles_file_read_backup: * @filename: name of backup file to open. * @content: where to store the file content. * * Load the backup file into a BackupContent structure. * * Structure content must be freed with #calcfiles_content_delete_backup when * no longer used. * * Return value: an error code, 0 otherwise. **/ CALCFILES_EXPORT int calcfiles_file_read_backup(const char *filename, BackupContent *content) { #if !defined(DISABLE_TI8X) if (calcfiles_calc_is_ti8x(calcfiles_file_get_model(filename))) return ti8x_file_read_backup(filename, content); else #endif #if !defined(DISABLE_TI9X) if (calcfiles_calc_is_ti9x(calcfiles_file_get_model(filename))) return ti9x_file_read_backup(filename, content); else #endif return ERR_BAD_CALC; return 0; } /** * calcfiles_file_write_backup: * @filename: name of backup file where to write. * @content: the file content to write. * * Write backup into file. * * Return value: an error code, 0 otherwise. **/ CALCFILES_EXPORT int calcfiles_file_write_backup(const char *filename, BackupContent *content) { #if !defined(DISABLE_TI8X) if (calcfiles_calc_is_ti8x(content->model)) return ti8x_file_write_backup(filename, content); else #endif #if !defined(DISABLE_TI9X) if (calcfiles_calc_is_ti9x(content->model)) return ti9x_file_write_backup(filename, content); else #endif return ERR_BAD_CALC; return 0; } /** * calcfiles_file_display_backup: * @content: the file content to show. * * Display file content informations. * * Return value: an error code, 0 otherwise. **/ CALCFILES_EXPORT int CALCFORGE_CALL calcfiles_file_display_backup(BackupContent *content) { #if !defined(DISABLE_TI8X) if (calcfiles_calc_is_ti8x(content->model)) return ti8x_content_display_backup(content); else #endif #if !defined(DISABLE_TI9X) if (calcfiles_calc_is_ti9x(content->model)) return ti9x_content_display_backup(content); else #endif return ERR_BAD_CALC; return 0; } /** * calcfiles_content_create_flash: * @model: a calculator model (compulsory). * * Allocates a #FlashContent structure. * * Return value: the allocated block. **/ CALCFILES_EXPORT FlashContent* CALCFORGE_CALL calcfiles_content_create_flash(CalcModel model) { FlashContent* content = g_malloc0(sizeof(FlashContent)); content->model = model; if(calcfiles_calc_is_ti9x(content->model)) { time_t tt; struct tm *lt; time(&tt); lt = localtime(&tt); content->revision_major = 1; content->revision_minor = 0; content->flags = 0; content->object_type = 0; content->revision_day = lt->tm_mday; content->revision_month = lt->tm_mon; content->revision_year = lt->tm_year + 1900; } return content; } /** * calcfiles_content_delete_flash: * * Free the whole content of a #FlashContent structure. * * Return value: none. **/ CALCFILES_EXPORT int CALCFORGE_CALL calcfiles_content_delete_flash(FlashContent *content) { int i; assert(content != NULL); #if !defined(DISABLE_TI8X) && !defined(DISABLE_TI9X) { FlashContent *ptr; g_free(content->data_part); ptr = content->next; while (ptr != NULL) { FlashContent *next = ptr->next; g_free(ptr->data_part); g_free(ptr); for(i = 0; i < content->num_pages; i++) { g_free(content->pages[i]->data); g_free(content->pages[i]); } g_free(content->pages); ptr = next; } g_free(content); } #else return ERR_BAD_CALC; #endif return 0; } /** * calcfiles_file_read_flash: * @filename: name of FLASH file to open. * @content: where to store the file content. * * Load the FLASH file into a FlashContent structure. * * Structure content must be freed with #calcfiles_content_delete_flash when * no longer used. * * Return value: an error code, 0 otherwise. **/ CALCFILES_EXPORT int calcfiles_file_read_flash(const char *filename, FlashContent *content) { #if !defined(DISABLE_TI8X) if (calcfiles_calc_is_ti8x(calcfiles_file_get_model(filename))) return ti8x_file_read_flash(filename, content); else #endif #if !defined(DISABLE_TI9X) if (calcfiles_calc_is_ti9x(calcfiles_file_get_model(filename)) || calcfiles_file_is_tib(filename)) return ti9x_file_read_flash(filename, content); else #endif if(content->model == CALC_NSPIRE) return tnsp_file_read_flash(filename, content); else return ERR_BAD_CALC; return 0; } /** * calcfiles_file_write_flash2: * @filename: name of flash file where to write or NULL. * @content: the file content to write. * @real_fname: pointer address or NULL. Must be freed if needed when no longer needed. * * Write a FLASH content to a file. If filename is set to NULL, the function build a filename * from appname and allocates resulting filename in %real_fname. * %filename and %real_fname can be NULL but not both ! * * %real_fname must be freed when no longer used. * * Return value: an error code, 0 otherwise. **/ CALCFILES_EXPORT int calcfiles_file_write_flash2(const char *filename, FlashContent *content, char **real_fname) { #if !defined(DISABLE_TI8X) if (calcfiles_calc_is_ti8x(content->model)) return ti8x_file_write_flash(filename, content, real_fname); else #endif #if !defined(DISABLE_TI9X) if (calcfiles_calc_is_ti9x(content->model)) return ti9x_file_write_flash(filename, content, real_fname); else #endif return ERR_BAD_CALC; return 0; } /** * calcfiles_file_write_flash: * @filename: name of flash file where to write or NULL. * @content: the file content to write. * @real_fname: pointer address or NULL. Must be freed if needed when no longer needed. * * Write a FLASH content to a file. If filename is set to NULL, the function build a filename * from appname and allocates resulting filename in %real_fname. * %filename and %real_fname can be NULL but not both ! * * %real_fname must be freed when no longer used. * * Return value: an error code, 0 otherwise. **/ CALCFILES_EXPORT int calcfiles_file_write_flash(const char *filename, FlashContent *content) { return calcfiles_file_write_flash2(filename, content, NULL); } /** * calcfiles_content_dup_flash: * * Allocates and copies a new FlashContent structure. * * Return value: none. **/ CALCFILES_EXPORT FlashContent* CALCFORGE_CALL calcfiles_content_dup_flash(FlashContent *content) { FlashContent *dup; FlashContent *p, *q; assert(content != NULL); dup = calcfiles_content_create_flash(content->model); for(p = content, q = dup; p; p = p->next, q = q->next) { memcpy(q, p, sizeof(FlashContent)); // TI9x part if(calcfiles_calc_is_ti9x(content->model)) { if(p->data_part) { q->data_part = (uint8_t *)g_malloc0(p->data_length+1); memcpy(q->data_part, p->data_part, p->data_length+1); } } // TI8x part if(calcfiles_calc_is_ti8x(content->model)) { int i; // copy pages q->pages = calcfiles_fp_create_array(p->num_pages); for(i = 0; i < content->num_pages; i++) { q->pages[i] = (FlashPage *)g_malloc0(sizeof(FlashPage)); memcpy(q->pages[i], p->pages[i], sizeof(FlashPage)); q->pages[i]->data = (uint8_t *) g_malloc0(p->pages[i]->size); memcpy(q->pages[i]->data, p->pages[i]->data, p->pages[i]->size); } } if(p->next) q->next = calcfiles_content_create_flash(p->model); } return dup; } /** * calcfiles_file_display_flash: * @content: the file content to show. * * Display file content informations. * * Return value: an error code, 0 otherwise. **/ CALCFILES_EXPORT int CALCFORGE_CALL calcfiles_file_display_flash(FlashContent *content) { #if !defined(DISABLE_TI8X) if (calcfiles_calc_is_ti8x(content->model)) return ti8x_content_display_flash(content); else #endif #if !defined(DISABLE_TI9X) if (calcfiles_calc_is_ti9x(content->model)) return ti9x_content_display_flash(content); else #endif return ERR_BAD_CALC; return 0; } /** * calcfiles_file_display: * @filename: a TI file. * * Determine file class and display internal content. * * Return value: an error code, 0 otherwise. **/ CALCFILES_EXPORT int CALCFORGE_CALL calcfiles_file_display(const char *filename) { if (calcfiles_file_is_tigroup(filename)) return calcfiles_file_display_tigroup(filename); #if !defined(DISABLE_TI8X) if (calcfiles_calc_is_ti8x(calcfiles_file_get_model(filename))) return ti8x_file_display(filename); else #endif #if !defined(DISABLE_TI9X) if (calcfiles_calc_is_ti9x(calcfiles_file_get_model(filename))) return ti9x_file_display(filename); else #endif return ERR_BAD_CALC; return 0; } /*****************/ /* Miscellaneous */ /*****************/ /** * calcfiles_create_table_of_entries: * @content: a TI file content structure. * @nfolders: returns the number of folders in the file. * * The goal of this function is to parse the file content structure in order to build * a table of entries so that it's easy to write it just after the header in a group * file. Mainly used as an helper. * The returned 'table' is an NULL-terminated array of int* pointers. * Each pointers points on an integer array. Each cell are an index on the 'VarEntry* * entries' array. * * In fact, this array represents a kind of tree. The array of pointer is the folder list * and each pointer is the variable list for each folder. * For accessing the entry, we use the index. * * This function may be difficult to understand but it avoids to use trees (and * linked list) which will require an implementation. * * Return value: a 2-dimensions allocated integer array. Must be freed when no * longer used. **/ CALCFILES_EXPORT int** calcfiles_create_table_of_entries(FileContent *content, int *nfolders) { int num_folders = 0; int i, j; char **ptr, *folder_list[32768] = { 0 }; int **table; // determine how many folders we have for (i = 0; i < content->num_entries; i++) { VarEntry *entry = content->entries[i]; // scan for an existing folder entry for (ptr = folder_list; *ptr != NULL; ptr++) { if (!strcmp(*ptr, entry->folder)) { //printf("break: %s\n", entry->folder); break; } } if (*ptr == NULL) { // add new folder entry folder_list[num_folders] = (char *) g_malloc0(10); //printf("%i: adding '%s'\n", num_folders, entry->folder); strcpy(folder_list[num_folders], entry->folder); folder_list[num_folders + 1] = NULL; num_folders++; g_assert(num_folders <= content->num_entries); } } if (calcfiles_calc_is_ti8x(content->model)) num_folders++; *nfolders = num_folders; // allocate the folder list table = (int **) g_malloc0((num_folders + 1) * sizeof(int *)); table[num_folders] = NULL; // for each folder, determine how many variables we have // and allocate array with indexes for (j = 0; j < num_folders; j++) { int k; for (i = 0, k = 0; i < content->num_entries; i++) { VarEntry *entry = content->entries[i]; if (!strcmp(folder_list[j], entry->folder)) { table[j] = (int *) realloc(table[j], (k + 2) * sizeof(int)); table[j][k] = i; //printf("%i %i: adding %i\n", j, k, i); table[j][k + 1] = -1; k++; } } } // g_free( memory for (j = 0; j < num_folders + 1; j++) g_free(folder_list[j]); return table; }