Esempio n. 1
0
File: MUS.cpp Progetto: 1c0n/xbmc
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;
        }
Esempio n. 2
0
File: MUS.cpp Progetto: 1c0n/xbmc
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;
}
Esempio n. 3
0
File: MUS.cpp Progetto: 1c0n/xbmc
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);
}
Esempio n. 4
0
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;
    }
}
Esempio n. 5
0
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;
        }
    }
}