void SidTune::MUS_installPlayer(uint_least8_t *c64buf) { if (status && (c64buf != 0)) { // Install MUS player #1. uint_least16_t dest = endian_16(_sidtune_sidplayer1[1], _sidtune_sidplayer1[0]); memcpy(c64buf+dest,_sidtune_sidplayer1+2,sizeof(_sidtune_sidplayer1)-2); // Point player #1 to data #1. c64buf[dest+0xc6e] = (SIDTUNE_MUS_DATA_ADDR+2)&0xFF; c64buf[dest+0xc70] = (SIDTUNE_MUS_DATA_ADDR+2)>>8; if (info.sidChipBase2 != 0) { // Install MUS player #2. dest = endian_16(_sidtune_sidplayer2[1], _sidtune_sidplayer2[0]); memcpy(c64buf+dest,_sidtune_sidplayer2+2,sizeof(_sidtune_sidplayer2)-2); // Point player #2 to data #2. c64buf[dest+0xc6e] = (SIDTUNE_MUS_DATA_ADDR+musDataLen+2)&0xFF; c64buf[dest+0xc70] = (SIDTUNE_MUS_DATA_ADDR+musDataLen+2)>>8; }
bool SidTune::MUS_mergeParts(Buffer_sidtt<const uint_least8_t>& musBuf, Buffer_sidtt<const uint_least8_t>& strBuf) { Buffer_sidtt<uint8_t> mergeBuf; uint_least32_t mergeLen = musBuf.len()+strBuf.len(); // Sanity check. I do not trust those MUS/STR files around. uint_least32_t freeSpace = endian_16(_sidtune_sidplayer1[1],_sidtune_sidplayer1[0]) - SIDTUNE_MUS_DATA_ADDR; if ( (musBuf.len()+strBuf.len()-4) > freeSpace) { info.statusString = _sidtune_txt_sizeExceeded; return false; } #ifdef HAVE_EXCEPTIONS if ( !mergeBuf.assign(new(std::nothrow) uint8_t[mergeLen],mergeLen) ) #else if ( !mergeBuf.assign(new uint8_t[mergeLen],mergeLen) ) #endif { info.statusString = _sidtune_txt_notEnoughMemory; return false; } // Install MUS data #1 including load address. #ifndef SID_HAVE_BAD_COMPILER memcpy(mergeBuf.get(),musBuf.get(),musBuf.len()); #else memcpy((void*)mergeBuf.get(),musBuf.get(),musBuf.len()); #endif if ( !strBuf.isEmpty() && info.sidChipBase2!=0 ) { // Install MUS data #2 _NOT_ including load address. #ifndef SID_HAVE_BAD_COMPILER memcpy(mergeBuf.get()+musBuf.len(),strBuf.get(),strBuf.len()); #else memcpy((void*)(mergeBuf.get()+musBuf.len()),strBuf.get(),strBuf.len()); #endif } musBuf.assign(mergeBuf.xferPtr(),mergeBuf.xferLen()); strBuf.erase(); return true; }
bool SidTune::MUS_detect(const void* buffer, const uint_least32_t bufLen, uint_least32_t& voice3Index) { SmartPtr_sidtt<const uint8_t> spMus((const uint8_t*)buffer,bufLen); // Skip load address and 3x length entry. uint_least32_t voice1Index = (2+3*2); // Add length of voice 1 data. voice1Index += endian_16(spMus[3],spMus[2]); // Add length of voice 2 data. uint_least32_t voice2Index = voice1Index + endian_16(spMus[5],spMus[4]); // Add length of voice 3 data. voice3Index = voice2Index + endian_16(spMus[7],spMus[6]); return ((endian_16(spMus[voice1Index-2],spMus[voice1Index+1-2]) == SIDTUNE_MUS_HLT_CMD) && (endian_16(spMus[voice2Index-2],spMus[voice2Index+1-2]) == SIDTUNE_MUS_HLT_CMD) && (endian_16(spMus[voice3Index-2],spMus[voice3Index+1-2]) == SIDTUNE_MUS_HLT_CMD) && spMus); }
bool SidTune::INFO_fileSupport(const void* dataBuffer, uint_least32_t dataLength, const void* infoBuffer, uint_least32_t infoLength) { // Require a first minimum safety size. uint_least32_t minSize = 1+sizeof(struct DiskObject); if (infoLength < minSize) return( false ); const DiskObject *dobject = (const DiskObject *)infoBuffer; // Require Magic_Id in the first two bytes of the file. if ( endian_16(dobject->Magic[0],dobject->Magic[1]) != WB_DISKMAGIC ) return false; // Only version 1.x supported. if ( endian_16(dobject->Version[0],dobject->Version[1]) != WB_DISKVERSION ) return false; // A PlaySID icon must be of type project. if ( dobject->Type != WB_PROJECT ) return false; uint i; // general purpose index variable // We want to skip a possible Gadget Image item. const char *icon = (const char*)infoBuffer + sizeof(DiskObject); if ( (endian_16(dobject->Gadget.Flags[0],dobject->Gadget.Flags[1]) & GFLG_GADGIMAGE) == 0) { // Calculate size of gadget borders (vector image). if (dobject->Gadget.pGadgetRender[0] | dobject->Gadget.pGadgetRender[1] | dobject->Gadget.pGadgetRender[2] | dobject->Gadget.pGadgetRender[3]) // border present? { // Require another minimum safety size. minSize += sizeof(struct Border); if (infoLength < minSize) return( false ); const Border *brd = (const Border *)icon; icon += sizeof(Border); icon += brd->Count * (2+2); // pair of uint_least16_t } if (dobject->Gadget.pSelectRender[0] | dobject->Gadget.pSelectRender[1] | dobject->Gadget.pSelectRender[2] | dobject->Gadget.pSelectRender[3]) // alternate border present? { // Require another minimum safety size. minSize += sizeof(Border); if (infoLength < minSize) return( false ); const Border *brd = (const Border *)icon; icon += sizeof(Border); icon += brd->Count * (2+2); // pair of uint_least16_t } } else { // Calculate size of gadget images (bitmap image). if (dobject->Gadget.pGadgetRender[0] | dobject->Gadget.pGadgetRender[1] | dobject->Gadget.pGadgetRender[2] | dobject->Gadget.pGadgetRender[3]) // image present? { // Require another minimum safety size. minSize += sizeof(Image); if (infoLength < minSize) return( false ); const Image *img = (const Image *)icon; icon += sizeof(Image); uint_least32_t imgsize = 0; for(i=0;i<endian_16(img->Depth[0],img->Depth[1]);i++) { if ( (img->PlanePick & (1<<i)) != 0) { // NOTE: Intuition relies on PlanePick to know how many planes // of data are found in ImageData. There should be no more // '1'-bits in PlanePick than there are planes in ImageData. imgsize++; } } imgsize *= ((endian_16(img->Width[0],img->Width[1])+15)/16)*2; // bytes per line imgsize *= endian_16(img->Height[0],img->Height[1]); // bytes per plane icon += imgsize; } if (dobject->Gadget.pSelectRender[0] | dobject->Gadget.pSelectRender[1] | dobject->Gadget.pSelectRender[2] | dobject->Gadget.pSelectRender[3]) // alternate image present? { // Require another minimum safety size. minSize += sizeof(Image); if (infoLength < minSize) return( false ); const Image *img = (const Image *)icon; icon += sizeof(Image); uint_least32_t imgsize = 0; for(i=0;i<endian_16(img->Depth[0],img->Depth[1]);i++) { if ( (img->PlanePick & (1<<i)) != 0) { // NOTE: Intuition relies on PlanePick to know how many planes // of data are found in ImageData. There should be no more // '1'-bits in PlanePick than there are planes in ImageData. imgsize++; } } imgsize *= ((endian_16(img->Width[0],img->Width[1])+15)/16)*2; // bytes per line imgsize *= endian_16(img->Height[0],img->Height[1]); // bytes per plane icon += imgsize; } } // Here use a smart pointer to prevent access violation errors. SmartPtr_sidtt<const char> spTool((const char*)icon,infoLength-(uint_least32_t)(icon-(const char*)infoBuffer)); if ( !spTool ) { info.formatString = _sidtune_txt_corruptError; return false; } // A separate safe buffer is used for each tooltype string. #ifdef HAVE_EXCEPTIONS SmartPtr_sidtt<char> spCmpBuf(new(std::nothrow) char[safeBufferSize],safeBufferSize,true); #else SmartPtr_sidtt<char> spCmpBuf(new char[safeBufferSize],safeBufferSize,true); #endif if ( !spCmpBuf ) { info.formatString = _sidtune_txt_noMemError; return false; } #ifndef SID_HAVE_BAD_COMPILER char* cmpBuf = spCmpBuf.tellBegin(); #else // This should not be necessary, but for some reason // Microsoft Visual C++ says spCmpBuf is const... char* cmpBuf = (char*) spCmpBuf.tellBegin(); #endif // Skip default tool. spTool += endian_32(spTool[0],spTool[1],spTool[2],spTool[3]) + 4; // Defaults. fileOffset = 0; // no header in separate data file info.sidChipBase1 = 0xd400; info.sidChipBase2 = 0; info.musPlayer = false; info.numberOfInfoStrings = 0; uint_least32_t oldStyleSpeed = 0; // Flags for required entries. bool hasAddress = false, hasName = false, hasAuthor = false, hasCopyright = false, hasSongs = false, hasSpeed = false, hasUnknownChunk = false; // Calculate number of tooltype strings. i = (endian_32(spTool[0],spTool[1],spTool[2],spTool[3])/4) - 1; spTool += 4; // skip size info while( i-- > 0 ) { // Get length of this tool. uint_least32_t toolLen = endian_32(spTool[0],spTool[1],spTool[2],spTool[3]); spTool += 4; // skip tool length // Copy item to safe buffer. for ( uint ci = 0; ci < toolLen; ci++ ) { #ifndef SID_HAVE_BAD_COMPILER spCmpBuf[ci] = spTool[ci]; #else // This should not be necessary, but for some reason // Microsoft Visual C++ says spCmpBuf is const... (*((char*) (&spCmpBuf[ci]))) = (char) spTool[ci]; #endif } if ( !(spTool&&spCmpBuf) ) { return false; } // Now check all possible keywords. if ( SidTuneTools::myStrNcaseCmp(cmpBuf,_sidtune_keyword_address) == 0 ) { const char *addrIn= cmpBuf + strlen(_sidtune_keyword_address); int len = toolLen - strlen(_sidtune_keyword_address); int pos = 0; info.loadAddr = (uint_least16_t)SidTuneTools::readHex( addrIn, len, pos ); info.initAddr = (uint_least16_t)SidTuneTools::readHex( addrIn, len, pos ); info.playAddr = (uint_least16_t)SidTuneTools::readHex( addrIn, len, pos ); if ( pos >= len ) { return false; } hasAddress = true; } else if ( SidTuneTools::myStrNcaseCmp(cmpBuf,_sidtune_keyword_songs) == 0 ) { const char *numIn = cmpBuf + strlen(_sidtune_keyword_songs); int len = toolLen - strlen(_sidtune_keyword_songs); int pos = 0; if ( !pos >= len ) { return false; } info.songs = (uint_least16_t)SidTuneTools::readDec( numIn, len, pos ); info.startSong = (uint_least16_t)SidTuneTools::readDec( numIn, len, pos ); hasSongs = true; } else if ( SidTuneTools::myStrNcaseCmp(cmpBuf,_sidtune_keyword_speed) == 0 ) { const char *speedIn = cmpBuf + strlen(_sidtune_keyword_speed); int len = toolLen - strlen(_sidtune_keyword_speed); int pos = 0; if ( pos >= len ) { return false; } oldStyleSpeed = SidTuneTools::readHex(speedIn, len, pos); hasSpeed = true; } else if ( SidTuneTools::myStrNcaseCmp(cmpBuf,_sidtune_keyword_name) == 0 ) { strncpy( &infoString[0][0], cmpBuf + strlen(_sidtune_keyword_name), 31 ); info.infoString[0] = &infoString[0][0]; hasName = true; } else if ( SidTuneTools::myStrNcaseCmp(cmpBuf,_sidtune_keyword_author) == 0 ) { strncpy( &infoString[1][0], cmpBuf + strlen(_sidtune_keyword_author), 31 ); info.infoString[1] = &infoString[1][0]; hasAuthor = true; } else if ( SidTuneTools::myStrNcaseCmp(cmpBuf,_sidtune_keyword_copyright) == 0 ) { strncpy( &infoString[2][0], cmpBuf + strlen(_sidtune_keyword_copyright), 31 ); info.infoString[2] = &infoString[2][0]; hasCopyright = true; } else if ( SidTuneTools::myStrNcaseCmp(cmpBuf,_sidtune_keyword_musPlayer) == 0 ) { info.musPlayer = true; } else { hasUnknownChunk = true; #if defined(SIDTUNE_REJECT_UNKNOWN_FIELDS) info.formatString = _sidtune_txt_chunkError; return false; #endif } // Skip to next tool. spTool += toolLen; } // Collected ``required'' information complete ? if ( hasAddress && hasName && hasAuthor && hasCopyright && hasSongs && hasSpeed ) { // Create the speed/clock setting table. convertOldStyleSpeedToTables(oldStyleSpeed); if (( info.loadAddr == 0 ) && ( dataLength != 0 )) { SmartPtr_sidtt<const uint_least8_t> spDataBuf((const uint_least8_t*)dataBuffer,dataLength); spDataBuf += fileOffset; info.loadAddr = endian_16(spDataBuf[1],spDataBuf[0]); if ( !spDataBuf ) { info.formatString = _sidtune_txt_dataCorruptError; return false; } fileOffset += 2; } if ( info.initAddr == 0 ) { info.initAddr = info.loadAddr; } info.numberOfInfoStrings = 3; // We finally accept the input data. info.formatString = _sidtune_txt_format; return true; } else if ( hasAddress || hasName || hasAuthor || hasCopyright || hasSongs || hasSpeed ) { // Something is missing (or damaged?). info.formatString = _sidtune_txt_corruptError; return false; } else { // No PlaySID conform info strings. info.formatString = _sidtune_txt_noStringsError; return false; } }
bool SidTune::SID_fileSupport(const void* dataBuffer, uint_least32_t dataBufLen, const void* sidBuffer, uint_least32_t sidBufLen) { // Make sure SID buffer pointer is not zero. // Check for a minimum file size. If it is smaller, we will not proceed. if ((sidBuffer==0) || (sidBufLen<sidMinFileSize)) { return false; } const char* pParseBuf = (const char*)sidBuffer; // First line has to contain the exact identification string. if ( SidTuneTools::myStrNcaseCmp( pParseBuf, keyword_id ) != 0 ) { return false; } else { // At least the ID was found, so set a default error message. info.formatString = text_truncatedError; // Defaults. fileOffset = 0; // no header in separate data file info.sidChipBase1 = 0xd400; info.sidChipBase2 = 0; info.musPlayer = false; info.numberOfInfoStrings = 0; uint_least32_t oldStyleSpeed = 0; // Flags for required entries. bool hasAddress = false, hasName = false, hasAuthor = false, hasReleased = false, hasSongs = false, hasSpeed = false; // Using a temporary instance of an input string chunk. #ifdef HAVE_EXCEPTIONS char* pParseChunk = new(std::nothrow) char[parseChunkLen+1]; #else char* pParseChunk = new char[parseChunkLen+1]; #endif if ( pParseChunk == 0 ) { info.formatString = text_noMemError; return false; } // Parse as long we have not collected all ``required'' entries. //while ( !hasAddress || !hasName || !hasAuthor || !hasCopyright // || !hasSongs || !hasSpeed ) // Above implementation is wrong, we need to get all known // fields and then check if all ``required'' ones were found. for (;;) { // Skip to next line. Leave loop, if none. if (( pParseBuf = SidTuneTools::returnNextLine( pParseBuf )) == 0 ) { break; } // And get a second pointer to the following line. const char* pNextLine = SidTuneTools::returnNextLine( pParseBuf ); uint_least32_t restLen; if ( pNextLine != 0 ) { // Calculate number of chars between current pos and next line. restLen = (uint_least32_t)(pNextLine - pParseBuf); } else { // Calculate number of chars between current pos and end of buf. restLen = sidBufLen - (uint_least32_t)(pParseBuf - (char*)sidBuffer); } // Create whitespace eating (!) input string stream. const char *s = pParseBuf; int pos = 0; int posCopy = 0; // Now copy the next X characters except white-spaces. for ( uint_least16_t i = 0; i < parseChunkLen; i++ ) { pParseChunk[i] = s[i]; } pParseChunk[parseChunkLen]=0; // Now check for the possible keywords. // ADDRESS if ( SidTuneTools::myStrNcaseCmp( pParseChunk, keyword_address ) == 0 ) { SidTuneTools::skipToEqu( s, restLen, pos ); info.loadAddr = (uint_least16_t)SidTuneTools::readHex( s, restLen, pos ); if ( pos>=restLen ) break; info.initAddr = (uint_least16_t)SidTuneTools::readHex( s, restLen, pos ); if ( pos>=restLen ) break; info.playAddr = (uint_least16_t)SidTuneTools::readHex( s, restLen, pos ); hasAddress = true; } // NAME else if ( SidTuneTools::myStrNcaseCmp( pParseChunk, keyword_name ) == 0 ) { SidTuneTools::copyStringValueToEOL(pParseBuf,&infoString[0][0],SIDTUNE_MAX_CREDIT_STRLEN); info.infoString[0] = &infoString[0][0]; hasName = true; } // AUTHOR else if ( SidTuneTools::myStrNcaseCmp( pParseChunk, keyword_author ) == 0 ) { SidTuneTools::copyStringValueToEOL(pParseBuf,&infoString[1][0],SIDTUNE_MAX_CREDIT_STRLEN); info.infoString[1] = &infoString[1][0]; hasAuthor = true; } // COPYRIGHT else if ( SidTuneTools::myStrNcaseCmp( pParseChunk, keyword_copyright ) == 0 ) { SidTuneTools::copyStringValueToEOL(pParseBuf,&infoString[2][0],SIDTUNE_MAX_CREDIT_STRLEN); info.infoString[2] = &infoString[2][0]; hasReleased = true; } // RELEASED else if ( SidTuneTools::myStrNcaseCmp( pParseChunk, keyword_released ) == 0 ) { SidTuneTools::copyStringValueToEOL(pParseBuf,&infoString[2][0],SIDTUNE_MAX_CREDIT_STRLEN); info.infoString[2] = &infoString[2][0]; hasReleased = true; } // SONGS else if ( SidTuneTools::myStrNcaseCmp( pParseChunk, keyword_songs ) == 0 ) { SidTuneTools::skipToEqu( s, restLen, pos ); info.songs = (uint_least16_t)SidTuneTools::readDec( s, restLen, pos ); info.startSong = (uint_least16_t)SidTuneTools::readDec( s, restLen, pos ); hasSongs = true; } // SPEED else if ( SidTuneTools::myStrNcaseCmp( pParseChunk, keyword_speed ) == 0 ) { SidTuneTools::skipToEqu( s, restLen, pos ); oldStyleSpeed = SidTuneTools::readHex( s, restLen, pos ); hasSpeed = true; } // SIDSONG else if ( SidTuneTools::myStrNcaseCmp( pParseChunk, keyword_musPlayer ) == 0 ) { info.musPlayer = true; } // RELOC else if ( SidTuneTools::myStrNcaseCmp( pParseChunk, keyword_reloc ) == 0 ) { info.relocStartPage = (uint_least8_t)SidTuneTools::readHex( s, restLen, pos ); if ( pos >= restLen ) break; info.relocPages = (uint_least8_t)SidTuneTools::readHex( s, restLen, pos ); } // CLOCK else if ( SidTuneTools::myStrNcaseCmp( pParseChunk, keyword_clock ) == 0 ) { char clock[8]; SidTuneTools::copyStringValueToEOL(pParseBuf,clock,sizeof(clock)); if ( SidTuneTools::myStrNcaseCmp( clock, "UNKNOWN" ) == 0 ) info.clockSpeed = SIDTUNE_CLOCK_UNKNOWN; else if ( SidTuneTools::myStrNcaseCmp( clock, "PAL" ) == 0 ) info.clockSpeed = SIDTUNE_CLOCK_PAL; else if ( SidTuneTools::myStrNcaseCmp( clock, "NTSC" ) == 0 ) info.clockSpeed = SIDTUNE_CLOCK_NTSC; else if ( SidTuneTools::myStrNcaseCmp( clock, "ANY" ) == 0 ) info.clockSpeed = SIDTUNE_CLOCK_ANY; } // SIDMODEL else if ( SidTuneTools::myStrNcaseCmp( pParseChunk, keyword_sidModel ) == 0 ) { char model[8]; SidTuneTools::copyStringValueToEOL(pParseBuf,model,sizeof(model)); if ( SidTuneTools::myStrNcaseCmp( model, "UNKNOWN" ) == 0 ) info.sidModel = SIDTUNE_SIDMODEL_UNKNOWN; else if ( SidTuneTools::myStrNcaseCmp( model, "6581" ) == 0 ) info.sidModel = SIDTUNE_SIDMODEL_6581; else if ( SidTuneTools::myStrNcaseCmp( model, "8580" ) == 0 ) info.sidModel = SIDTUNE_SIDMODEL_8580; else if ( SidTuneTools::myStrNcaseCmp( model, "ANY" ) == 0 ) info.sidModel = SIDTUNE_SIDMODEL_ANY; } // COMPATIBILITY else if ( SidTuneTools::myStrNcaseCmp( pParseChunk, keyword_compatibility ) == 0 ) { char comp[5]; SidTuneTools::copyStringValueToEOL(pParseBuf,comp,sizeof(comp)); if ( SidTuneTools::myStrNcaseCmp( comp, "C64" ) == 0 ) info.compatibility = SIDTUNE_COMPATIBILITY_C64; else if ( SidTuneTools::myStrNcaseCmp( comp, "PSID" ) == 0 ) info.compatibility = SIDTUNE_COMPATIBILITY_PSID; else if ( SidTuneTools::myStrNcaseCmp( comp, "R64" ) == 0 ) info.compatibility = SIDTUNE_COMPATIBILITY_R64; } }; delete[] pParseChunk; // Again check for the ``required'' values. if ( hasAddress || hasName || hasAuthor || hasReleased || hasSongs || hasSpeed ) { // Check reserved fields to force real c64 compliance if (info.compatibility == SIDTUNE_COMPATIBILITY_R64) { if (checkRealC64Info (oldStyleSpeed) == false) return false; } // Create the speed/clock setting table. convertOldStyleSpeedToTables(oldStyleSpeed, info.clockSpeed); // loadAddr = 0 means, the address is stored in front of the C64 data. // We cannot verify whether the dataBuffer contains valid data. // All we want to know is whether the SID buffer is valid. // If data is present, we access it (here to get the C64 load address). if (info.loadAddr==0 && (dataBufLen>=(fileOffset+2)) && dataBuffer!=0) { const uint8_t* pDataBufCp = (const uint8_t*)dataBuffer + fileOffset; info.loadAddr = endian_16( *(pDataBufCp + 1), *pDataBufCp ); fileOffset += 2; // begin of data } // Keep compatibility to PSID/SID. if ( info.initAddr == 0 ) { info.initAddr = info.loadAddr; } info.numberOfInfoStrings = 3; // We finally accept the input data. info.formatString = text_format; return true; } else { // Something is missing (or damaged ?). // Error string set above. return false; } } }