SidTune::LoadStatus SidTune::MUS_fileSupport(Buffer_sidtt<const uint_least8_t>& musBuf, Buffer_sidtt<const uint_least8_t>& strBuf) { return MUS_load (musBuf, strBuf, true); }
SidTune::LoadStatus SidTune::SID_fileSupport(Buffer_sidtt<const uint_least8_t>& dataBuf, Buffer_sidtt<const uint_least8_t>& sidBuf) { uint_least32_t parseLen = 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 (parseLen<sidMinFileSize) { return LOAD_NOT_MINE; } // Here use a smart pointer to prevent access violation errors. const char* pParseBuf = (const char*)sidBuf.get(); // First line has to contain the exact identification string. if ( SidTuneTools::myStrNcaseCmp( pParseBuf, keyword_id ) == 0 ) { // At least the ID was found, so set a default error message. m_info.formatString = text_truncatedError; // Defaults. fileOffset = 0; // no header in separate data file m_info.sidChipBase1 = 0xd400; m_info.sidChipBase2 = 0; m_info.musPlayer = false; m_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, hasInitAddr = 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 ) { m_info.formatString = text_noMemError; return LOAD_ERROR; } // 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. do { uint_least32_t restLen; { const char* pNextLine = SidTuneTools::returnNextLine( pParseBuf, parseLen ); 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 = parseLen; } } #ifdef HAVE_SSTREAM std::string sParse( pParseBuf, restLen ); // Create whitespace eating (!) input string stream. std::istringstream parseStream( sParse ); // A second one just for copying. std::istringstream parseCopyStream( sParse ); #else std::istrstream parseStream((char *) pParseBuf, restLen ); std::istrstream parseCopyStream((char *) pParseBuf, restLen ); #endif if ( !parseStream || !parseCopyStream ) { break; } // Now copy the next X characters except white-spaces. for ( uint_least16_t i = 0; i < parseChunkLen; i++ ) { char c; parseCopyStream >> c; pParseChunk[i] = c; } pParseChunk[parseChunkLen]=0; // Now check for the possible keywords. // ADDRESS if ( SidTuneTools::myStrNcaseCmp( pParseChunk, keyword_address ) == 0 ) { SidTuneTools::skipToEqu( parseStream ); m_info.loadAddr = (uint_least16_t)SidTuneTools::readHex( parseStream ); m_info.initAddr = m_info.loadAddr; hasInitAddr = true; if ( parseStream ) { m_info.initAddr = (uint_least16_t)SidTuneTools::readHex( parseStream ); if ( !parseStream ) break; m_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); m_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); m_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); m_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); m_info.infoString[2] = &infoString[2][0]; hasReleased = true; } // SONGS else if ( SidTuneTools::myStrNcaseCmp( pParseChunk, keyword_songs ) == 0 ) { SidTuneTools::skipToEqu( parseStream ); m_info.songs = (uint_least16_t)SidTuneTools::readDec( parseStream ); m_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 ) { m_info.musPlayer = true; } // RELOC else if ( SidTuneTools::myStrNcaseCmp( pParseChunk, keyword_reloc ) == 0 ) { m_info.relocStartPage = (uint_least8_t)SidTuneTools::readHex( parseStream ); if ( !parseStream ) break; m_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 ) m_info.clockSpeed = SIDTUNE_CLOCK_UNKNOWN; else if ( SidTuneTools::myStrNcaseCmp( clock, "PAL" ) == 0 ) m_info.clockSpeed = SIDTUNE_CLOCK_PAL; else if ( SidTuneTools::myStrNcaseCmp( clock, "NTSC" ) == 0 ) m_info.clockSpeed = SIDTUNE_CLOCK_NTSC; else if ( SidTuneTools::myStrNcaseCmp( clock, "ANY" ) == 0 ) m_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 ) m_info.sidModel1 = SIDTUNE_SIDMODEL_UNKNOWN; else if ( SidTuneTools::myStrNcaseCmp( model, "6581" ) == 0 ) m_info.sidModel1 = SIDTUNE_SIDMODEL_6581; else if ( SidTuneTools::myStrNcaseCmp( model, "8580" ) == 0 ) m_info.sidModel1 = SIDTUNE_SIDMODEL_8580; else if ( SidTuneTools::myStrNcaseCmp( model, "ANY" ) == 0 ) m_info.sidModel1 = 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 ) m_info.compatibility = SIDTUNE_COMPATIBILITY_C64; else if ( SidTuneTools::myStrNcaseCmp( comp, "PSID" ) == 0 ) m_info.compatibility = SIDTUNE_COMPATIBILITY_PSID; else if ( SidTuneTools::myStrNcaseCmp( comp, "R64" ) == 0 ) m_info.compatibility = SIDTUNE_COMPATIBILITY_R64; else if ( SidTuneTools::myStrNcaseCmp( comp, "BASIC" ) == 0 ) m_info.compatibility = SIDTUNE_COMPATIBILITY_BASIC; } parseLen -= restLen; pParseBuf += restLen; // Skip to next line. Leave loop, if none. } while (parseLen != 0); delete[] pParseChunk; if ( !(hasName && hasAuthor && hasReleased && hasSongs) ) { // Something is missing (or damaged ?). // Error string set above. return LOAD_ERROR; } switch ( m_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 ) m_info.loadAddr = 0; else if ( m_info.loadAddr || m_info.playAddr ) { m_info.formatString = text_invalidError; return LOAD_ERROR; } // Deliberate run on case SIDTUNE_COMPATIBILITY_BASIC: oldStyleSpeed = ~0; } // Create the speed/clock setting table. convertOldStyleSpeedToTables(oldStyleSpeed, m_info.clockSpeed); m_info.numberOfInfoStrings = 3; // We finally accept the input data. m_info.formatString = text_format; if ( m_info.musPlayer && !dataBuf.isEmpty() ) return MUS_load (dataBuf); return LOAD_OK; }