Main Page | Class Hierarchy | Compound List | File List | Compound Members | File Members | Related Pages

sidtune.cpp

Go to the documentation of this file.
00001 //
00002 // /home/ms/sidplay/libsidplay/RCS/sidtune.cpp,v
00003 // 
00004 // Information on usage of this class in "include/sidtune.h".
00005 //
00006 
00007 #include "sidtune.h"
00008 #include <string.h>
00009 #include <limits.h>
00010 
00011 #include "fformat.h"
00012 #include "myendian.h"
00013 #include "pp.h"
00014 #include <stdio.h>
00015 
00016 #if defined (__SYMBIAN32__)
00017 #include <f32file.h>
00018 #endif
00019 
00020 static const char text_songNumberExceed[] = "WARNING: Selected song number was too high";
00021 static const char text_unrecognizedFormat[] = "ERROR: Could not determine file format";
00022 static const char text_noDataFile[] = "ERROR: Did not find the corresponding data file";
00023 static const char text_notEnoughMemory[] = "ERROR: Not enough free memory";
00024 static const char text_cantLoadFile[] = "ERROR: Could not load input file";
00025 static const char text_cantOpenFile[] = "ERROR: Could not open file for binary input";
00026 static const char text_fileTooLong[] = "ERROR: Input file/data too long";
00027 static const char text_dataTooLong[] = "ERROR: Music data size exceeds C64 memory";
00028 static const char text_cantCreateFile[] = "ERROR: Could not create output file";
00029 static const char text_fileIoError[] = "ERROR: File I/O error";
00030 static const char text_fatalInternal[] = "FATAL: Internal error - contact the developers";
00031 static const char text_PAL_VBI[] = "50 Hz VBI (PAL)";
00032 static const char text_PAL_CIA[] = "CIA 1 Timer A (PAL)";
00033 static const char text_NTSC_VBI[] = "60 Hz VBI (NTSC)";
00034 static const char text_NTSC_CIA[] = "CIA 1 Timer A (NTSC)";
00035 static const char text_noErrors[] = "No errors";
00036 static const char text_na[] = "N/A";
00037 
00038 // Default sidtune file name extensions. This selection can be overriden
00039 // by specifying a custom list in the constructor.
00040 static const char * const defaultFileNameExt[] = 
00041 {
00042         // Preferred default file extension for single-file sidtunes
00043         // or sidtune description files in SIDPLAY INFOFILE format.
00044         ".sid",
00045         // Common file extension for single-file sidtunes due to SIDPLAY/DOS
00046         // displaying files *.DAT in its file selector by default.
00047         // Originally this was intended to be the extension of the raw data file
00048         // of two-file sidtunes in SIDPLAY INFOFILE format.
00049         ".dat",
00050         // Extension of Amiga Workbench tooltype icon info files, which
00051         // have been cut to MS-DOS file name length (8.3).
00052         ".inf",
00053         // No extension for the raw data file of two-file sidtunes in
00054         // PlaySID Amiga Workbench tooltype icon info format.
00055         "",
00056         // Common upper-case file extensions from MS-DOS (unconverted).
00057         ".DAT", ".SID", ".INF", 
00058         // File extensions used (and created) by various C64 emulators and
00059         // related utilities. These extensions are recommended to be used as
00060         // a replacement for ".dat" in conjunction with two-file sidtunes.
00061         ".c64", ".prg", ".C64", ".PRG",
00062         // Uncut extensions from Amiga.
00063         ".info", ".INFO", ".data", ".DATA",
00064         // End.
00065         0
00066 };
00067 
00068 // ------------------------------------------------- constructors, destructor
00069 
00070 EXPORT_C sidTune::sidTune( const char* fileName )
00071 {
00072         safeConstructor();
00073         if (fileName != 0)
00074         {
00075 #if !defined(NO_STDIN_LOADER)
00076                 // Filename ``-'' is used as a synonym for standard input.
00077                 if ( strcmp( fileName, "-" ) == 0 )
00078                 {
00079                         stdinConstructor();
00080                 }
00081                 else
00082                 {
00083 #endif
00084                         filesConstructor( fileName );
00085 #if !defined(NO_STDIN_LOADER)
00086                 }
00087 #endif
00088         }
00089         deleteFileBuffers();
00090 }
00091 
00092 
00093 sidTune::sidTune( ubyte* data, udword dataLen )
00094 {
00095         safeConstructor();
00096         if (data != 0)
00097         {
00098                 // Assume a failure, so we can simply return.
00099                 status = false;
00100                 if (dataLen > 65536)
00101                 {
00102                         info.statusString = text_fileTooLong;
00103                 }
00104                 else
00105                 {
00106                         info.dataFileLen = dataLen;
00107                         getSidtuneFromFileBuffer(data, dataLen);
00108                 }
00109         }
00110 }
00111 
00112 
00113 sidTune::sidTune( const char* fileName, const char **fileNameExt )
00114 {
00115         safeConstructor();      
00116         if ( fileNameExt != 0 )
00117                 fileNameExtensions = fileNameExt;
00118         if (fileName != 0)
00119         {
00120 #if !defined(NO_STDIN_LOADER)
00121                 // Filename ``-'' is used as a synonym for standard input.
00122                 if ( strcmp( fileName, "-" ) == 0 )
00123                 {
00124                         stdinConstructor();
00125                 }
00126                 else
00127                 {
00128 #endif
00129                         filesConstructor( fileName );
00130 #if !defined(NO_STDIN_LOADER)
00131                 }
00132 #endif
00133         }
00134         deleteFileBuffers();
00135 }
00136 
00137 
00138 sidTune::~sidTune()
00139 {
00140         safeDestructor();
00141 }
00142 
00143 
00144 // -------------------------------------------------- public member functions
00145 
00146 bool sidTune::load( ubyte* data, udword dataLen )
00147 {
00148         safeDestructor();
00149         safeConstructor();
00150         // Assume a failure, so we can simply return.
00151         status = false;
00152         if (data != 0)
00153         {
00154                 if (dataLen > 65536)
00155                 {
00156                         info.statusString = text_fileTooLong;
00157                 }
00158                 else
00159                 {
00160                         info.dataFileLen = dataLen;
00161                         getSidtuneFromFileBuffer(data, dataLen);
00162                 }
00163         }
00164         return status;
00165 }
00166 
00167 bool sidTune::open( const char* fileName )
00168 {
00169         safeDestructor();
00170         safeConstructor();
00171         filesConstructor(fileName);
00172         deleteFileBuffers();
00173         return status;
00174 }
00175 
00176 bool sidTune::setInfo(struct sidTuneInfo& /*inInfo*/)
00177         {
00178         return true; //TODO: what is this ?
00179         }
00180 
00181 EXPORT_C void sidTune::getInfo(struct sidTuneInfo& outInfo)
00187         {
00188         outInfo = info;
00189         }
00190 
00191 uword sidTune::selectSong(uword selectedSong)
00198         {
00199         // Determine and set starting song number.
00200         if (selectedSong == 0)
00201         {
00202                 selectedSong = info.startSong;
00203         }
00204         else if ((selectedSong > info.songs) || (selectedSong > classMaxSongs))
00205         {
00206                 info.statusString = text_songNumberExceed;
00207                 selectedSong = info.startSong;
00208         }
00209         // Retrieve song speed definition.
00210         info.songSpeed = songSpeed[selectedSong-1];
00211         // Assign song speed description string depending on clock speed.
00212         if (info.clockSpeed == SIDTUNE_CLOCK_PAL)
00213         {
00214                 if (info.songSpeed == SIDTUNE_SPEED_VBI_PAL)
00215                 {
00216                         info.speedString = text_PAL_VBI;
00217                 }
00218                 else
00219                 {
00220                         info.speedString = text_PAL_CIA;
00221                 }
00222         }
00223         else  //if (info.clockSpeed == SIDTUNE_CLOCK_NTSC)
00224         {
00225                 if (info.songSpeed == SIDTUNE_SPEED_VBI_NTSC)
00226                 {
00227                         info.speedString = text_NTSC_VBI;
00228                 }
00229                 else
00230                 {
00231                         info.speedString = text_NTSC_CIA;
00232                 }
00233         }
00234         return (info.currentSong=selectedSong);
00235 }
00236 
00237 void sidTune::setIRQaddress(uword address)
00238 {
00239         info.irqAddr = address;
00240 }
00241 
00242 // ------------------------------------------------- private member functions
00243 
00244 bool sidTune::placeSidTuneInC64mem( ubyte* c64buf )
00245 {
00246         if (isCached && status)
00247         {
00248                 // Check the size of the data.
00249                 if ( info.c64dataLen > 65536 )
00250                 {
00251                         info.statusString = text_dataTooLong;
00252                         return (status = false);
00253                 }
00254                 else
00255                 {
00256                         udword endPos = info.loadAddr + info.c64dataLen;
00257                         if (endPos <= 65536)
00258                         {
00259                                 // Copy data from cache to the correct destination.
00260                                 memcpy(c64buf+info.loadAddr,cachePtr+fileOffset,info.c64dataLen);
00261                         }
00262                         else
00263                         {
00264                                 // Security - split data which would exceed the end of the C64 memory.
00265                                 // Memcpy could not detect this.
00266                                 memcpy(c64buf+info.loadAddr,cachePtr+fileOffset,info.c64dataLen-(endPos-65536));
00267                                 // Wrap the remaining data to the start address of the C64 memory.
00268                                 memcpy(c64buf,cachePtr+fileOffset+info.c64dataLen-(endPos-65536),(endPos-65536));
00269                         }
00270                         return (status = true);
00271                 }
00272         }
00273         else
00274         {
00275                 return (status = false);
00276         }
00277 }
00278 
00279 
00280 udword sidTune::loadFile(const char* fileName, ubyte** bufferRef)
00281 {
00282         ELOG2(_L8("sidTune::loadFile %s \n") , fileName );
00283 
00284         udword fileLen = 0;
00285         status = false;
00286 
00287 #if defined (__SYMBIAN32__)
00288         TInt ret;
00289 
00290         ELOG1(_L8("connecting to Fileserver..."));
00291 
00292         RFs fs;
00293         ret = fs.Connect();
00294         if(ret != KErrNone)
00295                 {
00296                 ELOG2(_L8("Error [ret=%d]\n"), ret);
00297                 return 0;
00298                 }
00299         else ELOG1(_L8("OK\n"));
00300 
00301         ELOG2(_L8("opening file %s..."), fileName);
00302 
00303         TBuf8<256> buf8((const TUint8*)fileName);
00304         TBuf<256> buf;
00305         buf.Copy(buf8);
00306 
00307         RFile file;
00308         ret = file.Open(fs, buf, EFileRead | EFileShareReadersOnly);
00309         if(ret != KErrNone)
00310 #else
00311 
00312         // Open binary input file stream at end of file.
00313 #ifdef __BORLANDC__
00314         ifstream myIn( fileName, ios::in | ios::binary | ios::ate | ios::nocreate );
00315         if ( myIn.bad() )  // do not have is_open() !
00316 #else  
00317         ifstream myIn( fileName, ios::in | ios::bin | ios::ate | ios::nocreate );
00318         if ( !myIn.is_open() )
00319 #endif
00320 #endif // __SYMBIAN32__
00321         {
00322 #if defined (__SYMBIAN32__)
00323         ELOG2(_L8("ret = %d\n"), ret);
00324 #endif  
00325                 info.statusString = text_cantOpenFile;
00326         }
00327         else
00328         {
00329                 // Check for PowerPacker compression: load and decompress, if PP20 file.
00330 //      int ppRet = depp( myIn, bufferRef ); //TODO - use depp()
00331 //              if ( ppRet == TRUE )
00332 //              {
00333                         // Decompression successful, use uncompressed datafilelen.
00334 //                      fileLen = ppUncompressedLen();
00335 //                      info.statusString = ppErrorString;
00336 //                      status = true;
00337 //              }
00338 //              else if ( ppRet == (-1) )
00339 //              {
00340 //                      // An error occured while decompressing.
00341 //                      info.statusString = ppErrorString;
00342 //              }
00343 //              else if ( ppRet == FALSE )  // must be uncompressed file
00344                 {
00345 #if defined(__POWERPC__)
00346                         fileLen = (myIn.seekg(0,ios::end)).offset();
00347 #elif defined(__SYMBIAN32__)
00348                         ret = file.Size((TInt&)fileLen);
00349                         if(ret != KErrNone)
00350                                 {
00351                                 ELOG2(_L8("ret = %d\n"), ret);
00352                                 info.statusString = text_cantLoadFile;
00353                                 return 0;
00354                                 }
00355                         ELOG2(_L8("size: %d bytes\n"), fileLen);
00356 #else
00357                         myIn.seekg(0, ios::end);
00358                         fileLen = (udword)myIn.tellg();
00359 #endif
00360                         if ( *bufferRef != 0 )
00361                         {
00362                                 delete[] *bufferRef;  // free previously allocated memory
00363                         }
00364                         *bufferRef = new ubyte[fileLen+1];
00365                         if ( *bufferRef == 0 )
00366                         {
00367                                 info.statusString = text_notEnoughMemory;
00368                                 fileLen = 0;  // returning 0 = error condition.
00369                         }
00370                         else
00371                         {
00372                                 *(*bufferRef+fileLen) = 0;
00373                         }
00374 #if !defined (__SYMBIAN32__)
00375                         // Load uncompressed file.
00376                         myIn.seekg(0, ios::beg);
00377 #endif
00378                         udword restFileLen = fileLen;
00379                         while ( restFileLen > INT_MAX )
00380                         {
00381 #if defined (__SYMBIAN32__)
00382                         TPtr8 ptr(*bufferRef + (fileLen - restFileLen), INT_MAX);
00383                         ret = file.Read(ptr);
00384                         if(ret != KErrNone)
00385                                 {
00386                                 ELOG2(_L8("ret = %d\n"), ret);
00387                                 info.statusString = text_cantLoadFile;
00388                                 return 0;
00389                                 }
00390                         restFileLen -= INT_MAX;
00391 #else
00392                                 myIn.read( (ubyte*)*bufferRef + (fileLen - restFileLen), INT_MAX );
00393                                 restFileLen -= INT_MAX;
00394 #endif
00395                         }
00396                         if ( restFileLen > 0 )
00397                         {
00398 #if defined (__SYMBIAN32__)
00399                         TPtr8 ptr(*bufferRef + (fileLen - restFileLen), restFileLen);
00400                         ret = file.Read(ptr);
00401                         if(ret != KErrNone)
00402                                 {
00403                                 ELOG2(_L8("ret = %d\n"), ret);
00404                                 info.statusString = text_cantLoadFile;
00405                                 return 0;
00406                                 }
00407 #else
00408                                 myIn.read( (ubyte*)*bufferRef + (fileLen - restFileLen), restFileLen );
00409 #endif
00410                         }
00411 #if !defined(__SYMBIAN32__)
00412                         if ( myIn.bad() )
00413                         {
00414                                 info.statusString = text_cantLoadFile;
00415                         }
00416                         else
00417                         {
00418                                 info.statusString = text_noErrors;
00419                                 status = true;
00420                         }
00421 #endif
00422                 }
00423 #if defined(__SYMBIAN32__)
00424                 file.Close();
00425                 fs.Close();
00426 #else
00427                 myIn.close();
00428 #endif
00429         }
00430         return fileLen;
00431 }
00432 
00433 
00434 void sidTune::deleteFileBuffers()
00435 {
00436         // This function does not affect status and statusstring.
00437         // The filebuffers are global to the object.
00438         if ( fileBuf != 0 )
00439         {
00440                 delete[] fileBuf;
00441                 fileBuf = 0;
00442         }
00443         if ( fileBuf2 != 0 )
00444         {
00445                 delete[] fileBuf2;
00446                 fileBuf2 = 0;
00447         }
00448 }
00449 
00450 
00451 bool sidTune::cacheRawData( void* sourceBuf, udword sourceBufLen )
00452 {
00453         if ( cachePtr != 0 )
00454         {
00455                 delete[] cachePtr;
00456         }
00457         isCached = false;
00458         if ( (cachePtr = new ubyte[sourceBufLen]) == 0 )
00459         {
00460                 info.statusString = text_notEnoughMemory;
00461                 return (status = false);
00462         }
00463         else
00464         {
00465                 memcpy( cachePtr, (ubyte*)sourceBuf, sourceBufLen );
00466                 cacheLen = sourceBufLen;
00467                 isCached = true;
00468                 info.statusString = text_noErrors;
00469                 return (status = true);
00470         }
00471 }
00472 
00473 
00474 bool sidTune::getCachedRawData( void* destBuf, udword destBufLen )
00475 {
00476         if (( cachePtr == 0 ) || ( cacheLen > destBufLen ))
00477         {
00478                 info.statusString = text_fatalInternal;
00479                 return (status = false);
00480         }
00481         memcpy( (ubyte*)destBuf, cachePtr, cacheLen );
00482         info.dataFileLen = cacheLen;
00483         info.statusString = text_noErrors;
00484         return (status = true);
00485 }
00486 
00487 
00488 void sidTune::safeConstructor()
00489 {
00490     CTOR(sidTune);
00491         // Initialize the object with some safe defaults.
00492         status = false;
00493         
00494         info.statusString = text_na;
00495         info.dataFileName = 0;
00496         info.dataFileLen = 0;
00497         info.infoFileName = 0;
00498         info.formatString = text_na;
00499         info.speedString = text_na;
00500         info.loadAddr = ( info.initAddr = ( info.playAddr = 0 ));
00501         info.songs = ( info.startSong = ( info.currentSong = 0 ));
00502         info.musPlayer = false;
00503         info.songSpeed = SIDTUNE_SPEED_VBI_PAL;
00504         info.clockSpeed = SIDTUNE_CLOCK_PAL;
00505         
00506         for ( int si = 0; si < classMaxSongs; si++ )
00507         {
00508                 songSpeed[si] = SIDTUNE_SPEED_VBI_PAL;  // all: 50 Hz
00509         }
00510 
00511         cachePtr = 0;
00512         cacheLen = 0;
00513   
00514         fileBuf = ( fileBuf2 = 0 );
00515         fileOffset = 0;
00516         fileNameExtensions = defaultFileNameExt;
00517                 
00518         for ( int sNum = 0; sNum < infoStringNum; sNum++ )
00519         {
00520                 for ( int sPos = 0; sPos < infoStringLen; sPos++ )
00521                 {
00522                         infoString[sNum][sPos] = 0;
00523                 }
00524         }
00525         info.numberOfInfoStrings = 0;
00526 
00527         info.numberOfCommentStrings = 1;
00528         info.commentString = new char * [info.numberOfCommentStrings];
00529         info.commentString[0] = myStrDup("--- SAVED WITH SIDPLAY V?.?? ---");
00530 
00531         fillUpWidth = 0;
00532 }
00533 
00534 
00535 void sidTune::safeDestructor()
00536 {
00537     DTOR(sidTune);
00538         // Remove copy of comment field.
00539         udword strNum = 0;
00540         // Check and remove every available line.
00541         while (info.numberOfCommentStrings-- > 0)
00542         {
00543                 if (info.commentString[strNum] != 0)
00544                 {
00545                         delete[] info.commentString[strNum];
00546                         info.commentString[strNum] = 0;
00547                 }
00548                 strNum++;  // next string
00549         };
00550         delete[] info.commentString;  // free the array pointer
00551         
00552         if ( info.infoFileName != 0 )
00553                 delete[] info.infoFileName;
00554         if ( info.dataFileName != 0 )
00555                 delete[] info.dataFileName;
00556         if ( cachePtr != 0 )
00557                 delete[] cachePtr;
00558         deleteFileBuffers();
00559         
00560         status = false;
00561 }
00562 
00563 
00564 #if !defined(NO_STDIN_LOADER)
00565 
00566 void sidTune::stdinConstructor()
00567 {
00568         // Assume a failure, so we can simply return.
00569         status = false;
00570         // Assume the memory allocation to fail.
00571         info.statusString = text_notEnoughMemory;
00572         if (( fileBuf = new ubyte[65536] ) == 0 )
00573                 return;
00574         uword i = 0;
00575         ubyte datb;
00576         while ( cin.get(datb) )
00577                 fileBuf[i++] = datb; // uword index will wrap when > 65535
00578         if (( info.dataFileLen = cin.tellg() ) > 65536 )
00579         {
00580                 info.statusString = text_fileTooLong;
00581         }
00582         else
00583         {
00584                 getSidtuneFromFileBuffer(fileBuf,info.dataFileLen);
00585         }
00586         deleteFileBuffers();
00587 } 
00588 
00589 #endif
00590 
00591 
00592 bool sidTune::getSidtuneFromFileBuffer( ubyte* buffer, udword bufferLen )
00593 {
00594         bool foundFormat = false;
00595         // Here test for the possible single file formats. ------------------
00596         if ( PSID_fileSupport( buffer, bufferLen ))
00597         {
00598                 foundFormat = true;
00599         }
00600         /*              if ( SID2_fileSupport( buffer, bufferLen ))
00601         {
00602                 foundFormat = true;
00603         }
00604          */             else if ( MUS_fileSupport( buffer, bufferLen ))
00605          {
00606                  foundFormat = true;
00607          }
00608         else
00609         {
00610                 // No further single-file-formats available. --------------------
00611                 info.formatString = text_na;
00612                 info.statusString = text_unrecognizedFormat;
00613                 status = false;
00614         }
00615         if ( foundFormat )
00616         {
00617                 info.c64dataLen = bufferLen - fileOffset;
00618                 cacheRawData( buffer, bufferLen );
00619                 info.statusString = text_noErrors;
00620                 status = true;
00621         }
00622         return foundFormat;
00623 }
00624 
00625         
00626 void sidTune::acceptSidTune(const char* dataFileName, const char* infoFileName,
00627                                                          ubyte* dataBuf, udword dataLen )
00628 {
00629         // Make a copy of the data file name, if exist.
00630         if ( dataFileName != 0 )
00631         {
00632         info.dataFileName = myStrDup( dataFileName );
00633                 if ( info.dataFileName == 0 )
00634                 {
00635                         info.statusString = text_notEnoughMemory;
00636                         status = false;
00637                         return;
00638                 }
00639         }
00640         else
00641         {
00642                 info.dataFileName = 0;
00643         }
00644         // Make a copy of the info file name, if exist.
00645         if ( infoFileName != 0 )
00646         {
00647                 info.infoFileName = myStrDup( infoFileName );
00648                 if ( info.infoFileName == 0 )
00649                 {
00650                         info.statusString = text_notEnoughMemory;
00651                         status = false;
00652                         return;
00653                 }
00654         }
00655         else
00656         {
00657                 info.infoFileName = 0;
00658         }
00659         // Fix bad sidtune set up.
00660         if (info.startSong > info.songs)
00661                 info.startSong = 1;
00662         info.dataFileLen = dataLen;
00663         info.c64dataLen = dataLen - fileOffset;
00664         cacheRawData( dataBuf, dataLen );
00665 }
00666 
00667 
00668 bool sidTune::createNewFileName( char** destStringPtr,
00669                                                                  const char* sourceName,
00670                                                                  const char* sourceExt)
00671 {
00672         // Free any previously allocated object.
00673         if ( *destStringPtr != 0 )
00674         {
00675                 delete[] *destStringPtr;
00676         }
00677         // Get enough memory, so we can appended the extension.
00678         *destStringPtr = new char[strlen(sourceName) + strlen(sourceExt) +1];
00679         if ( *destStringPtr == 0 )
00680         {
00681                 info.statusString = text_notEnoughMemory;
00682                 return (status = false);
00683         }
00684         strcpy( *destStringPtr, sourceName );
00685         char* extPtr = fileExtOfFilename( fileNameWithoutPath(*destStringPtr) );
00686         strcpy( extPtr, sourceExt );
00687         return true;
00688 }
00689 
00690         
00691 // Initializing the object based upon what we find in the specified file.
00692 
00693 void sidTune::filesConstructor( const char* fileName )
00694 {
00695         fileBuf = 0;  // will later point to the buffered file
00696         // Try to load the single specified file.
00697         if (( info.dataFileLen = loadFile(fileName,&fileBuf)) != 0 )
00698         {
00699                 // File loaded. Now check if it is in a valid single-file-format.
00700                 if ( PSID_fileSupport(fileBuf,info.dataFileLen ))
00701                 {
00702                         acceptSidTune(fileName,0,fileBuf,info.dataFileLen);
00703                         return;
00704                 }
00705 /*              else if ( SID2_fileSupport(fileBuf,info.dataFileLen) )
00706                 {
00707                         acceptSidTune(fileName,0,fileBuf,info.dataFileLen);
00708                         return;
00709                 }
00710 */              else if ( MUS_fileSupport(fileBuf,info.dataFileLen) )
00711                 {
00712                         acceptSidTune(fileName,0,fileBuf,info.dataFileLen);
00713                         return;
00714                 }
00715         
00716 
00717 // -------------------------------------- Support for multiple-files formats.
00718                 else
00719                 {
00720 // We cannot simply try to load additional files, if a description file was
00721 // specified. It would work, but is error-prone. Imagine a filename mismatch
00722 // or more than one description file (in another) format. Any other file
00723 // with an appropriate file name can be the C64 data file.
00724 // First we see if ``fileName'' could be a raw data file. In that case we
00725 // have to find the corresponding description file.
00726 
00727                         // Right now we do not have a second file. Hence the (0, 0, ...)
00728                         // parameters are set for the data buffer. This will not hurt the
00729                         // file support procedures.
00730                         udword fileLen2;
00731                         char* fileName2 = 0;
00732                         
00733                         // Make sure that ``fileBuf'' does not contain a description file.
00734                         if ( !SID_fileSupport(0,0,fileBuf,info.dataFileLen) &&
00735                                 !INFO_fileSupport(0,0,fileBuf,info.dataFileLen) )
00736                         {
00737                                 // Assuming ``fileName'' to hold the name of the raw data file, 
00738                                 // we now create the name of a description file (=fileName2) by
00739                                 // appending various filename extensions.
00740 
00741 // ------------------------------------------ Looking for a description file.
00742 
00743                                 const char * const* tmpFileNameExt = fileNameExtensions;
00744                                 while (*tmpFileNameExt != 0)
00745                                 {
00746                                         if ( !createNewFileName(&fileName2,fileName,*tmpFileNameExt) )
00747                                                 return;
00748                                         // Do not load the first file again if names are equal.
00749 #if defined(ANSI) || defined(__BORLANDC__)
00750                                         if ( stricmp(fileName,fileName2) != 0 )
00751 #else                   
00752                                         if ( strcasecmp(fileName,fileName2) != 0 )
00753 #endif
00754                                         {
00755                                                 // 1st data file was loaded into ``fileBuf'',
00756                                                 // so we load the 2nd one into ``fileBuf2''.
00757                                                 if (( fileLen2 = loadFile(fileName2,&fileBuf2)) != 0 )
00758                                                 {
00759                                                         if ( SID_fileSupport(fileBuf,info.dataFileLen,fileBuf2,fileLen2) )
00760                                                         {
00761                                                                 acceptSidTune(fileName,fileName2,fileBuf,info.dataFileLen);
00762                                                                 delete[] fileName2;
00763                                                                 return;
00764                                                         }
00765                                                         else if ( INFO_fileSupport(fileBuf,info.dataFileLen,fileBuf2,fileLen2) )
00766                                                         {
00767                                                                 acceptSidTune(fileName,fileName2,fileBuf,info.dataFileLen);
00768                                                                 delete[] fileName2;
00769                                                                 return;
00770                                                         }
00771                                                 }
00772                                         }
00773                                         tmpFileNameExt++;
00774                                 };
00775                                            
00776 // --------------------------------------- Could not find a description file.
00777                                 
00778                                 delete[] fileName2;
00779                                 info.formatString = text_na;
00780                                 info.statusString = text_unrecognizedFormat;
00781                                 status = false;
00782                                 return;
00783                         }
00784           
00785 
00786 // -------------------------------------------------------------------------
00787 // Still unsuccessful ? Probably one put a description file name into
00788 // ``fileName''. Assuming ``fileName'' to hold the name of a description
00789 // file, we now create the name of the data file and swap both used memory
00790 // buffers - fileBuf and fileBuf2 - when calling the format support.
00791 // If it works, the second file is the data file ! If it is not, but does
00792 // exist, we are out of luck, since we cannot detect data files.
00793 
00794                         // Make sure ``fileBuf'' contains a description file.
00795                         else if ( SID_fileSupport(0,0,fileBuf,info.dataFileLen) || 
00796                                          INFO_fileSupport(0,0,fileBuf,info.dataFileLen))
00797                         {
00798 
00799 // --------------------- Description file found. --- Looking for a data file.
00800 
00801                                 const char* const* tmpFileNameExt = fileNameExtensions;
00802                                 while (*tmpFileNameExt != 0)
00803                                 {
00804                                         if ( !createNewFileName(&fileName2,fileName,*tmpFileNameExt) )
00805                                                 return;
00806                                         // Do not load the first file again if names are equal.
00807 #if defined(ANSI) || defined(__BORLANDC__)
00808                                         if ( stricmp(fileName,fileName2) != 0 )
00809 #else                   
00810                                         if ( strcasecmp(fileName,fileName2) != 0 )
00811 #endif
00812                                         {
00813                                                 // 1st info file was loaded into ``fileBuf'',
00814                                                 // so we load the 2nd one into ``fileBuf2''.
00815                                                 if (( fileLen2 = loadFile(fileName2,&fileBuf2)) != 0 )
00816                                                 {
00817 // -------------- Some data file found, now identifying the description file.
00818 
00819                                                         if ( SID_fileSupport(fileBuf2,fileLen2,fileBuf,info.dataFileLen) )
00820                                                         {
00821                                                                 acceptSidTune(fileName2,fileName,fileBuf2,fileLen2);
00822                                                                 delete[] fileName2;
00823                                                                 return;
00824                                                         }
00825                                                         else if ( INFO_fileSupport(fileBuf2,fileLen2,fileBuf,info.dataFileLen) )
00826                                                         {
00827                                                                 acceptSidTune(fileName2,fileName,fileBuf2,fileLen2);
00828                                                                 delete[] fileName2;
00829                                                                 return;
00830                                                         }
00831                                                 }
00832                                         }
00833                                         tmpFileNameExt++;
00834                                 };
00835                                 
00836 // ---------------------------------------- No corresponding data file found.
00837 
00838                                 delete[] fileName2;
00839                                 info.formatString = text_na;
00840                                 info.statusString = text_noDataFile;
00841                                 status = false;
00842                                 return;
00843                         } // end else if ( = is description file )
00844 
00845 // --------------------------------- Neither description nor data file found.
00846 
00847                         else
00848                         {
00849                                 info.formatString = text_na;
00850                                 info.statusString = text_unrecognizedFormat;
00851                                 status = false;
00852                                 return;
00853                         }
00854                 } // end else ( = is no singlefile )
00855 
00856 // ---------------------------------------------------------- File I/O error.
00857 
00858         } // if loaddatafile
00859         else
00860         {
00861                 // returned fileLen was 0 = error. The info.statusString is
00862                 // already set then.
00863                 info.formatString = text_na;
00864                 status = false;
00865                 return;
00866         }
00867 } 
00868 
00869 
00870 void sidTune::convertOldStyleSpeedToTables(udword oldStyleSpeed)
00871 {
00872         // Create the speed/clock setting tables.
00873         //
00874         // This does not take into account the PlaySID bug upon evaluating the
00875         // SPEED field. It would most likely break compatibility to lots of
00876         // sidtunes, which have been converted from .SID format and vice versa.
00877         // The .SID format did the bit-wise/song-wise evaluation of the SPEED
00878         // value correctly, like it was described in the PlaySID documentation.
00879 
00880         int toDo = ((info.songs <= classMaxSongs) ? info.songs : classMaxSongs);
00881         for (int s = 0; s < toDo; s++)
00882         {
00883                 if (( (oldStyleSpeed>>(s&31)) & 1 ) == 0 )
00884                 {
00885                         songSpeed[s] = SIDTUNE_SPEED_VBI_PAL;  // 50 Hz
00886                 }
00887                 else
00888                 {
00889                         songSpeed[s] = SIDTUNE_SPEED_CIA_1A;   // CIA 1 Timer A
00890                 }
00891         }
00892 }
00893 
00894 
00895 //
00896 // File format conversion ---------------------------------------------------
00897 //
00898 
00899 #if 0 //ALFRED - TODO
00900 bool sidTune::saveToOpenFile( ofstream& toFile, ubyte* buffer, udword bufLen )
00901 {
00902         udword lenToWrite = bufLen;
00903         while ( lenToWrite > INT_MAX )
00904         {
00905                 toFile.write( buffer + (bufLen - lenToWrite), INT_MAX );
00906                 lenToWrite -= INT_MAX;
00907         }
00908         if ( lenToWrite > 0 )
00909                 toFile.write( buffer + (bufLen - lenToWrite), lenToWrite );
00910         if ( toFile.bad() )
00911         {
00912                 info.statusString = text_fileIoError;
00913                 return false;
00914         }
00915         else
00916         {
00917                 info.statusString = text_noErrors;
00918                 return true;
00919         }
00920 }
00921 #endif //ALFRED - TODO
00922                 
00923 
00924 #if 0 //ALFRED - TODO
00925 bool sidTune::saveC64dataFile( const char* fileName, bool overWriteFlag )
00926 {
00927         bool success = false;  // assume error
00928         // This prevents saving from a bad object.
00929         if ( status )
00930         {
00931                 // Open binary output file stream.
00932                 long int createAttr;
00933 #ifdef __BORLANDC__
00934                 createAttr = ios::out | ios::binary;
00935 #else
00936                 createAttr = ios::out | ios::bin;
00937 #endif
00938                 if ( overWriteFlag )
00939                         createAttr |= ios::trunc;
00940                 else
00941                         createAttr |= ios::noreplace;
00942                 ofstream fMyOut( fileName, createAttr );
00943                 if ( !fMyOut )
00944                 { 
00945                         info.statusString = text_cantCreateFile;
00946                 }
00947                 else
00948                 {  
00949                         // Save c64 lo/hi load address.
00950                         ubyte saveAddr[2];
00951                         saveAddr[0] = info.loadAddr & 255;
00952                         saveAddr[1] = info.loadAddr >> 8;
00953                         fMyOut.write( saveAddr, 2 );
00954                         // Data starts at: bufferaddr + fileOffset
00955                         // Data length: info.dataFileLen - fileOffset
00956                         if ( !saveToOpenFile( fMyOut, cachePtr + fileOffset, info.dataFileLen - fileOffset ) )
00957                         {
00958                                 info.statusString = text_fileIoError;
00959                         }
00960                         else
00961                         {
00962                                 info.statusString = text_noErrors;
00963                                 success = true;
00964                         }
00965                         fMyOut.close();
00966                 }
00967         }
00968         return success;
00969 }
00970 #endif //ALFRED - TODO
00971 
00972 
00973 #if 0 //ALFRED - TODO
00974 bool sidTune::saveSIDfile( const char* fileName, bool overWriteFlag )
00975 {
00976         bool success = false;  // assume error
00977         // This prevents saving from a bad object.
00978         if ( status )
00979         {
00980                 // Open ASCII output file stream.
00981                 long int createAttr;
00982 #ifdef __BORLANDC__
00983                 createAttr = ios::out;
00984 #else
00985                 createAttr = ios::out;
00986 #endif
00987                 if ( overWriteFlag )
00988                         createAttr |= ios::trunc;
00989                 else
00990                         createAttr |= ios::noreplace;
00991                 ofstream fMyOut( fileName, createAttr );
00992                 if ( !fMyOut )
00993                 { 
00994                         info.statusString = text_cantCreateFile;
00995                 }
00996                 else
00997                 {  
00998                         if ( !SID_fileSupportSave( fMyOut ) )
00999                         {
01000                                 info.statusString = text_fileIoError;
01001                         }
01002                         else
01003                         {
01004                                 info.statusString = text_noErrors;
01005                                 success = true;
01006                         }
01007                         fMyOut.close();
01008                 }
01009         }
01010         return success;
01011 }
01012 #endif //ALFRED - TODO
01013                 
01014 /*
01015 bool sidTune::saveSID2file( const char* fileName, bool overWriteFlag )
01016 {
01017         bool success = false;  // assume error
01018         // This prevents saving from a bad object.
01019         if ( status )
01020         {
01021                 // Open binary output file stream.
01022                 long int createAttr;
01023 #ifdef __BORLANDC__
01024                 createAttr = ios::out | ios::binary;
01025 #else
01026                 createAttr = ios::out | ios::bin;
01027 #endif
01028                 if ( overWriteFlag )
01029                 {
01030                         createAttr |= ios::trunc;
01031                 }
01032                 else
01033                 {
01034                         createAttr |= ios::noreplace;
01035                 }
01036                 ofstream fMyOut( fileName, createAttr );
01037                 if ( !fMyOut )
01038                 {
01039                         info.statusString = text_cantCreateFile;
01040                 }
01041                 else
01042                 {
01043                         if ( !SID2_fileSupportSave( fMyOut, cachePtr ) )
01044                         {
01045                                 info.statusString = text_fileIoError;
01046                         }
01047                         else
01048                         {
01049                                 info.statusString = text_noErrors;
01050                                 success = true;
01051                         }
01052                         fMyOut.close();
01053                 }
01054         }
01055         return success;
01056 }
01057 */
01058 
01059 #if 0 //ALFRED - TODO
01060 bool sidTune::savePSIDfile( const char* fileName, bool overWriteFlag )
01061 {
01062         bool success = false;  // assume error
01063         // This prevents saving from a bad object.
01064         if ( status )
01065         {
01066                 // Open binary output file stream.
01067                 long int createAttr;
01068 #ifdef __BORLANDC__
01069                 createAttr = ios::out | ios::binary;
01070 #else
01071                 createAttr = ios::out | ios::bin;
01072 #endif
01073           if ( overWriteFlag )
01074                         createAttr |= ios::trunc;
01075                 else
01076                         createAttr |= ios::noreplace;
01077                 ofstream fMyOut( fileName, createAttr );
01078                 if ( !fMyOut )
01079                 {
01080                         info.statusString = text_cantCreateFile;
01081                 }
01082                 else
01083                 {  
01084                         if ( !PSID_fileSupportSave( fMyOut, cachePtr ) )
01085                         {
01086                                 info.statusString = text_fileIoError;
01087                         }
01088                         else
01089                         {
01090                                 info.statusString = text_noErrors;
01091                                 success = true;
01092                         }
01093                         fMyOut.close();
01094                 }
01095         }
01096         return success;
01097 }
01098 #endif //ALFRED - TODO

Generated on Tue Feb 8 04:14:15 2005 for Esidplay by doxygen 1.3.3