Mercurial > hg > sidinfo
view sidlib.c @ 85:4c0ecb078591
Rename various variables and functions and change relevant places to use the
new th_ctx API.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Thu, 11 Feb 2016 23:18:58 +0200 |
parents | d14c82880141 |
children | e1ff9cd27a84 |
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" #include "th_string.h" static void si_append_hash16(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 si_read_sid_file(th_ioctx *ctx, PSIDHeader *psid) { th_md5state_t state; uint8_t tmp8, *data = NULL; int index, ret = -1; size_t read; BOOL first; memset(psid, 0, sizeof(*psid)); if ((data = (uint8_t *) th_malloc(PSID_BUFFER_SIZE)) == NULL) { th_io_error(ctx, THERR_MALLOC, "Error allocating temporary data buffer of %d bytes.\n", PSID_BUFFER_SIZE); goto error; } // Read PSID header in if (!thfread_str(ctx, (uint8_t *) psid->magic, PSID_MAGIC_LEN) || !thfread_be16(ctx, &psid->version) || !thfread_be16(ctx, &psid->dataOffset) || !thfread_be16(ctx, &psid->loadAddress) || !thfread_be16(ctx, &psid->initAddress) || !thfread_be16(ctx, &psid->playAddress) || !thfread_be16(ctx, &psid->nSongs) || !thfread_be16(ctx, &psid->startSong) || !thfread_be32(ctx, &psid->speed)) { th_io_error(ctx, ctx->errno, "Could not read PSID/RSID header: %s.\n", th_error_str(ctx->errno)); 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) { th_io_error(ctx, THERR_NOT_SUPPORTED, "Not a supported PSID or RSID file.\n"); goto error; } psid->isRSID = psid->magic[0] == 'R'; if (!thfread_str(ctx, (uint8_t *) psid->sidName, PSID_STR_LEN) || !thfread_str(ctx, (uint8_t *) psid->sidAuthor, PSID_STR_LEN) || !thfread_str(ctx, (uint8_t *) psid->sidCopyright, PSID_STR_LEN)) { th_io_error(ctx, ctx->errno, "Error reading SID file header: %s.\n", th_error_str(ctx->errno)); 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 (!thfread_be16(ctx, &psid->flags) || !thfread_byte(ctx, &psid->startPage) || !thfread_byte(ctx, &psid->pageLength) || !thfread_be16(ctx, &psid->reserved)) { th_io_error(ctx, ctx->errno, "Error reading PSID/RSID v2+ extra header data: %s.\n", th_error_str(ctx->errno)); goto error; } } // Initialize MD5-hash calculation th_md5_init(&state); // Process actual data psid->dataSize = 0; first = TRUE; do { read = thfread(data, sizeof(uint8_t), PSID_BUFFER_SIZE, ctx); psid->dataSize += read; if (first && psid->loadAddress == 0) { if (read < 4) { th_io_error(ctx, THERR_FREAD, "Error reading song data, unexpectedly small file.\n"); goto error; } // Grab the actual load address psid->loadAddress = TH_LE16_TO_NATIVE(*(uint16_t *) data); // Strip load address (2 first bytes) th_md5_append(&state, &data[2], read - 2); first = FALSE; } else if (read > 0) { // Append "as is" th_md5_append(&state, data, read); } } while (read > 0 && !thfeof(ctx)); // Append header data to hash si_append_hash16(&state, psid->initAddress); si_append_hash16(&state, psid->playAddress); si_append_hash16(&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(data); return ret; } const char *si_get_sid_clock_str(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 *si_get_sid_model_str(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 "?"; } }