Mercurial > hg > sidinfo
view sidlib.c @ 77:d14c82880141
Cosmetic.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 01 Jan 2016 05:26:15 +0200 |
parents | 2b2376f1b0cc |
children | 4c0ecb078591 |
line wrap: on
line source
/* * SIDInfoLib - Way too simplistic PSID/RSID file library * Written by Matti 'ccr' Hämäläinen <ccr@tnsp.org> * (C) Copyright 2014-2016 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 *fh, 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(fh, (uint8_t *) psid->magic, PSID_MAGIC_LEN) || !th_fread_be16(fh, &psid->version) || !th_fread_be16(fh, &psid->dataOffset) || !th_fread_be16(fh, &psid->loadAddress) || !th_fread_be16(fh, &psid->initAddress) || !th_fread_be16(fh, &psid->playAddress) || !th_fread_be16(fh, &psid->nSongs) || !th_fread_be16(fh, &psid->startSong) || !th_fread_be32(fh, &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(fh, (uint8_t *)psid->sidName, PSID_STR_LEN) || !th_fread_str(fh, (uint8_t *)psid->sidAuthor, PSID_STR_LEN) || !th_fread_str(fh, (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(fh, &psid->flags) || !th_fread_byte(fh, &psid->startPage) || !th_fread_byte(fh, &psid->pageLength) || !th_fread_be16(fh, &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, fh); 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(fh)); // 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 "?"; } }