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