# HG changeset patch # User Matti Hamalainen # Date 1451611962 -7200 # Node ID 4779bbec2f2847005bf8af7106ffa6c4279d90ac # Parent 19cbd864287531f12692404aff86fccf874f3659 Split some functionality into sidlib.[ch]. diff -r 19cbd8642875 -r 4779bbec2f28 Makefile.gen --- a/Makefile.gen Fri Jan 01 03:17:11 2016 +0200 +++ b/Makefile.gen Fri Jan 01 03:32:42 2016 +0200 @@ -13,7 +13,7 @@ THLIBS_OBJ=th_util.o th_string.o th_endian.o th_args.o th_crypto.o -SIDINFO_OBJ=sidinfo.o +SIDINFO_OBJ=sidlib.o sidinfo.o SIDINFO_BIN=$(BINPATH)sidinfo$(EXEEXT) TARGETS += $(SIDINFO_BIN) diff -r 19cbd8642875 -r 4779bbec2f28 sidinfo.c --- a/sidinfo.c Fri Jan 01 03:17:11 2016 +0200 +++ b/sidinfo.c Fri Jan 01 03:32:42 2016 +0200 @@ -1,12 +1,12 @@ /* * SIDInfo - PSID/RSID information displayer - * Written by Matti 'ccr' Hämäläinen + * Written by Matti 'ccr' Hämäläinen * (C) Copyright 2014-2015 Tecnic Software productions (TNSP) */ #include "th_args.h" -#include "th_endian.h" #include "th_string.h" -#include "th_crypto.h" +#include "sidlib.h" + // Some constants #define PSID_MAGIC_LEN 4 @@ -378,233 +378,6 @@ } -typedef struct -{ - char magic[PSID_MAGIC_LEN + 1]; // "PSID" / "RSID" magic identifier - uint16_t - version, // Version number - dataOffset, // Start of actual c64 data in file - loadAddress, // Loading address - initAddress, // Initialization address - playAddress, // Play one frame - nSongs, // Number of subsongs - startSong; // Default starting song - uint32_t speed; // Speed - char sidName[PSID_STR_LEN + 1]; // Descriptive text-fields, ASCIIZ - char sidAuthor[PSID_STR_LEN + 1]; - char sidCopyright[PSID_STR_LEN + 1]; - - // PSIDv2 data - uint16_t flags; // Flags - uint8_t startPage, pageLength; - uint16_t reserved; - - // Extra data - BOOL isRSID; - size_t dataSize; // Total size of data - header - th_md5hash_t hash; // Songlength database hash - -} PSIDHeader; - - -enum -{ - PSF_PLAYER_TYPE = 0x0001, // 0 = built-in, 1 = Compute! SIDPlayer MUS - PSF_PLAYSID_TUNE = 0x0002, // 0 = Real C64-compatible, 1 = PlaySID specific (v2NG) - - PSF_CLOCK_UNKNOWN = 0x0000, // Video standard used (v2NG) - PSF_CLOCK_PAL = 0x0004, - PSF_CLOCK_NTSC = 0x0008, - PSF_CLOCK_ANY = 0x000c, - PSF_CLOCK_MASK = 0x000c, - - PSF_MODEL_UNKNOWN = 0x0000, // SID model (v2NG) - PSF_MODEL_MOS6581 = 0x0010, - PSF_MODEL_MOS8580 = 0x0020, - PSF_MODEL_ANY = 0x0030, - PSF_MODEL_MASK = 0x0030, -}; - - -static void siAppendHash16(th_md5state_t *state, uint16_t data) -{ - uint8_t ib8[2]; - ib8[0] = data & 0xff; - ib8[1] = data >> 8; - th_md5_append(state, (uint8_t *) &ib8, sizeof(ib8)); -} - - -int siReadPSIDFile(FILE *inFile, PSIDHeader *psid) -{ - th_md5state_t state; - uint8_t tmp8, *fileData = NULL; - int index, ret = -1; - size_t read; - BOOL first; - - memset(psid, 0, sizeof(*psid)); - - if ((fileData = (uint8_t *) th_malloc(PSID_BUFFER_SIZE)) == NULL) - { - THERR("Error allocating temporary data buffer of %d bytes.\n", PSID_BUFFER_SIZE); - goto error; - } - - // Read PSID header in - if (!th_fread_str(inFile, (uint8_t *) psid->magic, PSID_MAGIC_LEN) || - !th_fread_be16(inFile, &psid->version) || - !th_fread_be16(inFile, &psid->dataOffset) || - !th_fread_be16(inFile, &psid->loadAddress) || - !th_fread_be16(inFile, &psid->initAddress) || - !th_fread_be16(inFile, &psid->playAddress) || - !th_fread_be16(inFile, &psid->nSongs) || - !th_fread_be16(inFile, &psid->startSong) || - !th_fread_be32(inFile, &psid->speed)) - { - THERR("Could not read PSID/RSID header.\n"); - goto error; - } - - psid->magic[PSID_MAGIC_LEN] = 0; - - if ((psid->magic[0] != 'R' && psid->magic[0] != 'P') || - psid->magic[1] != 'S' || psid->magic[2] != 'I' || psid->magic[3] != 'D' || - psid->version < 1 || psid->version > 3) - { - THERR("Not a supported PSID or RSID file.\n"); - goto error; - } - - psid->isRSID = psid->magic[0] == 'R'; - - if (!th_fread_str(inFile, (uint8_t *)psid->sidName, PSID_STR_LEN) || - !th_fread_str(inFile, (uint8_t *)psid->sidAuthor, PSID_STR_LEN) || - !th_fread_str(inFile, (uint8_t *)psid->sidCopyright, PSID_STR_LEN)) - { - THERR("Error reading SID file header.\n"); - goto error; - } - - psid->sidName[PSID_STR_LEN] = 0; - psid->sidAuthor[PSID_STR_LEN] = 0; - psid->sidCopyright[PSID_STR_LEN] = 0; - - // Check if we need to load PSIDv2NG header ... - if (psid->version >= 2) - { - // Yes, we need to - if (!th_fread_be16(inFile, &psid->flags) || - !th_fread_byte(inFile, &psid->startPage) || - !th_fread_byte(inFile, &psid->pageLength) || - !th_fread_be16(inFile, &psid->reserved)) - { - THERR("Error reading PSID/RSID v2+ extra header data.\n"); - goto error; - } - } - - // Initialize MD5-hash calculation - th_md5_init(&state); - - // Process actual data - psid->dataSize = 0; - first = TRUE; - do - { - read = fread(fileData, sizeof(uint8_t), PSID_BUFFER_SIZE, inFile); - psid->dataSize += read; - - if (first && psid->loadAddress == 0) - { - if (read < 4) - { - THERR("Error reading song data, unexpectedly small file.\n"); - goto error; - } - - // Grab the actual load address - psid->loadAddress = TH_LE16_TO_NATIVE(*(uint16_t *) fileData); - - // Strip load address (2 first bytes) - th_md5_append(&state, &fileData[2], read - 2); - first = FALSE; - } - else - if (read > 0) - { - // Append "as is" - th_md5_append(&state, fileData, read); - } - } while (read > 0 && !feof(inFile)); - - // Append header data to hash - siAppendHash16(&state, psid->initAddress); - siAppendHash16(&state, psid->playAddress); - siAppendHash16(&state, psid->nSongs); - - // Append song speed data to hash - tmp8 = psid->isRSID ? 60 : 0; - for (index = 0; index < psid->nSongs && index < 32; index++) - { - if (psid->isRSID) - tmp8 = 60; - else - tmp8 = (psid->speed & (1 << index)) ? 60 : 0; - - th_md5_append(&state, &tmp8, sizeof(tmp8)); - } - - // Rest of songs (more than 32) - for (index = 32; index < psid->nSongs; index++) - th_md5_append(&state, &tmp8, sizeof(tmp8)); - - // PSIDv2NG specific - if (psid->version >= 2) - { - // REFER TO SIDPLAY HEADERS FOR MORE INFORMATION - tmp8 = (psid->flags >> 2) & 3; - if (tmp8 == 2) - th_md5_append(&state, &tmp8, sizeof(tmp8)); - } - - // Calculate the hash - th_md5_finish(&state, psid->hash); - ret = 0; - -error: - // Free buffer - th_free(fileData); - return ret; -} - - -const char *siGetSIDClockStr(int flags) -{ - switch (flags & PSF_CLOCK_MASK) - { - case PSF_CLOCK_UNKNOWN : return "Unknown"; - case PSF_CLOCK_PAL : return "PAL 50Hz"; - case PSF_CLOCK_NTSC : return "NTSC 60Hz"; - case PSF_CLOCK_ANY : return "PAL / NTSC"; - default : return "?"; - } -} - - -const char *siGetSIDModelStr(int flags) -{ - switch (flags & PSF_MODEL_MASK) - { - case PSF_MODEL_UNKNOWN : return "Unknown"; - case PSF_MODEL_MOS6581 : return "MOS6581"; - case PSF_MODEL_MOS8580 : return "MOS8580"; - case PSF_MODEL_ANY : return "MOS6581 / MOS8580"; - default : return "?"; - } -} - - static void siPrintStrEscapes(FILE *outFile, const char *str) { while (*str) @@ -777,7 +550,7 @@ int main(int argc, char *argv[]) { // Initialize - th_init("SIDInfo", "PSID/RSID information displayer", "0.6.0", NULL, NULL); + th_init("SIDInfo", "PSID/RSID information displayer", "0.6.1", NULL, NULL); th_verbosityLevel = 0; memset(&optFormat, 0, sizeof(optFormat)); diff -r 19cbd8642875 -r 4779bbec2f28 sidlib.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sidlib.c Fri Jan 01 03:32:42 2016 +0200 @@ -0,0 +1,186 @@ +/* + * SIDInfoLib - Way too simplistic PSID/RSID file library + * Written by Matti 'ccr' Hämäläinen + * (C) Copyright 2014-2015 Tecnic Software productions (TNSP) + */ +#include "sidlib.h" +#include "th_endian.h" + + +static void siAppendHash16(th_md5state_t *state, uint16_t data) +{ + uint8_t ib8[2]; + ib8[0] = data & 0xff; + ib8[1] = data >> 8; + th_md5_append(state, (uint8_t *) &ib8, sizeof(ib8)); +} + + +int siReadPSIDFile(FILE *inFile, PSIDHeader *psid) +{ + th_md5state_t state; + uint8_t tmp8, *fileData = NULL; + int index, ret = -1; + size_t read; + BOOL first; + + memset(psid, 0, sizeof(*psid)); + + if ((fileData = (uint8_t *) th_malloc(PSID_BUFFER_SIZE)) == NULL) + { + THERR("Error allocating temporary data buffer of %d bytes.\n", PSID_BUFFER_SIZE); + goto error; + } + + // Read PSID header in + if (!th_fread_str(inFile, (uint8_t *) psid->magic, PSID_MAGIC_LEN) || + !th_fread_be16(inFile, &psid->version) || + !th_fread_be16(inFile, &psid->dataOffset) || + !th_fread_be16(inFile, &psid->loadAddress) || + !th_fread_be16(inFile, &psid->initAddress) || + !th_fread_be16(inFile, &psid->playAddress) || + !th_fread_be16(inFile, &psid->nSongs) || + !th_fread_be16(inFile, &psid->startSong) || + !th_fread_be32(inFile, &psid->speed)) + { + THERR("Could not read PSID/RSID header.\n"); + goto error; + } + + psid->magic[PSID_MAGIC_LEN] = 0; + + if ((psid->magic[0] != 'R' && psid->magic[0] != 'P') || + psid->magic[1] != 'S' || psid->magic[2] != 'I' || psid->magic[3] != 'D' || + psid->version < 1 || psid->version > 3) + { + THERR("Not a supported PSID or RSID file.\n"); + goto error; + } + + psid->isRSID = psid->magic[0] == 'R'; + + if (!th_fread_str(inFile, (uint8_t *)psid->sidName, PSID_STR_LEN) || + !th_fread_str(inFile, (uint8_t *)psid->sidAuthor, PSID_STR_LEN) || + !th_fread_str(inFile, (uint8_t *)psid->sidCopyright, PSID_STR_LEN)) + { + THERR("Error reading SID file header.\n"); + goto error; + } + + psid->sidName[PSID_STR_LEN] = 0; + psid->sidAuthor[PSID_STR_LEN] = 0; + psid->sidCopyright[PSID_STR_LEN] = 0; + + // Check if we need to load PSIDv2NG header ... + if (psid->version >= 2) + { + // Yes, we need to + if (!th_fread_be16(inFile, &psid->flags) || + !th_fread_byte(inFile, &psid->startPage) || + !th_fread_byte(inFile, &psid->pageLength) || + !th_fread_be16(inFile, &psid->reserved)) + { + THERR("Error reading PSID/RSID v2+ extra header data.\n"); + goto error; + } + } + + // Initialize MD5-hash calculation + th_md5_init(&state); + + // Process actual data + psid->dataSize = 0; + first = TRUE; + do + { + read = fread(fileData, sizeof(uint8_t), PSID_BUFFER_SIZE, inFile); + psid->dataSize += read; + + if (first && psid->loadAddress == 0) + { + if (read < 4) + { + THERR("Error reading song data, unexpectedly small file.\n"); + goto error; + } + + // Grab the actual load address + psid->loadAddress = TH_LE16_TO_NATIVE(*(uint16_t *) fileData); + + // Strip load address (2 first bytes) + th_md5_append(&state, &fileData[2], read - 2); + first = FALSE; + } + else + if (read > 0) + { + // Append "as is" + th_md5_append(&state, fileData, read); + } + } while (read > 0 && !feof(inFile)); + + // Append header data to hash + siAppendHash16(&state, psid->initAddress); + siAppendHash16(&state, psid->playAddress); + siAppendHash16(&state, psid->nSongs); + + // Append song speed data to hash + tmp8 = psid->isRSID ? 60 : 0; + for (index = 0; index < psid->nSongs && index < 32; index++) + { + if (psid->isRSID) + tmp8 = 60; + else + tmp8 = (psid->speed & (1 << index)) ? 60 : 0; + + th_md5_append(&state, &tmp8, sizeof(tmp8)); + } + + // Rest of songs (more than 32) + for (index = 32; index < psid->nSongs; index++) + th_md5_append(&state, &tmp8, sizeof(tmp8)); + + // PSIDv2NG specific + if (psid->version >= 2) + { + // REFER TO SIDPLAY HEADERS FOR MORE INFORMATION + tmp8 = (psid->flags >> 2) & 3; + if (tmp8 == 2) + th_md5_append(&state, &tmp8, sizeof(tmp8)); + } + + // Calculate the hash + th_md5_finish(&state, psid->hash); + ret = 0; + +error: + // Free buffer + th_free(fileData); + return ret; +} + + +const char *siGetSIDClockStr(const int flags) +{ + switch (flags & PSF_CLOCK_MASK) + { + case PSF_CLOCK_UNKNOWN : return "Unknown"; + case PSF_CLOCK_PAL : return "PAL 50Hz"; + case PSF_CLOCK_NTSC : return "NTSC 60Hz"; + case PSF_CLOCK_ANY : return "PAL / NTSC"; + default : return "?"; + } +} + + +const char *siGetSIDModelStr(const int flags) +{ + switch (flags & PSF_MODEL_MASK) + { + case PSF_MODEL_UNKNOWN : return "Unknown"; + case PSF_MODEL_MOS6581 : return "MOS6581"; + case PSF_MODEL_MOS8580 : return "MOS8580"; + case PSF_MODEL_ANY : return "MOS6581 / MOS8580"; + default : return "?"; + } +} diff -r 19cbd8642875 -r 4779bbec2f28 sidlib.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sidlib.h Fri Jan 01 03:32:42 2016 +0200 @@ -0,0 +1,71 @@ +/* + * SIDInfoLib - Way too simplistic PSID/RSID file library + * Written by Matti 'ccr' Hämäläinen + * (C) Copyright 2014-2015 Tecnic Software productions (TNSP) + */ +#ifndef SIDLIB_H +#define SIDLIB_H 1 + +#include "th_util.h" +#include "th_crypto.h" + + +// Some constants +#define PSID_MAGIC_LEN 4 +#define PSID_STR_LEN 32 +#define PSID_BUFFER_SIZE (1024 * 16) + + +typedef struct +{ + char magic[PSID_MAGIC_LEN + 1]; // "PSID" / "RSID" magic identifier + uint16_t + version, // Version number + dataOffset, // Start of actual c64 data in file + loadAddress, // Loading address + initAddress, // Initialization address + playAddress, // Play one frame + nSongs, // Number of subsongs + startSong; // Default starting song + uint32_t speed; // Speed + char sidName[PSID_STR_LEN + 1]; // Descriptive text-fields, ASCIIZ + char sidAuthor[PSID_STR_LEN + 1]; + char sidCopyright[PSID_STR_LEN + 1]; + + // PSIDv2 data + uint16_t flags; // Flags + uint8_t startPage, pageLength; + uint16_t reserved; + + // Extra data + BOOL isRSID; + size_t dataSize; // Total size of data - header + th_md5hash_t hash; // Songlength database hash + +} PSIDHeader; + + +enum +{ + PSF_PLAYER_TYPE = 0x0001, // 0 = built-in, 1 = Compute! SIDPlayer MUS + PSF_PLAYSID_TUNE = 0x0002, // 0 = Real C64-compatible, 1 = PlaySID specific (v2NG) + + PSF_CLOCK_UNKNOWN = 0x0000, // Video standard used (v2NG) + PSF_CLOCK_PAL = 0x0004, + PSF_CLOCK_NTSC = 0x0008, + PSF_CLOCK_ANY = 0x000c, + PSF_CLOCK_MASK = 0x000c, + + PSF_MODEL_UNKNOWN = 0x0000, // SID model (v2NG) + PSF_MODEL_MOS6581 = 0x0010, + PSF_MODEL_MOS8580 = 0x0020, + PSF_MODEL_ANY = 0x0030, + PSF_MODEL_MASK = 0x0030, +}; + +int siReadPSIDFile(FILE *inFile, PSIDHeader *psid); +const char *siGetSIDClockStr(const int flags); +const char *siGetSIDModelStr(const int flags); + + +#endif // SIDLIB_H