static void tzx_write_archive_info( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length ) { size_t i, count, total_length; count = libspectrum_tape_block_count( block ); /* 1 count byte, 2 bytes (ID and length) for every string */ total_length = 1 + 2 * count; /* And then the length of all the strings */ for( i = 0; i < count; i++ ) total_length += strlen( (char*)libspectrum_tape_block_texts( block, i ) ); /* Make room for all that, along with ID byte and two bytes storing the total length */ libspectrum_make_room( buffer, total_length + 3, ptr, length ); /* Write out the metadata */ *(*ptr)++ = LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO; libspectrum_write_word( ptr, total_length ); *(*ptr)++ = count; /* And the strings */ for( i = 0; i < count; i++ ) { *(*ptr)++ = libspectrum_tape_block_ids( block, i ); tzx_write_string( ptr, libspectrum_tape_block_texts( block, i ) ); } }
static void tzx_write_hardware( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length ) { size_t i, count; /* We need one ID byte, one count byte and then three bytes for every entry */ count = libspectrum_tape_block_count( block ); libspectrum_make_room( buffer, 2 + 3 * count, ptr, length ); /* Write out the metadata */ *(*ptr)++ = LIBSPECTRUM_TAPE_BLOCK_HARDWARE; *(*ptr)++ = count; /* And the info */ for( i = 0; i < count; i++ ) { *(*ptr)++ = libspectrum_tape_block_types( block, i ); *(*ptr)++ = libspectrum_tape_block_ids ( block, i ); *(*ptr)++ = libspectrum_tape_block_values( block, i ); } }
// Return a string describing a give tape block const char *Tape::GetBlockDetails (libspectrum_tape_block *block) { static char sz[128]; sz[0] = '\0'; char szExtra[64] = ""; char szName[11] = ""; const char *psz = NULL; libspectrum_byte *data = libspectrum_tape_block_data(block); long length = static_cast<long>(libspectrum_tape_block_data_length(block)); // Is there enough data to include a possible filename? if (length >= 12) { for (int i = 0 ; i < 10 ; i++) { char ch = data[i+2]; szName[i] = (ch >= ' ' && ch <= 0x7f) ? ch : '?'; } szName[10] = '\0'; } // Spectrum header length and type byte? if (length == 17+2 && data[0] == 0x00) { // Examine Spectrum file type switch (data[1]) { case 0: { psz = "ZX BASIC"; UINT uLine = (data[15] << 8) | data[14]; if (uLine != 0xffff) sprintf(szExtra, " LINE %u", uLine); break; } case 1: psz = "ZX DATA()"; break; case 2: psz = "ZX DATA$()"; break; case 3: { psz = "ZX CODE"; UINT uAddr = (data[15] << 8) | data[14]; UINT uLen = (data[13] << 8) | data[12]; sprintf(szExtra, " %u,%u", uAddr, uLen); break; } } } // SAM header length and type byte? // Real length is 82, but TZX spec suggests there could be up to 7-8 trailing bits, so accept 83 else if ((length == 80+2 || length == 80+1+2) && data[0] == 0x01) { // Examine SAM file type switch (data[1]) { case 16: { psz = "BASIC"; UINT uLine = (data[40] << 8) | data[39]; if (data[38] == 0) sprintf(szExtra, " LINE %u", uLine); break; } case 17: psz = "DATA()"; break; case 18: psz = "DATA$"; break; case 19: { psz = "CODE"; UINT uAddr = TPeek(data+32) + 16384; UINT uLen = TPeek(data+35); sprintf(szExtra, " %u,%u", uAddr, uLen); if (data[38] == 0) sprintf(szExtra+strlen(szExtra), ",%u", TPeek(data+38)); break; } case 20: { psz = "SCREEN$"; UINT uMode = data[17]+1; sprintf(szExtra, " MODE %u", uMode); break; } } } // Do we have a type string? if (psz) { // Start with type and append filename strcpy(sz, psz); strcat(sz, ": '"); strcat(sz, szName); strcat(sz, "'"); // Append any additional type-specific details if (szExtra[0]) { strcat(sz, " "); strcat(sz, szExtra); } } // No details yet? if (!sz[0]) { libspectrum_tape_type type = libspectrum_tape_block_type(block); switch (type) { case LIBSPECTRUM_TAPE_BLOCK_ROM: case LIBSPECTRUM_TAPE_BLOCK_TURBO: { // Raw tape block data length size_t length = libspectrum_tape_block_data_length(block); // If possible, exclude the type, sync, and checksum bytes from the length if (length >= 3) length -= 3; snprintf(sz, sizeof(sz), "%u bytes", length); break; } case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA: case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA: snprintf(sz, sizeof(sz), "%u bytes", libspectrum_tape_block_data_length(block)); break; case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE: snprintf(sz, sizeof(sz), "%u tstates", libspectrum_tape_block_pulse_length(block)); break; case LIBSPECTRUM_TAPE_BLOCK_PULSES: snprintf(sz, sizeof(sz), "%u pulses", libspectrum_tape_block_count(block)); break; case LIBSPECTRUM_TAPE_BLOCK_PAUSE: snprintf(sz, sizeof(sz), "%ums", libspectrum_tape_block_pause(block)); break; case LIBSPECTRUM_TAPE_BLOCK_GROUP_START: case LIBSPECTRUM_TAPE_BLOCK_COMMENT: case LIBSPECTRUM_TAPE_BLOCK_MESSAGE: case LIBSPECTRUM_TAPE_BLOCK_CUSTOM: snprintf(sz, sizeof(sz), "%s", libspectrum_tape_block_text(block)); break; case LIBSPECTRUM_TAPE_BLOCK_JUMP: { int offset = libspectrum_tape_block_offset(block); if (offset >= 0) snprintf(sz, sizeof(sz), "Forward %d blocks", offset); else snprintf(sz, sizeof(sz), "Backward %d blocks", -offset); break; } case LIBSPECTRUM_TAPE_BLOCK_LOOP_START: snprintf(sz, sizeof(sz), "%u iterations", libspectrum_tape_block_count(block)); break; case LIBSPECTRUM_TAPE_BLOCK_SELECT: snprintf(sz, sizeof(sz), "%u options", libspectrum_tape_block_count(block)); break; case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA: snprintf(sz, sizeof(sz), "%u data symbols", libspectrum_tape_generalised_data_symbol_table_symbols_in_block(libspectrum_tape_block_data_table(block))); break; case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO: { size_t count = libspectrum_tape_block_count(block); for (size_t i = 0 ; i < count ; i++) { int id = libspectrum_tape_block_ids(block, i); const char *value = libspectrum_tape_block_texts(block, i); // Full title TZX id? if (id == 0x00) strncpy(sz, value, sizeof(sz)-1); } break; } case LIBSPECTRUM_TAPE_BLOCK_HARDWARE: { size_t count = libspectrum_tape_block_count(block); for (size_t i = 0 ; i < count ; i++) { int type = libspectrum_tape_block_types(block, i); int id = libspectrum_tape_block_ids(block, i); // Skip anything but the TZX "Computers" type if (type != 0) continue; // Check for relevant computer ids if (id == 9) strcpy(sz, "SAM Coupe"); else if ((id >= 0x00 && id <= 0x05) || id == 0x0e) strcpy(sz, "ZX Spectrum"); else if (id == 0x08) strcpy(sz, "Pentagon"); else if (id == 0x06 || id == 0x07) strcpy(sz, "Timex Sinclair"); else snprintf(sz, sizeof(sz), "Unknown (%02X)", id); } break; } default: break; } } return sz; }