/** * tnsp_file_read_regular: * @filename: name of file to open. * @content: where to store the file content. * * Load the file into a FileContent structure. * * Structure content must be freed with #tifiles_content_delete_regular when * no longer used. If error occurs, the structure content is released for you. * * Return value: an error code, 0 otherwise. **/ int tnsp_file_read_regular(const char *filename, FileContent *content) { FILE *f; if (!tifiles_file_is_regular(filename)) { return ERR_INVALID_FILE; } if (content == NULL) { tifiles_critical("%s: an argument is NULL", __FUNCTION__); return ERR_INVALID_FILE; } f = g_fopen(filename, "rb"); if (f == NULL) { tifiles_info( "Unable to open this file: %s", filename); return ERR_FILE_OPEN; } content->model = CALC_NSPIRE; content->model_dst = content->model; content->entries = g_malloc0((content->num_entries + 1) * sizeof(VarEntry*)); { VarEntry *entry = content->entries[0] = g_malloc0(sizeof(VarEntry)); gchar *basename = g_path_get_basename(filename); gchar *ext = tifiles_fext_get(basename); entry->type = tifiles_fext2vartype(content->model, ext); if(ext) *(ext-1) = '\0'; strcpy(entry->folder, ""); strcpy(entry->name, basename); g_free(basename); entry->attr = ATTRB_NONE; fseek(f, 0, SEEK_END); entry->size = (uint32_t)ftell(f); fseek(f, 0, SEEK_SET); entry->data = (uint8_t *)g_malloc0(entry->size); if(fread(entry->data, 1, entry->size, f) < entry->size) goto tffr; } content->num_entries++; fclose(f); return 0; tffr: // release on exit tifiles_critical("%s: error reading / understanding file %s", __FUNCTION__, filename); fclose(f); tifiles_content_delete_regular(content); return ERR_FILE_IO; }
TIEXPORT2 int TICALL tifiles_cert_field_next(const uint8_t **data, uint32_t *length) { int ret; const uint8_t * contents; uint32_t field_size; // Initial sanity checks. if (data == NULL) { tifiles_critical("%s: data is NULL", __FUNCTION__); return ERR_INVALID_PARAM; } if (length == NULL) { tifiles_critical("%s: length is NULL", __FUNCTION__); return ERR_INVALID_PARAM; } ret = tifiles_cert_field_get(*data, *length, NULL, &contents, &field_size); if (!ret) { *length -= contents + field_size - *data; *data = contents + field_size; } return ret; }
/* Write a string of 'n' chars max (NULL padded) to a file - s [in]: a string - f [in]: a file descriptor - [out]: -1 if error, 0 otherwise. */ int fwrite_n_chars(FILE * f, unsigned int n, const char *s) { unsigned int i; unsigned int l; l = strlen(s); if (l > n) { tifiles_critical("string passed to 'fwrite_n_chars' is too long (>n chars).\n"); tifiles_critical( "s = %s, len(s) = %u\n", s, l); tifiles_hexdump((uint8_t *)s, (l < n) ? n : l); return -1; } for (i = 0; i < l; i++) { if (fputc(s[i], f) == EOF) { return -1; } } for (i = l; i < n; i++) { if (fputc(0x00, f) == EOF) { return -1; } } return 0; }
/** * tifiles_content_delete_regular: * * Free the whole content of a #FileContent structure. * * Return value: none. **/ TIEXPORT2 int TICALL tifiles_content_delete_regular(FileContent *content) { int i; if (content != NULL) { for (i = 0; i < content->num_entries; i++) { VarEntry *entry = content->entries[i]; if(entry != NULL) { g_free(entry->data); g_free(entry); } else { tifiles_critical("tifiles_content_delete_regular(content with NULL entry)"); } } g_free(content->entries); g_free(content); } else { tifiles_critical("%s(NULL)", __FUNCTION__); } return 0; }
TIEXPORT2 int TICALL tifiles_cert_field_find(const uint8_t *data, uint32_t length, uint16_t field_type, const uint8_t **contents, uint32_t *field_size) { int ret = 0; uint16_t ft; // Initial sanity checks. if (data == NULL) { tifiles_critical("%s: data is NULL", __FUNCTION__); return ERR_INVALID_PARAM; } if (length < 2) { tifiles_critical("%s: length is too small to contain a valid cert field", __FUNCTION__); return ERR_INVALID_PARAM; } // Mask out the size indication, it is harmful for finding a field. field_type &= 0xFFF0; ft = 0xFFFF; while (!ret && ft != field_type) { ret = tifiles_cert_field_get(data, length, &ft, contents, field_size); ft &= 0xFFF0; if (!ret) { ret = tifiles_cert_field_next(&data, &length); } } return ret; }
/* Write a string of 'n' chars max (SPC padded) to a file - s [in]: a string - f [in]: a file descriptor - [out]: -1 if error, 0 otherwise. */ int fwrite_n_chars2(FILE * f, int n, const char *s) { int i; int l = n; l = strlen(s); if (l > n) { tifiles_critical("string passed in 'write_string8' is too long (>n chars).\n"); tifiles_critical( "s = %s, len(s) = %i\n", s, l); hexdump((uint8_t *) s, (l < 9) ? 9 : l); return -1; } for (i = 0; i < l; i++) { if(fputc(s[i], f) == EOF) { return -1; } } for (i = l; i < n; i++) { if(fputc(0x20, f) == EOF) { return -1; } } return 0; }
/** * tnsp_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 #tifiles_content_delete_flash when * no longer used. If error occurs, the structure content is released for you. * * Return value: an error code, 0 otherwise. **/ int tnsp_file_read_flash(const char *filename, FlashContent *content) { FILE *f; int c; if (!tifiles_file_is_tno(filename)) return ERR_INVALID_FILE; if (content == NULL) { tifiles_critical("%s: an argument is NULL", __FUNCTION__); return ERR_INVALID_FILE; } f = g_fopen(filename, "rb"); if (f == NULL) { tifiles_info("Unable to open this file: %s\n", filename); return ERR_FILE_OPEN; } content->model = CALC_NSPIRE; for(c = 0; c != ' '; c=fgetc(f)); content->revision_major = fgetc(f); fgetc(f); content->revision_minor = fgetc(f); fgetc(f); for(c = 0; c != ' '; c=fgetc(f)); if (fscanf(f, "%i", &(content->data_length)) < 1) { goto tfrf; } rewind(f); content->data_part = (uint8_t *)g_malloc0(content->data_length); if (content->data_part == NULL) { fclose(f); tifiles_content_delete_flash(content); return ERR_MALLOC; } content->next = NULL; if(fread(content->data_part, 1, content->data_length, f) < content->data_length) goto tfrf; fclose(f); return 0; tfrf: // release on exit tifiles_critical("%s: error reading / understanding file %s", __FUNCTION__, filename); fclose(f); tifiles_content_delete_flash(content); return ERR_FILE_IO; }
/** * tnsp_content_display_flash: * @content: a FlashContent structure. * * Display fields of a FlashContent structure. * * Return value: an error code, 0 otherwise. **/ int tnsp_content_display_flash(FlashContent *content) { FlashContent *ptr = content; if (content == NULL) { tifiles_critical("%s(NULL)", __FUNCTION__); return ERR_INVALID_FILE; } tifiles_info("Signature: %s", tifiles_calctype2signature(ptr->model)); tifiles_info("Revision: %i.%i", ptr->revision_major, ptr->revision_minor); tifiles_info("Flags: %02X", ptr->flags); tifiles_info("Object type: %02X", ptr->object_type); tifiles_info("Date: %02X/%02X/%02X%02X", ptr->revision_day, ptr->revision_month, ptr->revision_year & 0xff, (ptr->revision_year & 0xff00) >> 8); tifiles_info("Name: %s", ptr->name); tifiles_info("Device type: %s", ptr->device_type == DEVICE_TYPE_89 ? "ti89" : "ti92+"); tifiles_info("Data type: OS data"); tifiles_info("Length: %08X (%i)", ptr->data_length, ptr->data_length); tifiles_info(""); return 0; }
/** * ti9x_content_display_regular: * @content: a Ti9xRegular structure. * * Display fields of a Ti9xRegular structure. * * Return value: an error code, 0 otherwise. **/ int ti9x_content_display_regular(Ti9xRegular *content) { int i; char trans[17]; if (content == NULL) { tifiles_critical("%s(NULL)", __FUNCTION__); return ERR_INVALID_FILE; } tifiles_info("Signature: %s", tifiles_calctype2signature(content->model)); tifiles_info("Comment: %s", content->comment); tifiles_info("Default folder: %s", content->default_folder); tifiles_info("Number of entries: %i", content->num_entries); for (i = 0; i < content->num_entries; i++) { if (content->entries[i] != NULL) { tifiles_info("Entry #%i", i); tifiles_info(" folder: %s", content->entries[i]->folder); tifiles_info(" name: %s", ticonv_varname_to_utf8_s(content->model, content->entries[i]->name, trans, content->entries[i]->type)); tifiles_info(" type: %02X (%s)", content->entries[i]->type, tifiles_vartype2string(content->model, content->entries[i]->type)); tifiles_info(" attr: %s", tifiles_attribute_to_string(content->entries[i]->attr)); tifiles_info(" length: %04X (%i)", content->entries[i]->size, content->entries[i]->size); } } tifiles_info("Checksum: %04X (%i) ", content->checksum, content->checksum); return 0; }
/** * tifiles_signature2calctype: * @s: a TI file signature like "**TI89**". * * Returns the calculator model contained in the signature. * * Return value: a calculator model. **/ TIEXPORT2 CalcModel TICALL tifiles_signature2calctype(const char *s) { if (s != NULL) { if (!g_ascii_strcasecmp(s, "**TI73**")) return CALC_TI73; else if (!g_ascii_strcasecmp(s, "**TI82**")) return CALC_TI82; else if (!g_ascii_strcasecmp(s, "**TI83**")) return CALC_TI83; else if (!g_ascii_strcasecmp(s, "**TI83F*")) return CALC_TI83P; else if (!g_ascii_strcasecmp(s, "**TI85**")) return CALC_TI85; else if (!g_ascii_strcasecmp(s, "**TI86**")) return CALC_TI86; else if (!g_ascii_strcasecmp(s, "**TI89**")) return CALC_TI89; else if (!g_ascii_strcasecmp(s, "**TI92**")) return CALC_TI92; else if (!g_ascii_strcasecmp(s, "**TI92P*")) return CALC_TI92P; else if (!g_ascii_strcasecmp(s, "**V200**")) return CALC_V200; } tifiles_critical("%s: invalid signature.", __FUNCTION__); return CALC_NONE; }
/** * tifiles_build_fullname: * @model: a calculator model. * @full_name: the buffer where to store the result. * @fldname: the name of folder or "". * @varname: the name of variable * * Build the complete path from folder name and variable name. * Not all of calculators supports folder. * * Return value: a full path as string like 'fldname\varname'. **/ TIEXPORT2 char* TICALL tifiles_build_fullname(CalcModel model, char *full_name, const char *fldname, const char *varname) { if (full_name == NULL || fldname == NULL || varname == NULL) { tifiles_critical("%s: an argument is NULL", __FUNCTION__); return NULL; } if (tifiles_has_folder(model)) { if (fldname[0] == 0) { sprintf(full_name, "%s\\%s", fldname, varname); } else { strcpy(full_name, varname); } } else { strcpy(full_name, varname); } return full_name; }
/** * tifiles_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 #tifiles_content_delete_flash when * no longer used. * * Return value: an error code, 0 otherwise. **/ TIEXPORT2 int tifiles_file_read_flash(const char *filename, FlashContent *content) { if (filename == NULL || content == NULL) { tifiles_critical("%s: an argument is NULL", __FUNCTION__); return ERR_INVALID_FILE; } #if !defined(DISABLE_TI8X) if (tifiles_calc_is_ti8x(tifiles_file_get_model(filename))) return ti8x_file_read_flash(filename, content); else #endif #if !defined(DISABLE_TI9X) if (tifiles_calc_is_ti9x(tifiles_file_get_model(filename)) || tifiles_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; }
/** * tifiles_file_display_regular: * @content: the file content to show. * * Display file content information. * * Return value: an error code, 0 otherwise. **/ TIEXPORT2 int TICALL tifiles_file_display_regular(FileContent *content) { if (content == NULL) { tifiles_critical("%s(NULL)", __FUNCTION__); return ERR_INVALID_FILE; } #if !defined(DISABLE_TI8X) if (tifiles_calc_is_ti8x(content->model)) return ti8x_content_display_regular(content); else #endif #if !defined(DISABLE_TI9X) if (tifiles_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; }
/** * tifiles_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. **/ TIEXPORT2 int tifiles_file_write_regular(const char *filename, FileContent *content, char **real_fname) { if (content == NULL || (filename == NULL && real_fname == NULL)) { tifiles_critical("%s: an argument is NULL", __FUNCTION__); return ERR_INVALID_FILE; } #if !defined(DISABLE_TI8X) if (tifiles_calc_is_ti8x(content->model)) return ti8x_file_write_regular(filename, (Ti8xRegular *)content, real_fname); else #endif #if !defined(DISABLE_TI9X) if (tifiles_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; }
/** * tifiles_build_fullname: * @model: a calculator model. * @full_name: the buffer where to store the result. * @fldname: the name of folder or "". * @varname: the name of variable * * Build the complete path from folder name and variable name. * Not all of calculators supports folder. * * Return value: a full path as string like 'fldname\varname'. **/ char* TICALL tifiles_build_fullname(CalcModel model, char *full_name, const char *fldname, const char *varname) { if (full_name == NULL || fldname == NULL || varname == NULL) { tifiles_critical("%s: an argument is NULL", __FUNCTION__); return NULL; } if (tifiles_has_folder(model)) { if (strcmp(fldname, "")) { strcpy(full_name, fldname); strcat(full_name, "\\"); strcat(full_name, varname); } else { strcpy(full_name, varname); } } else { strcpy(full_name, varname); } return full_name; }
/** * tifiles_content_dup_regular: * * Allocates and copies a new #FileContent structure. * * Return value: none. **/ TIEXPORT2 FileContent* TICALL tifiles_content_dup_regular(FileContent *content) { FileContent *dup = NULL; int i; if (content != NULL) { dup = tifiles_content_create_regular(content->model); if (dup != NULL) { memcpy(dup, content, sizeof(FileContent)); dup->entries = tifiles_ve_create_array(content->num_entries); if (dup->entries != NULL) { for (i = 0; i < content->num_entries; i++) dup->entries[i] = tifiles_ve_dup(content->entries[i]); } } } else { tifiles_critical("%s(NULL)", __FUNCTION__); } return dup; }
/** * tnsp_content_display_flash: * @content: a FlashContent structure. * * Display fields of a FlashContent structure. * * Return value: an error code, 0 otherwise. **/ int tnsp_content_display_flash(FlashContent *content) { FlashContent *ptr = content; if (content == NULL) { tifiles_critical("%s(NULL)", __FUNCTION__); return ERR_INVALID_FILE; } for (ptr = content; ptr != NULL; ptr = ptr->next) { tifiles_info("FlashContent for TI-Nspire: %p", ptr); tifiles_info("Model: %02X (%u)", ptr->model, ptr->model); tifiles_info("Signature: %s", tifiles_calctype2signature(ptr->model)); tifiles_info("model_dst: %02X (%u)", ptr->model_dst, ptr->model_dst); tifiles_info("Revision: %u.%u", ptr->revision_major, ptr->revision_minor); tifiles_info("Flags: %02X", ptr->flags); tifiles_info("Object type: %02X", ptr->object_type); tifiles_info("Date: %02X/%02X/%02X%02X", ptr->revision_day, ptr->revision_month, ptr->revision_year & 0xff, (ptr->revision_year & 0xff00) >> 8); tifiles_info("Name: %s", ptr->name); tifiles_info("Data type: OS data"); tifiles_info("Length: %08X (%i)", ptr->data_length, ptr->data_length); tifiles_info("Data part: %p", ptr->data_part); tifiles_info("Next: %p", ptr->next); } return 0; }
/** * tifiles_group_del_file: * @src_filename: the file to remove from group file * @dst_filename: the group file * * Search for entry and remove it from file. * * Return value: 0 if successful, an error code otherwise. **/ TIEXPORT2 int TICALL tifiles_group_del_file(VarEntry *entry, const char *dst_filename) { CalcModel dst_model; FileContent* dst_content = NULL; int ret = 0; if (entry == NULL || dst_filename == NULL) { tifiles_critical("%s: an argument is NULL", __FUNCTION__); return ERR_INVALID_FILE; } // src can be single/group file and dst must be group file if(!tifiles_file_is_group(dst_filename)) return -1; dst_model = tifiles_file_get_model(dst_filename); dst_content = tifiles_content_create_regular(dst_model); ret = tifiles_file_read_regular(dst_filename, dst_content); if(ret) goto tgdf; tifiles_content_del_entry(dst_content, entry); tifiles_file_display_regular(dst_content); ret = tifiles_file_write_regular(dst_filename, dst_content, NULL); if(ret) goto tgdf; tgdf: tifiles_content_delete_regular(dst_content); return ret; }
/** * tifiles_ungroup_file: * @src_filename: full path of file to ungroup. * @dst_filenames: NULL or the address of a pointer where to store a NULL-terminated * array of strings which contain the list of ungrouped files. * * Ungroup a TI 'group' file into several files. Resulting files have the * same name as the variable stored within group file. * Beware: there is no existence check; files may be overwritten ! * * %dst_filenames must be freed when no longer used. * * Return value: an error code if unsuccessful, 0 otherwise. **/ TIEXPORT2 int TICALL tifiles_ungroup_file(const char *src_filename, char ***dst_filenames) { FileContent *src = NULL; FileContent **ptr, **dst = NULL; char *real_name, **p; int i, n; int ret; if (src_filename == NULL) { tifiles_critical("%s: an argument is NULL", __FUNCTION__); return ERR_INVALID_FILE; } if(tifiles_file_get_model(src_filename) == CALC_NSPIRE) return ERR_BAD_CALC; // read group file src = tifiles_content_create_regular(CALC_NONE); ret = tifiles_file_read_regular(src_filename, src); if(ret) goto tuf; // ungroup structure ret = tifiles_ungroup_content(src, &dst); if(ret) goto tuf; // count number of structures and allocates array of strings for(ptr = dst, n = 0; *ptr != NULL; ptr++, n++); if(dst_filenames != NULL) *dst_filenames = (char **)g_malloc((n + 1) * sizeof(char *)); // store each structure content to file for (ptr = dst, i = 0; *ptr != NULL; ptr++, i++) { ret = tifiles_file_write_regular(NULL, *ptr, &real_name); if(ret) goto tuf; if(dst_filenames != NULL) *dst_filenames[i] = real_name; else g_free(real_name); } // release allocated memory tifiles_content_delete_regular(src); tifiles_content_delete_group(dst); return 0; tuf: if(dst_filenames != NULL) { for(p = *dst_filenames; *p; p++) g_free(*p); g_free(p); } tifiles_content_delete_regular(src); tifiles_content_delete_group(dst); return ret; }
/** * tifiles_content_del_entry: * @content: a file content (single/group only). * @ve: the entry to remove * * Search for entry name and remove it from file content (not tested !). * * Return value: the number of entries or -1 if not found. **/ TIEXPORT2 int TICALL tifiles_content_del_entry(FileContent *content, VarEntry *ve) { int i, j; if (content != NULL) { if (ve == NULL) { tifiles_critical("%s: deleting NULL VarEntry ???", __FUNCTION__); return content->num_entries; } // Search for entry for(i = 0; i < content->num_entries; i++) { VarEntry *s = content->entries[i]; if(!strcmp(s->folder, ve->folder) && !strcmp(s->name, ve->name)) break; } // Not found ? Exit ! if(i == content->num_entries) return -1; // Release tifiles_ve_delete(content->entries[i]); // And shift for(j = i; j < content->num_entries; j++) content->entries[j] = content->entries[j+1]; content->entries[j] = NULL; // And resize content->entries = tifiles_ve_resize_array(content->entries, content->num_entries - 1); content->num_entries--; return content->num_entries; } else { tifiles_critical("%s: content is NULL", __FUNCTION__); return 0; } }
/** * tifiles_string2vartype: * @model: a calculator model. * @s: a type as string (like "REAL"). * * Returns the type of variable. * * Return value: a type ID. **/ TIEXPORT2 uint8_t TICALL tifiles_string2vartype(CalcModel model, const char *s) { if (s == NULL) { tifiles_critical("%s: invalid string !", __FUNCTION__); return 0; } switch (model) { #ifndef DISABLE_TI8X case CALC_TI73: return ti73_type2byte(s); case CALC_TI82: return ti82_type2byte(s); case CALC_TI83: return ti83_type2byte(s); case CALC_TI83P: case CALC_TI84P: case CALC_TI84P_USB: return ti83p_type2byte(s); case CALC_TI85: return ti85_type2byte(s); case CALC_TI86: return ti86_type2byte(s); #endif #ifndef DISABLE_TI9X case CALC_TI89: case CALC_TI89T: case CALC_TI89T_USB: return ti89_type2byte(s); case CALC_TI92: return ti92_type2byte(s); case CALC_TI92P: return ti92p_type2byte(s); case CALC_V200: return v200_type2byte(s); case CALC_NSPIRE: return nsp_type2byte(s); #endif default: tifiles_critical("%s: invalid model argument.", __FUNCTION__); return 0; } }
TIEXPORT2 int TICALL tifiles_cert_field_find_path(const uint8_t *data, uint32_t length, const uint16_t *field_path, uint16_t field_path_len, const uint8_t **contents, uint32_t *field_size) { int ret = 0; // Initial sanity checks. if (data == NULL) { tifiles_critical("%s: data is NULL", __FUNCTION__); return ERR_INVALID_PARAM; } if (field_path == NULL) { tifiles_critical("%s: field_path is NULL", __FUNCTION__); return ERR_INVALID_PARAM; } if (length < 2) { tifiles_critical("%s: length is too small to contain a valid cert field", __FUNCTION__); return ERR_INVALID_PARAM; } if (field_path_len == 0) { tifiles_warning("%s: field path is empty", __FUNCTION__); return ERR_INVALID_PARAM; } while (field_path_len != 0 && !ret) { ret = tifiles_cert_field_find(data, length, *field_path, &data, &length); //tifiles_warning("%p\t%u", data, length); field_path++; field_path_len--; if (contents != NULL) { *contents = data; } if (field_size != NULL) { *field_size = length; } } return ret; }
/** * ti9x_file_write_backup: * @filename: name of backup file where to write. * @content: the file content to write. * * Write content to a backup file. * * Return value: an error code, 0 otherwise. **/ int ti9x_file_write_backup(const char *filename, Ti9xBackup *content) { FILE *f; if (filename == NULL || content == NULL) { tifiles_critical("%s: an argument is NULL", __FUNCTION__); return ERR_INVALID_FILE; } f = g_fopen(filename, "wb"); if (f == NULL) { tifiles_info("Unable to open this file: %s", filename); return ERR_FILE_OPEN; } if (fwrite_8_chars(f, tifiles_calctype2signature(content->model)) < 0) goto tfwb; if (fwrite(fsignature, 1, 2, f) < 2) goto tfwb; if (fwrite_8_chars(f, "") < 0) goto tfwb; if (fwrite_n_bytes(f, 40, (uint8_t *)content->comment) < 0) goto tfwb; if (fwrite_word(f, 1) < 0) goto tfwb; if (fwrite_long(f, 0x52) < 0) goto tfwb; if (fwrite_8_chars(f, content->rom_version) < 0) goto tfwb; if (fwrite_word(f, content->type) < 0) goto tfwb; if (fwrite_word(f, 0) < 0) goto tfwb; if (fwrite_long(f, content->data_length + 0x52 + 2) < 0) goto tfwb; if (fwrite_word(f, 0x5aa5) < 0) goto tfwb; if (fwrite(content->data_part, 1, content->data_length, f) < content->data_length) goto tfwb; content->checksum = tifiles_checksum(content->data_part, content->data_length); if (fwrite_word(f, content->checksum) < 0) goto tfwb; fclose(f); return 0; tfwb: // release on exit tifiles_critical("%s: error writing file %s", __FUNCTION__, filename); fclose(f); return ERR_FILE_IO; }
/** * tifiles_content_dup_flash: * * Allocates and copies a new FlashContent structure. * * Return value: none. **/ TIEXPORT2 FlashContent* TICALL tifiles_content_dup_flash(FlashContent *content) { FlashContent *dup = NULL; FlashContent *p, *q; if (content != NULL) { dup = tifiles_content_create_flash(content->model); if (dup != NULL) { for(p = content, q = dup; p; p = p->next, q = q->next) { memcpy(q, p, sizeof(FlashContent)); // TI9x part if(tifiles_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(tifiles_calc_is_ti8x(content->model)) { int i; // copy pages q->pages = tifiles_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 = tifiles_content_create_flash(p->model); } } } else { tifiles_critical("%s(NULL)", __FUNCTION__); } return dup; }
/** * tnsp_file_write_regular: * @filename: name of file where to write or NULL. * @content: the file content to write. * @real_filename: pointer address or NULL. Must be freed if needed when no longer needed. * * Write one variable into a single 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. **/ int tnsp_file_write_regular(const char *fname, FileContent *content, char **real_fname) { FILE *f; char *filename = NULL; VarEntry *entry; if (content->entries == NULL || content->entries[0] == NULL) { tifiles_warning("%s: skipping content with NULL content->entries or content->entries[0]", __FUNCTION__); return ERR_FILE_IO; } if (fname != NULL) { filename = g_strdup(fname); if (filename == NULL) { return ERR_MALLOC; } } else { filename = tifiles_build_filename(content->model_dst, content->entries[0]); if (real_fname != NULL) { *real_fname = g_strdup(filename); } } f = g_fopen(filename, "wb"); if (f == NULL) { tifiles_info( "Unable to open this file: %s", filename); g_free(filename); return ERR_FILE_OPEN; } entry = content->entries[0]; if(fwrite(entry->data, 1, entry->size, f) < entry->size) { goto tfwr; } g_free(filename); fclose(f); return 0; tfwr: // release on exit tifiles_critical("%s: error writing file %s", __FUNCTION__, filename); g_free(filename); fclose(f); return ERR_FILE_IO; }
/** * tifiles_content_add_entry: * @content: a file content (single/group only). * @ve: the entry to add * * Adds the entry to the file content and updates internal structures. * Beware: the entry is not duplicated. * * Return value: the number of entries. **/ TIEXPORT2 int TICALL tifiles_content_add_entry(FileContent *content, VarEntry *ve) { if (content != NULL) { content->entries = tifiles_ve_resize_array(content->entries, content->num_entries + 1); if (ve == NULL) { tifiles_critical("%s: adding NULL VarEntry ???", __FUNCTION__); } content->entries[content->num_entries] = ve; content->num_entries++; return content->num_entries; } else { tifiles_critical("%s: content is NULL", __FUNCTION__); } return 0; }
/** * tifiles_group_files: * @src_filenames: a NULL-terminated array of strings (list of files to group). * @dst_filename: the filename where to store the group. * * Group several TI files into a single one (group file). * * Return value: an error code if unsuccessful, 0 otherwise. **/ TIEXPORT2 int TICALL tifiles_group_files(char **src_filenames, const char *dst_filename) { int i, n; FileContent **src = NULL; FileContent *dst = NULL; int ret = 0; if (src_filenames == NULL || dst_filename == NULL) { tifiles_critical("%s: an argument is NULL", __FUNCTION__); return ERR_INVALID_FILE; } if(tifiles_file_get_model(src_filenames[0]) == CALC_NSPIRE) return ERR_BAD_CALC; // counter number of files to group for (n = 0; src_filenames[n] != NULL; n++); // allocate space for that src = (FileContent **)g_malloc0((n + 1) * sizeof(FileContent *)); if (src == NULL) return ERR_MALLOC; // allocate each structure and load file content for (i = 0; i < n; i++) { src[i] = (FileContent *)g_malloc0(sizeof(FileContent)); if (src[i] == NULL) return ERR_MALLOC; ret = tifiles_file_read_regular(src_filenames[i], src[i]); if(ret) goto tgf; } src[i] = NULL; // group the array of structures ret = tifiles_group_contents(src, &dst); if(ret) goto tgf; // write grouped file ret = tifiles_file_write_regular(dst_filename, dst, NULL); if(ret) goto tgf; // release allocated memory tgf: tifiles_content_delete_group(src); tifiles_content_delete_regular(dst); return 0; }
/** * tifiles_get_varname: * @full_name: a calculator path such as 'fldname\varname'. * * Returns the name of the variable. * * Return value: varname as string. It should not be modified (static). **/ char *TICALL tifiles_get_varname(const char *full_name) { if (full_name != NULL) { char *bs = strchr(full_name, '\\'); if (bs == NULL) return (char *) full_name; else return (++bs); } tifiles_critical("%s(NULL)", __FUNCTION__); return NULL; }
/** * tifiles_group_contents: * @src_contents: a pointer on an array of #FileContent structures. The array must be NULL-terminated. * @dst_content: the address of a pointer. This pointer will see the allocated group file. * * Must be freed when no longer needed as well as the content of each #FileContent structure * (use #tifiles_content_delete_regular as usual). * * Group several #FileContent structures into a single one. * * Return value: an error code if unsuccessful, 0 otherwise. **/ TIEXPORT2 int TICALL tifiles_group_contents(FileContent **src_contents, FileContent **dst_content) { FileContent *dst; int i, j, n; if (src_contents == NULL || dst_content == NULL) { tifiles_critical("%s: an argument is NULL", __FUNCTION__); return ERR_INVALID_FILE; } for (n = 0; src_contents[n] != NULL; n++) { if(src_contents[n]->model == CALC_NSPIRE) { return ERR_BAD_CALC; } } dst = (FileContent *)g_malloc0(sizeof(FileContent)); if (dst == NULL) return ERR_MALLOC; if (n > 0) { memcpy(dst, src_contents[0], sizeof(FileContent)); } dst->num_entries = n; dst->entries = g_malloc0((n + 1) * sizeof(VarEntry*)); if (dst->entries == NULL) { free(dst); return ERR_MALLOC; } for (i = 0; i < n; i++) { FileContent *src = src_contents[i]; for(j = 0; j < src->num_entries; j++) dst->entries[i] = tifiles_ve_dup(src->entries[j]); } *dst_content = dst; return 0; }
/** * tifiles_build_filename: * @model: a calculator model. * @ve: a #VarEntry structure. * * Build a valid filename from folder name, variable name and variable type. * Example: real number x on TI89 in the 'main' folder will give 'main.x.89e'. * Note: this function is useable with FLASH apps, too (but you have to fill the #VarEntry structure yourself). * * Return value: a newly allocated string which must be freed when no longer used. **/ TIEXPORT2 char* TICALL tifiles_build_filename(CalcModel model, const VarEntry *ve) { char *filename; if (ve == NULL) { tifiles_critical("%s: an argument is NULL", __FUNCTION__); return NULL; } if(tifiles_calc_is_ti8x(model) || !strcmp(ve->folder, "") || (ve->type == tifiles_flash_type(model))) { char *part2; const char *part3; char *tmp; part2 = ticonv_varname_to_filename(model, ve->name, ve->type); part3 = tifiles_vartype2fext(model, ve->type); tmp = g_strconcat(part2, ".", part3, NULL); g_free(part2); filename = g_strdup(tmp); g_free(tmp); } else { char *part1; char *part2; const char *part3; char *tmp; part1 = ticonv_varname_to_filename(model, ve->folder, -1); part2 = ticonv_varname_to_filename(model, ve->name, ve->type); part3 = tifiles_vartype2fext(model, ve->type); tmp = g_strconcat(part1, ".", part2, ".", part3, NULL); g_free(part1); g_free(part2); filename = strdup(tmp); g_free(tmp); } return filename; }