static int send_pkt(CalcHandle* handle, uint16_t cmd, uint16_t len, uint8_t* data) { uint16_t sum; // command buf[0] = LSB(cmd); buf[1] = MSB(cmd); // length buf[2] = LSB(len); buf[3] = MSB(len); // data if(data) memcpy(buf+4, data, len); // checksum sum = tifiles_checksum(buf, 4 + len); buf[len+4+0] = LSB(sum); buf[len+4+1] = MSB(sum); TRYF(ticables_cable_send(handle->cable, buf, len+6)); return 0; }
/** * tifiles_ungroup_content: * @src_content: a pointer on the structure to unpack. * @dst_contents: the address of your pointer. This pointers will point on a * dynamically allocated array of structures. The array is terminated by NULL. * * Ungroup a TI file by exploding the structure into an array of structures. * * Array must be freed when no longer needed as well as the content of each #FileContent * structure (use #tifiles_content_delete_regular as usual). * * Return value: an error code if unsuccessful, 0 otherwise. **/ TIEXPORT2 int TICALL tifiles_ungroup_content(FileContent *src, FileContent ***dest) { int i; FileContent **dst; if (src == NULL || dest == NULL) { tifiles_critical("%s: an argument is NULL", __FUNCTION__); return ERR_INVALID_FILE; } if(src->model == CALC_NSPIRE) return ERR_BAD_CALC; // allocate an array of FileContent structures (NULL terminated) dst = *dest = (FileContent **)g_malloc0((src->num_entries + 1) * sizeof(FileContent *)); if (dst == NULL) return ERR_MALLOC; // parse each entry and duplicate it into a single content for (i = 0; i < src->num_entries; i++) { VarEntry *dst_entry = NULL; // allocate and duplicate content dst[i] = (FileContent *)g_malloc0(sizeof(FileContent)); if (dst[i] == NULL) return ERR_MALLOC; memcpy(dst[i], src, sizeof(FileContent)); // allocate and duplicate entry dst[i]->entries = g_malloc0((1+1) * sizeof(VarEntry*)); dst_entry = dst[i]->entries[0] = tifiles_ve_dup(src->entries[i]); // update some fields dst[i]->num_entries = 1; dst[i]->checksum += tifiles_checksum((uint8_t *) dst_entry, 15); dst[i]->checksum += tifiles_checksum(dst_entry->data, dst_entry->size); } dst[i] = NULL; return 0; }
/** * 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; }
/** * ti9x_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 Ti9xRegular 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 ti9x_file_read_regular(const char *filename, Ti9xRegular *content) { FILE *f; long cur_pos; char default_folder[FLDNAME_MAX]; char current_folder[FLDNAME_MAX]; uint32_t curr_offset = 0; uint32_t next_offset = 0; uint32_t file_size; uint16_t tmp; unsigned int i, j; char signature[9]; char varname[VARNAME_MAX]; int ret = ERR_FILE_IO; if (content == NULL) { tifiles_critical("%s: an argument is NULL", __FUNCTION__); return ERR_INVALID_FILE; } if (!tifiles_file_is_regular(filename)) { ret = ERR_INVALID_FILE; goto tfrr2; } f = g_fopen(filename, "rb"); if (f == NULL) { ret = ERR_FILE_OPEN; goto tfrr2; } // Get file size, then rewind. if (fseek(f, 0, SEEK_END) < 0) goto tfrr; cur_pos = ftell(f); if (cur_pos < 0) goto tfrr; if (fseek(f, 0, SEEK_SET) < 0) goto tfrr; // The TI-68k series' members have at best 4 MB of Flash (TODO: modify this code if this no longer holds). // Regular / group files larger than that size are highly dubious, files larger than twice that size are insane. if (cur_pos >= (8L << 20)) { ret = ERR_INVALID_FILE; goto tfrr; } file_size = (uint32_t)cur_pos; if (fread_8_chars(f, signature) < 0) goto tfrr; // Offset 0 content->model = tifiles_signature2calctype(signature); if (content->model == CALC_NONE) { ret = ERR_INVALID_FILE; goto tfrr; } if (content->model_dst == CALC_NONE) { content->model_dst = content->model; } if (fread_word(f, NULL) < 0) goto tfrr; // Offset 0x8 if (fread_8_chars(f, default_folder) < 0) goto tfrr; // Offset 0xA ticonv_varname_from_tifile_sn(content->model_dst, default_folder, content->default_folder, sizeof(content->default_folder), -1); strncpy(current_folder, content->default_folder, sizeof(current_folder) - 1); current_folder[sizeof(current_folder) - 1] = 0; if (fread_n_chars(f, 40, content->comment) < 0) goto tfrr; // Offset 0x12 if (fread_word(f, &tmp) < 0) goto tfrr; // Offset 0x3A content->num_entries = tmp; content->entries = g_malloc0((content->num_entries + 1) * sizeof(VarEntry*)); if (content->entries == NULL) { ret = ERR_MALLOC; goto tfrr; } for (i = 0, j = 0; i < content->num_entries; i++) { VarEntry *entry = content->entries[j] = g_malloc0(sizeof(VarEntry)); if (fread_long(f, &curr_offset) < 0) goto tfrr; // Offset N, 0x3C for the first entry if (curr_offset > file_size) { ret = ERR_INVALID_FILE; goto tfrr; } if (fread_8_chars(f, varname) < 0) goto tfrr; // Offset N+4, 0x40 for the first entry ticonv_varname_from_tifile_sn(content->model_dst, varname, entry->name, sizeof(entry->name), entry->type); if (fread_byte(f, &(entry->type)) < 0) goto tfrr; // Offset N+12, 0x48 for the first entry if (fread_byte(f, &(entry->attr)) < 0) goto tfrr; // Offset N+13, 0x49 for the first entry entry->attr = (entry->attr == 2 || entry->attr == 3) ? ATTRB_ARCHIVED : entry->attr; if (fread_word(f, NULL) < 0) goto tfrr; // Offset N+14, 0x4A for the first entry if (entry->type == TI92_DIR) // same as TI89_DIR, TI89t_DIR, ... { strncpy(current_folder, entry->name,sizeof(current_folder) - 1); current_folder[sizeof(current_folder) - 1] = 0; g_free(entry); continue; // folder: skip entry } else { uint16_t checksum, sum = 0; j++; strncpy(entry->folder, current_folder, sizeof(entry->folder) - 1); current_folder[sizeof(entry->folder) - 1] = 0; cur_pos = ftell(f); if (cur_pos < 0) goto tfrr; if (fread_long(f, &next_offset) < 0) goto tfrr; // Offset N+16, 0x4C for the first entry if (next_offset > file_size) { ret = ERR_INVALID_FILE; goto tfrr; } entry->size = next_offset - curr_offset - 4 - 2; if (entry->size > file_size) { ret = ERR_INVALID_FILE; goto tfrr; } entry->data = (uint8_t *)g_malloc0(entry->size); if (entry->data == NULL) { ret = ERR_MALLOC; goto tfrr; } if (fseek(f, curr_offset, SEEK_SET)) goto tfrr; if (fread_long(f, NULL) < 0) goto tfrr; // Normally: offset N+22, 0x52 for the first entry if (fread(entry->data, 1, entry->size, f) < entry->size) goto tfrr; // Normally: offset N+26, 0x56 for the first entry if (fread_word(f, &checksum) < 0) goto tfrr; if (fseek(f, cur_pos, SEEK_SET)) goto tfrr; sum = tifiles_checksum(entry->data, entry->size); if (sum != checksum) { ret = ERR_FILE_CHECKSUM; goto tfrr; } content->checksum += sum; // sum of all checksums but unused } } content->num_entries = j; content->entries = g_realloc(content->entries, content->num_entries * sizeof(VarEntry*)); //fread_long(f, &next_offset); //fseek(f, next_offset - 2, SEEK_SET); //fread_word(f, &(content->checksum)); fclose(f); return 0; tfrr: // release on exit tifiles_critical("%s: error reading / understanding file %s", __FUNCTION__, filename); fclose(f); tfrr2: tifiles_content_delete_regular(content); return ret; }
/** * ti9x_file_write_regular: * @filename: name of single/group 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 (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. **/ int ti9x_file_write_regular(const char *fname, Ti9xRegular *content, char **real_fname) { FILE *f; unsigned int i; char *filename = NULL; uint32_t offset = 0x52; int **table; unsigned int num_folders; char default_folder[FLDNAME_MAX]; char fldname[FLDNAME_MAX], varname[VARNAME_MAX]; if (content->entries == NULL) { tifiles_warning("%s: skipping content with NULL content->entries", __FUNCTION__); return 0; } if (fname != NULL) { filename = g_strdup(fname); if (filename == NULL) { return ERR_MALLOC; } } else { if (content->entries[0]) { filename = tifiles_build_filename(content->model_dst, content->entries[0]); } else { tifiles_warning("%s: asked to build a filename from null content->entries[0], bailing out", __FUNCTION__); if (real_fname != NULL) { *real_fname = NULL; } return 0; } if (real_fname != NULL) { *real_fname = g_strdup(filename); } } // build the table of folder & variable entries table = tifiles_create_table_of_entries((FileContent *)content, &num_folders); if (table == NULL) { g_free(filename); return ERR_MALLOC; } f = g_fopen(filename, "wb"); if (f == NULL) { tifiles_info( "Unable to open this file: %s", filename); tifiles_free_table_of_entries(table); g_free(filename); return ERR_FILE_OPEN; } // write header if (fwrite_8_chars(f, tifiles_calctype2signature(content->model)) < 0) goto tfwr; if (fwrite(fsignature, 1, 2, f) < 2) goto tfwr; if (content->num_entries == 1) // folder entry for single var is placed here { strncpy(content->default_folder, content->entries[0]->folder, sizeof(content->default_folder) - 1); content->default_folder[sizeof(content->default_folder) - 1] = 0; } ticonv_varname_to_tifile_sn(content->model, content->default_folder, default_folder, sizeof(default_folder), -1); if (fwrite_8_chars(f, default_folder) < 0) goto tfwr; if (fwrite_n_bytes(f, 40, (uint8_t *)content->comment) < 0) goto tfwr; if (content->num_entries > 1) { if (fwrite_word(f, (uint16_t) (content->num_entries + num_folders)) < 0) goto tfwr; offset += 16 * (content->num_entries + num_folders - 1); } else { if (fwrite_word(f, 1) < 0) goto tfwr; } // write table of entries for (i = 0; table[i] != NULL; i++) { VarEntry *fentry; int j, idx = table[i][0]; fentry = content->entries[idx]; if (fentry == NULL) { tifiles_warning("%s: skipping null content entry %d", __FUNCTION__, i); continue; } if (content->num_entries > 1) // single var does not have folder entry { if (fwrite_long(f, offset) < 0) goto tfwr; ticonv_varname_to_tifile_sn(content->model, fentry->folder, fldname, sizeof(fldname), -1); if (fwrite_8_chars(f, fldname) < 0) goto tfwr; if (fwrite_byte(f, (uint8_t)tifiles_folder_type(content->model)) < 0) goto tfwr; if (fwrite_byte(f, 0x00) < 0) goto tfwr; for (j = 0; table[i][j] != -1; j++); if (fwrite_word(f, (uint16_t) j) < 0) goto tfwr; } for (j = 0; table[i][j] != -1; j++) { int idx2 = table[i][j]; VarEntry *entry = content->entries[idx2]; uint8_t attr = ATTRB_NONE; if (fwrite_long(f, offset) < 0) goto tfwr; ticonv_varname_to_tifile_sn(content->model, entry->name, varname, sizeof(varname), entry->type); if (fwrite_8_chars(f, varname) < 0) goto tfwr; if (fwrite_byte(f, entry->type) < 0) goto tfwr; attr = (entry->attr == ATTRB_ARCHIVED) ? 3 : entry->attr; if (fwrite_byte(f, attr) < 0) goto tfwr; if (fwrite_word(f, 0) < 0) goto tfwr; offset += entry->size + 4 + 2; } } if (fwrite_long(f, offset) < 0) goto tfwr; if (fwrite_word(f, 0x5aa5) < 0) goto tfwr; // write data for (i = 0; table[i] != NULL; i++) { int j; for (j = 0; table[i][j] != -1; j++) { int idx = table[i][j]; VarEntry *entry = content->entries[idx]; uint16_t sum; if (fwrite_long(f, 0) < 0) goto tfwr; if (fwrite(entry->data, 1, entry->size, f) < entry->size) goto tfwr; sum = tifiles_checksum(entry->data, entry->size); if (fwrite_word(f, sum) < 0) goto tfwr; } } tifiles_free_table_of_entries(table); g_free(filename); fclose(f); return 0; tfwr: // release on exit tifiles_critical("%s: error writing file %s", __FUNCTION__, filename); tifiles_free_table_of_entries(table); g_free(filename); fclose(f); return ERR_FILE_IO; }
/** * ti9x_file_read_backup: * @filename: name of backup file to open. * @content: where to store the file content. * * Load the backup file into a Ti9xBackup structure. * * Structure content must be freed with #tifiles_content_delete_backup when * no longer used. If error occurs, the structure content is released for you. * * Return value: an error code, 0 otherwise. **/ int ti9x_file_read_backup(const char *filename, Ti9xBackup *content) { FILE *f; long cur_pos = 0; uint32_t file_size; char signature[9]; uint16_t sum; int ret = ERR_FILE_IO; if (content == NULL) { tifiles_critical("%s: an argument is NULL", __FUNCTION__); return ERR_INVALID_FILE; } if (!tifiles_file_is_backup(filename)) { ret = ERR_INVALID_FILE; goto tfrb2; } f = g_fopen(filename, "rb"); if (f == NULL) { tifiles_info( "Unable to open this file: %s", filename); ret = ERR_FILE_OPEN; goto tfrb2; } // Get file size, then rewind. if (fseek(f, 0, SEEK_END) < 0) goto tfrb; cur_pos = ftell(f); if (cur_pos < 0) goto tfrb; if (fseek(f, 0, SEEK_SET) < 0) goto tfrb; // The TI-68k series' members have at best 4 MB of Flash (TODO: modify this code if this no longer holds). // Backup files larger than that size are highly dubious, files larger than twice that size are insane. if (cur_pos >= (8L << 20)) { ret = ERR_INVALID_FILE; goto tfrb; } if (fread_8_chars(f, signature) < 0) goto tfrb; content->model = tifiles_signature2calctype(signature); if (content->model == CALC_NONE) { ret = ERR_INVALID_FILE; } if (fread_word(f, NULL) < 0) goto tfrb; if (fread_8_chars(f, NULL) < 0) goto tfrb; if (fread_n_chars(f, 40, content->comment) < 0) goto tfrb; if (fread_word(f, NULL) < 0) goto tfrb; if (fread_long(f, NULL) < 0) goto tfrb; if (fread_8_chars(f, content->rom_version) < 0) goto tfrb; if (fread_byte(f, &(content->type)) < 0) goto tfrb; if (fread_byte(f, NULL) < 0) goto tfrb; if (fread_word(f, NULL) < 0) goto tfrb; if (fread_long(f, &file_size) < 0) goto tfrb; if (file_size > (uint32_t)cur_pos) { ret = ERR_INVALID_FILE; goto tfrb; } content->data_length = file_size - 0x52 - 2; if (fread_word(f, NULL) < 0) goto tfrb; content->data_part = (uint8_t *)g_malloc0(content->data_length); if (content->data_part == NULL) { ret = ERR_MALLOC; goto tfrb; } if (fread(content->data_part, 1, content->data_length, f) < content->data_length) goto tfrb; if (fread_word(f, &(content->checksum)) < 0) goto tfrb; sum = tifiles_checksum(content->data_part, content->data_length); #if defined(CHECKSUM_ENABLED) if (sum != content->checksum) { ret = ERR_FILE_CHECKSUM; goto tfrb; } #endif fclose(f); return 0; tfrb: // release on exit tifiles_critical("%s: error reading / understanding file %s", __FUNCTION__, filename); fclose(f); tfrb2: tifiles_content_delete_backup(content); return ret; }
/* Send a packet from PC (host) to TI (target): - target [in] : a machine ID uint8_t - cmd [in] : a command ID uint8_t - length [in] : length of buffer - data [in] : data to send (or 0x00 if NULL) - int [out] : an error code */ TIEXPORT3 int TICALL dbus_send(CalcHandle* handle, uint8_t target, uint8_t cmd, uint16_t len, uint8_t* data) { int i; uint16_t sum; uint32_t length = (len == 0x0000) ? 65536 : len; // wrap around uint8_t *buf; int r, q; static int ref = 0; if (handle == NULL) { ticalcs_critical("%s: handle is NULL", __FUNCTION__); return ERR_INVALID_HANDLE; } buf = (uint8_t *)handle->priv2; //[65536+6]; if (buf == NULL) { ticalcs_critical("%s: handle->priv2 is NULL", __FUNCTION__); return ERR_INVALID_HANDLE; } ticables_progress_reset(handle->cable); if(data == NULL) { // short packet (no data) buf[0] = target; buf[1] = cmd; buf[2] = 0x00; buf[3] = 0x00; // TI80 does not use length if(target == PC_TI80) { TRYF(ticables_cable_send(handle->cable, buf, 2)); } else { TRYF(ticables_cable_send(handle->cable, buf, 4)); } } else { // std packet (data + checksum) buf[0] = target; buf[1] = cmd; buf[2] = LSB(length); buf[3] = MSB(length); // copy data memcpy(buf+4, data, length); // add checksum of packet sum = tifiles_checksum(data, length); buf[length+4+0] = LSB(sum); buf[length+4+1] = MSB(sum); // compute chunks MIN_SIZE = (handle->cable->model == CABLE_GRY) ? 512 : 2048; BLK_SIZE = (length + 6) / 20; // 5% if(BLK_SIZE == 0) BLK_SIZE = length + 6; if(BLK_SIZE < 32) BLK_SIZE = 128; // SilverLink doesn't like small block (< 32) q = (length + 6) / BLK_SIZE; r = (length + 6) % BLK_SIZE; handle->updat->max1 = length + 6; handle->updat->cnt1 = 0; // send full chunks for(i = 0; i < q; i++) { TRYF(ticables_cable_send(handle->cable, &buf[i*BLK_SIZE], BLK_SIZE)); ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate); handle->updat->cnt1 += BLK_SIZE; if(length > MIN_SIZE) handle->updat->pbar(); if (handle->updat->cancel) return ERR_ABORT; } // send last chunk { TRYF(ticables_cable_send(handle->cable, &buf[i*BLK_SIZE], (uint16_t)r)); ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate); handle->updat->cnt1 += 1; if(length > MIN_SIZE) handle->updat->pbar(); if (handle->updat->cancel) return ERR_ABORT; } } // force periodic refresh if(!(ref++ % 4)) handle->updat->refresh(); return 0; }
static int recv_pkt(CalcHandle* handle, uint16_t* cmd, uint16_t* len, uint8_t* data) { int i, r, q; uint16_t sum, chksum; // Any packet has always at least 4 bytes (cmd, len) TRYF(ticables_cable_recv(handle->cable, buf, 4)); *cmd = (buf[1] << 8) | buf[0]; *len = (buf[3] << 8) | buf[2]; if(!cmd_is_valid(*cmd)) return ERR_INVALID_CMD; if(*cmd == CMD_ERROR) return ERR_ROM_ERROR; // compute chunks BLK_SIZE = *len / 20; if(BLK_SIZE == 0) BLK_SIZE = 1; q = *len / BLK_SIZE; r = *len % BLK_SIZE; handle->updat->max1 = *len; handle->updat->cnt1 = 0; // recv full chunks for(i = 0; i < q; i++) { TRYF(ticables_cable_recv(handle->cable, &buf[i*BLK_SIZE + 4], BLK_SIZE)); ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate); handle->updat->cnt1 += BLK_SIZE; if(*len > MIN_SIZE) handle->updat->pbar(); //if (handle->updat->cancel) // return ERR_ABORT; } // recv last chunk { TRYF(ticables_cable_recv(handle->cable, &buf[i*BLK_SIZE + 4], (uint16_t)(r+2))); ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate); handle->updat->cnt1 += 1; if(*len > MIN_SIZE) handle->updat->pbar(); if (handle->updat->cancel) return ERR_ABORT; } // verify checksum chksum = (buf[*len+4 + 1] << 8) | buf[*len+4 + 0]; sum = tifiles_checksum(buf, *len + 4); //printf("<%04x %04x>\n", sum, chksum); if (chksum != sum) return ERR_CHECKSUM; if(data) memcpy(data, buf+4, *len); return 0; }
static int dbus_recv_(CalcHandle* handle, uint8_t* host, uint8_t* cmd, uint16_t* length, uint8_t* data, int host_check) { int i; uint16_t chksum; uint8_t buf[4]; int r, q; static int ref = 0; if (handle == NULL) { ticalcs_critical("%s: handle is NULL", __FUNCTION__); return ERR_INVALID_HANDLE; } if (host == NULL || cmd == NULL || length == NULL) { ticalcs_critical("%s: an argument is NULL", __FUNCTION__); return ERR_INVALID_PACKET; } // Any packet has always at least 2 bytes (MID, CID) TRYF(ticables_cable_recv(handle->cable, buf, 2)); *host = buf[0]; *cmd = buf[1]; // Any non-TI80 packet has a length; TI80 data packets also have a length if(*host != TI80_PC || *cmd == CMD_XDP) { TRYF(ticables_cable_recv(handle->cable, buf, 2)); *length = buf[0] | (buf[1] << 8); } else *length = 0; //removed for probing (pb here !) //if(host_check && (*host != host_ids(handle))) // return ERR_INVALID_HOST; if(*cmd == CMD_ERR || *cmd == CMD_ERR2) return ERR_CHECKSUM; switch (*cmd) { case CMD_VAR: // std packet ( data + checksum) case CMD_XDP: case CMD_SKP: case CMD_SID: case CMD_REQ: case CMD_IND: case CMD_RTS: if (data == NULL) { ticalcs_critical("%s: data is NULL", __FUNCTION__); return ERR_INVALID_CMD; } // compute chunks* MIN_SIZE = (handle->cable->model == CABLE_GRY) ? 512 : 2048; BLK_SIZE = *length / 20; if(BLK_SIZE == 0) BLK_SIZE = 1; q = *length / BLK_SIZE; r = *length % BLK_SIZE; handle->updat->max1 = *length; handle->updat->cnt1 = 0; // recv full chunks for(i = 0; i < q; i++) { TRYF(ticables_cable_recv(handle->cable, &data[i*BLK_SIZE], BLK_SIZE)); ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate); handle->updat->cnt1 += BLK_SIZE; if(*length > MIN_SIZE) handle->updat->pbar(); if (handle->updat->cancel) return ERR_ABORT; } // recv last chunk { TRYF(ticables_cable_recv(handle->cable, &data[i*BLK_SIZE], (uint16_t)r)); ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate); TRYF(ticables_cable_recv(handle->cable, buf, 2)); handle->updat->cnt1 += 1; if(*length > MIN_SIZE) handle->updat->pbar(); if (handle->updat->cancel) return ERR_ABORT; } // verify checksum chksum = buf[0] | (buf[1] << 8); if (chksum != tifiles_checksum(data, *length)) return ERR_CHECKSUM; break; case CMD_CTS: // short packet (no data) case CMD_ACK: case CMD_ERR: case CMD_ERR2: case CMD_RDY: case CMD_SCR: case CMD_RID: case CMD_KEY: case CMD_EOT: case CMD_CNT: break; default: return ERR_INVALID_CMD; } // force periodic refresh if(!(ref++ % 4)) handle->updat->refresh(); return 0; }
/* Send a packet from PC (host) to TI (target): - target [in] : a machine ID uint8_t - cmd [in] : a command ID uint8_t - length [in] : length of buffer - data [in] : data to send (or 0x00 if NULL) - int [out] : an error code */ TIEXPORT3 int TICALL dbus_send(CalcHandle* handle, uint8_t target, uint8_t cmd, uint16_t len, const uint8_t* data) { int i; uint16_t sum; uint32_t length = (len == 0x0000) ? 65536 : len; // wrap around uint8_t *buf; int r, q; static int ref = 0; int ret; VALIDATE_HANDLE(handle); buf = (uint8_t *)handle->buffer; //[65536+6]; if (buf == NULL) { ticalcs_critical("%s: handle->buffer is NULL", __FUNCTION__); return ERR_INVALID_HANDLE; } ticables_progress_reset(handle->cable); if (data == NULL) { // short packet (no data) buf[0] = target; buf[1] = cmd; buf[2] = 0x00; buf[3] = 0x00; // The TI-80 does not use length ret = ticables_cable_send(handle->cable, buf, (target == DBUS_MID_PC_TI80) ? 2 : 4); } else { // std packet (data + checksum) buf[0] = target; buf[1] = cmd; buf[2] = LSB(length); buf[3] = MSB(length); // copy data memcpy(buf+4, data, length); // add checksum of packet sum = tifiles_checksum(data, length); buf[length+4+0] = LSB(sum); buf[length+4+1] = MSB(sum); // compute chunks handle->priv.progress_min_size = (handle->cable->model == CABLE_GRY) ? 512 : 2048; handle->priv.progress_blk_size = (length + 6) / 20; // 5% if (handle->priv.progress_blk_size == 0) { handle->priv.progress_blk_size = length + 6; } if (handle->priv.progress_blk_size < 32) { handle->priv.progress_blk_size = 128; // SilverLink doesn't like small block (< 32) } q = (length + 6) / handle->priv.progress_blk_size; r = (length + 6) % handle->priv.progress_blk_size; handle->updat->max1 = length + 6; handle->updat->cnt1 = 0; ret = 0; // send full chunks for (i = 0; i < q; i++) { ret = ticables_cable_send(handle->cable, &buf[i*handle->priv.progress_blk_size], handle->priv.progress_blk_size); if (ret) { break; } ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate); handle->updat->cnt1 += handle->priv.progress_blk_size; if (length > handle->priv.progress_min_size) { handle->updat->pbar(); } if (handle->updat->cancel) { ret = ERR_ABORT; break; } } // send last chunk if (!ret) { ret = ticables_cable_send(handle->cable, &buf[i*handle->priv.progress_blk_size], (uint16_t)r); if (!ret) { ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate); handle->updat->cnt1 += 1; if (length > handle->priv.progress_min_size) { handle->updat->pbar(); } if (handle->updat->cancel) { ret = ERR_ABORT; } } } } // force periodic refresh if (!ret && !(ref++ % 4)) { handle->updat->refresh(); } return ret; }
TIEXPORT3 int TICALL dbus_recv_data(CalcHandle *handle, uint16_t* length, uint8_t* data) { int ret; int i; uint16_t chksum; uint8_t buf[4]; int r, q; VALIDATE_HANDLE(handle); VALIDATE_NONNULL(length); VALIDATE_NONNULL(data); // compute chunks handle->priv.progress_min_size = (handle->cable->model == CABLE_GRY) ? 512 : 2048; handle->priv.progress_blk_size = *length / 20; if (handle->priv.progress_blk_size == 0) { handle->priv.progress_blk_size = 1; } q = *length / handle->priv.progress_blk_size; r = *length % handle->priv.progress_blk_size; handle->updat->max1 = *length; handle->updat->cnt1 = 0; ret = 0; // recv full chunks for (i = 0; i < q; i++) { ret = ticables_cable_recv(handle->cable, &data[i*handle->priv.progress_blk_size], handle->priv.progress_blk_size); if (ret) { break; } ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate); handle->updat->cnt1 += handle->priv.progress_blk_size; if (*length > handle->priv.progress_min_size) { handle->updat->pbar(); } if (handle->updat->cancel) { ret = ERR_ABORT; break; } } // recv last chunk if (!ret) { ret = ticables_cable_recv(handle->cable, &data[i*handle->priv.progress_blk_size], (uint16_t)r); if (!ret) { ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate); ret = ticables_cable_recv(handle->cable, buf, 2); if (!ret) { handle->updat->cnt1++; if (*length > handle->priv.progress_min_size) { handle->updat->pbar(); } if (handle->updat->cancel) { ret = ERR_ABORT; } } } } if (!ret) { // verify checksum chksum = buf[0] | ((uint16_t)buf[1] << 8); if (chksum != tifiles_checksum(data, *length)) { ret = ERR_CHECKSUM; } } return ret; }
/** * ti9x_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 Ti9xRegular 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 ti9x_file_read_regular(const char *filename, Ti9xRegular *content) { FILE *f; long cur_pos = 0; char default_folder[FLDNAME_MAX]; char current_folder[FLDNAME_MAX]; uint32_t curr_offset = 0; uint32_t next_offset = 0; uint16_t tmp; int i, j; char signature[9]; char varname[VARNAME_MAX]; 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; } if(fread_8_chars(f, signature) < 0) goto tffr; content->model = tifiles_signature2calctype(signature); if (content->model == CALC_NONE) { return ERR_INVALID_FILE; } if(content->model_dst == CALC_NONE) { content->model_dst = content->model; } if(fread_word(f, NULL) < 0) goto tffr; if(fread_8_chars(f, default_folder) < 0) goto tffr; ticonv_varname_from_tifile_s(content->model_dst, default_folder, content->default_folder, -1); strcpy(current_folder, content->default_folder); if(fread_n_chars(f, 40, content->comment) < 0) goto tffr; if(fread_word(f, &tmp) < 0) goto tffr; content->num_entries = tmp; content->entries = g_malloc0((content->num_entries + 1) * sizeof(VarEntry*)); if (content->entries == NULL) { fclose(f); return ERR_MALLOC; } for (i = 0, j = 0; i < content->num_entries; i++) { VarEntry *entry = content->entries[j] = g_malloc0(sizeof(VarEntry)); if(fread_long(f, &curr_offset) < 0) goto tffr; if(fread_8_chars(f, varname) < 0) goto tffr; ticonv_varname_from_tifile_s(content->model_dst, varname, entry->name, entry->type); if(fread_byte(f, &(entry->type)) < 0) goto tffr; if(fread_byte(f, &(entry->attr)) < 0) goto tffr; entry->attr = (entry->attr == 2 || entry->attr == 3) ? ATTRB_ARCHIVED : entry->attr; if(fread_word(f, NULL) < 0) goto tffr; if (entry->type == TI92_DIR) // same as TI89_DIR, TI89t_DIR, ... { strcpy(current_folder, entry->name); g_free(entry); continue; // folder: skip entry } else { uint16_t checksum, sum = 0; j++; strcpy(entry->folder, current_folder); cur_pos = ftell(f); if(cur_pos == -1L) goto tffr; if(fread_long(f, &next_offset) < 0) goto tffr; entry->size = next_offset - curr_offset - 4 - 2; entry->data = (uint8_t *)g_malloc0(entry->size); if (entry->data == NULL) { fclose(f); tifiles_content_delete_regular(content); return ERR_MALLOC; } if(fseek(f, curr_offset, SEEK_SET)) goto tffr; if(fread_long(f, NULL) < 0) goto tffr; // 4 bytes (NULL) if(fread(entry->data, 1, entry->size, f) < entry->size) goto tffr; if(fread_word(f, &checksum) < 0) goto tffr; if(fseek(f, cur_pos, SEEK_SET)) goto tffr; sum = tifiles_checksum(entry->data, entry->size); if(sum != checksum) { fclose(f); tifiles_content_delete_regular(content); return ERR_FILE_CHECKSUM; } content->checksum += sum; // sum of all checksums but unused } } content->num_entries = j; content->entries = g_realloc(content->entries, content->num_entries * sizeof(VarEntry*)); //fread_long(f, &next_offset); //fseek(f, next_offset - 2, SEEK_SET); //fread_word(f, &(content->checksum)); 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; }
/** * ti9x_file_read_backup: * @filename: name of backup file to open. * @content: where to store the file content. * * Load the backup file into a Ti9xBackup structure. * * Structure content must be freed with #tifiles_content_delete_backup when * no longer used. If error occurs, the structure content is released for you. * * Return value: an error code, 0 otherwise. **/ int ti9x_file_read_backup(const char *filename, Ti9xBackup *content) { FILE *f; uint32_t file_size; char signature[9]; uint16_t sum; if (!tifiles_file_is_backup(filename)) { 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; } if (content == NULL) { tifiles_critical("%s: an argument is NULL", __FUNCTION__); return ERR_INVALID_FILE; } if(fread_8_chars(f, signature) < 0) goto tfrb; content->model = tifiles_signature2calctype(signature); if (content->model == CALC_NONE) { return ERR_INVALID_FILE; } if(fread_word(f, NULL) < 0) goto tfrb; if(fread_8_chars(f, NULL) < 0) goto tfrb; if(fread_n_chars(f, 40, content->comment) < 0) goto tfrb; if(fread_word(f, NULL) < 0) goto tfrb; if(fread_long(f, NULL) < 0) goto tfrb; if(fread_8_chars(f, content->rom_version) < 0) goto tfrb; if(fread_byte(f, &(content->type)) < 0) goto tfrb; if(fread_byte(f, NULL) < 0) goto tfrb; if(fread_word(f, NULL) < 0) goto tfrb; if(fread_long(f, &file_size) < 0) goto tfrb; content->data_length = file_size - 0x52 - 2; if(fread_word(f, NULL) < 0) goto tfrb; content->data_part = (uint8_t *)g_malloc0(content->data_length); if (content->data_part == NULL) { fclose(f); tifiles_content_delete_backup(content); return ERR_MALLOC; } if(fread(content->data_part, 1, content->data_length, f) < content->data_length) goto tfrb; if(fread_word(f, &(content->checksum)) < 0) goto tfrb; sum = tifiles_checksum(content->data_part, content->data_length); #if defined(CHECKSUM_ENABLED) if(sum != content->checksum) { fclose(f); tifiles_content_delete_backup(content); return ERR_FILE_CHECKSUM; } #endif fclose(f); return 0; tfrb: // release on exit tifiles_critical("%s: error reading / understanding file %s", __FUNCTION__, filename); fclose(f); tifiles_content_delete_backup(content); return ERR_FILE_IO; }