Mercurial > hg > sidinfo
diff sidlib.c @ 70:4779bbec2f28
Split some functionality into sidlib.[ch].
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 01 Jan 2016 03:32:42 +0200 |
parents | |
children | 1e6ad4be7f15 |
line wrap: on
line diff
--- /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 <ccr@tnsp.org> + * (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 "?"; + } +}