00001
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #ifndef MXFLIB__MXFFILE_H
00033 #define MXFLIB__MXFFILE_H
00034
00035
00036
00037 #include <algorithm>
00038
00039
00040
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
00067
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
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
00111
00112
00113
00114
00115
00116
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
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
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
00165
00166
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
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
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
00384 template<class TP, class T> TP mxflib::MXFFile__ReadObjectBase(MXFFilePtr This, PrimerPtr UsePrimer )
00385 {
00386 TP Ret;
00387
00388 UInt64 Location = This->Tell();
00389 ULPtr Key = This->ReadKey();
00390
00391
00392 if(!Key) return Ret;
00393
00394
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
00406 This->Seek(This->Tell() + Length);
00407
00408
00409 return Ret;
00410 }
00411
00412 if(Length > 0)
00413 {
00414
00415 UInt32 KLSize = static_cast<UInt32>(This->Tell() - Location);
00416
00417
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