/* * /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 #if defined(HAVE_SSTREAM) # include #else # include #endif #include "SidTune.h" #include "SidTuneTools.h" #include "sidendian.h" static const char text_format[] = "Raw plus SIDPLAY ASCII text file (SID)"; static const char text_truncatedError[] = "SIDTUNE ERROR: SID file is truncated"; static const char text_noMemError[] = "SIDTUNE ERROR: Not enough free memory"; static const char text_invalidError[] = "SIDTUNE ERROR: File contains invalid data"; static const char keyword_id[] = "SIDPLAY INFOFILE"; static const char keyword_name[] = "NAME="; // No white-space characters static const char keyword_author[] = "AUTHOR="; // in these keywords, because static const char keyword_copyright[] = "COPYRIGHT="; // we want to use a white-space (depreciated) static const char keyword_released[] = "RELEASED="; // we want to use a white-space static const char keyword_address[] = "ADDRESS="; // eating string stream to static const char keyword_songs[] = "SONGS="; // parse most of the header. static const char keyword_speed[] = "SPEED="; static const char keyword_musPlayer[] = "SIDSONG=YES"; static const char keyword_reloc[] = "RELOC="; static const char keyword_clock[] = "CLOCK="; static const char keyword_sidModel[] = "SIDMODEL="; static const char keyword_compatibility[] = "COMPATIBILITY="; static const uint_least16_t sidMinFileSize = 1+sizeof(keyword_id); // Just to avoid a first segm.fault. static const uint_least16_t parseChunkLen = 80; // Enough for all keywords incl. their values. SidTune::LoadStatus SidTune::SID_fileSupport(Buffer_sidtt& dataBuf, Buffer_sidtt& sidBuf) { uint_least32_t sidBufLen = sidBuf.len(); // Make sure SID buffer pointer is not zero. // Check for a minimum file size. If it is smaller, we will not proceed. if (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 ); info.initAddr = info.loadAddr; hasInitAddr = true; if ( parseStream ) { 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[6]; 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; else if ( SidTuneTools::myStrNcaseCmp( comp, "BASIC" ) == 0 ) info.compatibility = SIDTUNE_COMPATIBILITY_BASIC; } } delete[] pParseChunk; if ( !(hasName && hasAuthor && hasReleased && hasSongs) ) { // Something is missing (or damaged ?). // Error string set above. return LOAD_ERROR; } switch ( info.compatibility ) { case SIDTUNE_COMPATIBILITY_PSID: case SIDTUNE_COMPATIBILITY_C64: if ( !(hasAddress && hasSpeed) ) return LOAD_ERROR; // Error set above break; case SIDTUNE_COMPATIBILITY_R64: if ( !(hasInitAddr || hasAddress) ) return LOAD_ERROR; // Error set above // Allow user to provide single address if ( !hasAddress ) info.loadAddr = 0; else if ( info.loadAddr || info.playAddr ) { info.formatString = text_invalidError; return LOAD_ERROR; } // Deliberate run on case SIDTUNE_COMPATIBILITY_BASIC: oldStyleSpeed = ~0; } // Create the speed/clock setting table. convertOldStyleSpeedToTables(oldStyleSpeed, info.clockSpeed); info.numberOfInfoStrings = 3; // We finally accept the input data. info.formatString = text_format; if ( info.musPlayer && !dataBuf.isEmpty() ) return MUS_load (dataBuf); return LOAD_OK; } return LOAD_NOT_MINE; } bool SidTune::SID_fileSupportSave( std::ofstream& toFile ) { toFile << keyword_id << std::endl; int compatibility = info.compatibility; if ( info.musPlayer ) { compatibility = SIDTUNE_COMPATIBILITY_C64; } switch ( compatibility ) { case SIDTUNE_COMPATIBILITY_PSID: case SIDTUNE_COMPATIBILITY_C64: toFile << keyword_address << std::setfill('0') << std::hex << std::setw(4) << 0 << ','; if ( info.musPlayer ) { toFile << std::setw(4) << 0 << ',' << std::setw(4) << 0 << std::endl; } else { toFile << std::hex << std::setw(4) << info.initAddr << ',' << std::hex << std::setw(4) << info.playAddr << 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<