mxffile.h

Go to the documentation of this file.
00001 
00010 /*
00011  *  Copyright (c) 2003, Matt Beard
00012  *
00013  *  This software is provided 'as-is', without any express or implied warranty.
00014  *  In no event will the authors be held liable for any damages arising from
00015  *  the use of this software.
00016  *
00017  *  Permission is granted to anyone to use this software for any purpose,
00018  *  including commercial applications, and to alter it and redistribute it
00019  *  freely, subject to the following restrictions:
00020  *
00021  *    1. The origin of this software must not be misrepresented; you must
00022  *       not claim that you wrote the original software. If you use this
00023  *       software in a product, an acknowledgment in the product
00024  *       documentation would be appreciated but is not required.
00025  *  
00026  *    2. Altered source versions must be plainly marked as such, and must
00027  *       not be misrepresented as being the original software.
00028  *  
00029  *    3. This notice may not be removed or altered from any source
00030  *       distribution.
00031  */
00032 #ifndef MXFLIB__MXFFILE_H
00033 #define MXFLIB__MXFFILE_H
00034 
00035 
00036 // For find()
00037 #include <algorithm>
00038 
00039 
00040 // KLUDGE!! MSVC can't cope with template member functions!!!
00041 namespace mxflib
00042 {
00043     class MXFFile;
00044     template<class TP, class T> TP MXFFile__ReadObjectBase(MXFFilePtr This, PrimerPtr UsePrimer = NULL);
00045 }
00046 
00047 namespace mxflib
00048 {
00050     class MXFFile : public RefCount<MXFFile>
00051     {
00052     protected:
00053         bool isOpen;                    
00054         bool isMemoryFile;              
00055         FileHandle Handle;              
00056         UInt32 RunInSize;               
00057 
00058         DataChunkPtr Buffer;            
00059         UInt64 BufferOffset;            
00060         UInt64 BufferCurrentPos;        
00061 
00062         UInt32 BlockAlign;              
00063         Int32 BlockAlignEssenceOffset;  
00064         Int32 BlockAlignIndexOffset;    
00065 
00066         //DRAGONS: There should probably be a property to say that in-memory values have changed?
00067         //DRAGONS: Should we have a flush() function
00068     public:
00069         RIP FileRIP;
00070         DataChunk RunIn;
00071         std::string Name;
00072 
00073     public:
00074         MXFFile() : isOpen(false), isMemoryFile(false), BlockAlign(0) {};
00075         ~MXFFile() { if(isOpen) Close(); };
00076 
00077         virtual bool Open(std::string FileName, bool ReadOnly = false );
00078         virtual bool OpenNew(std::string FileName);
00079         virtual bool OpenMemory(DataChunkPtr Buff = NULL, Position Offset = 0);
00080         virtual bool Close(void);
00081 
00082         bool ReadRunIn(void);
00083 
00084         // RIP Readers
00085         bool ReadRIP(void);
00086         bool ScanRIP(Length MaxScan = 1024*1024);
00087         bool BuildRIP(void);
00088         bool GetRIP(Length MaxScan = 1024*1024);
00089 
00090         
00092 
00094         PartitionPtr ReadMasterPartition(Length MaxScan = 1024*1024);
00095 
00097 
00099         PartitionPtr ReadFooterPartition(Length MaxScan = 1024*1024);
00100 
00102         Position Tell(void) 
00103         { 
00104             if(!isOpen) return 0;
00105             if(isMemoryFile) return BufferCurrentPos-RunInSize;
00106             return UInt64(mxflib::FileTell(Handle))-RunInSize;
00107         }
00108 
00110         /* \return 0 if no error, else non-zero
00111          * DRAGONS: This is where we need to insert code to handle file discontinuities
00112          *          If a file has one or more chunks mising then we can build a list of
00113          *          discontinuities based on where partition packs start compared with
00114          *          where in the file they claim to be. This allows us to modify seeks
00115          *          so that they find the data originally at that part of the file even
00116          *          though they are now in a different position
00117          */
00118         int Seek(Position Pos)
00119         { 
00120             if(!isOpen) return 0;
00121             if(isMemoryFile)
00122             {
00123                 BufferCurrentPos = Pos+RunInSize;
00124                 return 0;
00125             }
00126 
00127             return mxflib::FileSeek(Handle, Pos+RunInSize);
00128         }
00129 
00130         int SeekEnd(void)
00131         { 
00132             if(!isOpen) return 0;
00133             if(isMemoryFile)
00134             {
00135                 error("MXFFile::SeekEnd() not supported on memory files\n");
00136 
00137                 // Seek to the end of the current buffer
00138                 BufferCurrentPos = BufferOffset + Buffer->Size;
00139                 return (int)Tell();
00140             }
00141 
00142             return mxflib::FileSeekEnd(Handle);
00143         }
00144 
00145 
00147         bool Eof(void) 
00148         { 
00149             if(!isOpen) return true;
00150             if(isMemoryFile)
00151             {
00152                 error("MXFFile::Eof() not supported on memory files\n");
00153 
00154                 // Return true if at the end of the current buffer
00155                 if((BufferCurrentPos - BufferOffset) <= Buffer->Size) return true; else return false;
00156             }
00157         
00158             return mxflib::FileEof(Handle) ? true : false; 
00159         };
00160 
00161         DataChunkPtr Read(size_t Size);
00162         size_t Read(UInt8 *Buffer, size_t Size);
00163 
00164 //      MDObjectPtr ReadObject(void);
00165 //      template<class TP, class T> TP ReadObjectBase(void) { TP x; return x; };
00166 //      template<> MDObjectPtr ReadObjectBase<MDObjectPtr, MDObject>(void) { MDObjectPtr x; return x; };
00167         MDObjectPtr ReadObject(PrimerPtr UsePrimer = NULL) { return MXFFile__ReadObjectBase<MDObjectPtr, MDObject>(this, UsePrimer); };
00168         PartitionPtr ReadPartition(void) { return MXFFile__ReadObjectBase<PartitionPtr, Partition>(this); };
00169 
00171         KLVObjectPtr ReadKLV(void);
00172 
00174         void WritePartitionPack(PartitionPtr ThisPartition, PrimerPtr UsePrimer = NULL);
00175 
00177         void WritePartition(PartitionPtr ThisPartition, UInt32 Padding = 0, UInt32 MinPartitionSize = 0) { WritePartition(ThisPartition, true, NULL, Padding, MinPartitionSize); };
00178 
00180 
00181         void WritePartitionWithIndex(PartitionPtr ThisPartition, DataChunkPtr IndexData, UInt32 Padding = 0, UInt32 MinPartitionSize = 0) { WritePartitionWithIndex(ThisPartition, IndexData, true, NULL, Padding, MinPartitionSize); };
00182 
00184         void WritePartition(PartitionPtr ThisPartition, PrimerPtr UsePrimer, UInt32 Padding = 0, UInt32 MinPartitionSize = 0) { WritePartition(ThisPartition, true, UsePrimer, Padding, MinPartitionSize); };
00185 
00187 
00188         void WritePartitionWithIndex(PartitionPtr ThisPartition, DataChunkPtr IndexData, PrimerPtr UsePrimer, UInt32 Padding = 0, UInt32 MinPartitionSize = 0) { WritePartitionWithIndex(ThisPartition, IndexData, true, UsePrimer, Padding, MinPartitionSize); };
00189 
00191         void WritePartition(PartitionPtr ThisPartition, bool IncludeMetadata, PrimerPtr UsePrimer = NULL, UInt32 Padding = 0, UInt32 MinPartitionSize = 0)
00192         {
00193             WritePartitionInternal(false, ThisPartition, IncludeMetadata, NULL, UsePrimer, Padding, MinPartitionSize);
00194         }
00195 
00197 
00198         void WritePartitionWithIndex(PartitionPtr ThisPartition, DataChunkPtr IndexData, bool IncludeMetadata, PrimerPtr UsePrimer = NULL, UInt32 Padding = 0, UInt32 MinPartitionSize = 0)
00199         {
00200             WritePartitionInternal(false, ThisPartition, IncludeMetadata, IndexData, UsePrimer, Padding, MinPartitionSize);
00201         }
00202 
00204 
00207         bool ReWritePartition(PartitionPtr ThisPartition, PrimerPtr UsePrimer = NULL) 
00208         {
00209             return WritePartitionInternal(true, ThisPartition, true, NULL, UsePrimer, 0, 0);
00210         }
00211 
00213 
00216         bool ReWritePartitionWithIndex(PartitionPtr ThisPartition, DataChunkPtr IndexData, PrimerPtr UsePrimer = NULL) 
00217         {
00218             return WritePartitionInternal(true, ThisPartition, true, IndexData, UsePrimer, 0, 0);
00219         }
00220 
00221     protected:
00223         bool WritePartitionInternal(bool ReWrite, PartitionPtr ThisPartition, bool IncludeMetadata, DataChunkPtr IndexData, PrimerPtr UsePrimer, UInt32 Padding, UInt32 MinPartitionSize);
00224 
00225     public:
00227         void WriteRIP(void)
00228         {
00229             MDObjectPtr RIPObject = new MDObject(RandomIndexMetadata_UL);
00230             ASSERT(RIPObject);
00231 
00232             if(RIPObject)
00233             {
00234                 MDObjectPtr PA = RIPObject->AddChild(PartitionArray_UL);
00235 
00236                 ASSERT(PA);
00237                 if(PA)
00238                 {
00239                     RIP::iterator it = FileRIP.begin();
00240                     while(it != FileRIP.end())
00241                     {
00242                         PA->AddChild(BodySID_UL, false)->SetUInt((*it).second->BodySID);
00243                         PA->AddChild(ByteOffset_UL, false)->SetUInt64((*it).second->ByteOffset);
00244                         it++;
00245                     }
00246                 }
00247                 
00248                 // Calculate the pack length
00249                 RIPObject->SetUInt(Length_UL, 16 + 4 + (static_cast<UInt32>(FileRIP.size()) * 12) + 4);
00250 
00251                 DataChunkPtr Buffer = RIPObject->WriteObject();
00252 
00253                 Write(Buffer->Data, Buffer->Size);
00254             }
00255         }
00256 
00258         UInt32 FillerSize(UInt64 FillPos, UInt32 KAGSize, UInt32 MinSize = 0) { return FillerSize(false, FillPos, KAGSize, MinSize); };
00259         UInt32 FillerSize(bool ForceBER4, UInt64 FillPos, UInt32 KAGSize, UInt32 MinSize = 0);
00260 
00262         UInt64 Align(UInt32 KAGSize, UInt32 MinSize = 0) { return Align(false, KAGSize, MinSize); };
00263         UInt64 Align(bool ForceBER4, UInt32 KAGSize, UInt32 MinSize = 0);
00264 
00265         ULPtr ReadKey(void);
00266         Length ReadBER(void);
00267 
00269 
00274         UInt32 WriteBER(UInt64 Length, UInt32 Size = 0) { DataChunkPtr BER = MakeBER(Length, Size); Write(*BER); return static_cast<UInt32>(BER->Size); };
00275 
00277         size_t Write(const UInt8 *Buffer, size_t Size) 
00278         { 
00279             if(isMemoryFile) return MemoryWrite(Buffer, Size);
00280 
00281             return FileWrite(Handle, Buffer, Size); 
00282         };
00283 
00285         size_t Write(const DataChunk &Data) 
00286         { 
00287             if(isMemoryFile) return MemoryWrite(Data.Data, Data.Size);
00288 
00289             return FileWrite(Handle, Data.Data, Data.Size); 
00290         };
00291 
00293         size_t Write(DataChunkPtr Data)
00294         { 
00295             if(isMemoryFile) return MemoryWrite(Data->Data, Data->Size);
00296 
00297             return static_cast<size_t>(FileWrite(Handle, Data->Data, Data->Size)); 
00298         };
00299 
00301         void WriteU8(UInt8 Val) { unsigned char Buffer[1]; PutU8(Val, Buffer); Write(Buffer, 1); }
00302 
00304         void WriteU16(UInt16 Val) { unsigned char Buffer[2]; PutU16(Val, Buffer); Write(Buffer, 2); }
00305 
00307         void WriteU32(UInt32 Val) { unsigned char Buffer[4]; PutU32(Val, Buffer); Write(Buffer, 4); }
00308 
00310         void WriteU64(UInt64 Val) { unsigned char Buffer[8]; PutU64(Val, Buffer); Write(Buffer, 8); }
00311 
00313         void WriteI8(Int8 Val) { unsigned char Buffer[1]; PutI8(Val, Buffer); Write(Buffer, 1); }
00314 
00316         void WriteI16(Int16 Val) { unsigned char Buffer[2]; PutI16(Val, Buffer); Write(Buffer, 2); }
00317 
00319         void WriteI32(Int32 Val) { unsigned char Buffer[4]; PutI32(Val, Buffer); Write(Buffer, 4); }
00320 
00322         void WriteI64(Int64 Val) { unsigned char Buffer[8]; PutI64(Val, Buffer); Write(Buffer, 8); }
00323 
00325         UInt8 ReadU8(void) { unsigned char Buffer[1]; if(Read(Buffer, 1) == 1) return GetU8(Buffer); else return 0; }
00326 
00328         UInt16 ReadU16(void) { unsigned char Buffer[2]; if(Read(Buffer, 2) == 2) return GetU16(Buffer); else return 0; }
00329 
00331         UInt32 ReadU32(void) { unsigned char Buffer[4]; if(Read(Buffer, 4) == 4) return GetU32(Buffer); else return 0; }
00332 
00334         UInt64 ReadU64(void) { unsigned char Buffer[8]; if(Read(Buffer, 8) == 8) return GetU64(Buffer); else return 0; }
00335 
00337         Int8 ReadI8(void) { return (Int8)ReadU8(); }
00338 
00340         Int16 ReadI16(void) { return (Int16)ReadU16(); }
00341         
00343         Int32 ReadI32(void) { return (Int32)ReadU32(); }
00344         
00346         Int64 ReadI64(void) { return (Int64)ReadU64(); }
00347 
00348         // Set a new buffer into this memory file
00349         void SetMemoryBuffer(DataChunkPtr Buff, UInt32 Offset)
00350         {
00351             if(isMemoryFile)
00352             {
00353                 Buffer = Buff;
00354                 BufferOffset = Offset;
00355             }
00356         }
00357 
00359         void SetBlockAlign(UInt32 Size, Int32 EssenceOffset = 0, Int32 IndexOffset = 0)
00360         {
00361             BlockAlign = Size;
00362             BlockAlignEssenceOffset = EssenceOffset;
00363             BlockAlignIndexOffset = IndexOffset;
00364         }
00365 
00367         bool IsBlockAligned(void) { return (BlockAlign != 0); }
00368 
00369     protected:
00370         Position ScanRIP_FindFooter(Length MaxScan);
00371 
00373 
00374         virtual size_t MemoryWrite(UInt8 const *Data, size_t Size);
00375 
00377 
00378         virtual size_t MemoryRead(UInt8 *Data, size_t Size);
00379     };
00380 }
00381 
00382 
00383 // DRAGONS: MSVC: Why does this work in a header, but not in the file?
00384 template<class TP, class T> /*inline*/ TP mxflib::MXFFile__ReadObjectBase(MXFFilePtr This, PrimerPtr UsePrimer /*=NULL*/)
00385 {
00386     TP Ret;
00387 
00388     UInt64 Location = This->Tell();
00389     ULPtr Key = This->ReadKey();
00390 
00391     // If we couldn't read the key then bug out
00392     if(!Key) return Ret;
00393 
00394     // Build the object (it may come back as an "unknown")
00395     Ret = new T(Key);
00396 
00397     ASSERT(Ret);
00398 
00399     Length Length = This->ReadBER();
00400     if((sizeof(size_t) < 8) && Length > 0xffffffff)
00401     {
00402         error("Maximum read size on this platform is 4Gbytes - However, requested to read object %s at 0x%s which has size of 0x%s\n",
00403               Ret->Name().c_str(), Int64toHexString(Location,8).c_str(), Int64toHexString(Length,8).c_str());
00404 
00405         // Skip over the item
00406         This->Seek(This->Tell() + Length);
00407 
00408         // Return an empty object
00409         return Ret;
00410     }
00411 
00412     if(Length > 0)
00413     {
00414         // Work out how big the key and length are in the file
00415         UInt32 KLSize = static_cast<UInt32>(This->Tell() - Location);
00416 
00417         // Read the actual data
00418         DataChunkPtr Data = This->Read(static_cast<size_t>(Length));
00419 
00420         if(Data->Size != static_cast<size_t>(Length))
00421         {
00422             error("Not enough data in file for object %s at 0x%s\n", Ret->Name().c_str(), Int64toHexString(Location,8).c_str());
00423         }
00424 
00425         Ret->SetParent(This, Location, KLSize);
00426         Ret->ReadValue(Data->Data, Data->Size, UsePrimer);
00427     }
00428 
00429     return Ret;
00430 }
00431 
00432 #endif // MXFLIB__MXFFILE_H
00433 

Generated on Mon Apr 2 15:20:53 2007 for MXFLib by  doxygen 1.5.1-p1