diff options
author | 2009-08-19 22:45:01 +0200 | |
---|---|---|
committer | 2009-08-19 22:45:01 +0200 | |
commit | 2f34377d0352ed5aae777f813bbbadcffacbb579 (patch) | |
tree | 17498521f4349cf16af4d47940bccb2885eb9727 /sid/sidplay-libs-2.1.0/libsidplay/src/sidtune | |
parent | 49875b085e4c1fa6881a54b482e8439fc1c6daa9 (diff) |
passed make distcheck; 0.1.0 release
Diffstat (limited to 'sid/sidplay-libs-2.1.0/libsidplay/src/sidtune')
13 files changed, 4203 insertions, 0 deletions
diff --git a/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/IconInfo.cpp b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/IconInfo.cpp new file mode 100644 index 00000000..37717694 --- /dev/null +++ b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/IconInfo.cpp @@ -0,0 +1,468 @@ +/* + * /home/ms/files/source/libsidtune/RCS/IconInfo.cpp,v + * + * Amiga icon tooltype PlaySID file format (.info) support. + * + * This is a derived work, courtesy of Peter Kunath, who has + * provided an examplary source code to examine an Amiga icon file. + * + * It has been ported and heavily modified to suit certain + * requirements. This replaces the old code, which was simply + * scanning input data for a first, presumedly constant, Id string. + * This code does not require the default tool to serve as a + * constant Id by containing "SID:PlaySID". + * + * 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" +#include "SidTune.h" +#include "SmartPtr.h" +#include "SidTuneTools.h" +#include "sidendian.h" + +#ifdef HAVE_EXCEPTIONS +# include <new> +#endif +#include <string.h> +#include <strstream> + +// Amiga Workbench specific structures. + +struct Border +{ + uint8_t LeftEdge[2]; // uint_least16_t; initial offsets from the origin + uint8_t TopEdge[2]; // uint_least16_t + uint8_t FrontPen, BackPen; // pens numbers for rendering + uint8_t DrawMode; // mode for rendering + uint8_t Count; // number of XY pairs + uint8_t pXY[4]; // int_least16_t *XY; vector coordinate pairs rel to LeftTop + uint8_t pNextBorder[4]; // Border *NextBorder; pointer to any other Border too +}; + +struct Image +{ + uint8_t LeftEdge[2]; // uint_least16_t; starting offset relative to some origin + uint8_t TopEdge[2]; // uint_least16_t; starting offsets relative to some origin + uint8_t Width[2]; // uint_least16_t; pixel size (though data is word-aligned) + uint8_t Height[2]; // uint_least16_t + uint8_t Depth[2]; // uint_least16_t; >= 0, for images you create + uint8_t pImageData[4]; // uint_least16_t *ImageData; pointer to the actual word-aligned bits + uint8_t PlanePick, PlaneOnOff; + uint8_t pNextImage[4]; // Image *NextImage; +}; + +struct Gadget +{ + uint8_t pNextGadget[4]; // Gadget *NextGadget; next gadget in the list + uint8_t LeftEdge[2]; // uint_least16_t; "hit box" of gadget + uint8_t TopEdge[2]; // uint_least16_t + uint8_t Width[2]; // uint_least16_t; "hit box" of gadget + uint8_t Height[2]; // uint_least16_t + uint8_t Flags[2]; // uint_least16_t; see below for list of defines + uint8_t Activation[2]; // uint_least16_t + uint8_t GadgetType[2]; // uint_least16_t; see below for defines + uint8_t pGadgetRender[4]; // Image *GadgetRender; + uint8_t pSelectRender[4]; // Image *SelectRender; + uint8_t pGadgetText[4]; // void *GadgetText; + uint8_t MutualExclude[4]; // udword + uint8_t pSpecialInfo[4]; // void *SpecialInfo; + uint8_t GadgetID[2]; // uint_least16_t + uint8_t UserData[4]; // udword; ptr to general purpose User data +}; + +struct DiskObject +{ + uint8_t Magic[2]; // uint_least16_t; a magic num at the start of the file + uint8_t Version[2]; // uint_least16_t; a version number, so we can change it + struct Gadget Gadget; // a copy of in core gadget + uint8_t Type; + uint8_t PAD_BYTE; // Pad it out to the next word boundry + uint8_t pDefaultTool[4]; // char *DefaultTool; + uint8_t ppToolTypes[4]; // char **ToolTypes; + uint8_t CurrentX[4]; // udword + uint8_t CurrentY[4]; // udword + uint8_t pDrawerData[4]; // char *DrawerData; + uint8_t pToolWindow[4]; // char *ToolWindow; only applies to tools + uint8_t StackSize[4]; // udword; only applies to tools +}; + + +// A magic number, not easily impersonated. +#define WB_DISKMAGIC 0xE310 +// Our current version number. +#define WB_DISKVERSION 1 +// Our current revision number. +#define WB_DISKREVISION 1 +// I only use the lower 8 bits of Gadget.UserData for the revision #. +#define WB_DISKREVISIONMASK 0xFF + +// The Workbench object types. +#define WB_DISK 1 +#define WB_DRAWER 2 +#define WB_TOOL 3 +#define WB_PROJECT 4 +#define WB_GARBAGE 5 +#define WB_DEVICE 6 +#define WB_KICK 7 +#define WB_APPICON 8 + +// --- Gadget.Flags values --- +// Combinations in these bits describe the highlight technique to be used. +#define GFLG_GADGHIGHBITS 0x0003 +// Complement the select box. +#define GFLG_GADGHCOMP 0x0000 +// Draw a box around the image. +#define GFLG_GADGHBOX 0x0001 +// Blast in this alternate image. +#define GFLG_GADGHIMAGE 0x0002 +// Don't highlight. +#define GFLG_GADGHNONE 0x0003 +// Set if GadgetRender and SelectRender point to an Image structure, +// clear if they point to Border structures. +#define GFLG_GADGIMAGE 0x0004 + +const char _sidtune_txt_format[] = "Raw plus PlaySID icon tooltype file (INFO)"; + +const char _sidtune_keyword_id[] = "SID:PLAYSID"; +const char _sidtune_keyword_address[] = "ADDRESS="; +const char _sidtune_keyword_songs[] = "SONGS="; +const char _sidtune_keyword_speed[] = "SPEED="; +const char _sidtune_keyword_name[] = "NAME="; +const char _sidtune_keyword_author[] = "AUTHOR="; +const char _sidtune_keyword_copyright[] = "COPYRIGHT="; +const char _sidtune_keyword_musPlayer[] = "SIDSONG=YES"; + +const char _sidtune_txt_noMemError[] = "ERROR: Not enough free memory"; +const char _sidtune_txt_corruptError[] = "ERROR: Info file is incomplete or corrupt"; +const char _sidtune_txt_noStringsError[] = "ERROR: Info file does not contain required strings"; +const char _sidtune_txt_dataCorruptError[] = "ERROR: C64 data file is corrupt"; +#if defined(SIDTUNE_REJECT_UNKNOWN_FIELDS) +const char _sidtune_txt_chunkError[] = "ERROR: Invalid tooltype information in icon file"; +#endif + +const uint_least16_t safeBufferSize = 64; // for string comparison, stream parsing + + +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 ) + { + std::istrstream addrIn(cmpBuf + strlen(_sidtune_keyword_address), + toolLen - strlen(_sidtune_keyword_address)); + info.loadAddr = (uint_least16_t)SidTuneTools::readHex( addrIn ); + info.initAddr = (uint_least16_t)SidTuneTools::readHex( addrIn ); + info.playAddr = (uint_least16_t)SidTuneTools::readHex( addrIn ); + if ( !addrIn ) + { + return false; + } + hasAddress = true; + } + else if ( SidTuneTools::myStrNcaseCmp(cmpBuf,_sidtune_keyword_songs) == 0 ) + { + std::istrstream numIn( cmpBuf + strlen(_sidtune_keyword_songs), + toolLen - strlen(_sidtune_keyword_songs) ); + if ( !numIn ) + { + return false; + } + info.songs = (uint_least16_t)SidTuneTools::readDec( numIn ); + info.startSong = (uint_least16_t)SidTuneTools::readDec( numIn ); + hasSongs = true; + } + else if ( SidTuneTools::myStrNcaseCmp(cmpBuf,_sidtune_keyword_speed) == 0 ) + { + std::istrstream speedIn( cmpBuf + strlen(_sidtune_keyword_speed), + toolLen - strlen(_sidtune_keyword_speed) ); + if ( !speedIn ) + { + return false; + } + oldStyleSpeed = SidTuneTools::readHex(speedIn); + 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; + } +} diff --git a/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/InfoFile.cpp b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/InfoFile.cpp new file mode 100644 index 00000000..18e6d1b8 --- /dev/null +++ b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/InfoFile.cpp @@ -0,0 +1,395 @@ +/* + * /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 <new> +#endif +#include <iostream> +#include <iomanip> +#include <strstream> +#include <ctype.h> +#include <string.h> + +#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<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. + std::istrstream parseStream((char *) pParseBuf, restLen ); + // A second one just for copying. + std::istrstream parseCopyStream((char *) pParseBuf, restLen ); + 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 ); + 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<<s); + } + } + + toFile + << keyword_speed << std::hex << std::setw(8) + << oldStyleSpeed << std::endl + << keyword_name << info.infoString[0] << std::endl + << keyword_author << info.infoString[1] << std::endl + << keyword_released << info.infoString[2] << std::endl; + if ( info.musPlayer ) + { + toFile << keyword_musPlayer << std::endl; + } + if ( info.relocStartPage ) + { + toFile + << keyword_reloc << std::setfill('0') + << std::hex << std::setw(2) << (int) info.relocStartPage << "," + << std::hex << std::setw(2) << (int) info.relocPages << std::endl; + } + if ( info.clockSpeed != SIDTUNE_CLOCK_UNKNOWN ) + { + toFile << keyword_clock; + switch (info.clockSpeed) + { + case SIDTUNE_CLOCK_PAL: + toFile << "PAL"; + break; + case SIDTUNE_CLOCK_NTSC: + toFile << "NTSC"; + break; + case SIDTUNE_CLOCK_ANY: + toFile << "ANY"; + break; + } + toFile << std::endl; + } + if ( info.sidModel != SIDTUNE_SIDMODEL_UNKNOWN ) + { + toFile << keyword_sidModel; + switch (info.sidModel) + { + case SIDTUNE_SIDMODEL_6581: + toFile << "6581"; + break; + case SIDTUNE_SIDMODEL_8580: + toFile << "8580"; + break; + case SIDTUNE_SIDMODEL_ANY: + toFile << "ANY"; + break; + } + toFile << std::endl; + } + if ( info.compatibility == SIDTUNE_COMPATIBILITY_PSID ) + { + toFile << keyword_compatibility << "C64" << std::endl; + } + else if ( info.compatibility == SIDTUNE_COMPATIBILITY_R64 ) + { + toFile << keyword_compatibility << "R64" << std::endl; + } + + if ( !toFile ) + { + return false; + } + else + { + return true; + } +} diff --git a/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/MUS.cpp b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/MUS.cpp new file mode 100644 index 00000000..16ea8fe9 --- /dev/null +++ b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/MUS.cpp @@ -0,0 +1,681 @@ +/* + * /home/ms/files/source/libsidtune/RCS/MUS.cpp,v + * + * Sidplayer and Stereo Sidplayer 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 <string.h> + +#include "config.h" +#include "SidTuneCfg.h" +#include "SidTune.h" +#include "sidendian.h" + +#ifdef HAVE_EXCEPTIONS +# include <new> +#endif + +static const char _sidtune_txt_format_mus[] = "C64 Sidplayer format (MUS)"; +static const char _sidtune_txt_format_str[] = "C64 Stereo Sidplayer format (MUS+STR)"; +static const char _sidtune_txt_notEnoughMemory[] = "ERROR: Not enough free memory"; +static const char _sidtune_txt_sizeExceeded[] = "ERROR: Total file size too large"; + +static const uint_least16_t SIDTUNE_MUS_HLT_CMD = 0x14F; + +static const uint_least16_t SIDTUNE_MUS_DATA_ADDR = 0x0900; +static const uint_least16_t SIDTUNE_SID1_BASE_ADDR = 0xd400; +static const uint_least16_t SIDTUNE_SID2_BASE_ADDR = 0xd500; + +bool SidTune::MUS_fileSupport(Buffer_sidtt<const uint8_t>& musBuf, + Buffer_sidtt<const uint8_t>& strBuf) +{ + // Clear info strings. + for (int i = 0; i < SIDTUNE_MAX_CREDIT_STRINGS; i++) + infoString[i][0] = 0; + + uint_least32_t voice3Index; + if ( !MUS_detect(musBuf.get(),musBuf.len(),voice3Index) ) + return false; + + // Voice3Index now is offset to text lines (uppercase Pet-strings). + SmartPtr_sidtt<const uint8_t> spPet(musBuf.get(),musBuf.len()); + spPet += voice3Index; + { + for ( int line = 0; line < 5; line++ ) + { + MUS_decodePetLine(spPet,infoString[line]); + info.infoString[line] = infoString[line]; + } + } + info.numberOfInfoStrings = 5; + + info.loadAddr = SIDTUNE_MUS_DATA_ADDR; + info.sidChipBase1 = SIDTUNE_SID1_BASE_ADDR; + info.songs = (info.startSong = 1); + info.musPlayer = true; + + songSpeed[0] = SIDTUNE_SPEED_CIA_1A; +#ifdef SIDTUNE_PSID2NG + clockSpeed[0] = SIDTUNE_CLOCK_ANY; +#endif + fileOffset = 2; // data after load address + + if ( !strBuf.isEmpty() ) + { + if ( !MUS_detect(strBuf.get(),strBuf.len(),voice3Index) ) + return false; + + // Voice3Index now is offset to text lines (uppercase Pet-strings). + SmartPtr_sidtt<const uint8_t> spPet(strBuf.get(),strBuf.len()); + spPet += voice3Index; + for ( int line = 5; line < 10; line++ ) + { + MUS_decodePetLine(spPet,infoString[line]); + info.infoString[line] = infoString[line]; + } + info.numberOfInfoStrings += 5; + + info.sidChipBase2 = SIDTUNE_SID2_BASE_ADDR; + info.formatString = _sidtune_txt_format_str; + } + else + { + info.sidChipBase2 = 0; + info.formatString = _sidtune_txt_format_mus; + } + MUS_setPlayerAddress(); + + // Remove trailing empty lines. + const int lines = info.numberOfInfoStrings; + { + for ( int line = lines-1; line >= 0; line-- ) + { + if (strlen(info.infoString[line]) == 0) + --info.numberOfInfoStrings; + else + break; + } + } + + 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); +} + +void SidTune::MUS_setPlayerAddress() +{ + if (info.sidChipBase2 == 0) + { + // Player #1. + info.initAddr = 0xec60; + info.playAddr = 0xec80; + } + else + { + // Player #1 + #2. + info.initAddr = 0xfc90; + info.playAddr = 0xfc96; + } +} + +static const char _sidtune_CHRtab[256] = // CHR$ conversion table (0x01 = no output) +{ + 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0xd, 0x1, 0x1, + 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, + 0x20,0x21, 0x1,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x24,0x5d,0x20,0x20, + // alternative: CHR$(92=0x5c) => ISO Latin-1(0xa3) + 0x2d,0x23,0x7c,0x2d,0x2d,0x2d,0x2d,0x7c,0x7c,0x5c,0x5c,0x2f,0x5c,0x5c,0x2f,0x2f, + 0x5c,0x23,0x5f,0x23,0x7c,0x2f,0x58,0x4f,0x23,0x7c,0x23,0x2b,0x7c,0x7c,0x26,0x5c, + // 0x80-0xFF + 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, + 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, + 0x20,0x7c,0x23,0x2d,0x2d,0x7c,0x23,0x7c,0x23,0x2f,0x7c,0x7c,0x2f,0x5c,0x5c,0x2d, + 0x2f,0x2d,0x2d,0x7c,0x7c,0x7c,0x7c,0x2d,0x2d,0x2d,0x2f,0x5c,0x5c,0x2f,0x2f,0x23, + 0x2d,0x23,0x7c,0x2d,0x2d,0x2d,0x2d,0x7c,0x7c,0x5c,0x5c,0x2f,0x5c,0x5c,0x2f,0x2f, + 0x5c,0x23,0x5f,0x23,0x7c,0x2f,0x58,0x4f,0x23,0x7c,0x23,0x2b,0x7c,0x7c,0x26,0x5c, + 0x20,0x7c,0x23,0x2d,0x2d,0x7c,0x23,0x7c,0x23,0x2f,0x7c,0x7c,0x2f,0x5c,0x5c,0x2d, + 0x2f,0x2d,0x2d,0x7c,0x7c,0x7c,0x7c,0x2d,0x2d,0x2d,0x2f,0x5c,0x5c,0x2f,0x2f,0x23 +}; + +int SidTune::MUS_decodePetLine(SmartPtr_sidtt<const uint8_t>& spPet, char* dest) +{ + int count = 0; + char c; + do + { + c = _sidtune_CHRtab[*spPet]; // ASCII CHR$ conversion + if ((c>=0x20) && (count<=31)) + { + dest[count++] = c; // copy to info string + } + // If character is 0x9d (left arrow key) then move back. + if ((*spPet==0x9d) && (count>=0)) + { + count--; + } + spPet++; + } + while ( !((c==0x0D)||(c==0x00)||spPet.fail()) ); + return count; +} + +static const uint8_t _sidtune_sidplayer1[] = +{ + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x61, 0xe1, 0x60, 0x01, 0x02, 0x04, 0x00, 0x07, 0x0e, 0x02, 0x02, 0xfe, 0x02, 0x02, 0xfe, + 0xfe, 0x00, 0x01, 0x00, 0xff, 0x00, 0x02, 0x04, 0x05, 0x07, 0x09, 0x0b, 0x1e, 0x18, 0x8b, 0x7e, + 0xfa, 0x06, 0xac, 0xf3, 0xe6, 0x8f, 0xf8, 0x2e, 0x86, 0x8e, 0x96, 0x9f, 0xa8, 0xb3, 0xbd, 0xc8, + 0xd4, 0xe1, 0xee, 0xfd, 0x8c, 0x78, 0x64, 0x50, 0x3c, 0x28, 0x14, 0x00, 0x00, 0x02, 0x03, 0x05, + 0x07, 0x08, 0x0a, 0x0c, 0x0d, 0x0f, 0x11, 0x12, 0x00, 0xe0, 0x00, 0x05, 0x0a, 0x0f, 0xf9, 0x00, + 0xf5, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x30, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x50, 0x00, 0x00, 0x60, 0x00, 0x00, 0x70, 0x00, 0x00, 0x80, 0x00, 0x00, 0x90, 0x00, 0x00, 0xa0, + 0x00, 0xa9, 0x00, 0x8d, 0x00, 0xe0, 0xa2, 0x95, 0xa0, 0x42, 0xad, 0xa6, 0x02, 0xf0, 0x04, 0xa2, + 0x25, 0xa0, 0x40, 0x8e, 0x5b, 0xe1, 0x8c, 0x5c, 0xe1, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, + 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, + 0xea, 0x60, 0xa9, 0x00, 0x8d, 0x00, 0xe0, 0x86, 0x61, 0x84, 0x62, 0xa0, 0xbc, 0x99, 0x00, 0xe0, + 0x88, 0xd0, 0xfa, 0xa0, 0x72, 0x99, 0xbc, 0xe0, 0x88, 0xd0, 0xfa, 0x8d, 0x15, 0xd4, 0x8d, 0x16, + 0xd4, 0xa9, 0x08, 0x8d, 0x25, 0xe0, 0x8d, 0x17, 0xd4, 0x8d, 0x26, 0xe0, 0x8d, 0x18, 0xd4, 0xa9, + 0x90, 0x8d, 0x27, 0xe0, 0xa9, 0x60, 0x8d, 0x28, 0xe0, 0xa9, 0x0c, 0x8d, 0x29, 0xe0, 0xad, 0x5b, + 0xe1, 0x8d, 0x2d, 0xe0, 0xad, 0x5c, 0xe1, 0x8d, 0x2e, 0xe0, 0xa9, 0xff, 0x8d, 0xcc, 0xe0, 0xa9, + 0xd4, 0x85, 0x64, 0xa2, 0x02, 0xa9, 0xff, 0x9d, 0x0b, 0xe0, 0xa9, 0x01, 0x9d, 0x30, 0xe0, 0x9d, + 0x2a, 0xe0, 0x8a, 0x9d, 0x33, 0xe0, 0x9d, 0xae, 0xe0, 0xa9, 0x04, 0x9d, 0x39, 0xe0, 0xbd, 0xa8, + 0xe1, 0x9d, 0xba, 0xe0, 0xa9, 0x5b, 0x9d, 0x7e, 0xe0, 0xbd, 0x65, 0xe1, 0x85, 0x63, 0xa9, 0x00, + 0xa8, 0x91, 0x63, 0xc8, 0x91, 0x63, 0xc8, 0x91, 0x63, 0xa9, 0x08, 0x9d, 0x17, 0xe0, 0x9d, 0x9c, + 0xe0, 0xc8, 0x91, 0x63, 0xc8, 0x91, 0x63, 0xa9, 0x40, 0x9d, 0x1a, 0xe0, 0x91, 0x63, 0xa9, 0x20, + 0x9d, 0x1d, 0xe0, 0xc8, 0x91, 0x63, 0xa9, 0xf5, 0x9d, 0x20, 0xe0, 0xc8, 0x91, 0x63, 0xca, 0x10, + 0xa4, 0x8a, 0xa2, 0x17, 0x9d, 0x3e, 0xe1, 0xca, 0x10, 0xfa, 0xa5, 0x61, 0x18, 0x69, 0x06, 0x85, + 0x63, 0xa9, 0x00, 0xaa, 0xa8, 0x65, 0x62, 0x85, 0x64, 0x9d, 0xab, 0xe0, 0x9d, 0xb4, 0xe0, 0xa5, + 0x63, 0x9d, 0xa8, 0xe0, 0x9d, 0xb1, 0xe0, 0x18, 0x71, 0x61, 0x85, 0x63, 0xa5, 0x64, 0xc8, 0x71, + 0x61, 0xc8, 0xe8, 0xe0, 0x03, 0xd0, 0xe0, 0xa6, 0x63, 0xa8, 0x60, 0xa9, 0x00, 0x8d, 0x04, 0xd4, + 0x8d, 0x0b, 0xd4, 0x8d, 0x12, 0xd4, 0x8d, 0x01, 0xd4, 0x8d, 0x08, 0xd4, 0x8d, 0x0f, 0xd4, 0xa9, + 0x08, 0x8d, 0x17, 0xd4, 0xad, 0x5b, 0xe1, 0x8d, 0x04, 0xdc, 0xad, 0x5c, 0xe1, 0x8d, 0x05, 0xdc, + 0x60, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0x60, + 0xa9, 0x08, 0x8d, 0x00, 0xe0, 0x6c, 0x5d, 0xe1, 0xea, 0xea, 0xea, 0xad, 0x00, 0xe0, 0x30, 0xf0, + 0x09, 0x80, 0xa8, 0x29, 0x07, 0xf0, 0xee, 0xd8, 0x8c, 0x00, 0xe0, 0xea, 0xa5, 0xfb, 0x8d, 0x56, + 0xe1, 0xa5, 0xfc, 0x8d, 0x57, 0xe1, 0xa5, 0xfd, 0x8d, 0x58, 0xe1, 0xa5, 0xfe, 0x8d, 0x59, 0xe1, + 0xa5, 0xff, 0x8d, 0x5a, 0xe1, 0xad, 0x23, 0xe0, 0x18, 0x6d, 0xd9, 0xe0, 0x48, 0x29, 0x07, 0xa8, + 0xad, 0xdc, 0xe0, 0x69, 0x00, 0x85, 0xff, 0x68, 0x46, 0xff, 0x6a, 0x46, 0xff, 0x6a, 0x46, 0xff, + 0x6a, 0x18, 0x6d, 0x24, 0xe0, 0x8c, 0x15, 0xd4, 0x8d, 0x16, 0xd4, 0xad, 0x25, 0xe0, 0x8d, 0x17, + 0xd4, 0xad, 0x26, 0xe0, 0x8d, 0x18, 0xd4, 0xa9, 0xd4, 0x85, 0xfc, 0xa2, 0x00, 0xad, 0x00, 0xe0, + 0x3d, 0x62, 0xe1, 0xf0, 0x51, 0xbd, 0x65, 0xe1, 0x85, 0xfb, 0xbd, 0x0e, 0xe0, 0x18, 0x7d, 0x51, + 0xe0, 0xa8, 0xbd, 0x11, 0xe0, 0x7d, 0x54, 0xe0, 0x48, 0x98, 0x18, 0x7d, 0xcd, 0xe0, 0xa0, 0x00, + 0x91, 0xfb, 0x68, 0x7d, 0xd0, 0xe0, 0xc8, 0x91, 0xfb, 0xbd, 0x14, 0xe0, 0x18, 0x7d, 0x69, 0xe0, + 0x85, 0xff, 0xbd, 0x17, 0xe0, 0x7d, 0x6c, 0xe0, 0x48, 0xa5, 0xff, 0x18, 0x7d, 0xd3, 0xe0, 0xc8, + 0x91, 0xfb, 0x68, 0x7d, 0xd6, 0xe0, 0xc8, 0x91, 0xfb, 0xbd, 0x1d, 0xe0, 0xc8, 0xc8, 0x91, 0xfb, + 0xbd, 0x20, 0xe0, 0xc8, 0x91, 0xfb, 0xe8, 0xe0, 0x03, 0xd0, 0xa2, 0xac, 0x1a, 0xe0, 0xae, 0x1b, + 0xe0, 0xad, 0x1c, 0xe0, 0x8c, 0x04, 0xd4, 0x8e, 0x0b, 0xd4, 0x8d, 0x12, 0xd4, 0xae, 0x2d, 0xe0, + 0xac, 0x2e, 0xe0, 0x8e, 0x04, 0xdc, 0x8c, 0x05, 0xdc, 0xad, 0x1b, 0xd4, 0x8d, 0xbe, 0xe0, 0xad, + 0x1c, 0xd4, 0x8d, 0xbf, 0xe0, 0xa2, 0x00, 0xad, 0x00, 0xe0, 0x3d, 0x62, 0xe1, 0xf0, 0x10, 0x8e, + 0x2f, 0xe0, 0x20, 0x36, 0xe5, 0xad, 0x00, 0xe0, 0x29, 0x78, 0xf0, 0x03, 0x4c, 0x0c, 0xe5, 0xe8, + 0xe0, 0x03, 0xd0, 0xe3, 0xad, 0xc9, 0xe0, 0xd0, 0x52, 0xad, 0xca, 0xe0, 0x0d, 0xcb, 0xe0, 0xf0, + 0x78, 0xad, 0xdf, 0xe0, 0xd0, 0x28, 0xad, 0xca, 0xe0, 0xf0, 0x28, 0x18, 0x6d, 0xbd, 0xe0, 0xb0, + 0x07, 0xcd, 0xcc, 0xe0, 0x90, 0x60, 0xf0, 0x5e, 0xa9, 0x00, 0x8d, 0xdf, 0xe0, 0xad, 0xcb, 0xe0, + 0xf0, 0x54, 0xee, 0xdf, 0xe0, 0xad, 0xbd, 0xe0, 0xed, 0xcb, 0xe0, 0x4c, 0xb4, 0xe4, 0xad, 0xcb, + 0xe0, 0xf0, 0xd3, 0xad, 0xbd, 0xe0, 0x38, 0xed, 0xcb, 0xe0, 0xb0, 0x3a, 0xa9, 0x00, 0x8d, 0xdf, + 0xe0, 0xad, 0xca, 0xe0, 0xd0, 0x30, 0xee, 0xdf, 0xe0, 0xd0, 0x28, 0xce, 0xe0, 0xe0, 0xd0, 0x29, + 0xad, 0xdf, 0xe0, 0xd0, 0x11, 0xee, 0xdf, 0xe0, 0xad, 0xcb, 0xe0, 0xd0, 0x02, 0xa9, 0x20, 0x8d, + 0xe0, 0xe0, 0xa9, 0x00, 0xf0, 0x10, 0xce, 0xdf, 0xe0, 0xad, 0xca, 0xe0, 0xd0, 0x02, 0xa9, 0x20, + 0x8d, 0xe0, 0xe0, 0xad, 0xcc, 0xe0, 0x8d, 0xbd, 0xe0, 0xa2, 0x00, 0xbd, 0xc3, 0xe0, 0xf0, 0x44, + 0xa9, 0x00, 0x85, 0xff, 0xbc, 0xc0, 0xe0, 0xb9, 0xbd, 0xe0, 0xbc, 0xc6, 0xe0, 0xf0, 0x0e, 0x30, + 0x08, 0x0a, 0x26, 0xff, 0x88, 0xd0, 0xfa, 0xf0, 0x04, 0x4a, 0xc8, 0xd0, 0xfc, 0xbc, 0xc3, 0xe0, + 0x88, 0xd0, 0x0b, 0x9d, 0xcd, 0xe0, 0xa5, 0xff, 0x9d, 0xd0, 0xe0, 0x4c, 0x02, 0xe5, 0x88, 0xd0, + 0x0b, 0x9d, 0xd3, 0xe0, 0xa5, 0xff, 0x9d, 0xd6, 0xe0, 0x4c, 0x02, 0xe5, 0x8d, 0xd9, 0xe0, 0xa5, + 0xff, 0x8d, 0xdc, 0xe0, 0xe8, 0xe0, 0x03, 0xd0, 0xb2, 0xad, 0x00, 0xe0, 0x29, 0x7f, 0x8d, 0x00, + 0xe0, 0xad, 0x56, 0xe1, 0x85, 0xfb, 0xad, 0x57, 0xe1, 0x85, 0xfc, 0xad, 0x58, 0xe1, 0x85, 0xfd, + 0xad, 0x59, 0xe1, 0x85, 0xfe, 0xad, 0x5a, 0xe1, 0x85, 0xff, 0x6c, 0x5d, 0xe1, 0xbd, 0x60, 0xe0, + 0xd0, 0x03, 0x4c, 0x9f, 0xe6, 0x4c, 0xba, 0xe5, 0xde, 0x30, 0xe0, 0xd0, 0x03, 0x4c, 0xa0, 0xe6, + 0xbd, 0x36, 0xe0, 0x30, 0xe8, 0xd0, 0x1a, 0xbd, 0x3f, 0xe0, 0xf0, 0x05, 0xde, 0x3f, 0xe0, 0xd0, + 0x10, 0xbd, 0x39, 0xe0, 0xdd, 0x30, 0xe0, 0x90, 0x08, 0xbd, 0x1a, 0xe0, 0x29, 0xfe, 0x9d, 0x1a, + 0xe0, 0xbd, 0x42, 0xe0, 0xf0, 0x56, 0x0a, 0xbd, 0x0e, 0xe0, 0xb0, 0x1d, 0x7d, 0x45, 0xe0, 0x9d, + 0x0e, 0xe0, 0xa8, 0xbd, 0x11, 0xe0, 0x7d, 0x48, 0xe0, 0x9d, 0x11, 0xe0, 0x48, 0x98, 0xdd, 0x8d, + 0xe0, 0x68, 0xfd, 0x90, 0xe0, 0xb0, 0x1f, 0x90, 0x2e, 0xfd, 0x45, 0xe0, 0x9d, 0x0e, 0xe0, 0xbd, + 0x11, 0xe0, 0xfd, 0x48, 0xe0, 0x9d, 0x11, 0xe0, 0xbd, 0x8d, 0xe0, 0xdd, 0x0e, 0xe0, 0xbd, 0x90, + 0xe0, 0xfd, 0x11, 0xe0, 0x90, 0x11, 0xbd, 0x8d, 0xe0, 0x9d, 0x0e, 0xe0, 0xbd, 0x90, 0xe0, 0x9d, + 0x11, 0xe0, 0xa9, 0x00, 0x9d, 0x42, 0xe0, 0xbd, 0x60, 0xe0, 0xf0, 0x55, 0xbd, 0x4b, 0xe0, 0xf0, + 0x4b, 0xa0, 0x00, 0xde, 0x4e, 0xe0, 0xd0, 0x31, 0xbd, 0x51, 0xe0, 0x1d, 0x54, 0xe0, 0xd0, 0x1b, + 0xbd, 0x5d, 0xe0, 0x9d, 0x57, 0xe0, 0x9d, 0x4e, 0xe0, 0xbd, 0x4b, 0xe0, 0x0a, 0xbd, 0x5a, 0xe0, + 0x90, 0x04, 0x49, 0xff, 0x69, 0x00, 0x9d, 0x4b, 0xe0, 0xd0, 0x10, 0xbd, 0x57, 0xe0, 0x9d, 0x4e, + 0xe0, 0x98, 0x38, 0xfd, 0x4b, 0xe0, 0x9d, 0x4b, 0xe0, 0xc9, 0x00, 0x10, 0x01, 0x88, 0x18, 0x7d, + 0x51, 0xe0, 0x9d, 0x51, 0xe0, 0x98, 0x7d, 0x54, 0xe0, 0x9d, 0x54, 0xe0, 0xbd, 0x36, 0xe0, 0x30, + 0x15, 0xbd, 0x93, 0xe0, 0xf0, 0x10, 0x18, 0x7d, 0x14, 0xe0, 0x9d, 0x14, 0xe0, 0xbd, 0x96, 0xe0, + 0x7d, 0x17, 0xe0, 0x9d, 0x17, 0xe0, 0xbd, 0x63, 0xe0, 0xf0, 0x4b, 0xa0, 0x00, 0xde, 0x66, 0xe0, + 0xd0, 0x31, 0xbd, 0x69, 0xe0, 0x1d, 0x6c, 0xe0, 0xd0, 0x1b, 0xbd, 0x72, 0xe0, 0x9d, 0x6f, 0xe0, + 0x9d, 0x66, 0xe0, 0xbd, 0x63, 0xe0, 0x0a, 0xbd, 0x75, 0xe0, 0x90, 0x04, 0x49, 0xff, 0x69, 0x00, + 0x9d, 0x63, 0xe0, 0xd0, 0x10, 0xbd, 0x6f, 0xe0, 0x9d, 0x66, 0xe0, 0x98, 0x38, 0xfd, 0x63, 0xe0, + 0x9d, 0x63, 0xe0, 0xc9, 0x00, 0x10, 0x01, 0x88, 0x18, 0x7d, 0x69, 0xe0, 0x9d, 0x69, 0xe0, 0x98, + 0x7d, 0x6c, 0xe0, 0x9d, 0x6c, 0xe0, 0xbd, 0x36, 0xe0, 0x10, 0x03, 0x4c, 0x9f, 0xe6, 0xa0, 0x00, + 0xbd, 0xa2, 0xe0, 0xf0, 0x1c, 0x10, 0x01, 0xc8, 0x18, 0x6d, 0x23, 0xe0, 0x48, 0x29, 0x07, 0x8d, + 0x23, 0xe0, 0x68, 0x6a, 0x4a, 0x4a, 0x18, 0x79, 0xa6, 0xe1, 0x18, 0x6d, 0x24, 0xe0, 0x8d, 0x24, + 0xe0, 0x60, 0xbd, 0xa8, 0xe0, 0x85, 0xfd, 0xbd, 0xab, 0xe0, 0x85, 0xfe, 0xd0, 0x04, 0x60, 0x20, + 0x98, 0xe8, 0xad, 0x00, 0xe0, 0x3d, 0x62, 0xe1, 0xf0, 0xf4, 0xa0, 0x00, 0xb1, 0xfd, 0x85, 0xff, + 0xc8, 0xb1, 0xfd, 0xa8, 0xa5, 0xfd, 0x18, 0x69, 0x02, 0x85, 0xfd, 0x9d, 0xa8, 0xe0, 0xa5, 0xfe, + 0x69, 0x00, 0x85, 0xfe, 0x9d, 0xab, 0xe0, 0xa5, 0xff, 0x29, 0x03, 0xd0, 0xd2, 0xbd, 0x8d, 0xe0, + 0x9d, 0x0e, 0xe0, 0xbd, 0x90, 0xe0, 0x9d, 0x11, 0xe0, 0xa5, 0xff, 0x9d, 0x05, 0xe0, 0x98, 0x9d, + 0x02, 0xe0, 0x29, 0x07, 0xa8, 0xb9, 0x67, 0xe1, 0x8d, 0x6f, 0xe1, 0xbd, 0x02, 0xe0, 0x29, 0x38, + 0x4a, 0x4a, 0x4a, 0x7d, 0x81, 0xe0, 0x85, 0xfd, 0xbd, 0x02, 0xe0, 0x29, 0xc0, 0x0a, 0x2a, 0x2a, + 0xa8, 0xb9, 0x6f, 0xe1, 0x85, 0xfe, 0xbd, 0x02, 0xe0, 0x29, 0x07, 0xf0, 0x62, 0xa8, 0xb9, 0x72, + 0xe1, 0x65, 0xfe, 0x18, 0x7d, 0x84, 0xe0, 0x10, 0x05, 0x18, 0x69, 0x0c, 0xe6, 0xfd, 0xc9, 0x0c, + 0x90, 0x04, 0xe9, 0x0c, 0xc6, 0xfd, 0x85, 0xfe, 0xa8, 0xb9, 0x86, 0xe1, 0x85, 0xff, 0xb9, 0x7a, + 0xe1, 0xa4, 0xfd, 0x88, 0x30, 0x06, 0x46, 0xff, 0x6a, 0x88, 0x10, 0xfa, 0x18, 0x7d, 0x87, 0xe0, + 0x9d, 0x8d, 0xe0, 0xa5, 0xff, 0x7d, 0x8a, 0xe0, 0x9d, 0x90, 0xe0, 0xbd, 0x05, 0xe0, 0xd0, 0x03, + 0x4c, 0xa0, 0xe6, 0xbd, 0x45, 0xe0, 0x1d, 0x48, 0xe0, 0xf0, 0x16, 0xbd, 0x0e, 0xe0, 0xdd, 0x8d, + 0xe0, 0xbd, 0x11, 0xe0, 0xfd, 0x90, 0xe0, 0xa9, 0xfe, 0x6a, 0x9d, 0x42, 0xe0, 0x90, 0x11, 0xf0, + 0x4a, 0x9d, 0x42, 0xe0, 0xbd, 0x8d, 0xe0, 0x9d, 0x0e, 0xe0, 0xbd, 0x90, 0xe0, 0x9d, 0x11, 0xe0, + 0xbd, 0x36, 0xe0, 0x0a, 0xd0, 0x35, 0xbd, 0x93, 0xe0, 0xf0, 0x0c, 0xbd, 0x99, 0xe0, 0x9d, 0x14, + 0xe0, 0xbd, 0x9c, 0xe0, 0x9d, 0x17, 0xe0, 0xbd, 0x9f, 0xe0, 0xf0, 0x0f, 0xa4, 0xfd, 0x18, 0x79, + 0x92, 0xe1, 0xa4, 0xfe, 0x18, 0x79, 0x9a, 0xe1, 0x18, 0x90, 0x08, 0xbd, 0xa2, 0xe0, 0xf0, 0x0b, + 0xbd, 0xa5, 0xe0, 0x8d, 0x24, 0xe0, 0xa9, 0x00, 0x8d, 0x23, 0xe0, 0xbd, 0x3c, 0xe0, 0x9d, 0x3f, + 0xe0, 0xbd, 0x05, 0xe0, 0x29, 0x40, 0x9d, 0x36, 0xe0, 0xbd, 0x05, 0xe0, 0x4a, 0x4a, 0x29, 0x07, + 0xd0, 0x30, 0xbd, 0x05, 0xe0, 0x30, 0x14, 0xad, 0x27, 0xe0, 0x29, 0x3c, 0xd0, 0x1e, 0xad, 0x27, + 0xe0, 0x0a, 0x2a, 0x2a, 0xd0, 0x02, 0xa9, 0x04, 0x4c, 0x70, 0xe8, 0xad, 0x28, 0xe0, 0xf0, 0x0c, + 0x29, 0x3f, 0xd0, 0x08, 0xad, 0x28, 0xe0, 0x0a, 0x2a, 0x2a, 0xd0, 0x66, 0xa9, 0x10, 0x8d, 0x00, + 0xe0, 0x60, 0xc9, 0x01, 0xd0, 0x13, 0xbd, 0x05, 0xe0, 0x29, 0x20, 0xd0, 0x06, 0xad, 0x29, 0xe0, + 0x4c, 0x70, 0xe8, 0xbd, 0x2a, 0xe0, 0x4c, 0x70, 0xe8, 0xa8, 0xbd, 0x05, 0xe0, 0x29, 0xa0, 0xc9, + 0x80, 0xf0, 0x30, 0x85, 0xff, 0x18, 0xad, 0x27, 0xe0, 0xd0, 0x01, 0x38, 0x88, 0x88, 0xf0, 0x06, + 0x6a, 0xb0, 0x4e, 0x88, 0xd0, 0xfa, 0xa4, 0xff, 0x85, 0xff, 0xf0, 0x26, 0x46, 0xff, 0xb0, 0x41, + 0xf0, 0x42, 0x65, 0xff, 0xb0, 0x3e, 0xc8, 0x10, 0x19, 0x46, 0xff, 0xb0, 0x34, 0x65, 0xff, 0x90, + 0x11, 0xb0, 0x31, 0xad, 0x28, 0xe0, 0xf0, 0x29, 0x88, 0x88, 0xf0, 0x06, 0x4a, 0xb0, 0x22, 0x88, + 0xd0, 0xfa, 0x9d, 0x30, 0xe0, 0xbd, 0x1a, 0xe0, 0x29, 0xf6, 0x9d, 0x1a, 0xe0, 0x38, 0xbd, 0x02, + 0xe0, 0x29, 0x07, 0xd0, 0x03, 0x7e, 0x36, 0xe0, 0xbd, 0x1a, 0xe0, 0x69, 0x00, 0x9d, 0x1a, 0xe0, + 0x60, 0xa9, 0x10, 0x2c, 0xa9, 0x18, 0x8d, 0x00, 0xe0, 0x60, 0x98, 0x48, 0xa5, 0xff, 0x4a, 0x90, + 0x03, 0x4c, 0x42, 0xea, 0x4a, 0x4a, 0xb0, 0x1e, 0x4a, 0xb0, 0x0e, 0x9d, 0x9c, 0xe0, 0x9d, 0x17, + 0xe0, 0x68, 0x9d, 0x99, 0xe0, 0x9d, 0x14, 0xe0, 0x60, 0x4a, 0x90, 0x02, 0x09, 0xf8, 0x9d, 0x8a, + 0xe0, 0x68, 0x9d, 0x87, 0xe0, 0x60, 0x4a, 0xb0, 0x03, 0x4c, 0x4a, 0xe9, 0x4a, 0xb0, 0x61, 0x4a, + 0xb0, 0x0f, 0xd0, 0x08, 0x68, 0x9d, 0xa5, 0xe0, 0x8d, 0x24, 0xe0, 0x60, 0x68, 0x9d, 0x3c, 0xe0, + 0x60, 0xd0, 0x48, 0x68, 0x9d, 0x7e, 0xe0, 0xc9, 0x5b, 0xf0, 0x33, 0xa8, 0x4a, 0x4a, 0x4a, 0x38, + 0xe9, 0x0b, 0x18, 0x7d, 0x84, 0xe0, 0x30, 0x0c, 0xc9, 0x0c, 0x90, 0x11, 0xe9, 0x0c, 0xde, 0x81, + 0xe0, 0x4c, 0x0b, 0xe9, 0xc9, 0xf5, 0xb0, 0x05, 0x69, 0x0c, 0xfe, 0x81, 0xe0, 0x9d, 0x84, 0xe0, + 0x98, 0x29, 0x07, 0x38, 0xe9, 0x03, 0x18, 0x7d, 0x81, 0xe0, 0x9d, 0x81, 0xe0, 0x60, 0xbd, 0x78, + 0xe0, 0x9d, 0x81, 0xe0, 0xbd, 0x7b, 0xe0, 0x9d, 0x84, 0xe0, 0x60, 0x68, 0x9d, 0xc6, 0xe0, 0x60, + 0x4a, 0xb0, 0x08, 0x9d, 0x0b, 0xe0, 0x68, 0x9d, 0x08, 0xe0, 0x60, 0x4a, 0x6a, 0x6a, 0x6d, 0x5b, + 0xe1, 0x8d, 0x2d, 0xe0, 0x68, 0x6d, 0x5c, 0xe1, 0x8d, 0x2e, 0xe0, 0x60, 0x4a, 0x90, 0x03, 0x4c, + 0xd3, 0xe9, 0x4a, 0xb0, 0x40, 0x4a, 0xb0, 0x17, 0x4a, 0xb0, 0x0f, 0x68, 0x8d, 0x27, 0xe0, 0x4a, + 0x4a, 0x4a, 0xa8, 0xb9, 0xaf, 0xe1, 0x8d, 0x28, 0xe0, 0x60, 0x68, 0x9d, 0x5d, 0xe0, 0x60, 0x4a, + 0xb0, 0x05, 0x68, 0x8d, 0x01, 0xe0, 0x60, 0x68, 0xf0, 0x11, 0x9d, 0x75, 0xe0, 0xbc, 0x63, 0xe0, + 0xd0, 0x08, 0x9d, 0x63, 0xe0, 0xa9, 0x01, 0x9d, 0x66, 0xe0, 0x60, 0x9d, 0x63, 0xe0, 0x9d, 0x69, + 0xe0, 0x9d, 0x6c, 0xe0, 0x60, 0x4a, 0xb0, 0x30, 0x4a, 0xb0, 0x05, 0x68, 0x9d, 0x39, 0xe0, 0x60, + 0x68, 0xa0, 0x00, 0x4a, 0x90, 0x02, 0xc8, 0x18, 0x48, 0x29, 0x07, 0x79, 0xac, 0xe1, 0x9d, 0x78, + 0xe0, 0x9d, 0x81, 0xe0, 0x68, 0x4a, 0x4a, 0x4a, 0x18, 0x79, 0xad, 0xe1, 0x9d, 0x7b, 0xe0, 0x9d, + 0x84, 0xe0, 0xa9, 0x5b, 0x9d, 0x7e, 0xe0, 0x60, 0x4a, 0xb0, 0x05, 0x68, 0x9d, 0xa2, 0xe0, 0x60, + 0x68, 0x8d, 0xcc, 0xe0, 0x60, 0x4a, 0xb0, 0x27, 0x4a, 0xb0, 0x0d, 0x4a, 0xb0, 0x05, 0x68, 0x8d, + 0x29, 0xe0, 0x60, 0x68, 0x9d, 0x9f, 0xe0, 0x60, 0x4a, 0xb0, 0x0f, 0x68, 0x9d, 0x93, 0xe0, 0xa0, + 0x00, 0x0a, 0x90, 0x01, 0x88, 0x98, 0x9d, 0x96, 0xe0, 0x60, 0x68, 0x9d, 0x72, 0xe0, 0x60, 0x4a, + 0xb0, 0x1c, 0x4a, 0xb0, 0x15, 0x68, 0x9d, 0xb7, 0xe0, 0xa5, 0xfd, 0x9d, 0xb1, 0xe0, 0xa5, 0xfe, + 0x9d, 0xb4, 0xe0, 0xbd, 0x33, 0xe0, 0x9d, 0xae, 0xe0, 0x60, 0x68, 0x6c, 0x5f, 0xe1, 0x4a, 0xb0, + 0x1e, 0x68, 0xd0, 0x0a, 0x9d, 0x4b, 0xe0, 0x9d, 0x51, 0xe0, 0x9d, 0x54, 0xe0, 0x60, 0x9d, 0x5a, + 0xe0, 0xbc, 0x4b, 0xe0, 0xd0, 0x08, 0x9d, 0x4b, 0xe0, 0xa9, 0x01, 0x9d, 0x4e, 0xe0, 0x60, 0x68, + 0x9d, 0x2a, 0xe0, 0x60, 0x4a, 0x90, 0x08, 0x9d, 0x48, 0xe0, 0x68, 0x9d, 0x45, 0xe0, 0x60, 0x68, + 0x4a, 0xb0, 0x61, 0x4a, 0xb0, 0x25, 0x4a, 0xb0, 0x05, 0x4a, 0xa0, 0xf0, 0xd0, 0x06, 0x0a, 0x0a, + 0x0a, 0x0a, 0xa0, 0x0f, 0x85, 0xff, 0x98, 0xb0, 0x09, 0x3d, 0x1d, 0xe0, 0x05, 0xff, 0x9d, 0x1d, + 0xe0, 0x60, 0x3d, 0x20, 0xe0, 0x05, 0xff, 0x9d, 0x20, 0xe0, 0x60, 0x4a, 0xb0, 0x38, 0x4a, 0xb0, + 0x64, 0x85, 0xff, 0xbd, 0xba, 0xe0, 0xdd, 0xa9, 0xe1, 0xf0, 0x54, 0xfe, 0xba, 0xe0, 0xa8, 0xa5, + 0xfd, 0x99, 0xe1, 0xe0, 0xa5, 0xfe, 0x99, 0xf0, 0xe0, 0xbd, 0x33, 0xe0, 0x99, 0x2f, 0xe1, 0xa4, + 0xff, 0xb9, 0x17, 0xe1, 0xf0, 0x36, 0x85, 0xfe, 0xb9, 0xff, 0xe0, 0x85, 0xfd, 0xb9, 0x3e, 0xe1, + 0x9d, 0x33, 0xe0, 0x60, 0xb0, 0x4b, 0x4a, 0xb0, 0x3c, 0xa8, 0xa5, 0xfd, 0x99, 0xff, 0xe0, 0xa5, + 0xfe, 0x99, 0x17, 0xe1, 0xbd, 0x33, 0xe0, 0x99, 0x3e, 0xe1, 0xbd, 0xba, 0xe0, 0xdd, 0xa9, 0xe1, + 0xf0, 0x0d, 0xfe, 0xba, 0xe0, 0xa8, 0xa9, 0x00, 0x99, 0xf0, 0xe0, 0x60, 0xa9, 0x30, 0x2c, 0xa9, + 0x28, 0x8d, 0x00, 0xe0, 0x60, 0x0a, 0x0a, 0x0a, 0x0a, 0x4d, 0x25, 0xe0, 0x29, 0xf0, 0x4d, 0x25, + 0xe0, 0x8d, 0x25, 0xe0, 0x60, 0x4d, 0x26, 0xe0, 0x29, 0x0f, 0x4d, 0x26, 0xe0, 0x8d, 0x26, 0xe0, + 0x60, 0x4a, 0xb0, 0x0b, 0x4a, 0xb0, 0x04, 0x8d, 0xca, 0xe0, 0x60, 0x8d, 0xcb, 0xe0, 0x60, 0x4a, + 0x90, 0x03, 0x4c, 0xa5, 0xeb, 0x4a, 0xa8, 0xf0, 0x21, 0x88, 0xf0, 0x34, 0x88, 0xf0, 0x42, 0x88, + 0xf0, 0x4a, 0x88, 0xf0, 0x52, 0x88, 0xf0, 0x5c, 0x88, 0xf0, 0x66, 0x88, 0xf0, 0x73, 0x29, 0x07, + 0x09, 0x10, 0xb0, 0x03, 0x4c, 0xb7, 0xea, 0x4c, 0x7f, 0xea, 0xac, 0x26, 0xe0, 0xb0, 0x07, 0xc8, + 0x98, 0x29, 0x0f, 0xd0, 0x07, 0x60, 0x98, 0x29, 0x0f, 0xf0, 0x04, 0x88, 0x8c, 0x26, 0xe0, 0x60, + 0xbd, 0x62, 0xe1, 0x49, 0xff, 0x2d, 0x25, 0xe0, 0x90, 0x03, 0x1d, 0x62, 0xe1, 0x8d, 0x25, 0xe0, + 0x60, 0xbd, 0x1a, 0xe0, 0x29, 0xfb, 0x90, 0x55, 0x09, 0x04, 0xb0, 0x51, 0xbd, 0x1a, 0xe0, 0x29, + 0xfd, 0x90, 0x4a, 0x09, 0x02, 0xb0, 0x46, 0xad, 0x25, 0xe0, 0x29, 0xf7, 0x90, 0x02, 0x09, 0x08, + 0x8d, 0x25, 0xe0, 0x60, 0xad, 0x26, 0xe0, 0x29, 0x7f, 0x90, 0x02, 0x09, 0x80, 0x8d, 0x26, 0xe0, + 0x60, 0x98, 0x8d, 0xbd, 0xe0, 0x8d, 0xdf, 0xe0, 0xc8, 0x8c, 0xe0, 0xe0, 0x2a, 0x8d, 0xc9, 0xe0, + 0x60, 0x98, 0x2a, 0x9d, 0x60, 0xe0, 0x60, 0x4a, 0xb0, 0x27, 0x4a, 0xb0, 0x14, 0xd0, 0x02, 0xa9, + 0x08, 0x0a, 0x0a, 0x0a, 0x0a, 0x5d, 0x1a, 0xe0, 0x29, 0xf0, 0x5d, 0x1a, 0xe0, 0x9d, 0x1a, 0xe0, + 0x60, 0x0a, 0x0a, 0x0a, 0x0a, 0x4d, 0x26, 0xe0, 0x29, 0x70, 0x4d, 0x26, 0xe0, 0x8d, 0x26, 0xe0, + 0x60, 0x4a, 0x90, 0x04, 0x9d, 0xc0, 0xe0, 0x60, 0xa8, 0xf0, 0x20, 0x88, 0xf0, 0x40, 0x88, 0xf0, + 0x63, 0x29, 0x03, 0x9d, 0xc3, 0xe0, 0xa9, 0x00, 0x9d, 0xcd, 0xe0, 0x9d, 0xd0, 0xe0, 0x9d, 0xd3, + 0xe0, 0x9d, 0xd6, 0xe0, 0x8d, 0xd9, 0xe0, 0x8d, 0xdc, 0xe0, 0x60, 0xbd, 0xb7, 0xe0, 0xf0, 0x05, + 0xde, 0xb7, 0xe0, 0xf0, 0x12, 0xbd, 0x33, 0xe0, 0xdd, 0xae, 0xe0, 0xd0, 0x0b, 0xbd, 0xb1, 0xe0, + 0x85, 0xfd, 0xbd, 0xb4, 0xe0, 0x85, 0xfe, 0x60, 0xa9, 0x38, 0x8d, 0x00, 0xe0, 0x60, 0xbd, 0xba, + 0xe0, 0xdd, 0xa8, 0xe1, 0xf0, 0x18, 0xde, 0xba, 0xe0, 0xa8, 0x88, 0xb9, 0xf0, 0xe0, 0xf0, 0x0d, + 0x85, 0xfe, 0xb9, 0xe1, 0xe0, 0x85, 0xfd, 0xb9, 0x2f, 0xe1, 0x9d, 0x33, 0xe0, 0x60, 0xa9, 0x20, + 0x8d, 0x00, 0xe0, 0x60, 0xad, 0x00, 0xe0, 0x5d, 0x62, 0xe1, 0x8d, 0x00, 0xe0, 0xa9, 0x01, 0x9d, + 0x30, 0xe0, 0x60, 0xad, 0x00, 0xe0, 0x29, 0x07, 0x8d, 0x81, 0xec, 0xd0, 0x03, 0x20, 0xe9, 0xe2, + 0x60, 0x00, 0xa2, 0x51, 0xa0, 0xec, 0x8e, 0x5d, 0xe1, 0x8c, 0x5e, 0xe1, 0x20, 0xcf, 0xe1, 0xa2, + 0x00, 0xa0, 0x09, 0x20, 0x00, 0xe2, 0xa9, 0x07, 0x8d, 0x00, 0xe0, 0x8d, 0x81, 0xec, 0x60, 0x00, + 0x00, 0x00, 0xa9, 0x00, 0x29, 0xff, 0xf0, 0xf6, 0x4c, 0x29, 0xe3, 0xa9, 0x07, 0x8d, 0x00, 0xe0, + 0x60 +}; + +static const uint8_t _sidtune_sidplayer2[] = +{ + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x61, 0xf1, 0x60, 0x01, 0x02, 0x04, 0x00, 0x07, 0x0e, 0x02, 0x02, 0xfe, 0x02, 0x02, 0xfe, + 0xfe, 0x00, 0x01, 0x00, 0xff, 0x00, 0x02, 0x04, 0x05, 0x07, 0x09, 0x0b, 0x1e, 0x18, 0x8b, 0x7e, + 0xfa, 0x06, 0xac, 0xf3, 0xe6, 0x8f, 0xf8, 0x2e, 0x86, 0x8e, 0x96, 0x9f, 0xa8, 0xb3, 0xbd, 0xc8, + 0xd4, 0xe1, 0xee, 0xfd, 0x8c, 0x78, 0x64, 0x50, 0x3c, 0x28, 0x14, 0x00, 0x00, 0x02, 0x03, 0x05, + 0x07, 0x08, 0x0a, 0x0c, 0x0d, 0x0f, 0x11, 0x12, 0x00, 0xe0, 0x00, 0x05, 0x0a, 0x0f, 0xf9, 0x00, + 0xf5, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x30, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x50, 0x00, 0x00, 0x60, 0x00, 0x00, 0x70, 0x00, 0x00, 0x80, 0x00, 0x00, 0x90, 0x00, 0x00, 0xa0, + 0x00, 0xa9, 0x00, 0x8d, 0x00, 0xf0, 0xa2, 0x95, 0xa0, 0x42, 0xad, 0xa6, 0x02, 0xf0, 0x04, 0xa2, + 0x25, 0xa0, 0x40, 0x8e, 0x5b, 0xf1, 0x8c, 0x5c, 0xf1, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, + 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, + 0xea, 0x60, 0xa9, 0x00, 0x8d, 0x00, 0xf0, 0x86, 0x61, 0x84, 0x62, 0xa0, 0xbc, 0x99, 0x00, 0xf0, + 0x88, 0xd0, 0xfa, 0xa0, 0x72, 0x99, 0xbc, 0xf0, 0x88, 0xd0, 0xfa, 0x8d, 0x15, 0xd5, 0x8d, 0x16, + 0xd5, 0xa9, 0x08, 0x8d, 0x25, 0xf0, 0x8d, 0x17, 0xd5, 0x8d, 0x26, 0xf0, 0x8d, 0x18, 0xd5, 0xa9, + 0x90, 0x8d, 0x27, 0xf0, 0xa9, 0x60, 0x8d, 0x28, 0xf0, 0xa9, 0x0c, 0x8d, 0x29, 0xf0, 0xad, 0x5b, + 0xf1, 0x8d, 0x2d, 0xf0, 0xad, 0x5c, 0xf1, 0x8d, 0x2e, 0xf0, 0xa9, 0xff, 0x8d, 0xcc, 0xf0, 0xa9, + 0xd5, 0x85, 0x64, 0xa2, 0x02, 0xa9, 0xff, 0x9d, 0x0b, 0xf0, 0xa9, 0x01, 0x9d, 0x30, 0xf0, 0x9d, + 0x2a, 0xf0, 0x8a, 0x9d, 0x33, 0xf0, 0x9d, 0xae, 0xf0, 0xa9, 0x04, 0x9d, 0x39, 0xf0, 0xbd, 0xa8, + 0xf1, 0x9d, 0xba, 0xf0, 0xa9, 0x5b, 0x9d, 0x7e, 0xf0, 0xbd, 0x65, 0xf1, 0x85, 0x63, 0xa9, 0x00, + 0xa8, 0x91, 0x63, 0xc8, 0x91, 0x63, 0xc8, 0x91, 0x63, 0xa9, 0x08, 0x9d, 0x17, 0xf0, 0x9d, 0x9c, + 0xf0, 0xc8, 0x91, 0x63, 0xc8, 0x91, 0x63, 0xa9, 0x40, 0x9d, 0x1a, 0xf0, 0x91, 0x63, 0xa9, 0x20, + 0x9d, 0x1d, 0xf0, 0xc8, 0x91, 0x63, 0xa9, 0xf5, 0x9d, 0x20, 0xf0, 0xc8, 0x91, 0x63, 0xca, 0x10, + 0xa4, 0x8a, 0xa2, 0x17, 0x9d, 0x3e, 0xf1, 0xca, 0x10, 0xfa, 0xa5, 0x61, 0x18, 0x69, 0x06, 0x85, + 0x63, 0xa9, 0x00, 0xaa, 0xa8, 0x65, 0x62, 0x85, 0x64, 0x9d, 0xab, 0xf0, 0x9d, 0xb4, 0xf0, 0xa5, + 0x63, 0x9d, 0xa8, 0xf0, 0x9d, 0xb1, 0xf0, 0x18, 0x71, 0x61, 0x85, 0x63, 0xa5, 0x64, 0xc8, 0x71, + 0x61, 0xc8, 0xe8, 0xe0, 0x03, 0xd0, 0xe0, 0xa6, 0x63, 0xa8, 0x60, 0xa9, 0x00, 0x8d, 0x04, 0xd5, + 0x8d, 0x0b, 0xd5, 0x8d, 0x12, 0xd5, 0x8d, 0x01, 0xd5, 0x8d, 0x08, 0xd5, 0x8d, 0x0f, 0xd5, 0xa9, + 0x08, 0x8d, 0x17, 0xd5, 0xad, 0x5b, 0xf1, 0x8d, 0x04, 0xdc, 0xad, 0x5c, 0xf1, 0x8d, 0x05, 0xdc, + 0x60, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0x60, + 0xa9, 0x08, 0x8d, 0x00, 0xf0, 0x6c, 0x5d, 0xf1, 0xea, 0xea, 0xea, 0xad, 0x00, 0xf0, 0x30, 0xf0, + 0x09, 0x80, 0xa8, 0x29, 0x07, 0xf0, 0xee, 0xd8, 0x8c, 0x00, 0xf0, 0xea, 0xa5, 0xfb, 0x8d, 0x56, + 0xf1, 0xa5, 0xfc, 0x8d, 0x57, 0xf1, 0xa5, 0xfd, 0x8d, 0x58, 0xf1, 0xa5, 0xfe, 0x8d, 0x59, 0xf1, + 0xa5, 0xff, 0x8d, 0x5a, 0xf1, 0xad, 0x23, 0xf0, 0x18, 0x6d, 0xd9, 0xf0, 0x48, 0x29, 0x07, 0xa8, + 0xad, 0xdc, 0xf0, 0x69, 0x00, 0x85, 0xff, 0x68, 0x46, 0xff, 0x6a, 0x46, 0xff, 0x6a, 0x46, 0xff, + 0x6a, 0x18, 0x6d, 0x24, 0xf0, 0x8c, 0x15, 0xd5, 0x8d, 0x16, 0xd5, 0xad, 0x25, 0xf0, 0x8d, 0x17, + 0xd5, 0xad, 0x26, 0xf0, 0x8d, 0x18, 0xd5, 0xa9, 0xd5, 0x85, 0xfc, 0xa2, 0x00, 0xad, 0x00, 0xf0, + 0x3d, 0x62, 0xf1, 0xf0, 0x51, 0xbd, 0x65, 0xf1, 0x85, 0xfb, 0xbd, 0x0e, 0xf0, 0x18, 0x7d, 0x51, + 0xf0, 0xa8, 0xbd, 0x11, 0xf0, 0x7d, 0x54, 0xf0, 0x48, 0x98, 0x18, 0x7d, 0xcd, 0xf0, 0xa0, 0x00, + 0x91, 0xfb, 0x68, 0x7d, 0xd0, 0xf0, 0xc8, 0x91, 0xfb, 0xbd, 0x14, 0xf0, 0x18, 0x7d, 0x69, 0xf0, + 0x85, 0xff, 0xbd, 0x17, 0xf0, 0x7d, 0x6c, 0xf0, 0x48, 0xa5, 0xff, 0x18, 0x7d, 0xd3, 0xf0, 0xc8, + 0x91, 0xfb, 0x68, 0x7d, 0xd6, 0xf0, 0xc8, 0x91, 0xfb, 0xbd, 0x1d, 0xf0, 0xc8, 0xc8, 0x91, 0xfb, + 0xbd, 0x20, 0xf0, 0xc8, 0x91, 0xfb, 0xe8, 0xe0, 0x03, 0xd0, 0xa2, 0xac, 0x1a, 0xf0, 0xae, 0x1b, + 0xf0, 0xad, 0x1c, 0xf0, 0x8c, 0x04, 0xd5, 0x8e, 0x0b, 0xd5, 0x8d, 0x12, 0xd5, 0xae, 0x2d, 0xf0, + 0xac, 0x2e, 0xf0, 0x8e, 0x04, 0xdc, 0x8c, 0x05, 0xdc, 0xad, 0x1b, 0xd5, 0x8d, 0xbe, 0xf0, 0xad, + 0x1c, 0xd5, 0x8d, 0xbf, 0xf0, 0xa2, 0x00, 0xad, 0x00, 0xf0, 0x3d, 0x62, 0xf1, 0xf0, 0x10, 0x8e, + 0x2f, 0xf0, 0x20, 0x36, 0xf5, 0xad, 0x00, 0xf0, 0x29, 0x78, 0xf0, 0x03, 0x4c, 0x0c, 0xf5, 0xe8, + 0xe0, 0x03, 0xd0, 0xe3, 0xad, 0xc9, 0xf0, 0xd0, 0x52, 0xad, 0xca, 0xf0, 0x0d, 0xcb, 0xf0, 0xf0, + 0x78, 0xad, 0xdf, 0xf0, 0xd0, 0x28, 0xad, 0xca, 0xf0, 0xf0, 0x28, 0x18, 0x6d, 0xbd, 0xf0, 0xb0, + 0x07, 0xcd, 0xcc, 0xf0, 0x90, 0x60, 0xf0, 0x5e, 0xa9, 0x00, 0x8d, 0xdf, 0xf0, 0xad, 0xcb, 0xf0, + 0xf0, 0x54, 0xee, 0xdf, 0xf0, 0xad, 0xbd, 0xf0, 0xed, 0xcb, 0xf0, 0x4c, 0xb4, 0xf4, 0xad, 0xcb, + 0xf0, 0xf0, 0xd3, 0xad, 0xbd, 0xf0, 0x38, 0xed, 0xcb, 0xf0, 0xb0, 0x3a, 0xa9, 0x00, 0x8d, 0xdf, + 0xf0, 0xad, 0xca, 0xf0, 0xd0, 0x30, 0xee, 0xdf, 0xf0, 0xd0, 0x28, 0xce, 0xe0, 0xf0, 0xd0, 0x29, + 0xad, 0xdf, 0xf0, 0xd0, 0x11, 0xee, 0xdf, 0xf0, 0xad, 0xcb, 0xf0, 0xd0, 0x02, 0xa9, 0x20, 0x8d, + 0xe0, 0xf0, 0xa9, 0x00, 0xf0, 0x10, 0xce, 0xdf, 0xf0, 0xad, 0xca, 0xf0, 0xd0, 0x02, 0xa9, 0x20, + 0x8d, 0xe0, 0xf0, 0xad, 0xcc, 0xf0, 0x8d, 0xbd, 0xf0, 0xa2, 0x00, 0xbd, 0xc3, 0xf0, 0xf0, 0x44, + 0xa9, 0x00, 0x85, 0xff, 0xbc, 0xc0, 0xf0, 0xb9, 0xbd, 0xf0, 0xbc, 0xc6, 0xf0, 0xf0, 0x0e, 0x30, + 0x08, 0x0a, 0x26, 0xff, 0x88, 0xd0, 0xfa, 0xf0, 0x04, 0x4a, 0xc8, 0xd0, 0xfc, 0xbc, 0xc3, 0xf0, + 0x88, 0xd0, 0x0b, 0x9d, 0xcd, 0xf0, 0xa5, 0xff, 0x9d, 0xd0, 0xf0, 0x4c, 0x02, 0xf5, 0x88, 0xd0, + 0x0b, 0x9d, 0xd3, 0xf0, 0xa5, 0xff, 0x9d, 0xd6, 0xf0, 0x4c, 0x02, 0xf5, 0x8d, 0xd9, 0xf0, 0xa5, + 0xff, 0x8d, 0xdc, 0xf0, 0xe8, 0xe0, 0x03, 0xd0, 0xb2, 0xad, 0x00, 0xf0, 0x29, 0x7f, 0x8d, 0x00, + 0xf0, 0xad, 0x56, 0xf1, 0x85, 0xfb, 0xad, 0x57, 0xf1, 0x85, 0xfc, 0xad, 0x58, 0xf1, 0x85, 0xfd, + 0xad, 0x59, 0xf1, 0x85, 0xfe, 0xad, 0x5a, 0xf1, 0x85, 0xff, 0x6c, 0x5d, 0xf1, 0xbd, 0x60, 0xf0, + 0xd0, 0x03, 0x4c, 0x9f, 0xf6, 0x4c, 0xba, 0xf5, 0xde, 0x30, 0xf0, 0xd0, 0x03, 0x4c, 0xa0, 0xf6, + 0xbd, 0x36, 0xf0, 0x30, 0xe8, 0xd0, 0x1a, 0xbd, 0x3f, 0xf0, 0xf0, 0x05, 0xde, 0x3f, 0xf0, 0xd0, + 0x10, 0xbd, 0x39, 0xf0, 0xdd, 0x30, 0xf0, 0x90, 0x08, 0xbd, 0x1a, 0xf0, 0x29, 0xfe, 0x9d, 0x1a, + 0xf0, 0xbd, 0x42, 0xf0, 0xf0, 0x56, 0x0a, 0xbd, 0x0e, 0xf0, 0xb0, 0x1d, 0x7d, 0x45, 0xf0, 0x9d, + 0x0e, 0xf0, 0xa8, 0xbd, 0x11, 0xf0, 0x7d, 0x48, 0xf0, 0x9d, 0x11, 0xf0, 0x48, 0x98, 0xdd, 0x8d, + 0xf0, 0x68, 0xfd, 0x90, 0xf0, 0xb0, 0x1f, 0x90, 0x2e, 0xfd, 0x45, 0xf0, 0x9d, 0x0e, 0xf0, 0xbd, + 0x11, 0xf0, 0xfd, 0x48, 0xf0, 0x9d, 0x11, 0xf0, 0xbd, 0x8d, 0xf0, 0xdd, 0x0e, 0xf0, 0xbd, 0x90, + 0xf0, 0xfd, 0x11, 0xf0, 0x90, 0x11, 0xbd, 0x8d, 0xf0, 0x9d, 0x0e, 0xf0, 0xbd, 0x90, 0xf0, 0x9d, + 0x11, 0xf0, 0xa9, 0x00, 0x9d, 0x42, 0xf0, 0xbd, 0x60, 0xf0, 0xf0, 0x55, 0xbd, 0x4b, 0xf0, 0xf0, + 0x4b, 0xa0, 0x00, 0xde, 0x4e, 0xf0, 0xd0, 0x31, 0xbd, 0x51, 0xf0, 0x1d, 0x54, 0xf0, 0xd0, 0x1b, + 0xbd, 0x5d, 0xf0, 0x9d, 0x57, 0xf0, 0x9d, 0x4e, 0xf0, 0xbd, 0x4b, 0xf0, 0x0a, 0xbd, 0x5a, 0xf0, + 0x90, 0x04, 0x49, 0xff, 0x69, 0x00, 0x9d, 0x4b, 0xf0, 0xd0, 0x10, 0xbd, 0x57, 0xf0, 0x9d, 0x4e, + 0xf0, 0x98, 0x38, 0xfd, 0x4b, 0xf0, 0x9d, 0x4b, 0xf0, 0xc9, 0x00, 0x10, 0x01, 0x88, 0x18, 0x7d, + 0x51, 0xf0, 0x9d, 0x51, 0xf0, 0x98, 0x7d, 0x54, 0xf0, 0x9d, 0x54, 0xf0, 0xbd, 0x36, 0xf0, 0x30, + 0x15, 0xbd, 0x93, 0xf0, 0xf0, 0x10, 0x18, 0x7d, 0x14, 0xf0, 0x9d, 0x14, 0xf0, 0xbd, 0x96, 0xf0, + 0x7d, 0x17, 0xf0, 0x9d, 0x17, 0xf0, 0xbd, 0x63, 0xf0, 0xf0, 0x4b, 0xa0, 0x00, 0xde, 0x66, 0xf0, + 0xd0, 0x31, 0xbd, 0x69, 0xf0, 0x1d, 0x6c, 0xf0, 0xd0, 0x1b, 0xbd, 0x72, 0xf0, 0x9d, 0x6f, 0xf0, + 0x9d, 0x66, 0xf0, 0xbd, 0x63, 0xf0, 0x0a, 0xbd, 0x75, 0xf0, 0x90, 0x04, 0x49, 0xff, 0x69, 0x00, + 0x9d, 0x63, 0xf0, 0xd0, 0x10, 0xbd, 0x6f, 0xf0, 0x9d, 0x66, 0xf0, 0x98, 0x38, 0xfd, 0x63, 0xf0, + 0x9d, 0x63, 0xf0, 0xc9, 0x00, 0x10, 0x01, 0x88, 0x18, 0x7d, 0x69, 0xf0, 0x9d, 0x69, 0xf0, 0x98, + 0x7d, 0x6c, 0xf0, 0x9d, 0x6c, 0xf0, 0xbd, 0x36, 0xf0, 0x10, 0x03, 0x4c, 0x9f, 0xf6, 0xa0, 0x00, + 0xbd, 0xa2, 0xf0, 0xf0, 0x1c, 0x10, 0x01, 0xc8, 0x18, 0x6d, 0x23, 0xf0, 0x48, 0x29, 0x07, 0x8d, + 0x23, 0xf0, 0x68, 0x6a, 0x4a, 0x4a, 0x18, 0x79, 0xa6, 0xf1, 0x18, 0x6d, 0x24, 0xf0, 0x8d, 0x24, + 0xf0, 0x60, 0xbd, 0xa8, 0xf0, 0x85, 0xfd, 0xbd, 0xab, 0xf0, 0x85, 0xfe, 0xd0, 0x04, 0x60, 0x20, + 0x98, 0xf8, 0xad, 0x00, 0xf0, 0x3d, 0x62, 0xf1, 0xf0, 0xf4, 0xa0, 0x00, 0xb1, 0xfd, 0x85, 0xff, + 0xc8, 0xb1, 0xfd, 0xa8, 0xa5, 0xfd, 0x18, 0x69, 0x02, 0x85, 0xfd, 0x9d, 0xa8, 0xf0, 0xa5, 0xfe, + 0x69, 0x00, 0x85, 0xfe, 0x9d, 0xab, 0xf0, 0xa5, 0xff, 0x29, 0x03, 0xd0, 0xd2, 0xbd, 0x8d, 0xf0, + 0x9d, 0x0e, 0xf0, 0xbd, 0x90, 0xf0, 0x9d, 0x11, 0xf0, 0xa5, 0xff, 0x9d, 0x05, 0xf0, 0x98, 0x9d, + 0x02, 0xf0, 0x29, 0x07, 0xa8, 0xb9, 0x67, 0xf1, 0x8d, 0x6f, 0xf1, 0xbd, 0x02, 0xf0, 0x29, 0x38, + 0x4a, 0x4a, 0x4a, 0x7d, 0x81, 0xf0, 0x85, 0xfd, 0xbd, 0x02, 0xf0, 0x29, 0xc0, 0x0a, 0x2a, 0x2a, + 0xa8, 0xb9, 0x6f, 0xf1, 0x85, 0xfe, 0xbd, 0x02, 0xf0, 0x29, 0x07, 0xf0, 0x62, 0xa8, 0xb9, 0x72, + 0xf1, 0x65, 0xfe, 0x18, 0x7d, 0x84, 0xf0, 0x10, 0x05, 0x18, 0x69, 0x0c, 0xe6, 0xfd, 0xc9, 0x0c, + 0x90, 0x04, 0xe9, 0x0c, 0xc6, 0xfd, 0x85, 0xfe, 0xa8, 0xb9, 0x86, 0xf1, 0x85, 0xff, 0xb9, 0x7a, + 0xf1, 0xa4, 0xfd, 0x88, 0x30, 0x06, 0x46, 0xff, 0x6a, 0x88, 0x10, 0xfa, 0x18, 0x7d, 0x87, 0xf0, + 0x9d, 0x8d, 0xf0, 0xa5, 0xff, 0x7d, 0x8a, 0xf0, 0x9d, 0x90, 0xf0, 0xbd, 0x05, 0xf0, 0xd0, 0x03, + 0x4c, 0xa0, 0xf6, 0xbd, 0x45, 0xf0, 0x1d, 0x48, 0xf0, 0xf0, 0x16, 0xbd, 0x0e, 0xf0, 0xdd, 0x8d, + 0xf0, 0xbd, 0x11, 0xf0, 0xfd, 0x90, 0xf0, 0xa9, 0xfe, 0x6a, 0x9d, 0x42, 0xf0, 0x90, 0x11, 0xf0, + 0x4a, 0x9d, 0x42, 0xf0, 0xbd, 0x8d, 0xf0, 0x9d, 0x0e, 0xf0, 0xbd, 0x90, 0xf0, 0x9d, 0x11, 0xf0, + 0xbd, 0x36, 0xf0, 0x0a, 0xd0, 0x35, 0xbd, 0x93, 0xf0, 0xf0, 0x0c, 0xbd, 0x99, 0xf0, 0x9d, 0x14, + 0xf0, 0xbd, 0x9c, 0xf0, 0x9d, 0x17, 0xf0, 0xbd, 0x9f, 0xf0, 0xf0, 0x0f, 0xa4, 0xfd, 0x18, 0x79, + 0x92, 0xf1, 0xa4, 0xfe, 0x18, 0x79, 0x9a, 0xf1, 0x18, 0x90, 0x08, 0xbd, 0xa2, 0xf0, 0xf0, 0x0b, + 0xbd, 0xa5, 0xf0, 0x8d, 0x24, 0xf0, 0xa9, 0x00, 0x8d, 0x23, 0xf0, 0xbd, 0x3c, 0xf0, 0x9d, 0x3f, + 0xf0, 0xbd, 0x05, 0xf0, 0x29, 0x40, 0x9d, 0x36, 0xf0, 0xbd, 0x05, 0xf0, 0x4a, 0x4a, 0x29, 0x07, + 0xd0, 0x30, 0xbd, 0x05, 0xf0, 0x30, 0x14, 0xad, 0x27, 0xf0, 0x29, 0x3c, 0xd0, 0x1e, 0xad, 0x27, + 0xf0, 0x0a, 0x2a, 0x2a, 0xd0, 0x02, 0xa9, 0x04, 0x4c, 0x70, 0xf8, 0xad, 0x28, 0xf0, 0xf0, 0x0c, + 0x29, 0x3f, 0xd0, 0x08, 0xad, 0x28, 0xf0, 0x0a, 0x2a, 0x2a, 0xd0, 0x66, 0xa9, 0x10, 0x8d, 0x00, + 0xf0, 0x60, 0xc9, 0x01, 0xd0, 0x13, 0xbd, 0x05, 0xf0, 0x29, 0x20, 0xd0, 0x06, 0xad, 0x29, 0xf0, + 0x4c, 0x70, 0xf8, 0xbd, 0x2a, 0xf0, 0x4c, 0x70, 0xf8, 0xa8, 0xbd, 0x05, 0xf0, 0x29, 0xa0, 0xc9, + 0x80, 0xf0, 0x30, 0x85, 0xff, 0x18, 0xad, 0x27, 0xf0, 0xd0, 0x01, 0x38, 0x88, 0x88, 0xf0, 0x06, + 0x6a, 0xb0, 0x4e, 0x88, 0xd0, 0xfa, 0xa4, 0xff, 0x85, 0xff, 0xf0, 0x26, 0x46, 0xff, 0xb0, 0x41, + 0xf0, 0x42, 0x65, 0xff, 0xb0, 0x3e, 0xc8, 0x10, 0x19, 0x46, 0xff, 0xb0, 0x34, 0x65, 0xff, 0x90, + 0x11, 0xb0, 0x31, 0xad, 0x28, 0xf0, 0xf0, 0x29, 0x88, 0x88, 0xf0, 0x06, 0x4a, 0xb0, 0x22, 0x88, + 0xd0, 0xfa, 0x9d, 0x30, 0xf0, 0xbd, 0x1a, 0xf0, 0x29, 0xf6, 0x9d, 0x1a, 0xf0, 0x38, 0xbd, 0x02, + 0xf0, 0x29, 0x07, 0xd0, 0x03, 0x7e, 0x36, 0xf0, 0xbd, 0x1a, 0xf0, 0x69, 0x00, 0x9d, 0x1a, 0xf0, + 0x60, 0xa9, 0x10, 0x2c, 0xa9, 0x18, 0x8d, 0x00, 0xf0, 0x60, 0x98, 0x48, 0xa5, 0xff, 0x4a, 0x90, + 0x03, 0x4c, 0x42, 0xfa, 0x4a, 0x4a, 0xb0, 0x1e, 0x4a, 0xb0, 0x0e, 0x9d, 0x9c, 0xf0, 0x9d, 0x17, + 0xf0, 0x68, 0x9d, 0x99, 0xf0, 0x9d, 0x14, 0xf0, 0x60, 0x4a, 0x90, 0x02, 0x09, 0xf8, 0x9d, 0x8a, + 0xf0, 0x68, 0x9d, 0x87, 0xf0, 0x60, 0x4a, 0xb0, 0x03, 0x4c, 0x4a, 0xf9, 0x4a, 0xb0, 0x61, 0x4a, + 0xb0, 0x0f, 0xd0, 0x08, 0x68, 0x9d, 0xa5, 0xf0, 0x8d, 0x24, 0xf0, 0x60, 0x68, 0x9d, 0x3c, 0xf0, + 0x60, 0xd0, 0x48, 0x68, 0x9d, 0x7e, 0xf0, 0xc9, 0x5b, 0xf0, 0x33, 0xa8, 0x4a, 0x4a, 0x4a, 0x38, + 0xe9, 0x0b, 0x18, 0x7d, 0x84, 0xf0, 0x30, 0x0c, 0xc9, 0x0c, 0x90, 0x11, 0xe9, 0x0c, 0xde, 0x81, + 0xf0, 0x4c, 0x0b, 0xf9, 0xc9, 0xf5, 0xb0, 0x05, 0x69, 0x0c, 0xfe, 0x81, 0xf0, 0x9d, 0x84, 0xf0, + 0x98, 0x29, 0x07, 0x38, 0xe9, 0x03, 0x18, 0x7d, 0x81, 0xf0, 0x9d, 0x81, 0xf0, 0x60, 0xbd, 0x78, + 0xf0, 0x9d, 0x81, 0xf0, 0xbd, 0x7b, 0xf0, 0x9d, 0x84, 0xf0, 0x60, 0x68, 0x9d, 0xc6, 0xf0, 0x60, + 0x4a, 0xb0, 0x08, 0x9d, 0x0b, 0xf0, 0x68, 0x9d, 0x08, 0xf0, 0x60, 0x4a, 0x6a, 0x6a, 0x6d, 0x5b, + 0xf1, 0x8d, 0x2d, 0xf0, 0x68, 0x6d, 0x5c, 0xf1, 0x8d, 0x2e, 0xf0, 0x60, 0x4a, 0x90, 0x03, 0x4c, + 0xd3, 0xf9, 0x4a, 0xb0, 0x40, 0x4a, 0xb0, 0x17, 0x4a, 0xb0, 0x0f, 0x68, 0x8d, 0x27, 0xf0, 0x4a, + 0x4a, 0x4a, 0xa8, 0xb9, 0xaf, 0xf1, 0x8d, 0x28, 0xf0, 0x60, 0x68, 0x9d, 0x5d, 0xf0, 0x60, 0x4a, + 0xb0, 0x05, 0x68, 0x8d, 0x01, 0xf0, 0x60, 0x68, 0xf0, 0x11, 0x9d, 0x75, 0xf0, 0xbc, 0x63, 0xf0, + 0xd0, 0x08, 0x9d, 0x63, 0xf0, 0xa9, 0x01, 0x9d, 0x66, 0xf0, 0x60, 0x9d, 0x63, 0xf0, 0x9d, 0x69, + 0xf0, 0x9d, 0x6c, 0xf0, 0x60, 0x4a, 0xb0, 0x30, 0x4a, 0xb0, 0x05, 0x68, 0x9d, 0x39, 0xf0, 0x60, + 0x68, 0xa0, 0x00, 0x4a, 0x90, 0x02, 0xc8, 0x18, 0x48, 0x29, 0x07, 0x79, 0xac, 0xf1, 0x9d, 0x78, + 0xf0, 0x9d, 0x81, 0xf0, 0x68, 0x4a, 0x4a, 0x4a, 0x18, 0x79, 0xad, 0xf1, 0x9d, 0x7b, 0xf0, 0x9d, + 0x84, 0xf0, 0xa9, 0x5b, 0x9d, 0x7e, 0xf0, 0x60, 0x4a, 0xb0, 0x05, 0x68, 0x9d, 0xa2, 0xf0, 0x60, + 0x68, 0x8d, 0xcc, 0xf0, 0x60, 0x4a, 0xb0, 0x27, 0x4a, 0xb0, 0x0d, 0x4a, 0xb0, 0x05, 0x68, 0x8d, + 0x29, 0xf0, 0x60, 0x68, 0x9d, 0x9f, 0xf0, 0x60, 0x4a, 0xb0, 0x0f, 0x68, 0x9d, 0x93, 0xf0, 0xa0, + 0x00, 0x0a, 0x90, 0x01, 0x88, 0x98, 0x9d, 0x96, 0xf0, 0x60, 0x68, 0x9d, 0x72, 0xf0, 0x60, 0x4a, + 0xb0, 0x1c, 0x4a, 0xb0, 0x15, 0x68, 0x9d, 0xb7, 0xf0, 0xa5, 0xfd, 0x9d, 0xb1, 0xf0, 0xa5, 0xfe, + 0x9d, 0xb4, 0xf0, 0xbd, 0x33, 0xf0, 0x9d, 0xae, 0xf0, 0x60, 0x68, 0x6c, 0x5f, 0xf1, 0x4a, 0xb0, + 0x1e, 0x68, 0xd0, 0x0a, 0x9d, 0x4b, 0xf0, 0x9d, 0x51, 0xf0, 0x9d, 0x54, 0xf0, 0x60, 0x9d, 0x5a, + 0xf0, 0xbc, 0x4b, 0xf0, 0xd0, 0x08, 0x9d, 0x4b, 0xf0, 0xa9, 0x01, 0x9d, 0x4e, 0xf0, 0x60, 0x68, + 0x9d, 0x2a, 0xf0, 0x60, 0x4a, 0x90, 0x08, 0x9d, 0x48, 0xf0, 0x68, 0x9d, 0x45, 0xf0, 0x60, 0x68, + 0x4a, 0xb0, 0x61, 0x4a, 0xb0, 0x25, 0x4a, 0xb0, 0x05, 0x4a, 0xa0, 0xf0, 0xd0, 0x06, 0x0a, 0x0a, + 0x0a, 0x0a, 0xa0, 0x0f, 0x85, 0xff, 0x98, 0xb0, 0x09, 0x3d, 0x1d, 0xf0, 0x05, 0xff, 0x9d, 0x1d, + 0xf0, 0x60, 0x3d, 0x20, 0xf0, 0x05, 0xff, 0x9d, 0x20, 0xf0, 0x60, 0x4a, 0xb0, 0x38, 0x4a, 0xb0, + 0x64, 0x85, 0xff, 0xbd, 0xba, 0xf0, 0xdd, 0xa9, 0xf1, 0xf0, 0x54, 0xfe, 0xba, 0xf0, 0xa8, 0xa5, + 0xfd, 0x99, 0xe1, 0xf0, 0xa5, 0xfe, 0x99, 0xf0, 0xf0, 0xbd, 0x33, 0xf0, 0x99, 0x2f, 0xf1, 0xa4, + 0xff, 0xb9, 0x17, 0xf1, 0xf0, 0x36, 0x85, 0xfe, 0xb9, 0xff, 0xf0, 0x85, 0xfd, 0xb9, 0x3e, 0xf1, + 0x9d, 0x33, 0xf0, 0x60, 0xb0, 0x4b, 0x4a, 0xb0, 0x3c, 0xa8, 0xa5, 0xfd, 0x99, 0xff, 0xf0, 0xa5, + 0xfe, 0x99, 0x17, 0xf1, 0xbd, 0x33, 0xf0, 0x99, 0x3e, 0xf1, 0xbd, 0xba, 0xf0, 0xdd, 0xa9, 0xf1, + 0xf0, 0x0d, 0xfe, 0xba, 0xf0, 0xa8, 0xa9, 0x00, 0x99, 0xf0, 0xf0, 0x60, 0xa9, 0x30, 0x2c, 0xa9, + 0x28, 0x8d, 0x00, 0xf0, 0x60, 0x0a, 0x0a, 0x0a, 0x0a, 0x4d, 0x25, 0xf0, 0x29, 0xf0, 0x4d, 0x25, + 0xf0, 0x8d, 0x25, 0xf0, 0x60, 0x4d, 0x26, 0xf0, 0x29, 0x0f, 0x4d, 0x26, 0xf0, 0x8d, 0x26, 0xf0, + 0x60, 0x4a, 0xb0, 0x0b, 0x4a, 0xb0, 0x04, 0x8d, 0xca, 0xf0, 0x60, 0x8d, 0xcb, 0xf0, 0x60, 0x4a, + 0x90, 0x03, 0x4c, 0xa5, 0xfb, 0x4a, 0xa8, 0xf0, 0x21, 0x88, 0xf0, 0x34, 0x88, 0xf0, 0x42, 0x88, + 0xf0, 0x4a, 0x88, 0xf0, 0x52, 0x88, 0xf0, 0x5c, 0x88, 0xf0, 0x66, 0x88, 0xf0, 0x73, 0x29, 0x07, + 0x09, 0x10, 0xb0, 0x03, 0x4c, 0xb7, 0xfa, 0x4c, 0x7f, 0xfa, 0xac, 0x26, 0xf0, 0xb0, 0x07, 0xc8, + 0x98, 0x29, 0x0f, 0xd0, 0x07, 0x60, 0x98, 0x29, 0x0f, 0xf0, 0x04, 0x88, 0x8c, 0x26, 0xf0, 0x60, + 0xbd, 0x62, 0xf1, 0x49, 0xff, 0x2d, 0x25, 0xf0, 0x90, 0x03, 0x1d, 0x62, 0xf1, 0x8d, 0x25, 0xf0, + 0x60, 0xbd, 0x1a, 0xf0, 0x29, 0xfb, 0x90, 0x55, 0x09, 0x04, 0xb0, 0x51, 0xbd, 0x1a, 0xf0, 0x29, + 0xfd, 0x90, 0x4a, 0x09, 0x02, 0xb0, 0x46, 0xad, 0x25, 0xf0, 0x29, 0xf7, 0x90, 0x02, 0x09, 0x08, + 0x8d, 0x25, 0xf0, 0x60, 0xad, 0x26, 0xf0, 0x29, 0x7f, 0x90, 0x02, 0x09, 0x80, 0x8d, 0x26, 0xf0, + 0x60, 0x98, 0x8d, 0xbd, 0xf0, 0x8d, 0xdf, 0xf0, 0xc8, 0x8c, 0xe0, 0xf0, 0x2a, 0x8d, 0xc9, 0xf0, + 0x60, 0x98, 0x2a, 0x9d, 0x60, 0xf0, 0x60, 0x4a, 0xb0, 0x27, 0x4a, 0xb0, 0x14, 0xd0, 0x02, 0xa9, + 0x08, 0x0a, 0x0a, 0x0a, 0x0a, 0x5d, 0x1a, 0xf0, 0x29, 0xf0, 0x5d, 0x1a, 0xf0, 0x9d, 0x1a, 0xf0, + 0x60, 0x0a, 0x0a, 0x0a, 0x0a, 0x4d, 0x26, 0xf0, 0x29, 0x70, 0x4d, 0x26, 0xf0, 0x8d, 0x26, 0xf0, + 0x60, 0x4a, 0x90, 0x04, 0x9d, 0xc0, 0xf0, 0x60, 0xa8, 0xf0, 0x20, 0x88, 0xf0, 0x40, 0x88, 0xf0, + 0x63, 0x29, 0x03, 0x9d, 0xc3, 0xf0, 0xa9, 0x00, 0x9d, 0xcd, 0xf0, 0x9d, 0xd0, 0xf0, 0x9d, 0xd3, + 0xf0, 0x9d, 0xd6, 0xf0, 0x8d, 0xd9, 0xf0, 0x8d, 0xdc, 0xf0, 0x60, 0xbd, 0xb7, 0xf0, 0xf0, 0x05, + 0xde, 0xb7, 0xf0, 0xf0, 0x12, 0xbd, 0x33, 0xf0, 0xdd, 0xae, 0xf0, 0xd0, 0x0b, 0xbd, 0xb1, 0xf0, + 0x85, 0xfd, 0xbd, 0xb4, 0xf0, 0x85, 0xfe, 0x60, 0xa9, 0x38, 0x8d, 0x00, 0xf0, 0x60, 0xbd, 0xba, + 0xf0, 0xdd, 0xa8, 0xf1, 0xf0, 0x18, 0xde, 0xba, 0xf0, 0xa8, 0x88, 0xb9, 0xf0, 0xf0, 0xf0, 0x0d, + 0x85, 0xfe, 0xb9, 0xe1, 0xf0, 0x85, 0xfd, 0xb9, 0x2f, 0xf1, 0x9d, 0x33, 0xf0, 0x60, 0xa9, 0x20, + 0x8d, 0x00, 0xf0, 0x60, 0xad, 0x00, 0xf0, 0x5d, 0x62, 0xf1, 0x8d, 0x00, 0xf0, 0xa9, 0x01, 0x9d, + 0x30, 0xf0, 0x60, 0xad, 0x00, 0xf0, 0x29, 0x07, 0x8d, 0x81, 0xfc, 0xd0, 0x03, 0x20, 0xe9, 0xf2, + 0x60, 0x00, 0xa2, 0x51, 0xa0, 0xfc, 0x8e, 0x5d, 0xf1, 0x8c, 0x5e, 0xf1, 0x20, 0xcf, 0xf1, 0xa2, + 0x00, 0xa0, 0x09, 0x20, 0x00, 0xf2, 0xa9, 0x07, 0x8d, 0x00, 0xf0, 0x8d, 0x81, 0xfc, 0x60, 0x00, + 0x00, 0x00, 0xa9, 0x00, 0x29, 0xff, 0xf0, 0xf6, 0x4c, 0x29, 0xf3, 0xa9, 0x07, 0x8d, 0x00, 0xf0, + 0x60, 0x00, 0x20, 0x60, 0xec, 0x4c, 0x60, 0xfc, 0x20, 0x80, 0xec, 0x4c, 0x80, 0xfc +}; + +bool SidTune::MUS_mergeParts(Buffer_sidtt<const uint8_t>& musBuf, + Buffer_sidtt<const uint8_t>& strBuf) +{ + Buffer_sidtt<uint8_t> mergeBuf; + + uint_least32_t mergeLen = musBuf.len()+strBuf.len(); + + musDataLen = musBuf.len()-2; + + // 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()+2,strBuf.len()-2); +#else + memcpy((void*)(mergeBuf.get()+musBuf.len()),strBuf.get()+2,strBuf.len()-2); +#endif + } + + musBuf.assign(mergeBuf.xferPtr(),mergeBuf.xferLen()); + strBuf.erase(); + + return true; +} + +void SidTune::MUS_installPlayer(uint8_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&0xFF; + c64buf[dest+0xc70] = SIDTUNE_MUS_DATA_ADDR>>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)&0xFF; + c64buf[dest+0xc70] = (SIDTUNE_MUS_DATA_ADDR+musDataLen)>>8; + } + } +} diff --git a/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/Makefile.am b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/Makefile.am new file mode 100644 index 00000000..e1c06822 --- /dev/null +++ b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/Makefile.am @@ -0,0 +1,17 @@ + +noinst_LTLIBRARIES = libsidtune.la + +libsidtune_la_SOURCES = IconInfo.cpp \ +InfoFile.cpp \ +MUS.cpp \ +PP20.cpp \ +PP20.h \ +PP20_Defs.h \ +PSID.cpp \ +SidTune.cpp \ +SidTuneCfg.h \ +SidTuneTools.cpp \ +SidTuneTools.h + +# Remove bad default includes +DEFAULT_INCLUDES= diff --git a/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/Makefile.in b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/Makefile.in new file mode 100644 index 00000000..bb5a7c27 --- /dev/null +++ b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/Makefile.in @@ -0,0 +1,446 @@ +# Makefile.in generated by automake 1.7.1 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_triplet = @host@ +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBVERSION = @LIBVERSION@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SID_HAVE_BOOL = @SID_HAVE_BOOL@ +SID_HAVE_STDBOOL_H = @SID_HAVE_STDBOOL_H@ +SID_SIZEOF_CHAR = @SID_SIZEOF_CHAR@ +SID_SIZEOF_INT = @SID_SIZEOF_INT@ +SID_SIZEOF_LONG_INT = @SID_SIZEOF_LONG_INT@ +SID_SIZEOF_SHORT_INT = @SID_SIZEOF_SHORT_INT@ +SID_WORDS_ENDIANESS = @SID_WORDS_ENDIANESS@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__quote = @am__quote@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builders = @builders@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ + +noinst_LTLIBRARIES = libsidtune.la + +libsidtune_la_SOURCES = IconInfo.cpp \ +InfoFile.cpp \ +MUS.cpp \ +PP20.cpp \ +PP20.h \ +PP20_Defs.h \ +PSID.cpp \ +SidTune.cpp \ +SidTuneCfg.h \ +SidTuneTools.cpp \ +SidTuneTools.h + + +# Remove bad default includes +DEFAULT_INCLUDES = +subdir = src/sidtune +mkinstalldirs = $(SHELL) $(top_srcdir)/unix/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/unix/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) + +libsidtune_la_LDFLAGS = +libsidtune_la_LIBADD = +am_libsidtune_la_OBJECTS = IconInfo.lo InfoFile.lo MUS.lo PP20.lo \ + PSID.lo SidTune.lo SidTuneTools.lo +libsidtune_la_OBJECTS = $(am_libsidtune_la_OBJECTS) +depcomp = $(SHELL) $(top_srcdir)/unix/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/IconInfo.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/InfoFile.Plo ./$(DEPDIR)/MUS.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/PP20.Plo ./$(DEPDIR)/PSID.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/SidTune.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/SidTuneTools.Plo +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \ + $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libsidtune_la_SOURCES) +DIST_COMMON = Makefile.am Makefile.in +SOURCES = $(libsidtune_la_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/sidtune/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" = "$$p" && dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libsidtune.la: $(libsidtune_la_OBJECTS) $(libsidtune_la_DEPENDENCIES) + $(CXXLINK) $(libsidtune_la_LDFLAGS) $(libsidtune_la_OBJECTS) $(libsidtune_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IconInfo.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/InfoFile.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MUS.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PP20.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PSID.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SidTune.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SidTuneTools.Plo@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.cpp.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +.cpp.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`; \ +@am__fastdepCXX_TRUE@ then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'` + +.cpp.lo: +@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = ../.. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) + +installdirs: + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am info \ + info-am install install-am install-data install-data-am \ + install-exec install-exec-am install-info install-info-am \ + install-man install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/PP20.cpp b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/PP20.cpp new file mode 100644 index 00000000..8bec5cfe --- /dev/null +++ b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/PP20.cpp @@ -0,0 +1,289 @@ +/* + * /home/ms/files/source/libsidtune/RCS/PP20.cpp,v + * + * PowerPacker (AMIGA) "PP20" format decompressor. + * Copyright (C) Michael Schwendt <mschwendt@yahoo.com> + * + * 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 "PP20.h" + +#include <string.h> +#ifdef PP20_HAVE_EXCEPTIONS +#include <new> +#endif + +/* Read a big-endian 32-bit word from four bytes in memory. + No endian-specific optimizations applied. */ +inline udword_ppt readBEdword(const ubyte_ppt ptr[4]) +{ + return ( (((udword_ppt)ptr[0])<<24) + (((udword_ppt)ptr[1])<<16) + + (((udword_ppt)ptr[2])<<8) + ((udword_ppt)ptr[3]) ); +} + +const char _pp20_txt_packeddatacorrupt[] = "PowerPacker: Packed data is corrupt"; +const char _pp20_txt_unrecognized[] = "PowerPacker: Unrecognized compression method"; +const char _pp20_txt_uncompressed[] = "Not compressed with PowerPacker (PP20)"; +const char _pp20_txt_notenoughmemory[] = "Not enough free memory"; +const char _pp20_txt_fast[] = "PowerPacker: fast compression"; +const char _pp20_txt_mediocre[] = "PowerPacker: mediocre compression"; +const char _pp20_txt_good[] = "PowerPacker: good compression"; +const char _pp20_txt_verygood[] = "PowerPacker: very good compression"; +const char _pp20_txt_best[] = "PowerPacker: best compression"; +const char _pp20_txt_na[] = "N/A"; + +const char* PP20::PP_ID = "PP20"; + +PP20::PP20() +{ + statusString = _pp20_txt_uncompressed; +} + +bool PP20::isCompressed(const void* source, const udword_ppt size) +{ + // Check minimum input size, PP20 ID, and efficiency table. + if ( size<8 ) + { + return false; + } + // We hope that every file with a valid signature and a valid + // efficiency table is PP-compressed actually. + const char* idPtr = (const char*)source; + if ( strncmp(idPtr,PP_ID,4) != 0 ) + { + statusString = _pp20_txt_uncompressed; + return false; + } + return checkEfficiency(idPtr+4); +} + +bool PP20::checkEfficiency(const void* source) +{ + const udword_ppt PP_BITS_FAST = 0x09090909; + const udword_ppt PP_BITS_MEDIOCRE = 0x090a0a0a; + const udword_ppt PP_BITS_GOOD = 0x090a0b0b; + const udword_ppt PP_BITS_VERYGOOD = 0x090a0c0c; + const udword_ppt PP_BITS_BEST = 0x090a0c0d; + + // Copy efficiency table. + memcpy(efficiency,(const ubyte_ppt*)source,4); + udword_ppt eff = readBEdword(efficiency); + if (( eff != PP_BITS_FAST ) && + ( eff != PP_BITS_MEDIOCRE ) && + ( eff != PP_BITS_GOOD ) && + ( eff != PP_BITS_VERYGOOD ) && + ( eff != PP_BITS_BEST )) + { + statusString = _pp20_txt_unrecognized; + return false; + } + + // Define string describing compression encoding used. + switch ( eff) + { + case PP_BITS_FAST: + statusString = _pp20_txt_fast; + break; + case PP_BITS_MEDIOCRE: + statusString = _pp20_txt_mediocre; + break; + case PP_BITS_GOOD: + statusString = _pp20_txt_good; + break; + case PP_BITS_VERYGOOD: + statusString = _pp20_txt_verygood; + break; + case PP_BITS_BEST: + statusString = _pp20_txt_best; + break; + } + + return true; +} + +// Move four bytes to Motorola big-endian double-word. +inline void PP20::bytesTOdword() +{ + readPtr -= 4; + if ( readPtr < sourceBeg ) + { + statusString = _pp20_txt_packeddatacorrupt; + globalError = true; + } + else + { + current = readBEdword(readPtr); + } +} + +inline udword_ppt PP20::readBits(int count) +{ + udword_ppt data = 0; + // read 'count' bits of packed data + for (; count > 0; count--) + { + // equal to shift left + data += data; + // merge bit 0 + data |= (current&1); + current >>= 1; + if (--bits == 0) + { + bytesTOdword(); + bits = 32; + } + } + return data; +} + +inline void PP20::bytes() +{ + udword_ppt count, add; + count = (add = readBits(2)); + while (add == 3) + { + add = readBits(2); + count += add; + } + for ( ++count; count > 0 ; count--) + { + if (writePtr > destBeg) + { + *(--writePtr) = (ubyte_ppt)readBits(8); + } + else + { + statusString = _pp20_txt_packeddatacorrupt; + globalError = true; + } + } +} + +inline void PP20::sequence() +{ + udword_ppt offset, add; + udword_ppt length = readBits(2); // is length-2 + int offsetBitLen = (int)efficiency[length]; + length += 2; + if ( length != 5 ) + offset = readBits( offsetBitLen ); + else + { + if ( readBits(1) == 0 ) + offsetBitLen = 7; + offset = readBits( offsetBitLen ); + add = readBits(3); + length += add; + while ( add == 7 ) + { + add = readBits(3); + length += add; + } + } + for ( ; length > 0 ; length-- ) + { + if ( writePtr > destBeg ) + { + --writePtr; + *writePtr = *(writePtr+1+offset); + } + else + { + statusString = _pp20_txt_packeddatacorrupt; + globalError = true; + } + } +} + +udword_ppt PP20::decompress(const void* source, + udword_ppt size, + ubyte_ppt** destRef) +{ + globalError = false; // assume no error + + sourceBeg = (const ubyte_ppt*)source; + readPtr = sourceBeg; + + if ( !isCompressed(readPtr,size) ) + { + return 0; + } + + // Uncompressed size is stored at end of source file. + // Backwards decompression. + readPtr += (size-4); + + udword_ppt lastDword = readBEdword(readPtr); + // Uncompressed length in bits 31-8 of last dword. + udword_ppt outputLen = lastDword>>8; + + // Allocate memory for output data. + ubyte_ppt* dest; +#ifdef PP20_HAVE_EXCEPTIONS + if (( dest = new(std::nothrow) ubyte_ppt[outputLen]) == 0 ) +#else + if (( dest = new ubyte_ppt[outputLen]) == 0 ) +#endif + { + statusString = _pp20_txt_notenoughmemory; + return 0; + } + + // Lowest dest. address for range-checks. + destBeg = dest; + // Put destptr to end of uncompressed data. + writePtr = dest+outputLen; + + // Read number of unused bits in 1st data dword + // from lowest bits 7-0 of last dword. + bits = 32 - (lastDword&0xFF); + + // Main decompression loop. + bytesTOdword(); + if ( bits != 32 ) + current >>= (32-bits); + do + { + if ( readBits(1) == 0 ) + bytes(); + if ( writePtr > dest ) + sequence(); + if ( globalError ) + { + // statusString already set. + outputLen = 0; // unsuccessful decompression + break; + } + } while ( writePtr > dest ); + + // Finished. + + if (outputLen > 0) // successful + { + // Free any previously existing destination buffer. + if ( *destRef != 0 ) + { + delete[] *destRef; + } + *destRef = dest; + } + else + { + delete[] dest; + } + + return outputLen; +} diff --git a/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/PP20.h b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/PP20.h new file mode 100644 index 00000000..74e7f5f7 --- /dev/null +++ b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/PP20.h @@ -0,0 +1,70 @@ +/* + * /home/ms/files/source/libsidtune/RCS/PP20.h,v + * + * PowerPacker (AMIGA) "PP20" format decompressor. + * Copyright (C) Michael Schwendt <mschwendt@yahoo.com> + * + * 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 + */ + +#ifndef PP_DECOMPRESSOR_H +#define PP_DECOMPRESSOR_H + +#include "PP20_Defs.h" + +class PP20 +{ + public: + + PP20(); + + bool isCompressed(const void* source, const udword_ppt size); + + // If successful, allocates a new buffer containing the + // uncompresse data and returns the uncompressed length. + // Else, returns 0. + udword_ppt decompress(const void* source, + udword_ppt size, + ubyte_ppt** destRef); + + const char* getStatusString() { return statusString; } + + private: + bool checkEfficiency(const void* source); + + void bytesTOdword(); + udword_ppt readBits(int count); + void bytes(); + void sequence(); + + static const char* PP_ID; + + ubyte_ppt efficiency[4]; + + const ubyte_ppt* sourceBeg; + const ubyte_ppt* readPtr; + + const ubyte_ppt* destBeg; + ubyte_ppt* writePtr; + + udword_ppt current; // compressed data longword + int bits; // number of bits in 'current' to evaluate + + bool globalError; // exception-free version of code + + const char* statusString; +}; + +#endif /* PP_DECOMPRESSOR_H */ diff --git a/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/PP20_Defs.h b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/PP20_Defs.h new file mode 100644 index 00000000..9e3b345b --- /dev/null +++ b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/PP20_Defs.h @@ -0,0 +1,39 @@ +/* + * /home/ms/files/source/libsidtune/RCS/PP20_Defs.h,v + * + * PowerPacker (AMIGA) "PP20" format decompressor. + * Copyright (C) Michael Schwendt <mschwendt@yahoo.com> + * + * 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 + */ + +#ifndef PP_DECOMPRESSOR_DEFS_H +#define PP_DECOMPRESSOR_DEFS_H + +#include "sidtypes.h" + +#ifdef HAVE_EXCEPTIONS + #define PP20_HAVE_EXCEPTIONS +#else + #undef PP20_HAVE_EXCEPTIONS +#endif + +// Wanted: 8-bit unsigned. +typedef uint_least8_t ubyte_ppt; + +// Wanted: 32-bit unsigned. +typedef uint_least32_t udword_ppt; + +#endif /* PP_DECOMPRESSOR_DEFS_H */ diff --git a/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/PSID.cpp b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/PSID.cpp new file mode 100644 index 00000000..0cc96969 --- /dev/null +++ b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/PSID.cpp @@ -0,0 +1,313 @@ +/* + * /home/ms/files/source/libsidtune/RCS/PSID.cpp,v + * + * PlaySID one-file 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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "config.h" +#include "SidTuneCfg.h" +#include "SidTune.h" +#include "sidendian.h" + +#define PSID_ID 0x50534944 +#define RSID_ID 0x52534944 + +// Header has been extended for 'RSID' format +// The following changes are present: +// id = 'RSID' +// version = 2 only +// play, load and speed reserved 0 +// psidspecific flag reserved 0 +// init cannot be under ROMS/IO +// load cannot be less than 0x0801 (start of basic) + +struct psidHeader // all values big-endian +{ + char id[4]; // 'PSID' (ASCII) + uint8_t version[2]; // 0x0001 or 0x0002 + uint8_t data[2]; // 16-bit offset to binary data in file + uint8_t load[2]; // 16-bit C64 address to load file to + uint8_t init[2]; // 16-bit C64 address of init subroutine + uint8_t play[2]; // 16-bit C64 address of play subroutine + uint8_t songs[2]; // number of songs + uint8_t start[2]; // start song out of [1..256] + uint8_t speed[4]; // 32-bit speed info + // bit: 0=50 Hz, 1=CIA 1 Timer A (default: 60 Hz) + char name[32]; // ASCII strings, 31 characters long and + char author[32]; // terminated by a trailing zero + char released[32]; // + uint8_t flags[2]; // only version 0x0002 + uint8_t relocStartPage; // only version 0x0002B + uint8_t relocPages; // only version 0x0002B + uint8_t reserved[2]; // only version 0x0002 +}; + +enum +{ + PSID_MUS = 1 << 0, + PSID_SPECIFIC = 1 << 1, + PSID_CLOCK = 3 << 2, + PSID_SIDMODEL = 3 << 4 +}; + +enum +{ + PSID_CLOCK_UNKNOWN = 0, + PSID_CLOCK_PAL = 1 << 2, + PSID_CLOCK_NTSC = 1 << 3, + PSID_CLOCK_ANY = PSID_CLOCK_PAL | PSID_CLOCK_NTSC +}; + +enum +{ + PSID_SIDMODEL_UNKNOWN = 0, + PSID_SIDMODEL_6581 = 1 << 4, + PSID_SIDMODEL_8580 = 1 << 5, + PSID_SIDMODEL_ANY = PSID_SIDMODEL_6581 | PSID_SIDMODEL_8580 +}; + +static const char _sidtune_format_psid[] = "PlaySID one-file format (PSID)"; +static const char _sidtune_format_rsid[] = "Real C64 one-file format (RSID)"; +static const char _sidtune_unknown_psid[] = "Unsupported PSID version"; +static const char _sidtune_unknown_rsid[] = "Unsupported RSID version"; +static const char _sidtune_truncated[] = "ERROR: File is most likely truncated"; +static const char _sidtune_invalid[] = "ERROR: File contains invalid data"; + +const int _sidtune_psid_maxStrLen = 31; + + +bool SidTune::PSID_fileSupport(const void* buffer, const uint_least32_t bufLen) +{ + int clock, compatibility; + uint_least32_t speed; +#ifdef SIDTUNE_PSID2NG + clock = SIDTUNE_CLOCK_UNKNOWN; +#else + clock = info.clockSpeed; +#endif + compatibility = SIDTUNE_COMPATIBILITY_C64; + + // Require minimum size to allow access to the first few bytes. + // Require a valid ID and version number. + const psidHeader* pHeader = (const psidHeader*)buffer; + + // File format check + if (bufLen<6) + return false; + if (endian_big32((const uint_least8_t*)pHeader->id)==PSID_ID) + { + if (endian_big16(pHeader->version) >= 3) + { + info.formatString = _sidtune_unknown_psid; + return false; + } + info.formatString = _sidtune_format_psid; + } + else if (endian_big32((const uint_least8_t*)pHeader->id)==RSID_ID) + { + if (endian_big16(pHeader->version) != 2) + { + info.formatString = _sidtune_unknown_rsid; + return false; + } + info.formatString = _sidtune_format_rsid; + compatibility = SIDTUNE_COMPATIBILITY_R64; + } + else + { + return false; + } + + // Due to security concerns, input must be at least as long as version 1 + // header plus 16-bit C64 load address. That is the area which will be + // accessed. + if ( bufLen < (sizeof(psidHeader)+2) ) + { + info.formatString = _sidtune_truncated; + return false; + } + + fileOffset = endian_big16(pHeader->data); + info.loadAddr = endian_big16(pHeader->load); + info.initAddr = endian_big16(pHeader->init); + info.playAddr = endian_big16(pHeader->play); + info.songs = endian_big16(pHeader->songs); + info.startSong = endian_big16(pHeader->start); + info.sidChipBase1 = 0xd400; + info.sidChipBase2 = 0; + info.compatibility = compatibility; + speed = endian_big32(pHeader->speed); + + if (info.songs > SIDTUNE_MAX_SONGS) + { + info.songs = SIDTUNE_MAX_SONGS; + } + + info.musPlayer = false; + info.sidModel = SIDTUNE_SIDMODEL_UNKNOWN; + info.relocPages = 0; + info.relocStartPage = 0; + if ( endian_big16(pHeader->version) >= 2 ) + { + uint_least16_t flags = endian_big16(pHeader->flags); + if (flags & PSID_MUS) + { // MUS tunes run at any speed + clock = SIDTUNE_CLOCK_ANY; + info.musPlayer = true; + } + +#ifdef SIDTUNE_PSID2NG + if (flags & PSID_SPECIFIC) + info.compatibility = SIDTUNE_COMPATIBILITY_PSID; + + if (flags & PSID_CLOCK_PAL) + clock |= SIDTUNE_CLOCK_PAL; + if (flags & PSID_CLOCK_NTSC) + clock |= SIDTUNE_CLOCK_NTSC; + info.clockSpeed = clock; + + info.sidModel = SIDTUNE_SIDMODEL_UNKNOWN; + if (flags & PSID_SIDMODEL_6581) + info.sidModel |= SIDTUNE_SIDMODEL_6581; + if (flags & PSID_SIDMODEL_8580) + info.sidModel |= SIDTUNE_SIDMODEL_8580; + + info.relocStartPage = pHeader->relocStartPage; + info.relocPages = pHeader->relocPages; +#endif // SIDTUNE_PSID2NG + } + + // Reserved meaning for possible future use + if ( info.playAddr == 0xffff ) + info.playAddr = 0; + + // Check reserved fields to force real c64 compliance + if (compatibility == SIDTUNE_COMPATIBILITY_R64) + { + if (checkRealC64Info (speed) == false) + { + info.formatString = _sidtune_invalid; + return false; + } + // Real C64 tunes appear as CIA + speed = ~0; + } + // Create the speed/clock setting table. + convertOldStyleSpeedToTables(speed, clock); + + if ( info.loadAddr == 0 ) + { + uint_least8_t* pData = (uint_least8_t*)buffer + fileOffset; + info.loadAddr = endian_16( *(pData+1), *pData ); + fileOffset += 2; + } + + info.c64dataLen = bufLen - fileOffset; + if ( resolveAddrs((uint_least8_t*)buffer + fileOffset) == false ) + return false; + + if ( checkRelocInfo() == false ) + return false; + + // Copy info strings, so they will not get lost. + info.numberOfInfoStrings = 3; + // Name + strncpy(&infoString[0][0],pHeader->name,_sidtune_psid_maxStrLen); + info.infoString[0] = &infoString[0][0]; + // Author + strncpy(&infoString[1][0],pHeader->author,_sidtune_psid_maxStrLen); + info.infoString[1] = &infoString[1][0]; + // Released + strncpy(&infoString[2][0],pHeader->released,_sidtune_psid_maxStrLen); + info.infoString[2] = &infoString[2][0]; + return true; +} + + +bool SidTune::PSID_fileSupportSave(std::ofstream& fMyOut, const uint_least8_t* dataBuffer) +{ + psidHeader myHeader; + endian_big32((uint_least8_t*)myHeader.id,PSID_ID); + endian_big16(myHeader.version,2); + endian_big16(myHeader.data,sizeof(psidHeader)); + endian_big16(myHeader.load,0); + endian_big16(myHeader.init,info.initAddr); + endian_big16(myHeader.play,info.playAddr); + endian_big16(myHeader.songs,info.songs); + endian_big16(myHeader.start,info.startSong); + + uint_least32_t speed = 0, check = 0; + uint_least32_t maxBugSongs = ((info.songs <= 32) ? info.songs : 32); + for (uint_least32_t s = 0; s < maxBugSongs; s++) + { + if (songSpeed[s] == SIDTUNE_SPEED_CIA_1A) + speed |= (1<<s); + check |= (1<<s); + } + endian_big32(myHeader.speed,speed); + + uint_least16_t tmpFlags = 0; + if ( info.musPlayer ) + tmpFlags |= PSID_MUS; + + if (info.compatibility == SIDTUNE_COMPATIBILITY_PSID) + tmpFlags |= PSID_SPECIFIC; + + tmpFlags |= (info.clockSpeed << 2); + tmpFlags |= (info.sidModel << 4); + endian_big16(myHeader.flags,tmpFlags); + endian_big16(myHeader.reserved,0); + myHeader.relocStartPage = info.relocStartPage; + myHeader.relocPages = info.relocPages; + + for ( uint i = 0; i < 32; i++ ) + { + myHeader.name[i] = 0; + myHeader.author[i] = 0; + myHeader.released[i] = 0; + } + strncpy( myHeader.name, info.infoString[0], _sidtune_psid_maxStrLen); + strncpy( myHeader.author, info.infoString[1], _sidtune_psid_maxStrLen); + strncpy( myHeader.released, info.infoString[2], _sidtune_psid_maxStrLen); + + if (info.compatibility == SIDTUNE_COMPATIBILITY_R64) + { + endian_big32((uint_least8_t*)myHeader.id,RSID_ID); + endian_big16(myHeader.play,0); + endian_big32(myHeader.speed,0); + } + + fMyOut.write( (char*)&myHeader, sizeof(psidHeader) ); + + // Save C64 lo/hi load address (little-endian). + uint_least8_t saveAddr[2]; + saveAddr[0] = info.loadAddr & 255; + saveAddr[1] = info.loadAddr >> 8; + fMyOut.write( (char*)saveAddr, 2 ); // !cast! + + // Data starts at: bufferaddr + fileoffset + // Data length: datafilelen - fileoffset + fMyOut.write( (const char*)dataBuffer + fileOffset, info.dataFileLen - fileOffset ); // !cast! + if ( !fMyOut ) + return false; + else + return true; +} diff --git a/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/SidTune.cpp b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/SidTune.cpp new file mode 100644 index 00000000..29638775 --- /dev/null +++ b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/SidTune.cpp @@ -0,0 +1,1150 @@ +/* + * /home/ms/files/source/libsidtune/RCS/SidTune.cpp,v + * + * 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 + */ + +#define _SidTune_cpp_ + +#include "config.h" +#include "SidTuneCfg.h" +#include "SidTune.h" +#include "SidTuneTools.h" +#include "sidendian.h" +#include "PP20.h" + +#ifdef HAVE_EXCEPTIONS +# include <new> +#endif +#include <iostream> +#include <iomanip> +#include <string.h> +#include <limits.h> + +#if defined(HAVE_IOS_OPENMODE) + typedef std::ios::openmode openmode; +#else + typedef int openmode; +#endif + +// Used in address resolution procedure +#define SIDTUNE_BASIC_START 0x0801 + +const char* SidTune::txt_songNumberExceed = "SIDTUNE WARNING: Selected song number was too high"; +const char* SidTune::txt_empty = "SIDTUNE ERROR: No data to load"; +const char* SidTune::txt_unrecognizedFormat = "SIDTUNE ERROR: Could not determine file format"; +const char* SidTune::txt_noDataFile = "SIDTUNE ERROR: Did not find the corresponding data file"; +const char* SidTune::txt_notEnoughMemory = "SIDTUNE ERROR: Not enough free memory"; +const char* SidTune::txt_cantLoadFile = "SIDTUNE ERROR: Could not load input file"; +const char* SidTune::txt_cantOpenFile = "SIDTUNE ERROR: Could not open file for binary input"; +const char* SidTune::txt_fileTooLong = "SIDTUNE ERROR: Input data too long"; +const char* SidTune::txt_dataTooLong = "SIDTUNE ERROR: Size of music data exceeds C64 memory"; +const char* SidTune::txt_cantCreateFile = "SIDTUNE ERROR: Could not create output file"; +const char* SidTune::txt_fileIoError = "SIDTUNE ERROR: File I/O error"; +const char* SidTune::txt_VBI = "VBI"; +const char* SidTune::txt_CIA = "CIA 1 Timer A"; +const char* SidTune::txt_noErrors = "No errors"; +const char* SidTune::txt_na = "N/A"; +const char* SidTune::txt_badAddr = "SIDTUNE ERROR: Bad address data"; +const char* SidTune::txt_badReloc = "SIDTUNE ERROR: Bad reloc data"; + +// Default sidtune file name extensions. This selection can be overriden +// by specifying a custom list in the constructor. +const char* defaultFileNameExt[] = +{ + // Preferred default file extension for single-file sidtunes + // or sidtune description files in SIDPLAY INFOFILE format. + ".sid", + // Common file extension for single-file sidtunes due to SIDPLAY/DOS + // displaying files *.DAT in its file selector by default. + // Originally this was intended to be the extension of the raw data file + // of two-file sidtunes in SIDPLAY INFOFILE format. + ".dat", + // Extension of Amiga Workbench tooltype icon info files, which + // have been cut to MS-DOS file name length (8.3). + ".inf", + // No extension for the raw data file of two-file sidtunes in + // PlaySID Amiga Workbench tooltype icon info format. + "", + // Common upper-case file extensions from MS-DOS (unconverted). + ".DAT", ".SID", ".INF", + // File extensions used (and created) by various C64 emulators and + // related utilities. These extensions are recommended to be used as + // a replacement for ".dat" in conjunction with two-file sidtunes. + ".c64", ".prg", ".C64", ".PRG", + // Uncut extensions from Amiga. + ".info", ".INFO", ".data", ".DATA", + // Stereo Sidplayer (.mus/.MUS ought not be included because + // these must be loaded first; it sometimes contains the first + // credit lines of a MUS/STR pair). + ".str", ".STR", ".mus", ".MUS", + // End. + 0 +}; + +const char** SidTune::fileNameExtensions = defaultFileNameExt; + +inline void SidTune::setFileNameExtensions(const char **fileNameExt) +{ + fileNameExtensions = ((fileNameExt!=0)?fileNameExt:defaultFileNameExt); +} + +SidTune::SidTune(const char* fileName, const char **fileNameExt, + const bool separatorIsSlash) +{ + init(); + isSlashedFileName = separatorIsSlash; + setFileNameExtensions(fileNameExt); +#if !defined(SIDTUNE_NO_STDIN_LOADER) + // Filename ``-'' is used as a synonym for standard input. + if ( fileName!=0 && (strcmp(fileName,"-")==0) ) + { + getFromStdIn(); + } + else +#endif + if (fileName != 0) + { + getFromFiles(fileName); + } +} + +SidTune::SidTune(const uint_least8_t* data, const uint_least32_t dataLen) +{ + init(); + getFromBuffer(data,dataLen); +} + +SidTune::~SidTune() +{ + cleanup(); +} + +bool SidTune::load(const char* fileName, const bool separatorIsSlash) +{ + cleanup(); + init(); + isSlashedFileName = separatorIsSlash; + getFromFiles(fileName); + return status; +} + +bool SidTune::read(const uint_least8_t* data, uint_least32_t dataLen) +{ + cleanup(); + init(); + getFromBuffer(data,dataLen); + return status; +} + +const SidTuneInfo& SidTune::operator[](const uint_least16_t songNum) +{ + selectSong(songNum); + return info; +} + +void SidTune::getInfo(SidTuneInfo& outInfo) +{ + outInfo = info; // copy +} + +const SidTuneInfo& SidTune::getInfo() +{ + return info; +} + +// First check, whether a song is valid. Then copy any song-specific +// variable information such a speed/clock setting to the info structure. +uint_least16_t SidTune::selectSong(const uint_least16_t selectedSong) +{ + if ( !status ) + return 0; + else + info.statusString = SidTune::txt_noErrors; + + uint_least16_t song = selectedSong; + // Determine and set starting song number. + if (selectedSong == 0) + song = info.startSong; + if (selectedSong>info.songs || selectedSong>SIDTUNE_MAX_SONGS) + { + song = info.startSong; + info.statusString = SidTune::txt_songNumberExceed; + } + info.currentSong = song; + info.songLength = songLength[song-1]; + // Retrieve song speed definition. + info.songSpeed = songSpeed[song-1]; + info.clockSpeed = clockSpeed[song-1]; + // Assign song speed description string depending on clock speed. + // Final speed description is available only after song init. + if (info.songSpeed == SIDTUNE_SPEED_VBI) + info.speedString = txt_VBI; + else + info.speedString = txt_CIA; + return info.currentSong; +} + +void SidTune::fixLoadAddress(bool force, uint_least16_t init, uint_least16_t play) +{ + if (info.fixLoad || force) + { + info.fixLoad = false; + info.loadAddr += 2; + fileOffset += 2; + + if (force) + { + info.initAddr = init; + info.playAddr = play; + } + } +} + +// ------------------------------------------------- private member functions + +bool SidTune::placeSidTuneInC64mem(uint_least8_t* c64buf) +{ + if ( status && c64buf!=0 ) + { + uint_least32_t endPos = info.loadAddr + info.c64dataLen; + if (endPos <= SIDTUNE_MAX_MEMORY) + { + // Copy data from cache to the correct destination. + memcpy(c64buf+info.loadAddr,cache.get()+fileOffset,info.c64dataLen); + info.statusString = SidTune::txt_noErrors; + } + else + { + // Security - cut data which would exceed the end of the C64 + // memory. Memcpy could not detect this. + // + // NOTE: In libsidplay1 the rest gets wrapped to the beginning + // of the C64 memory. It is an undocumented hack most likely not + // used by any sidtune. Here we no longer do it like that, set + // an error message, and hope the modified behaviour will find + // a few badly ripped sids. + memcpy(c64buf+info.loadAddr,cache.get()+fileOffset,info.c64dataLen-(endPos-SIDTUNE_MAX_MEMORY)); + info.statusString = SidTune::txt_dataTooLong; + } + if (info.musPlayer) + { + MUS_installPlayer(c64buf); + } + } + return ( status && c64buf!=0 ); +} + +bool SidTune::loadFile(const char* fileName, Buffer_sidtt<const uint_least8_t>& bufferRef) +{ + Buffer_sidtt<uint_least8_t> fileBuf; + uint_least32_t fileLen = 0; + + // This sucks big time + //openmode createAtrr = std::ios::in; + std::_Ios_Openmode createAtrr = std::ios::in; +#ifdef HAVE_IOS_NOCREATE + createAtrr |= std::ios::nocreate; +#endif + // Open binary input file stream at end of file. +#if defined(HAVE_IOS_BIN) + createAtrr |= std::ios::bin; +#else + createAtrr |= std::ios::binary; +#endif + + std::fstream myIn(fileName,createAtrr); + // As a replacement for !is_open(), bad() and the NOT-operator don't seem + // to work on all systems. +#if defined(DONT_HAVE_IS_OPEN) + if ( !myIn ) +#else + if ( !myIn.is_open() ) +#endif + { + info.statusString = SidTune::txt_cantOpenFile; + return false; + } + else + { +#if defined(HAVE_SEEKG_OFFSET) + fileLen = (myIn.seekg(0,std::ios::end)).offset(); +#else + myIn.seekg(0,std::ios::end); + fileLen = (uint_least32_t)myIn.tellg(); +#endif +#ifdef HAVE_EXCEPTIONS + if ( !fileBuf.assign(new(std::nothrow) uint_least8_t[fileLen],fileLen) ) +#else + if ( !fileBuf.assign(new uint_least8_t[fileLen],fileLen) ) +#endif + { + info.statusString = SidTune::txt_notEnoughMemory; + return false; + } + myIn.seekg(0,std::ios::beg); + uint_least32_t restFileLen = fileLen; + // 16-bit compatible loading. Is this really necessary? + while ( restFileLen > INT_MAX ) + { + myIn.read((char*)fileBuf.get()+(fileLen-restFileLen),INT_MAX); // !cast! + restFileLen -= INT_MAX; + } + if ( restFileLen > 0 ) + { + myIn.read((char*)fileBuf.get()+(fileLen-restFileLen),restFileLen); // !cast! + } + if ( myIn.bad() ) + { + info.statusString = SidTune::txt_cantLoadFile; + return false; + } + else + { + info.statusString = SidTune::txt_noErrors; + } + } + myIn.close(); + if ( fileLen==0 ) + { + info.statusString = SidTune::txt_empty; + return false; + } + + // Check for PowerPacker compression: load and decompress, if PP20 file. + PP20 myPP; + if ( myPP.isCompressed(fileBuf.get(),fileBuf.len()) ) + { + uint_least8_t* destBufRef = 0; + if ( 0 == (fileLen = myPP.decompress(fileBuf.get(),fileBuf.len(), + &destBufRef)) ) + { + info.statusString = myPP.getStatusString(); + return false; + } + else + { + info.statusString = myPP.getStatusString(); + // Replace compressed buffer with uncompressed buffer. + fileBuf.assign(destBufRef,fileLen); + } + } + + bufferRef.assign(fileBuf.xferPtr(),fileBuf.xferLen()); + + return true; +} + +void SidTune::deleteFileNameCopies() +{ + // When will it be fully safe to call delete[](0) on every system? + if ( info.dataFileName != 0 ) + delete[] info.dataFileName; + if ( info.infoFileName != 0 ) + delete[] info.infoFileName; + if ( info.path != 0 ) + delete[] info.path; + info.dataFileName = 0; + info.infoFileName = 0; + info.path = 0; +} + +void SidTune::init() +{ + // Initialize the object with some safe defaults. + status = false; + + info.statusString = SidTune::txt_na; + info.path = info.infoFileName = info.dataFileName = 0; + info.dataFileLen = info.c64dataLen = 0; + info.formatString = SidTune::txt_na; + info.speedString = SidTune::txt_na; + info.loadAddr = ( info.initAddr = ( info.playAddr = 0 )); + info.songs = ( info.startSong = ( info.currentSong = 0 )); + info.sidChipBase1 = 0xd400; + info.sidChipBase2 = 0; + info.musPlayer = false; + info.fixLoad = false; + info.songSpeed = SIDTUNE_SPEED_VBI; +#ifdef SIDTUNE_PSID2NG + info.clockSpeed = SIDTUNE_CLOCK_UNKNOWN; + info.sidModel = SIDTUNE_SIDMODEL_UNKNOWN; +#else + info.clockSpeed = SIDTUNE_CLOCK_PAL; + info.sidModel = SIDTUNE_SIDMODEL_6581; +#endif + info.compatibility = SIDTUNE_COMPATIBILITY_C64; + info.songLength = 0; + info.relocStartPage = 0; + info.relocPages = 0; + + for ( uint_least16_t si = 0; si < SIDTUNE_MAX_SONGS; si++ ) + { + songSpeed[si] = info.songSpeed; + clockSpeed[si] = info.clockSpeed; + songLength[si] = 0; + } + + fileOffset = 0; + musDataLen = 0; + + for ( uint_least16_t sNum = 0; sNum < SIDTUNE_MAX_CREDIT_STRINGS; sNum++ ) + { + for ( uint_least16_t sPos = 0; sPos < SIDTUNE_MAX_CREDIT_STRLEN; sPos++ ) + { + infoString[sNum][sPos] = 0; + } + } + info.numberOfInfoStrings = 0; + + // Not used!!! + info.numberOfCommentStrings = 1; +#ifdef HAVE_EXCEPTIONS + info.commentString = new(std::nothrow) char* [info.numberOfCommentStrings]; +#else + info.commentString = new char* [info.numberOfCommentStrings]; +#endif + if (info.commentString != 0) + info.commentString[0] = SidTuneTools::myStrDup("--- SAVED WITH SIDPLAY ---"); + else + info.commentString[0] = 0; +} + +void SidTune::cleanup() +{ + // Remove copy of comment field. + uint_least32_t strNum = 0; + // Check and remove every available line. + while (info.numberOfCommentStrings-- > 0) + { + if (info.commentString[strNum] != 0) + { + delete[] info.commentString[strNum]; + info.commentString[strNum] = 0; + } + strNum++; // next string + }; + delete[] info.commentString; // free the array pointer + + deleteFileNameCopies(); + + status = false; +} + +#if !defined(SIDTUNE_NO_STDIN_LOADER) + +void SidTune::getFromStdIn() +{ + // Assume a failure, so we can simply return. + status = false; + // Assume the memory allocation to fail. + info.statusString = SidTune::txt_notEnoughMemory; + uint_least8_t* fileBuf; +#ifdef HAVE_EXCEPTIONS + if ( 0 == (fileBuf = new(std::nothrow) uint_least8_t[SIDTUNE_MAX_FILELEN]) ) +#else + if ( 0 == (fileBuf = new uint_least8_t[SIDTUNE_MAX_FILELEN]) ) +#endif + { + return; + } + // We only read as much as fits in the buffer. + // This way we avoid choking on huge data. + uint_least32_t i = 0; + char datb; + while (std::cin.get(datb) && i<SIDTUNE_MAX_FILELEN) + fileBuf[i++] = (uint_least8_t) datb; + info.dataFileLen = i; + getFromBuffer(fileBuf,info.dataFileLen); + delete[] fileBuf; +} + +#endif + +void SidTune::getFromBuffer(const uint_least8_t* const buffer, const uint_least32_t bufferLen) +{ + // Assume a failure, so we can simply return. + status = false; + + if (buffer==0 || bufferLen==0) + { + info.statusString = SidTune::txt_empty; + return; + } + else if (bufferLen > SIDTUNE_MAX_FILELEN) + { + info.statusString = SidTune::txt_fileTooLong; + return; + } + + uint_least8_t* tmpBuf; +#ifdef HAVE_EXCEPTIONS + if ( 0 == (tmpBuf = new(std::nothrow) uint_least8_t[bufferLen]) ) +#else + if ( 0 == (tmpBuf = new uint_least8_t[bufferLen]) ) +#endif + { + info.statusString = SidTune::txt_notEnoughMemory; + return; + } + memcpy(tmpBuf,buffer,bufferLen); + + Buffer_sidtt<const uint_least8_t> buf1(tmpBuf,bufferLen); + Buffer_sidtt<const uint_least8_t> buf2; // empty + + bool foundFormat = false; + // Here test for the possible single file formats. -------------- + if ( PSID_fileSupport( buffer, bufferLen )) + { + foundFormat = true; + } + else if ( MUS_fileSupport(buf1,buf2) ) + { + foundFormat = MUS_mergeParts(buf1,buf2); + } + else + { + // No further single-file-formats available. + info.statusString = SidTune::txt_unrecognizedFormat; + } + if ( foundFormat ) + { + status = acceptSidTune("-","-",buf1); + } +} + +bool SidTune::acceptSidTune(const char* dataFileName, const char* infoFileName, + Buffer_sidtt<const uint_least8_t>& buf) +{ + deleteFileNameCopies(); + // Make a copy of the data file name and path, if available. + if ( dataFileName != 0 ) + { + info.path = SidTuneTools::myStrDup(dataFileName); + if (isSlashedFileName) + { + info.dataFileName = SidTuneTools::myStrDup(SidTuneTools::slashedFileNameWithoutPath(info.path)); + *SidTuneTools::slashedFileNameWithoutPath(info.path) = 0; // path only + } + else + { + info.dataFileName = SidTuneTools::myStrDup(SidTuneTools::fileNameWithoutPath(info.path)); + *SidTuneTools::fileNameWithoutPath(info.path) = 0; // path only + } + if ((info.path==0) || (info.dataFileName==0)) + { + info.statusString = SidTune::txt_notEnoughMemory; + return false; + } + } + else + { + // Provide empty strings. + info.path = SidTuneTools::myStrDup(""); + info.dataFileName = SidTuneTools::myStrDup(""); + } + // Make a copy of the info file name, if available. + if ( infoFileName != 0 ) + { + char* tmp = SidTuneTools::myStrDup(infoFileName); + if (isSlashedFileName) + info.infoFileName = SidTuneTools::myStrDup(SidTuneTools::slashedFileNameWithoutPath(tmp)); + else + info.infoFileName = SidTuneTools::myStrDup(SidTuneTools::fileNameWithoutPath(tmp)); + if ((tmp==0) || (info.infoFileName==0)) + { + info.statusString = SidTune::txt_notEnoughMemory; + return false; + } + delete[] tmp; + } + else + { + // Provide empty string. + info.infoFileName = SidTuneTools::myStrDup(""); + } + // Fix bad sidtune set up. + if (info.songs > SIDTUNE_MAX_SONGS) + info.songs = SIDTUNE_MAX_SONGS; + else if (info.songs == 0) + info.songs++; + if (info.startSong > info.songs) + info.startSong = 1; + else if (info.startSong == 0) + info.startSong++; + + if ( info.musPlayer ) + MUS_setPlayerAddress(); + + info.dataFileLen = buf.len(); + info.c64dataLen = buf.len() - fileOffset; + + if (info.dataFileLen >= 2) + { + // We only detect an offset of two. Some position independent + // sidtunes contain a load address of 0xE000, but are loaded + // to 0x0FFE and call player at 0x1000. + info.fixLoad = (endian_little16(buf.get()+fileOffset)==(info.loadAddr+2)); + } + + // Check the size of the data. + if ( info.c64dataLen > SIDTUNE_MAX_MEMORY ) + { + info.statusString = SidTune::txt_dataTooLong; + return false; + } + else if ( info.c64dataLen == 0 ) + { + info.statusString = SidTune::txt_empty; + return false; + } + + cache.assign(buf.xferPtr(),buf.xferLen()); + + info.statusString = SidTune::txt_noErrors; + return true; +} + +bool SidTune::createNewFileName(Buffer_sidtt<char>& destString, + const char* sourceName, + const char* sourceExt) +{ + Buffer_sidtt<char> newBuf; + uint_least32_t newLen = strlen(sourceName)+strlen(sourceExt)+1; + // Get enough memory, so we can appended the extension. +#ifdef HAVE_EXCEPTIONS + newBuf.assign(new(std::nothrow) char[newLen],newLen); +#else + newBuf.assign(new char[newLen],newLen); +#endif + if ( newBuf.isEmpty() ) + { + info.statusString = SidTune::txt_notEnoughMemory; + return (status = false); + } + strcpy(newBuf.get(),sourceName); + strcpy(SidTuneTools::fileExtOfPath(newBuf.get()),sourceExt); + destString.assign(newBuf.xferPtr(),newBuf.xferLen()); + return true; +} + +// Initializing the object based upon what we find in the specified file. + +void SidTune::getFromFiles(const char* fileName) +{ + // Assume a failure, so we can simply return. + status = false; + + Buffer_sidtt<const uint_least8_t> fileBuf1, fileBuf2; + Buffer_sidtt<char> fileName2; + + // Try to load the single specified file. + if ( loadFile(fileName,fileBuf1) ) + { + // File loaded. Now check if it is in a valid single-file-format. + if ( PSID_fileSupport(fileBuf1.get(),fileBuf1.len()) ) + { + status = acceptSidTune(fileName,0,fileBuf1); + return; + } + else if ( MUS_fileSupport(fileBuf1,fileBuf2) ) + { + // Try to find second file. + int n = 0; + while (fileNameExtensions[n] != 0) + { + if ( !createNewFileName(fileName2,fileName,fileNameExtensions[n]) ) + return; + // 1st data file was loaded into ``fileBuf1'', + // so we load the 2nd one into ``fileBuf2''. + // Do not load the first file again if names are equal. + if ( MYSTRICMP(fileName,fileName2.get())!=0 && + loadFile(fileName2.get(),fileBuf2) ) + { + if ( MUS_fileSupport(fileBuf1,fileBuf2) ) + { + if ( MUS_mergeParts(fileBuf1,fileBuf2) ) + { + status = acceptSidTune(fileName,fileName2.get(), + fileBuf1); + } + return; // in either case + } + } + n++; + }; + // No second file. + status = acceptSidTune(fileName,0,fileBuf1); + return; + } + +// -------------------------------------- Support for multiple-files formats. + else + { +// We cannot simply try to load additional files, if a description file was +// specified. It would work, but is error-prone. Imagine a filename mismatch +// or more than one description file (in another) format. Any other file +// with an appropriate file name can be the C64 data file. + +// First we see if ``fileName'' could be a raw data file. In that case we +// have to find the corresponding description file. + + // Right now we do not have a second file. Hence the (0, 0, ...) + // parameters are set for the data buffer. This will not hurt the + // file support procedures. + + // Make sure that ``fileBuf1'' does not contain a description file. + if ( !SID_fileSupport(0,0,fileBuf1.get(),fileBuf1.len()) && + !INFO_fileSupport(0,0,fileBuf1.get(),fileBuf1.len()) ) + { + // Assuming ``fileName'' to hold the name of the raw data file, + // we now create the name of a description file (=fileName2) by + // appending various filename extensions. + +// ------------------------------------------ Looking for a description file. + + int n = 0; + while (fileNameExtensions[n] != 0) + { + if ( !createNewFileName(fileName2,fileName,fileNameExtensions[n]) ) + return; + // 1st data file was loaded into ``fileBuf1'', + // so we load the 2nd one into ``fileBuf2''. + // Do not load the first file again if names are equal. + if ( MYSTRICMP(fileName,fileName2.get())!=0 && + loadFile(fileName2.get(),fileBuf2) ) + { + if ( SID_fileSupport(fileBuf1.get(),fileBuf1.len(), + fileBuf2.get(),fileBuf2.len()) + || INFO_fileSupport(fileBuf1.get(),fileBuf1.len(), + fileBuf2.get(),fileBuf2.len()) + ) + { + status = acceptSidTune(fileName,fileName2.get(), + fileBuf1); + return; + } + } + n++; + }; + +// --------------------------------------- Could not find a description file. + + info.statusString = SidTune::txt_unrecognizedFormat; + return; + } + +// ------------------------------------------------------------------------- +// Still unsuccessful ? Probably one put a description file name into +// ``fileName''. Assuming ``fileName'' to hold the name of a description +// file, we now create the name of the data file and swap both used memory +// buffers - fileBuf1 and fileBuf2 - when calling the format support. +// If it works, the second file is the data file ! If it is not, but does +// exist, we are out of luck, since we cannot detect data files. + + // Make sure ``fileBuf1'' contains a description file. + else if ( SID_fileSupport(0,0,fileBuf1.get(),fileBuf1.len()) || + INFO_fileSupport(0,0,fileBuf1.get(),fileBuf1.len()) ) + { + +// --------------------- Description file found. --- Looking for a data file. + + int n = 0; + while (fileNameExtensions[n] != 0) + { + if ( !createNewFileName(fileName2,fileName,fileNameExtensions[n]) ) + return; + // 1st info file was loaded into ``fileBuf'', + // so we load the 2nd one into ``fileBuf2''. + // Do not load the first file again if names are equal. + if ( MYSTRICMP(fileName,fileName2.get())!=0 && + + loadFile(fileName2.get(),fileBuf2) ) + { +// -------------- Some data file found, now identifying the description file. + + if ( SID_fileSupport(fileBuf2.get(),fileBuf2.len(), + fileBuf1.get(),fileBuf1.len()) + || INFO_fileSupport(fileBuf2.get(),fileBuf2.len(), + fileBuf1.get(),fileBuf1.len()) + ) + { + status = acceptSidTune(fileName2.get(),fileName, + fileBuf2); + return; + } + } + n++; + }; + +// ---------------------------------------- No corresponding data file found. + + info.statusString = SidTune::txt_noDataFile; + return; + } // end else if ( = is description file ) + +// --------------------------------- Neither description nor data file found. + + else + { + info.statusString = SidTune::txt_unrecognizedFormat; + return; + } + } // end else ( = is no singlefile ) + +// ---------------------------------------------------------- File I/O error. + + } // if loaddatafile + else + { + // returned fileLen was 0 = error. The info.statusString is + // already set then. + return; + } +} + +void SidTune::convertOldStyleSpeedToTables(uint_least32_t speed, int clock) +{ + // Create the speed/clock setting tables. + // + // This does not take into account the PlaySID bug upon evaluating the + // SPEED field. It would most likely break compatibility to lots of + // sidtunes, which have been converted from .SID format and vice versa. + // The .SID format does the bit-wise/song-wise evaluation of the SPEED + // value correctly, like it is described in the PlaySID documentation. + + int toDo = ((info.songs <= SIDTUNE_MAX_SONGS) ? info.songs : SIDTUNE_MAX_SONGS); + for (int s = 0; s < toDo; s++) + { + clockSpeed[s] = clock; + if (( (speed>>(s&31)) & 1 ) == 0 ) + songSpeed[s] = SIDTUNE_SPEED_VBI; + else + songSpeed[s] = SIDTUNE_SPEED_CIA_1A; + } +} + +// +// File format conversion --------------------------------------------------- +// + +bool SidTune::saveToOpenFile(std::ofstream& toFile, const uint_least8_t* buffer, + uint_least32_t bufLen ) +{ + uint_least32_t lenToWrite = bufLen; + while ( lenToWrite > INT_MAX ) + { + toFile.write((char*)buffer+(bufLen-lenToWrite),INT_MAX); + lenToWrite -= INT_MAX; + } + if ( lenToWrite > 0 ) + toFile.write((char*)buffer+(bufLen-lenToWrite),lenToWrite); + if ( toFile.bad() ) + { + info.statusString = SidTune::txt_fileIoError; + return false; + } + else + { + info.statusString = SidTune::txt_noErrors; + return true; + } +} + +bool SidTune::saveC64dataFile( const char* fileName, bool overWriteFlag ) +{ + bool success = false; // assume error + // This prevents saving from a bad object. + if ( status ) + { + // Open binary output file stream. + //openmode createAttr = std::ios::out; + std::_Ios_Openmode createAttr = std::ios::out; +#if defined(HAVE_IOS_BIN) + createAttr |= std::ios::bin; +#else + createAttr |= std::ios::binary; +#endif + if ( overWriteFlag ) + createAttr |= std::ios::trunc; + else + createAttr |= std::ios::app; + std::ofstream fMyOut( fileName, createAttr ); + if ( !fMyOut || fMyOut.tellp()>0 ) + { + info.statusString = SidTune::txt_cantCreateFile; + } + else + { + // Save c64 lo/hi load address. + uint_least8_t saveAddr[2]; + saveAddr[0] = info.loadAddr & 255; + saveAddr[1] = info.loadAddr >> 8; + fMyOut.write((char*)saveAddr,2); + // Data starts at: bufferaddr + fileOffset + // Data length: info.dataFileLen - fileOffset + if ( !saveToOpenFile( fMyOut,cache.get()+fileOffset, info.dataFileLen - fileOffset ) ) + { + info.statusString = SidTune::txt_fileIoError; + } + else + { + info.statusString = SidTune::txt_noErrors; + success = true; + } + fMyOut.close(); + } + } + return success; +} + +bool SidTune::saveSIDfile( const char* fileName, bool overWriteFlag ) +{ + bool success = false; // assume error + // This prevents saving from a bad object. + if ( status ) + { + // Open ASCII output file stream. +// openmode createAttr = std::ios::out; + std::_Ios_Openmode createAttr = std::ios::out; + if ( overWriteFlag ) + createAttr |= std::ios::trunc; + else + createAttr |= std::ios::app; + std::ofstream fMyOut( fileName, createAttr ); + if ( !fMyOut || fMyOut.tellp()>0 ) + { + info.statusString = SidTune::txt_cantCreateFile; + } + else + { + if ( !SID_fileSupportSave( fMyOut ) ) + { + info.statusString = SidTune::txt_fileIoError; + } + else + { + info.statusString = SidTune::txt_noErrors; + success = true; + } + fMyOut.close(); + } + } + return success; +} + +bool SidTune::savePSIDfile( const char* fileName, bool overWriteFlag ) +{ + bool success = false; // assume error + // This prevents saving from a bad object. + if ( status ) + { + // Open binary output file stream. + //openmode createAttr = std::ios::out; + std::_Ios_Openmode createAttr = std::ios::out; +#if defined(HAVE_IOS_BIN) + createAttr |= std::ios::bin; +#else + createAttr |= std::ios::binary; +#endif + if ( overWriteFlag ) + createAttr |= std::ios::trunc; + else + createAttr |= std::ios::app; + std::ofstream fMyOut( fileName, createAttr ); + if ( !fMyOut || fMyOut.tellp()>0 ) + { + info.statusString = SidTune::txt_cantCreateFile; + } + else + { + if ( !PSID_fileSupportSave( fMyOut,cache.get() ) ) + { + info.statusString = SidTune::txt_fileIoError; + } + else + { + info.statusString = SidTune::txt_noErrors; + success = true; + } + fMyOut.close(); + } + } + return success; +} + +bool SidTune::checkRealC64Info (uint_least32_t speed) +{ + if (info.loadAddr != 0) + return false; + if (info.playAddr != 0) + return false; + if (speed != 0) + return false; + if (info.compatibility == SIDTUNE_COMPATIBILITY_PSID) + return false; + return true; +} + +bool SidTune::checkRealC64Init (void) +{ + if (info.initAddr == 0) + info.initAddr = info.loadAddr; + + // Check valid init address + switch (info.initAddr >> 12) + { + case 0x0F: + case 0x0E: + case 0x0D: + case 0x0B: + case 0x0A: + return false; + default: + if ( (info.initAddr < info.loadAddr) || + (info.initAddr > (info.loadAddr + info.c64dataLen - 1)) ) + { + return false; + } + } + return true; +} + +bool SidTune::checkRelocInfo (void) +{ + uint_least8_t startp, endp; + + // Fix relocation information + if (info.relocStartPage == 0xFF) + { + info.relocPages = 0; + return true; + } + else if (info.relocPages == 0) + { + info.relocStartPage = 0; + return true; + } + + // Calculate start/end page + startp = info.relocStartPage; + endp = (startp + info.relocPages - 1) & 0xff; + if (endp < startp) + { + info.formatString = txt_badReloc; + return false; + } + + { // Check against load range + uint_least8_t startlp, endlp; + startlp = (uint_least8_t) (info.loadAddr >> 8); + endlp = startlp; + endlp += (uint_least8_t) ((info.c64dataLen - 1) >> 8); + + if ( ((startp <= startlp) && (endp >= startlp)) || + ((startp <= endlp) && (endp >= endlp)) ) + { + info.formatString = txt_badReloc; + return false; + } + } + + // Check that the relocation information does not use the following + // memory areas: 0x0000-0x03FF, 0xA000-0xBFFF and 0xD000-0xFFFF + if ((startp < 0x04) + || ((0xa0 <= startp) && (startp <= 0xbf)) + || (startp >= 0xd0) + || ((0xa0 <= endp) && (endp <= 0xbf)) + || (endp >= 0xd0)) + { + info.formatString = txt_badReloc; + return false; + } + return true; +} + +bool SidTune::resolveAddrs (const uint_least8_t* c64data) +{ + if ( info.compatibility == SIDTUNE_COMPATIBILITY_R64 ) + { + bool initAddrCheck = true; + + // Check tune is loadable on a real C64 + if ( info.loadAddr < SIDTUNE_R64_MIN_LOAD_ADDR ) + { + info.formatString = txt_badAddr; + return false; + } + + if ( (info.initAddr == 0) && (info.loadAddr == SIDTUNE_BASIC_START) ) + { // Scan basic for a sys call + const uint_least8_t* pData = c64data; + uint_least16_t addr = 0; + uint_least16_t next = endian_little16(pData); + uint_least16_t init = 0; + + while (next) + { // skip addr & line number + const uint_least8_t *p = &pData[addr + 4]; + +SidTune_resolveAddrs_basic: + // Check for SYS + if (*p++ != 0x9e) + { // Check for ':' instruction seperator before + // jumping to next basic line + while (*p != '\0') + { + if (*p++ == ':') + { // Skip spaces + while (*p == ' ') + p++; + // Make sure havent hit end of line + if (*p != '\0') + goto SidTune_resolveAddrs_basic; + } + } + // Not a sys so jump to next intruction + addr = next; + // Get addr of next line of basic + next = endian_little16(&pData[addr]); + continue; + } + // Skip spaces + while (*p == ' ') + p++; + // Found a sys, extract all numbers + while ( (*p >= '0') && (*p <= '9') ) + { + init *= 10; + init += *p++ - '0'; + } + info.initAddr = init; + // Assume address is legal otherwise + // a real c64 would crash + initAddrCheck = false; + break; + } + } + + if ( checkRealC64Init() == false ) + { + info.formatString = txt_badAddr; + return false; + } + } + else if ( info.initAddr == 0 ) + info.initAddr = info.loadAddr; + return true; +} diff --git a/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/SidTuneCfg.h b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/SidTuneCfg.h new file mode 100644 index 00000000..7b184156 --- /dev/null +++ b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/SidTuneCfg.h @@ -0,0 +1,35 @@ +/* SidTuneCfg.h (template) */ + +#ifndef SIDTUNECFG_H +#define SIDTUNECFG_H + +#include "config.h" + +/* Define to add PSID2NG support */ +#define SIDTUNE_PSID2NG + +/* Minimum load address for real c64 only tunes */ +#define SIDTUNE_R64_MIN_LOAD_ADDR 0x07e8 + +/* -------------------------------------------------------------------------- + * Don't touch these! + * -------------------------------------------------------------------------- + */ +#undef SIDTUNE_NO_STDIN_LOADER +#undef SIDTUNE_REJECT_UNKNOWN_FIELDS + + +/* Define the file/path separator(s) that your filesystem uses: + SID_FS_IS_COLON_AND_BACKSLASH, SID_FS_IS_COLON_AND_SLASH, + SID_FS_IS_BACKSLASH, SID_FS_IS_COLON, SID_FS_IS_SLASH */ +#if defined(HAVE_MSWINDOWS) || defined(HAVE_MSDOS) || defined(HAVE_OS2) + #define SID_FS_IS_COLON_AND_BACKSLASH_AND_SLASH +#elif defined(HAVE_MACOS) + #define SID_FS_IS_COLON +#elif defined(HAVE_AMIGAOS) + #define SID_FS_IS_COLON_AND_SLASH +#else + #define SID_FS_IS_SLASH +#endif + +#endif /* SIDTUNECFG_H */ diff --git a/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/SidTuneTools.cpp b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/SidTuneTools.cpp new file mode 100644 index 00000000..79bf1597 --- /dev/null +++ b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/SidTuneTools.cpp @@ -0,0 +1,215 @@ +/* + * /home/ms/files/source/libsidtune/RCS/SidTuneTools.cpp,v + * + * Copyright (C) Michael Schwendt <mschwendt@yahoo.com> + * + * 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 "SidTuneTools.h" + +#ifdef HAVE_EXCEPTIONS +# include <new> +#endif +#include <ctype.h> +#include <string.h> + +// Own version of strdup, which uses new instead of malloc. +char* SidTuneTools::myStrDup(const char *source) +{ + char *dest; +#ifdef HAVE_EXCEPTIONS + if ( (dest = new(std::nothrow) char[strlen(source)+1]) != 0) +#else + if ( (dest = new char[strlen(source)+1]) != 0) +#endif + { + strcpy(dest,source); + } + return dest; +} + +// Return pointer to file name position in complete path. +char* SidTuneTools::fileNameWithoutPath(char* s) +{ + int last_slash_pos = -1; + for ( uint_least32_t pos = 0; pos < strlen(s); pos++ ) + { +#if defined(SID_FS_IS_COLON_AND_BACKSLASH_AND_SLASH) + if ( s[pos] == ':' || s[pos] == '\\' || + s[pos] == '/' ) +#elif defined(SID_FS_IS_COLON_AND_SLASH) + if ( s[pos] == ':' || s[pos] == '/' ) +#elif defined(SID_FS_IS_SLASH) + if ( s[pos] == '/' ) +#elif defined(SID_FS_IS_BACKSLASH) + if ( s[pos] == '\\' ) +#elif defined(SID_FS_IS_COLON) + if ( s[pos] == ':' ) +#else +#error Missing file/path separator definition. +#endif + { + last_slash_pos = pos; + } + } + return( &s[last_slash_pos +1] ); +} + +// Return pointer to file name position in complete path. +// Special version: file separator = forward slash. +char* SidTuneTools::slashedFileNameWithoutPath(char* s) +{ + int last_slash_pos = -1; + for ( uint_least32_t pos = 0; pos < strlen(s); pos++ ) + { + if ( s[pos] == '/' ) + { + last_slash_pos = pos; + } + } + return( &s[last_slash_pos +1] ); +} + +// Return pointer to file name extension in path. +// The backwards-version. +char* SidTuneTools::fileExtOfPath(char* s) +{ + uint_least32_t last_dot_pos = strlen(s); // assume no dot and append + for ( int pos = last_dot_pos; pos >= 0; --pos ) + { + if ( s[pos] == '.' ) + { + last_dot_pos = pos; + break; + } + } + return( &s[last_dot_pos] ); +} + +// Parse input string stream. Read and convert a hexa-decimal number up +// to a ``,'' or ``:'' or ``\0'' or end of stream. +uint_least32_t SidTuneTools::readHex( std::istrstream& hexin ) +{ + uint_least32_t hexLong = 0; + char c; + do + { + hexin >> c; + if ( !hexin ) + break; + if (( c != ',') && ( c != ':' ) && ( c != 0 )) + { + // machine independed to_upper + c &= 0xdf; + ( c < 0x3a ) ? ( c &= 0x0f ) : ( c -= ( 0x41 - 0x0a )); + hexLong <<= 4; + hexLong |= (uint_least32_t)c; + } + else + { + if ( c == 0 ) + hexin.putback(c); + break; + } + } while ( hexin ); + return hexLong; +} + +// Parse input string stream. Read and convert a decimal number up +// to a ``,'' or ``:'' or ``\0'' or end of stream. +uint_least32_t SidTuneTools::readDec( std::istrstream& decin ) +{ + uint_least32_t hexLong = 0; + char c; + do + { + decin >> c; + if ( !decin ) + break; + if (( c != ',') && ( c != ':' ) && ( c != 0 )) + { + c &= 0x0f; + hexLong *= 10; + hexLong += (uint_least32_t)c; + } + else + { + if ( c == 0 ) + decin.putback(c); + break; + } + } while ( decin ); + return hexLong; +} + +// Search terminated string for next newline sequence. +// Skip it and return pointer to start of next line. +const char* SidTuneTools::returnNextLine(const char* s) +{ + // Unix: LF = 0x0A + // Windows, DOS: CR,LF = 0x0D,0x0A + // Mac: CR = 0x0D + char c; + while ((c = *s) != 0) + { + s++; // skip read character + if (c == 0x0A) + { + break; // LF found + } + else if (c == 0x0D) + { + if (*s == 0x0A) + { + s++; // CR,LF found, skip LF + } + break; // CR or CR,LF found + } + } + if (*s == 0) // end of string ? + { + return 0; // no next line available + } + return s; // next line available +} + +// Skip any characters in an input string stream up to '='. +void SidTuneTools::skipToEqu( std::istrstream& parseStream ) +{ + char c; + do + { + parseStream >> c; + } + while ( c != '=' ); +} + +void SidTuneTools::copyStringValueToEOL(const char* pSourceStr, char* pDestStr, int DestMaxLen ) +{ + // Start at first character behind '='. + while ( *pSourceStr != '=' ) + { + pSourceStr++; + } + pSourceStr++; // Skip '='. + while (( DestMaxLen > 0 ) && ( *pSourceStr != 0 ) + && ( *pSourceStr != '\n' ) && ( *pSourceStr != '\r' )) + { + *pDestStr++ = *pSourceStr++; + DestMaxLen--; + } + *pDestStr++ = 0; +} diff --git a/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/SidTuneTools.h b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/SidTuneTools.h new file mode 100644 index 00000000..bc67fa93 --- /dev/null +++ b/sid/sidplay-libs-2.1.0/libsidplay/src/sidtune/SidTuneTools.h @@ -0,0 +1,85 @@ +/* + * /home/ms/files/source/libsidtune/RCS/SidTuneTools.h,v + * + * Copyright (C) Michael Schwendt <mschwendt@yahoo.com> + * + * 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 + */ + +#ifndef TOOLS_H +#define TOOLS_H + +#include "SidTuneCfg.h" +#include "sidtypes.h" + +#include <string.h> +#include <strstream> + +#define MYSTRICMP stricmp +#if defined(HAVE_STRCASECMP) + #undef MYSTRICMP + #define MYSTRICMP strcasecmp +#endif + +#define MYSTRNICMP strnicmp +#if defined(HAVE_STRNCASECMP) + #undef MYSTRNICMP + #define MYSTRNICMP strncasecmp +#endif + +class SidTuneTools +{ + public: + + // Wrapper for ``strnicmp'' without third argument. + static int myStrNcaseCmp(const char* s1, const char* s2) + { + return MYSTRNICMP(s1,s2,strlen(s2)); + } + + // Own version of strdup, which uses new instead of malloc. + static char* myStrDup(const char *source); + + // Return pointer to file name position in complete path. + static char* fileNameWithoutPath(char* s); + + // Return pointer to file name position in complete path. + // Special version: file separator = forward slash. + static char* slashedFileNameWithoutPath(char* s); + + // Return pointer to file name extension in path. + // Searching backwards until first dot is found. + static char* fileExtOfPath(char* s); + + // Parse input string stream. Read and convert a hexa-decimal number up + // to a ``,'' or ``:'' or ``\0'' or end of stream. + static uint_least32_t readHex(std::istrstream& parseStream); + + // Parse input string stream. Read and convert a decimal number up + // to a ``,'' or ``:'' or ``\0'' or end of stream. + static uint_least32_t readDec(std::istrstream& parseStream); + + // Search terminated string for next newline sequence. + // Skip it and return pointer to start of next line. + static const char* returnNextLine(const char* pBuffer); + + // Skip any characters in an input string stream up to '='. + static void skipToEqu(std::istrstream& parseStream); + + // Start at first character behind '=' and copy rest of string. + static void copyStringValueToEOL(const char* pSourceStr, char* pDestStr, int destMaxLen); +}; + +#endif /* TOOLS_H */ |