/* * /home/ms/files/source/libsidtune/RCS/InfoFile.cpp,v * * SIDPLAY INFOFILE format support. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #ifdef HAVE_EXCEPTIONS # include #endif #include #include #include #include #include #include "SidTune.h" #include "SidTuneTools.h" #include "sidendian.h" const char text_format[] = "Raw plus SIDPLAY ASCII text file (SID)"; const char text_truncatedError[] = "ERROR: SID file is truncated"; const char text_noMemError[] = "ERROR: Not enough free memory"; const char keyword_id[] = "SIDPLAY INFOFILE"; const char keyword_name[] = "NAME="; // No white-space characters const char keyword_author[] = "AUTHOR="; // in these keywords, because const char keyword_copyright[] = "COPYRIGHT="; // we want to use a white-space const char keyword_released[] = "RELEASED="; // we want to use a white-space const char keyword_address[] = "ADDRESS="; // eating string stream to const char keyword_songs[] = "SONGS="; // parse most of the header. const char keyword_speed[] = "SPEED="; const char keyword_musPlayer[] = "SIDSONG=YES"; const char keyword_reloc[] = "RELOC="; const char keyword_clock[] = "CLOCK="; const char keyword_sidModel[] = "SIDMODEL="; const char keyword_compatibility[] = "COMPATIBILITY="; const uint_least16_t sidMinFileSize = 1+sizeof(keyword_id); // Just to avoid a first segm.fault. const uint_least16_t parseChunkLen = 80; // Enough for all keywords incl. their values. 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> c; pParseChunk[i] = c; } pParseChunk[parseChunkLen]=0; // Now check for the possible keywords. // ADDRESS if ( SidTuneTools::myStrNcaseCmp( pParseChunk, keyword_address ) == 0 ) { SidTuneTools::skipToEqu( parseStream ); info.loadAddr = (uint_least16_t)SidTuneTools::readHex( parseStream ); if ( !parseStream ) break; info.initAddr = (uint_least16_t)SidTuneTools::readHex( parseStream ); if ( !parseStream ) break; info.playAddr = (uint_least16_t)SidTuneTools::readHex( parseStream ); 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( parseStream ); info.songs = (uint_least16_t)SidTuneTools::readDec( parseStream ); info.startSong = (uint_least16_t)SidTuneTools::readDec( parseStream ); hasSongs = true; } // SPEED else if ( SidTuneTools::myStrNcaseCmp( pParseChunk, keyword_speed ) == 0 ) { SidTuneTools::skipToEqu( parseStream ); oldStyleSpeed = SidTuneTools::readHex(parseStream); 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( parseStream ); if ( !parseStream ) break; info.relocPages = (uint_least8_t)SidTuneTools::readHex( parseStream ); } // 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; } } } bool SidTune::SID_fileSupportSave( std::ofstream& toFile ) { toFile << keyword_id << std::endl << keyword_address << std::hex << std::setw(4) << std::setfill('0') << 0 << ',' << std::hex << std::setw(4) << info.initAddr << "," << std::hex << std::setw(4) << info.playAddr << std::endl << keyword_songs << std::dec << (int)info.songs << "," << (int)info.startSong << std::endl; uint_least32_t oldStyleSpeed = 0; int maxBugSongs = ((info.songs <= 32) ? info.songs : 32); for (int s = 0; s < maxBugSongs; s++) { if (songSpeed[s] == SIDTUNE_SPEED_CIA_1A) { oldStyleSpeed |= (1<