rifffile.cpp

Go to the documentation of this file.
00001 // $Id: rifffile.cpp 1282 2006-06-09 09:46:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 // *********RIFF file handling class
00099 
00100 /*
00101 */
00102 
00103 #include "camtypes.h"
00104 #include "rifffile.h"
00105 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 #include "riffdata.h"
00108 
00109 DECLARE_SOURCE("$Revision: 1282 $");
00110 
00111 CC_IMPLEMENT_MEMDUMP(RIFFFile, CC_CLASS_MEMDUMP)
00112 
00113 #define new CAM_DEBUG_NEW
00114 
00115 #define RIFFFILE_RETURNERR {Error = TRUE; return FALSE;}
00116 
00117 #define ALIGNSIZE(x) ((((x) & 1) == 0)?(x):((x) + 1))
00118 
00119 
00120 /********************************************************************************************
00121 
00122 >   RIFFFile::RIFFFile(void)
00123 
00124     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00125     Created:    21 03 95
00126     Inputs:     
00127     Returns:    
00128     Purpose:    Constructor for the RIFFFile class
00129     SeeAlso:    
00130 
00131 ********************************************************************************************/
00132 
00133 RIFFFile::RIFFFile(void)
00134 {
00135     File = NULL;
00136     Error = FALSE;
00137     AquiredData = NULL;
00138 }
00139 
00140 
00141 /********************************************************************************************
00142 
00143 >   RIFFFile::~RIFFFile(void)
00144 
00145     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00146     Created:    21 03 95
00147     Inputs:     
00148     Returns:    
00149     Purpose:    Destructor for the RIFFFile class
00150     SeeAlso:    
00151 
00152 ********************************************************************************************/
00153 
00154 RIFFFile::~RIFFFile(void)
00155 {
00156     // get rid of all the list entries in the file
00157     Levels.DeleteAll();
00158 
00159     // Get rid of the aquired object, if there is one
00160     if(AquiredData != 0)
00161         CCFree(AquiredData);
00162 }
00163 
00164 
00165 /********************************************************************************************
00166 
00167 >   FOURCC RIFFFile::Init(CCLexFile *pFile, BOOL NoHeader = FALSE)
00168 
00169     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00170     Created:    21/03/95
00171     Inputs:     File to read from, whether it has a header
00172     Returns:    0 = not a RIFF file
00173                 1 = error occured
00174                 other = RIFF form type
00175     Purpose:    Initialises the class for reading in a RIFF file. If NoHeader is TRUE then
00176                 the file has no header and a RIFF chunk is expected to start immediately.
00177     SeeAlso:    
00178 
00179 ********************************************************************************************/
00180 
00181 FOURCC RIFFFile::Init(CCLexFile *pFile, BOOL NoHeader)
00182 {
00183     // store Mr. NiceCCFile
00184     File = pFile;
00185 
00186     FOURCC FileType = 0;
00187 
00188     // if this file has a header, check it and get the type
00189     if(!NoHeader)
00190     {
00191         // read in the header of the file
00192         RIFFFile_Header Header;
00193 
00194         if(File->read(&Header, sizeof(Header)).bad())
00195             return FALSE;
00196 
00197     
00198         // and check it for being a valid form
00199         FileType = CheckRIFFHeader((ADDR)&Header, File->Size());
00200 
00201         // and was it?
00202         if(FileType == 0)
00203           return 0;     // not a RIFF form
00204     }
00205         
00206     // OK, set up lots of nice variables for the funky business of RIFF reading
00207     ObjType = RIFFOBJECTTYPE_NONE;
00208     RepeatObject = FALSE;
00209     Error = FALSE;
00210     Location = NoHeader?0:sizeof(RIFFFile_Header);
00211     Size = File->Size();
00212     GotData = FALSE;
00213     CurrentLevel = 0;
00214     AquiredData = 0;
00215     AlignedObjectSize = 0;
00216 
00217     return FileType;
00218 }
00219 
00220 /********************************************************************************************
00221 
00222 >   FOURCC RIFFFile::CheckRIFFHeader(ADDR Header, DWORD Size)
00223 
00224     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00225     Created:    21 03 95
00226     Inputs:     None
00227     Returns:    0 = not a RIFF file
00228                 other = RIFF form type
00229     Purpose:    Checks to see if the header supplied is that of a valid RIFF form. Useful for
00230                 HowCompatable functions in filter code.
00231     SeeAlso:    
00232 
00233 ********************************************************************************************/
00234 
00235 FOURCC RIFFFile::CheckRIFFHeader(ADDR Header, DWORD Size)
00236 {
00237 PORTNOTE("byteorder", "TODO: Check byte ordering")
00238     RIFFFile_Header *Hdr = (RIFFFile_Header *)Header;
00239 
00240     if(RIFFDATA_FOURCC(Hdr->CK.ckID) != RIFFTYPE_RIFF)
00241         return 0;       // file doesn't start "RIFF"
00242 
00243     if(RIFFDATA_DWORD(Hdr->CK.ckSize) > (Size - sizeof(RIFFFile_Header)) &&
00244                 RIFFDATA_DWORD(Hdr->CK.ckSize) < (Size - sizeof(RIFFFile_Header)))
00245         return 0;       // Size doesn't match that in header. Be a bit relaxed about exact lengths
00246 
00247     return Hdr->FormType;
00248 }
00249 
00250 
00251 /********************************************************************************************
00252 
00253 >   BOOL RIFFFile::NextObject(void)
00254 
00255     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00256     Created:    21 03 95
00257     Inputs:     None
00258     Returns:    whether an error occured
00259     Purpose:    Initialises the class for reading in a RIFF file
00260     SeeAlso:    
00261 
00262 ********************************************************************************************/
00263 
00264 BOOL RIFFFile::NextObject(void)
00265 {
00266     if(Error)
00267         return FALSE;
00268 
00269     // do we need to return the current object again?
00270     if(RepeatObject)
00271     {
00272         RepeatObject = FALSE;
00273         return TRUE;            // all data nicely set up already
00274     }
00275 
00276     // skip over any data it it hasn't already been got
00277     if(ObjType == RIFFOBJECTTYPE_CHUNK && (GotData == FALSE || Location != (ObjLocation + AlignedObjectSize)))
00278     {
00279         if(File->seek(ObjLocation + AlignedObjectSize).bad()) {
00280 TRACEUSER( "Ben", _T("RIFFFile: Error on seek when jumping object data\n"));
00281             RIFFFILE_RETURNERR;
00282         }
00283 
00284         Location = ObjLocation + AlignedObjectSize;
00285 
00286         // as we may come this way again...
00287         GotData = TRUE;
00288     }
00289 
00290     // have we gone past the end of the file?
00291     if(Location >= Size)
00292     //if (File->eof())
00293     {
00294         // Yes. Firstly, ensure that all the lists got the end list thingy - is the list empty?
00295         if(!Levels.IsEmpty())
00296         {
00297 TRACEUSER( "Ben", _T("RIFFFile: Ending... terminating list\n"));
00298             RIFFFileLevel *Level = (RIFFFileLevel *)Levels.GetTail();
00299 
00300             ERROR3IF(Level == NULL, "List class returned a null tail for a non empty list! Help!");
00301             
00302             // set up a nice list end object
00303             ObjType = RIFFOBJECTTYPE_LISTEND;
00304             ObjChunkType = Level->Type;
00305             ObjLevel = CurrentLevel;
00306             ObjLocation = Location;
00307             GotData = TRUE;
00308 
00309             // level down one
00310             CurrentLevel--;
00311 
00312             // get rid of the last level on the list
00313             delete Levels.RemoveTail();
00314 
00315             return TRUE;
00316         }
00317 
00318         // And if they all have, say that the file ended
00319         ObjType = RIFFOBJECTTYPE_FILEEND;
00320         ObjChunkType = 0;
00321         ObjSize = 0;
00322         ObjLevel = 0;
00323         ObjLocation = Location;
00324         GotData = TRUE;
00325 TRACEUSER( "Ben", _T("returning file end\n"));
00326         return TRUE;
00327     }
00328 
00329     // check to see if the current list has ended
00330     if(!Levels.IsEmpty())
00331     {
00332         RIFFFileLevel *Level = (RIFFFileLevel *)Levels.GetTail();
00333         
00334         ERROR3IF(Level == NULL, "List class returned a null tail for a non empty list! Help!");
00335 
00336         if(Location >= Level->End)
00337         {
00338             // RIFF list has ended
00339             ObjType = RIFFOBJECTTYPE_LISTEND;
00340             ObjChunkType = Level->Type;
00341             ObjLevel = CurrentLevel;
00342             ObjSize = 0;
00343             ObjLocation = Location;
00344             GotData = TRUE;
00345             
00346             // down a level
00347             CurrentLevel--;
00348 
00349             // delete the last entry in the list
00350             delete Levels.RemoveTail();
00351 
00352             return TRUE;
00353         }
00354     }
00355 
00356     // right then, let's see what the next object in the file is.
00357     RIFFck ChunkHeader;
00358 
00359     if(File->read(&ChunkHeader, sizeof(ChunkHeader)).bad())
00360     {
00361 TRACEUSER( "Ben", _T("RIFFFile: file error on reading chunk header\n"));
00362         RIFFFILE_RETURNERR;
00363     }
00364 
00365     Location += sizeof(ChunkHeader);
00366 
00367     // is it a list chunk?
00368     if(RIFFDATA_FOURCC(ChunkHeader.ckID) == RIFFTYPE_LIST)
00369     {
00370         // yep... process it
00371         RIFFFile_List ListHdr;
00372 
00373         // read in a list header
00374         if(File->read(&ListHdr, sizeof(ListHdr)).bad())
00375         {
00376 TRACEUSER( "Ben", _T("RIFFFile: file error on reading list id\n"));
00377             RIFFFILE_RETURNERR;
00378         }
00379 
00380         Location += sizeof(ListHdr);
00381 
00382         // make a new entry in the list
00383         RIFFFileLevel *NewLevel;
00384 
00385         if((NewLevel = new RIFFFileLevel) == 0)
00386             RIFFFILE_RETURNERR;
00387 
00388         NewLevel->Start = Location;
00389         NewLevel->End = Location + ALIGNSIZE(RIFFDATA_DWORD(ChunkHeader.ckSize)) - sizeof(ListHdr);
00390         NewLevel->Type = RIFFDATA_FOURCC(ListHdr.ListType);
00391 
00392         // and add it to the list
00393         Levels.AddTail(NewLevel);
00394 
00395         // up a level
00396         CurrentLevel++;
00397         
00398         // return a nice list start object
00399         ObjType = RIFFOBJECTTYPE_LISTSTART;
00400         ObjChunkType = RIFFDATA_FOURCC(ListHdr.ListType);
00401         ObjSize = 0;
00402         ObjLevel = CurrentLevel;
00403         ObjLocation = Location;
00404         GotData = TRUE;
00405         return TRUE;
00406     }
00407 
00408     // and after all that excitement, if it was just a normal, boring chunk, return stuff about that
00409     ObjType = RIFFOBJECTTYPE_CHUNK;
00410     ObjChunkType = RIFFDATA_FOURCC(ChunkHeader.ckID);
00411     ObjSize = RIFFDATA_DWORD(ChunkHeader.ckSize);
00412     ObjLevel = CurrentLevel;
00413     ObjLocation = Location;
00414 
00415     // set up some useful data
00416     GotData = FALSE;
00417     AlignedObjectSize = ALIGNSIZE(ObjSize);
00418 
00419     // and that's all folks
00420     return TRUE;
00421 }
00422 
00423 
00424 /********************************************************************************************
00425 
00426 >   BOOL RIFFFile::GetChunkData(ADDR Block, INT32 Size)
00427 
00428     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00429     Created:    21 03 95
00430     Inputs:     Pointer to the block where you want the data, and the size of the block
00431     Returns:    whether an error occured
00432     Purpose:    Gets the all data from a RIFF chunk
00433     SeeAlso:    
00434 
00435 ********************************************************************************************/
00436 
00437 BOOL RIFFFile::GetChunkData(ADDR Block, INT32 BSize)
00438 {
00439     // first of all, check to see if the caller has been a little bit silly
00440     if(ObjType != RIFFOBJECTTYPE_CHUNK)
00441     {
00442         Error = TRUE;       // only chunks have getable data
00443         ERROR2(FALSE, "RIFFFile::GetChunkData called for a non-chunk object\n");
00444     }
00445 
00446     if(BSize < ObjSize)
00447     {
00448         Error = TRUE;       // wrong size...
00449         ERROR2(FALSE, "RIFFFile::GetChunkData called with a block which is just *too* small\n");
00450     }
00451 
00452     // has the data already been got for this object?
00453     if(GotData)
00454     {
00455         // yep, go back and get it again
00456 TRACEUSER( "Ben", _T("Chunk data asked for more than once\n"));
00457         if(File->seek(ObjLocation).bad())
00458             RIFFFILE_RETURNERR;
00459 
00460         Location = ObjLocation;
00461     }
00462 
00463     // and get that data!
00464     if(File->read(Block, ObjSize).bad())
00465     {
00466 TRACEUSER( "Ben", _T("RIFFFile: file error when reading chunk data\n"));
00467         RIFFFILE_RETURNERR;
00468     }
00469 
00470     // ensure alignment is maintained within the file
00471     if(ObjSize != AlignedObjectSize)
00472     {
00473         // read a byte to align this to the correct position
00474         BYTE junk;
00475 
00476         if(File->read(&junk, sizeof(junk)).bad())
00477             RIFFFILE_RETURNERR;
00478     }
00479 
00480     // update locations
00481     Location += AlignedObjectSize;
00482 
00483     // and set an essential flag!
00484     GotData = TRUE;
00485 
00486     return TRUE;
00487 }
00488 
00489 
00490 /********************************************************************************************
00491 
00492 >   BOOL RIFFFile::GetChunkData(ADDR Block, INT32 Size, INT32 Offset)
00493 
00494     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00495     Created:    21 03 95
00496     Inputs:     Pointer to the block where you want the data, and the size of the block
00497                 and the offset within the block of the data you want
00498     Returns:    whether an error occured
00499     Purpose:    Gets a certain amount of the data from a RIFF chunk. ATM it's a bit
00500                 inefficient
00501     SeeAlso:    
00502 
00503 ********************************************************************************************/
00504 
00505 BOOL RIFFFile::GetChunkData(ADDR Block, INT32 BSize, INT32 Offset)
00506 {
00507     // first of all, check to see if the caller has been a little bit silly
00508     if(ObjType != RIFFOBJECTTYPE_CHUNK)
00509     {
00510         Error = TRUE;       // only chunks have getable data
00511         ERROR2(FALSE, "RIFFFile::GetChunkData called for a non-chunk object\n");
00512     }
00513 
00514     // check offset is OK
00515     if(Offset >= ObjSize)
00516         Offset = ObjSize - 1;
00517 
00518     // check that we'll be grabbing a nice amount of data
00519     if((Offset + BSize) > ObjSize)
00520         BSize = ObjSize - Offset;
00521     
00522     // don't do anything if there's no data to get
00523     if(BSize <= 0)
00524         return TRUE;
00525     
00526     // where in the file do we wish to get data from?
00527     INT32 TargetLocation = ObjLocation + Offset;
00528 
00529     // seek to the data we want, but only if it's necessary
00530     if(TargetLocation != Location)
00531     {
00532         if(File->seek(TargetLocation).bad())
00533             RIFFFILE_RETURNERR;
00534     
00535         Location = TargetLocation;
00536     }
00537 
00538     // and get that data!
00539     if(File->read(Block, BSize).bad())
00540     {
00541 TRACEUSER( "Ben", _T("RIFFFile: file error when reading chunk data\n"));
00542         RIFFFILE_RETURNERR;
00543     }
00544 
00545     // update locations
00546     Location += BSize;
00547 
00548     // and set an essential flag!
00549     GotData = TRUE;
00550 
00551     return TRUE;
00552 }
00553 
00554 
00555 /********************************************************************************************
00556 
00557 >   BOOL RIFFFile::RIFFFile::SkipToListEnd(UINT32 Level)
00558 
00559     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00560     Created:    21 03 95
00561     Inputs:     The level number of the list to skip to the end of
00562     Returns:    whether an error occured
00563     Purpose:    Skips to the end of a given level. ListEnd objects are not returned for the
00564                 lists you skip
00565     SeeAlso:    
00566 
00567 ********************************************************************************************/
00568 
00569 BOOL RIFFFile::SkipToListEnd(UINT32 LevelNumber)
00570 {
00571     RIFFFileLevel *Level;
00572     RIFFFileLevel *Next;
00573 
00574 TRACEUSER( "Ben", _T("SkipToListEnd called to level %d\n"), LevelNumber);
00575     Level = (RIFFFileLevel *)Levels.FindItem(LevelNumber - 1);
00576                 // - 1 because level 0 doesn't have an entry as
00577                 // it's the root level of the file
00578 
00579     ERROR2IF(Level == 0, FALSE, "Couldn't find given level to jump to in list");
00580 
00581     // seek to the end of the level
00582     if(File->seek(Level->End).bad())
00583     {
00584 TRACEUSER( "Ben", _T("RIFFFile: file error when seeking to end of level\n"));
00585         RIFFFILE_RETURNERR;
00586     }
00587 
00588     // update the location
00589     Location = Level->End;
00590 
00591     // update the level we're at
00592     CurrentLevel = LevelNumber - 1;
00593     
00594     // remove the last few entries from the list, including this one
00595     while(Level != 0)
00596     {
00597         Next = (RIFFFileLevel *)Levels.GetNext(Level);
00598         delete Levels.RemoveItem(Level);
00599         Level = Next;
00600     }   
00601 
00602     return TRUE;
00603 }
00604 
00605 
00606 /********************************************************************************************
00607 
00608 >   BOOL RIFFFile::EnsureAquiredSizeIsAtLeast(INT32 Size)
00609 
00610     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00611     Created:    06/06/95
00612     Inputs:     minimum size required
00613     Returns:    whether an error occured
00614     Purpose:    Ensures that the aquired block is at least a certain size
00615     SeeAlso:    
00616 
00617 ********************************************************************************************/
00618 
00619 BOOL RIFFFile::EnsureAquiredSizeIsAtLeast(INT32 Size)
00620 {
00621     if(AquiredData == 0 || AquiredDataSize < Size)
00622     {
00623         if(AquiredData != 0) 
00624         {
00625             CCFree(AquiredData);
00626             AquiredData = 0;
00627         }
00628 
00629         if((AquiredData = (BYTE *)CCMalloc(Size)) == 0)
00630             RIFFFILE_RETURNERR;
00631 
00632         AquiredDataSize = Size;
00633     }
00634 
00635     return TRUE;
00636 }
00637 
00638 
00639 /********************************************************************************************
00640 
00641 >   BOOL RIFFFile::AquireChunkData()
00642 
00643     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00644     Created:    21 03 95
00645     Inputs:     none
00646     Returns:    whether an error occured
00647     Purpose:    Gets the data from a RIFF chunk and puts it into a buffer maintained by the
00648                 class. Any previous data is lost.
00649     SeeAlso:    
00650 
00651 ********************************************************************************************/
00652 
00653 BOOL RIFFFile::AquireChunkData()
00654 {
00655     // check to see if the current object is a chunk
00656     ERROR2IF(ObjType != RIFFOBJECTTYPE_CHUNK, FALSE, "Tried an AquiredChunkData on a non-chunk RIFF object\n");
00657     
00658     // ensure that AquiredData points at enough space for this to be hoopy
00659     if(!EnsureAquiredSizeIsAtLeast(ObjSize))
00660         return FALSE;
00661 
00662     // there is at enough space in AquiredData to store the current object
00663     // use GetChunkData on it
00664 
00665     return GetChunkData(AquiredData, AquiredDataSize);
00666 }
00667 
00668 
00669 /********************************************************************************************
00670 
00671 >   BOOL RIFFFile::AquireListContents(INT32 *ListSize)
00672 
00673     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00674     Created:    06/06/95
00675     Inputs:     none
00676     Returns:    whether an error occured
00677     Purpose:    Aquires the data of an entire list. Fills in ListSize to be the size of the
00678                 data.
00679     SeeAlso:    
00680 
00681 ********************************************************************************************/
00682 
00683 BOOL RIFFFile::AquireListContents(INT32 *ListSize)
00684 {
00685     ERROR2IF(ObjType != RIFFOBJECTTYPE_LISTSTART, FALSE, "Tried an GetListContents on a non-list start RIFF object\n");
00686 
00687     // OK, first thing we need to do is to get the list's header... where is it?
00688     INT32 StartLocation = Location - sizeof(RIFFck) - sizeof(RIFFFile_List);
00689 
00690     // seek there
00691     if(File->seek(StartLocation).bad())
00692     {
00693         RIFFFILE_RETURNERR;
00694     }
00695 
00696     // OK, get the chunk header (not the list header which gives it's type
00697     RIFFck ChunkHeader;
00698 
00699     if(File->read(&ChunkHeader, sizeof(ChunkHeader)).bad())
00700     {
00701         RIFFFILE_RETURNERR;
00702     }
00703 
00704     // right then, we now know how much data we need to extract from the file...
00705     INT32 ContentsSize =    RIFFDATA_DWORD(ChunkHeader.ckSize) + sizeof(RIFFck);
00706 
00707     // now we need a block of data to get it into
00708     if(!EnsureAquiredSizeIsAtLeast(ContentsSize))
00709         return FALSE;
00710 
00711     // and getting it would be a cunning plan! seek to the beginning
00712     if(File->seek(StartLocation).bad())
00713     {
00714         RIFFFILE_RETURNERR;
00715     }
00716 
00717     // grab the data
00718     if(File->read(AquiredData, ContentsSize).bad())
00719     {
00720         RIFFFILE_RETURNERR;
00721     }
00722     
00723     // seek back to the location we were at the beginning
00724     if(File->seek(Location).bad())
00725     {
00726         RIFFFILE_RETURNERR;
00727     }
00728 
00729     // and set up the return values
00730     *ListSize = ContentsSize;
00731     
00732     return TRUE;
00733 }
00734 
00735 
00736 /********************************************************************************************
00737 
00738 >   BOOL RIFFFile::RepeatCurrent()
00739 
00740     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00741     Created:    21 03 95
00742     Inputs:     none
00743     Returns:    whether an error occured
00744     Purpose:    Makes the next NextObject return the current object
00745     SeeAlso:    
00746 
00747 ********************************************************************************************/
00748 
00749 BOOL RIFFFile::RepeatCurrent()
00750 {
00751     if(RepeatObject == TRUE)
00752     {
00753 TRACEUSER( "Ben", _T("RepeatObject already set for this object...\n"));
00754     }
00755 
00756     RepeatObject = TRUE;
00757 
00758     return TRUE;
00759 }
00760 
00761 
00762 /********************************************************************************************
00763 
00764 >   BOOL RIFFFile::GetListContents(ADDR *Block, INT32 *Size)
00765 
00766     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00767     Created:    19/04/95
00768     Inputs:     pointer to a pointer for the block address, pointer to size to return size
00769     Returns:    whether an error occured
00770     Purpose:    gets the contents from a list. This is in the raw form from the RIFF file
00771     SeeAlso:    
00772 
00773 ********************************************************************************************/
00774 
00775 BOOL RIFFFile::GetListContents(ADDR *Block, INT32 *Size)
00776 {
00777     ERROR2IF(ObjType != RIFFOBJECTTYPE_LISTSTART, FALSE, "Tried an GetListContents on a non-list start RIFF object\n");
00778 
00779     // OK, first thing we need to do is to get the list's header... where is it?
00780     INT32 StartLocation = Location - sizeof(RIFFck) - sizeof(RIFFFile_List);
00781 
00782     // seek there
00783     if(File->seek(StartLocation).bad())
00784     {
00785         RIFFFILE_RETURNERR;
00786     }
00787 
00788     // OK, get the chunk header (not the list header which gives it's type
00789     RIFFck ChunkHeader;
00790 
00791     if(File->read(&ChunkHeader, sizeof(ChunkHeader)).bad())
00792     {
00793         RIFFFILE_RETURNERR;
00794     }
00795 
00796     // right then, we now know how much data we need to extract from the file...
00797     INT32 ContentsSize =    RIFFDATA_DWORD(ChunkHeader.ckSize) + sizeof(RIFFck);
00798 
00799     // now we need a block of data to get it into
00800     ADDR Contents = (ADDR)CCMalloc(ContentsSize);
00801     
00802     if(Contents == 0)
00803         return FALSE;
00804 
00805     // and getting it would be a cunning plan! seek to the beginning
00806     if(File->seek(StartLocation).bad())
00807     {
00808         RIFFFILE_RETURNERR;
00809     }
00810 
00811     // grab the data
00812     if(File->read(Contents, ContentsSize).bad())
00813     {
00814         RIFFFILE_RETURNERR;
00815     }
00816     
00817     // seek back to the location we were at the beginning
00818     if(File->seek(Location).bad())
00819     {
00820         RIFFFILE_RETURNERR;
00821     }
00822 
00823     // and set up the return values
00824     *Block = Contents;
00825     *Size = ContentsSize;
00826     
00827     return TRUE;
00828 }
00829 
00830 
00831 /********************************************************************************************
00832 
00833 >   BOOL RIFFFile::FindChunkWithinListContents(ADDR ListContents, INT32 ListSize, FOURCC Type,
00834                 INT32 Entry, ADDR *Chunk, INT32 *ChunkSize);
00835 
00836     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00837     Created:    06/06/95
00838     Inputs:     ListContents    Pointer to list contents
00839                 ListSize        Size of the list
00840                 Type            Type of chunk required
00841                 Entry           The number of that type of chunk to skip
00842                 Chunk           Pointer to a pointer to a chunk to be filled in
00843                 ChunkSize       Pointer to a value to be filled in with the chunk length.
00844     Returns:    whether the chunk could be found
00845     Purpose:    Finds a chunk within a list
00846 
00847 ********************************************************************************************/
00848 
00849 BOOL RIFFFile::FindChunkWithinListContents(ADDR ListContents, INT32 ListSize, FOURCC Type,
00850         INT32 Entry, ADDR *Chunk, INT32 *ChunkSize)
00851 {
00852     RIFFck *Header;
00853     INT32 OffsetWithin = sizeof(RIFFck) + sizeof(RIFFFile_List);
00854 
00855     while(OffsetWithin < ListSize)
00856     {
00857         Header = (RIFFck *)(ListContents + OffsetWithin);
00858 
00859         INT32 Size = RIFFDATA_DWORD(Header->ckSize);
00860         if(RIFFDATA_FOURCC(Header->ckID) == Type)
00861         {
00862             if(Entry <= 0)
00863             {
00864                 // return this one...
00865                 if(Chunk != 0)
00866                     (*Chunk) = ListContents + OffsetWithin + sizeof(RIFFck);
00867 
00868                 if(ChunkSize != 0)
00869                     (*ChunkSize) = Size;
00870 
00871                 return TRUE;
00872             }
00873             else
00874             {
00875                 Entry--;
00876             }
00877         }
00878         OffsetWithin += Size + sizeof(RIFFck);
00879     }
00880 
00881     return FALSE;
00882 }
00883 

Generated on Sat Nov 10 03:46:44 2007 for Camelot by  doxygen 1.4.4