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

info_.cpp

Go to the documentation of this file.
00001 //
00002 // /home/ms/sidplay/libsidplay/fformat/RCS/info_.cpp,v
00003 //
00004 // Amiga PlaySID icon tooltype file format (.INFO) support.
00005 //
00006 // This is a derived work, courtesy of Peter Kunath, who has provided an
00007 // examplary source code to examine an Amiga icon file.
00008 //
00009 // It has been ported and heavily modified to suit certain requirements.
00010 //
00011 // This replaces the old code, which was simply scanning input data for
00012 // a first, presumedly constant, Id string. This code does not require the
00013 // default tool to serve as a constant Id by containing "SID:PlaySID".
00014 
00015 #include "info_.h"
00016 
00017 
00018 const char text_format[] = "Raw plus PlaySID icon tooltype file (INFO)";
00019 
00020 const char keyword_id[] = "SID:PLAYSID";
00021 const char keyword_address[] = "ADDRESS=";
00022 const char keyword_songs[] = "SONGS=";
00023 const char keyword_speed[] = "SPEED=";
00024 const char keyword_name[] = "NAME=";
00025 const char keyword_author[] = "AUTHOR=";
00026 const char keyword_copyright[] = "COPYRIGHT=";
00027 const char keyword_musPlayer[] = "SIDSONG=YES";
00028 
00029 const char text_noMemError[] = "ERROR: Not enough free memory";
00030 const char text_corruptError[] = "ERROR: Info file is incomplete or corrupt";
00031 const char text_noStringsError[] = "ERROR: Info file does not contain required strings";
00032 const char text_dataCorruptError[] = "ERROR: C64 data file is corrupt";
00033 //const char text_chunkError[] = "ERROR: Invalid tooltype information in icon file";
00034 
00035 const int safeBufferSize = 64;  // for string comparison, stream parsing
00036 
00037 
00038 bool copyItem(smartPtr<char>& spIn, smartPtr<char>& spCmpBuf, udword itemLen)
00039 {
00040         for ( uword i = 0; i < itemLen; i++ )
00041         {
00042                 spCmpBuf[i] = spIn[i];
00043         }
00044         return (spIn && spCmpBuf);
00045 }
00046 
00047 
00048 bool sidTune::INFO_fileSupport(void* dataBuffer, udword dataLength,
00049                                                            void* infoBuffer, udword infoLength)
00050 {
00051         // Remove any format description or format error string.
00052         info.formatString = 0;
00053         
00054         // Require a first minimum safety size.
00055         ulong minSize = 1+sizeof(struct DiskObject);
00056         if (infoLength < minSize)
00057                 return( false );
00058 
00059         struct DiskObject *dobject = (struct DiskObject *)infoBuffer;
00060 
00061         // Require Magic_Id in the first two bytes of the file.
00062         if ( readEndian(dobject->Magic[0],dobject->Magic[1]) != WB_DISKMAGIC )
00063                 return false;
00064 
00065         // Only version 1.x supported.
00066         if ( readEndian(dobject->Version[0],dobject->Version[1]) != WB_DISKVERSION )
00067                 return false;
00068 
00069         // A PlaySID icon must be of type project.
00070         if ( dobject->Type != WB_PROJECT )
00071                 return false;
00072 
00073         int i;  // general purpose index variable
00074 
00075         // We want to skip a possible Gadget Image item.
00076         char *icon = (char*)infoBuffer + sizeof(struct DiskObject);
00077 
00078         if ( (readEndian(dobject->Gadget.Flags[0],dobject->Gadget.Flags[1]) & GFLG_GADGIMAGE) == 0)
00079     {
00080                 // Calculate size of gadget borders (vector image).
00081                 
00082                 if (dobject->Gadget.pGadgetRender[0] |
00083                         dobject->Gadget.pGadgetRender[1] |
00084                         dobject->Gadget.pGadgetRender[2] |
00085                         dobject->Gadget.pGadgetRender[3])  // border present ?
00086                 {
00087                         // Require another minimum safety size.
00088                         minSize += sizeof(struct Border);
00089                         if (infoLength < minSize)
00090                                 return( false );
00091 
00092                         struct Border *brd = (struct Border *)icon;
00093                         icon += sizeof(struct Border);
00094                         icon += brd->Count * (2+2);            // pair of uword
00095                 }
00096 
00097                 if (dobject->Gadget.pSelectRender[0] |
00098                         dobject->Gadget.pSelectRender[1] |
00099                         dobject->Gadget.pSelectRender[2] |
00100                         dobject->Gadget.pSelectRender[3])  // alternate border present ?
00101                 {
00102                         // Require another minimum safety size.
00103                         minSize += sizeof(struct Border);
00104                         if (infoLength < minSize)
00105                                 return( false );
00106                         
00107                         struct Border *brd = (struct Border *)icon;
00108                         icon += sizeof(struct Border);
00109                         icon += brd->Count * (2+2);            // pair of uword
00110                 }
00111     }
00112   else
00113     {
00114                 // Calculate size of gadget images (bitmap image).
00115       
00116                 if (dobject->Gadget.pGadgetRender[0] |
00117                         dobject->Gadget.pGadgetRender[1] |
00118                         dobject->Gadget.pGadgetRender[2] |
00119                         dobject->Gadget.pGadgetRender[3])  // image present ?
00120                 {
00121                         // Require another minimum safety size.
00122                         minSize += sizeof(struct Image);
00123                         if (infoLength < minSize)
00124                                 return( false );
00125 
00126                         struct Image *img = (struct Image *)icon;
00127                         icon += sizeof(struct Image);
00128                         
00129                         udword imgsize = 0;
00130                         for(i=0;i<readEndian(img->Depth[0],img->Depth[1]);i++)
00131                         {
00132                                 if ( (img->PlanePick & (1<<i)) != 0)
00133                                 {
00134                                         // NOTE: Intuition relies on PlanePick to know how many planes
00135                                         // of data are found in ImageData. There should be no more
00136                                         // '1'-bits in PlanePick than there are planes in ImageData.
00137                                         imgsize++;
00138                                 }
00139                         }
00140 
00141                         imgsize *= ((readEndian(img->Width[0],img->Width[1])+15)/16)*2;  // bytes per line
00142                         imgsize *= readEndian(img->Height[0],img->Height[1]);              // bytes per plane
00143 
00144                         icon += imgsize;
00145                 }
00146       
00147                 if (dobject->Gadget.pSelectRender[0] |
00148                         dobject->Gadget.pSelectRender[1] |
00149                         dobject->Gadget.pSelectRender[2] |
00150                         dobject->Gadget.pSelectRender[3])  // alternate image present ?
00151                 {
00152                         // Require another minimum safety size.
00153                         minSize += sizeof(struct Image);
00154                         if (infoLength < minSize)
00155                                 return( false );
00156 
00157                         struct Image *img = (struct Image *)icon;
00158                         icon += sizeof(struct Image);
00159                         
00160                         udword imgsize = 0;
00161                         for(i=0;i<readEndian(img->Depth[0],img->Depth[1]);i++)
00162                         {
00163                                 if ( (img->PlanePick & (1<<i)) != 0)
00164                                 {
00165                                         // NOTE: Intuition relies on PlanePick to know how many planes
00166                                         // of data are found in ImageData. There should be no more
00167                                         // '1'-bits in PlanePick than there are planes in ImageData.
00168                                         imgsize++;
00169                                 }
00170                         }
00171                         
00172                         imgsize *= ((readEndian(img->Width[0],img->Width[1])+15)/16)*2;  // bytes per line
00173                         imgsize *= readEndian(img->Height[0],img->Height[1]);              // bytes per plane
00174                         icon += imgsize;
00175                 }
00176     }
00177         
00178         // Here use a smart pointer to prevent access violation errors.
00179         smartPtr<char> spTool((char*)icon,infoLength-(ulong)(icon-(char*)infoBuffer));
00180         if ( !spTool )
00181         {
00182                 info.formatString = text_corruptError;
00183                 return false;
00184         }
00185 
00186         // A separate safe buffer is used for each tooltype string.
00187         smartPtr<char> spCmpBuf(safeBufferSize);
00188         if ( !spCmpBuf )
00189         {
00190                 info.formatString = text_noMemError;
00191                 return false;
00192         }
00193         char* cmpBuf = spCmpBuf.tellBegin();
00194 
00195         // Skip default tool.
00196         spTool += readEndian(spTool[0],spTool[1],spTool[2],spTool[3]) + 4;
00197 
00198         // Defaults.
00199         fileOffset = 0;                // no header in separate data file
00200         info.musPlayer = false;
00201         info.numberOfInfoStrings = 0;
00202         udword oldStyleSpeed = 0;
00203 
00204         // Flags for required entries.
00205         bool hasAddress = false,
00206                 hasName = false,
00207                 hasAuthor = false,
00208                 hasCopyright = false,
00209                 hasSongs = false,
00210                 hasSpeed = false,
00211                 hasUnknownChunk = false;
00212 
00213         // Calculate number of tooltype strings.
00214         i = (readEndian(spTool[0],spTool[1],spTool[2],spTool[3])/4) - 1;
00215         spTool += 4;  // skip size info
00216 
00217         while( i-- > 0 )
00218     {
00219                 // Get length of this tool.
00220                 udword toolLen = readEndian(spTool[0],spTool[1],spTool[2],spTool[3]);
00221                 spTool += 4;  // skip tool length
00222                 // Copy item to safe buffer.
00223                 if ( !copyItem(spTool,spCmpBuf,toolLen) )
00224                 {
00225                         return false;
00226                 }
00227                 
00228                 // Now check all possible keywords.
00229                 if ( myStrNcaseCmp(cmpBuf,keyword_address) == 0 )
00230                 {
00231 #if 0 //ALFRED - TODO
00232                         istrstream addrIn( cmpBuf + strlen(keyword_address), 
00233                                                           toolLen - strlen(keyword_address) );
00234                         info.loadAddr = (uword)readHex( addrIn );
00235                         info.initAddr = (uword)readHex( addrIn );
00236                         info.playAddr = (uword)readHex( addrIn );
00237                         if ( !addrIn )  
00238                         {
00239                                 return false;
00240                         }
00241 #endif //ALFRED - TODO
00242                         hasAddress = true;
00243                 }
00244                 else if ( myStrNcaseCmp(cmpBuf,keyword_songs) == 0 )
00245                 {
00246 #if 0 //ALFRED - TODO
00247                         istrstream numIn( cmpBuf + strlen(keyword_songs), 
00248                                                          toolLen - strlen(keyword_songs) );
00249                         if ( !numIn )
00250                         {
00251                                 return false;
00252                         }
00253                         info.songs = (uword)readDec( numIn );
00254                         info.startSong = (uword)readDec( numIn );
00255                         if ( info.startSong == 0 )
00256                         {
00257                                 info.startSong++;
00258                         }
00259 #endif //ALFRED - TODO
00260                         hasSongs = true;
00261                 }
00262                 else if ( myStrNcaseCmp(cmpBuf,keyword_speed) == 0 )
00263                 {
00264 #if 0 //ALFRED - TODO
00265                         istrstream speedIn( cmpBuf + strlen(keyword_speed),
00266                                                            toolLen - strlen(keyword_speed) );
00267                         if ( !speedIn )
00268                         {
00269                                 return false;
00270                         }
00271                         oldStyleSpeed = readHex(speedIn);
00272 #endif //ALFRED - TODO
00273                         hasSpeed = true;
00274                 }
00275                 else if ( myStrNcaseCmp(cmpBuf,keyword_name) == 0 )
00276                 {
00277                         strncpy( &infoString[0][0], cmpBuf + strlen(keyword_name), 31 );
00278                         info.nameString = &infoString[0][0];
00279                         info.infoString[0] = &infoString[0][0];
00280                         hasName = true;
00281                 }
00282                 else if ( myStrNcaseCmp(cmpBuf,keyword_author) == 0 )
00283                         {
00284                                 strncpy( &infoString[1][0], cmpBuf + strlen(keyword_author), 31 );
00285                                 info.authorString = &infoString[1][0];
00286                                 info.infoString[1] = &infoString[1][0];
00287                                 hasAuthor = true;
00288                         }
00289                         else if ( myStrNcaseCmp(cmpBuf,keyword_copyright) == 0 )
00290                         {
00291                                 strncpy( &infoString[2][0], cmpBuf + strlen(keyword_copyright), 31 );
00292                                 info.copyrightString = &infoString[2][0];
00293                                 info.infoString[2] = &infoString[2][0];
00294                                 hasCopyright = true;
00295                         }
00296                         else if ( myStrNcaseCmp(cmpBuf,keyword_musPlayer) == 0 )
00297                         {
00298                                 info.musPlayer = true;
00299                         }
00300                         else
00301                         {
00302                                 hasUnknownChunk = true;  // --- not used ---
00303                                 //info.formatString = text_chunkError;
00304                                 //return false;
00305                         }
00306                 // Skip to next tool.
00307                 spTool += toolLen;
00308         }
00309 
00310         if (info.songs > classMaxSongs)
00311         {
00312                 info.songs = classMaxSongs;
00313         }
00314         
00315         // Collected ``required'' information complete ?
00316         if ( hasAddress && hasName && hasAuthor && hasCopyright && hasSongs && hasSpeed )
00317         {
00318                 // Create the speed/clock setting table.
00319                 convertOldStyleSpeedToTables(oldStyleSpeed);
00320                 if (( info.loadAddr == 0 ) && ( dataLength != 0 ))
00321                 {
00322                         smartPtr<ubyte> spDataBuf((ubyte*)dataBuffer,dataLength);
00323                         spDataBuf += fileOffset;
00324                         info.loadAddr = readEndian(spDataBuf[1],spDataBuf[0]);
00325                         if ( !spDataBuf )
00326                         {
00327                                 info.formatString = text_dataCorruptError;
00328                                 return false;
00329                         }
00330                         fileOffset += 2;
00331                 }
00332                 if ( info.initAddr == 0 )
00333                 {
00334                         info.initAddr = info.loadAddr;
00335                 }
00336                 // Now adjust MUS songs.
00337                 if ( info.musPlayer )
00338                 {
00339                         info.loadAddr = 0x1000;
00340                         info.initAddr = 0xc7b0;
00341                         info.playAddr = 0;
00342                 }
00343                 info.numberOfInfoStrings = 3;
00344                 // We finally accept the input data.
00345                 info.formatString = text_format;
00346                 return true;
00347         }
00348         else if ( hasAddress || hasName || hasAuthor || hasCopyright || hasSongs || hasSpeed )
00349         {
00350                 // Something is missing (or damaged ?).
00351                 info.formatString = text_corruptError;
00352                 return false;
00353         }
00354         else
00355         {
00356                 // No PlaySID conform info strings.
00357                 info.formatString = text_noStringsError;
00358                 return false;
00359         }
00360 }

Generated on Tue Feb 8 04:13:58 2005 for Esidplay by doxygen 1.3.3