/* Copyright (c) MediaArea.net SARL. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license that can
* be found in the License.html file in the root of the source tree.
*/
//---------------------------------------------------------------------------
// Pre-compilation
#include "MediaInfo/PreComp.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include "MediaInfo/Setup.h"
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#if defined(MEDIAINFO_AAF_YES)
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include "MediaInfo/Multiple/File_Aaf.h"
#include "MediaInfo/Multiple/File__ReferenceFilesHelper.h"
#include "MediaInfo/MediaInfo_Config_MediaInfo.h"
#include "ZenLib/FileName.h"
#if defined(MEDIAINFO_REFERENCES_YES)
#include "ZenLib/File.h"
#endif //defined(MEDIAINFO_REFERENCES_YES)
#include "tinyxml2.h"
using namespace ZenLib;
using namespace tinyxml2;
//---------------------------------------------------------------------------
namespace MediaInfoLib
{
//***************************************************************************
// Info
//***************************************************************************
static const char* AAf_tagSTGTY (int8u tagSTGTY)
{
switch (tagSTGTY)
{
case 0 : return "unknown";
case 1 : return "storage";
case 2 : return "stream";
case 3 : return "ILockBytes";
case 4 : return "IPropertyStorage";
case 5 : return "root";
default: return "";
}
}
static const char* AAf_tagDECOLOR (int8u tagDECOLOR)
{
switch (tagDECOLOR)
{
case 0 : return "red";
case 1 : return "black";
default: return "";
}
}
//***************************************************************************
// Constructor/Destructor
//***************************************************************************
//---------------------------------------------------------------------------
File_Aaf::File_Aaf()
:File__Analyze(), File__HasReferences()
{
#if MEDIAINFO_EVENTS
ParserIDs[0]=MediaInfo_Parser_Aaf;
StreamIDs_Width[0]=16;
#endif //MEDIAINFO_EVENTS
}
//---------------------------------------------------------------------------
File_Aaf::~File_Aaf()
{
for (size_t Pos=0; Pos<Streams.size(); Pos++)
delete Streams[Pos];
}
//***************************************************************************
// Buffer - File header
//***************************************************************************
//---------------------------------------------------------------------------
bool File_Aaf::FileHeader_Begin()
{
if (File_Size<0x100)
{
Reject("Aaf");
return false;
}
//Element_Size
if (Buffer_Size<0x18)
return false; //Must wait for more data
if (Buffer[ 0x0]!=0xD0
|| Buffer[ 0x1]!=0xCF
|| Buffer[ 0x2]!=0x11
|| Buffer[ 0x3]!=0xE0
|| Buffer[ 0x4]!=0xA1
|| Buffer[ 0x5]!=0xB1
|| Buffer[ 0x6]!=0x1A
|| Buffer[ 0x7]!=0xE1
|| Buffer[ 0x8]!=0x41
|| Buffer[ 0x9]!=0x41
|| Buffer[ 0xA]!=0x46
|| Buffer[ 0xB]!=0x42
|| Buffer[ 0xC]!=0x0D
|| Buffer[ 0xD]!=0x00
|| Buffer[ 0xE]!=0x4F
|| Buffer[ 0xF]!=0x4D
|| Buffer[0x10]!=0x06
|| Buffer[0x11]!=0x0E
|| Buffer[0x12]!=0x2B
|| Buffer[0x13]!=0x34
|| Buffer[0x14]!=0x01
|| Buffer[0x15]!=0x01
|| Buffer[0x16]!=0x01
|| Buffer[0x17]!=0xFF)
{
Reject("Aaf");
return false;
}
//Element_Size
if (Buffer_Size<File_Size)
return false; //Must wait for more data
//Accept the file
Accept("Aaf");
Fill(Stream_General, 0, General_Format, "AAF");
Step=Step_None;
ReferenceFiles_Accept(this, Config);
//All should be OK...
return true;
}
//---------------------------------------------------------------------------
void File_Aaf::Read_Buffer_Continue()
{
if (File_Offset || Buffer_Offset)
return;
//Parsing
Element_Begin1("Header");
int32u csectFat;
int16u DllVersion, ByteOrder;
Skip_B8( "abSig");
Skip_B16( "clsid");
Skip_L2( "MinorVersion");
Get_L2 (DllVersion, "DllVersion");
Get_L2 (ByteOrder, "ByteOrder");
Get_L2 (SectorShift, "SectorShift");
Get_L2 (MiniSectorShift, "MiniSectorShift");
Skip_L2( "Reserved");
Skip_L4( "Reserved");
Skip_L4( "csectDir");
Get_L4 (csectFat, "csectFat");
Get_L4 (sectDirStart, "sectDirStart");
Skip_L4( "signature");
Get_L4 (MiniSectorCutoff, "MiniSectorCutoff");
Get_L4 (sectMiniFatStart, "sectMiniFatStart");
Skip_L4( "csectMiniFat");
Skip_L4( "sectDifStart");
Skip_L4( "sectDif");
Element_Begin1("sectFat");
for (int16u Pos=0; Pos<(csectFat>109?109:csectFat); Pos++)
{
int32u sectFat;
Get_L4 (sectFat, "sectFat");
sectsFat.push_back(sectFat);
}
if (csectFat<109)
Skip_XX((109-csectFat)*4, "unused sectsFat");
Element_End();
Element_End();
FILLING_BEGIN();
Fill("Aaf");
Step=Step_Fat;
sectsFat_Pos=0;
if (sectsFat.empty())
{
Finish();
}
else
GoTo((1+sectsFat[0])*(1<<SectorShift));
FILLING_END();
}
//***************************************************************************
// Buffer - Per element
//***************************************************************************
//---------------------------------------------------------------------------
void File_Aaf::Header_Parse()
{
switch (Step)
{
case Step_Fat : Header_Fill_Code(0, "FAT");
Header_Fill_Size(((int64u)1) << SectorShift);
break;
case Step_MiniFat : Header_Fill_Code(0, "MiniFAT");
Header_Fill_Size(((int64u)1) << SectorShift);
break;
case Step_Directory : Header_Fill_Code(0, "Directory");
Header_Fill_Size(((int64u)1) << SectorShift);
break;
case Step_Stream : Header_Fill_Code(0, "Stream");
Header_Fill_Size(((int64u)1) << (Streams[0]->Size<MiniSectorCutoff ? MiniSectorShift : SectorShift));
break;
default : ;
}
}
//---------------------------------------------------------------------------
void File_Aaf::Data_Parse()
{
//Parsing
switch (Step)
{
case Step_Fat : Fat(); return;
case Step_MiniFat : MiniFat(); break;
case Step_Directory : Directory(); break;
case Step_Stream : StreamElement(); return;
default : Skip_XX(Element_Size, "Unknown");
}
size_t Pointers_Pos=(size_t)((File_Offset+Buffer_Offset)>>SectorShift)-1;
if (Pointers_Pos<Pointers.size())
{
if (Pointers[Pointers_Pos]<0xFFFFFFF0)
GoTo((1+Pointers[Pointers_Pos])*(1<<SectorShift));
else if (Step==Step_MiniFat)
{
Step=Step_Directory;
Directory_Pos=0;
GoTo((1+sectDirStart)*(1<<SectorShift));
}
else if (Step==Step_Directory)
{
Step=Step_Stream;
if (Streams.empty())
Finish();
else
{
Streams_Pos=0;
Streams_Pos2=0;
GoTo(Streams[0]->StreamOffsets[0]);
}
}
else
Finish();
}
else
Finish();
}
//---------------------------------------------------------------------------
void File_Aaf::Fat()
{
//Parsing
while (Element_Offset<Element_Size)
{
int32u Pointer;
Get_L4 (Pointer, "Pointer"); Param_Info1(Ztring::ToZtring(Pointers.size()));
//Pointer=LittleEndian2int32u(Buffer+Buffer_Offset+(size_t)Element_Offset);
//Element_Offset+=4;
Pointers.push_back(Pointer);
}
//Next FAT sector or next step
sectsFat_Pos++;
if (sectsFat_Pos<sectsFat.size())
GoTo((1+sectsFat[sectsFat_Pos])*(1<<SectorShift));
else
{
Step=Step_MiniFat;
GoTo((1+sectMiniFatStart)*(1<<SectorShift));
}
}
//---------------------------------------------------------------------------
void File_Aaf::MiniFat()
{
//Parsing
while (Element_Offset<Element_Size)
{
int32u Pointer;
Get_L4 (Pointer, "Pointer"); Param_Info1(Ztring::ToZtring(MiniPointers.size()));
//Pointer=LittleEndian2int32u(Buffer+Buffer_Offset+(size_t)Element_Offset);
//Element_Offset+=4;
MiniPointers.push_back(Pointer);
}
}
//---------------------------------------------------------------------------
void File_Aaf::Directory()
{
//Parsing
while (Element_Offset<Element_Size)
Directory_Entry();
}
//---------------------------------------------------------------------------
void File_Aaf::Directory_Entry()
{
//Parsing
Element_Begin1("Directory entry");
Element_Info1(Directory_Pos);
Ztring ab;
int64u Size;
int32u SectStart;
int8u mse;
Get_UTF16L(64, ab, "ab"); Element_Info1(ab);
Skip_L2( "cb");
Get_L1 (mse, "mse"); Element_Info1(AAf_tagSTGTY(mse));
Info_L1(flags, "flags"); Element_Info1(AAf_tagDECOLOR(flags));
Skip_L4( "LeftSib SID");
Skip_L4( "RightSib SID");
Skip_L4( mse==2?"0":"Child SID"); //Zero if stream
Skip_L16( mse==2?"0":"clsId");//Zero if stream
Skip_L4( "UserFlags");
Info_L8(CreationTime, mse==2?"0":"Create time"); if (mse!=2) {Param_Info1(CreationTime?Ztring().Date_From_Milliseconds_1601(CreationTime/10000):Ztring());} //Zero if stream
Info_L8(ModificationTime, mse==2?"0":"Modify time"); if (mse!=2) {Param_Info1(CreationTime?Ztring().Date_From_Milliseconds_1601(ModificationTime/10000):Ztring());} //Zero if stream
Get_L4 (SectStart, mse==1?"0":"SectStart"); //Zero if storage
if (SectorShift<=9)
{
int32u Size32;
Get_L4 (Size32, mse==1?"0":"Size"); //Zero if storage
Skip_L4( "PropType");
Size=Size32;
}
else
{
Get_L8 (Size, mse==1?"0":"Size"); //Zero if storage
}
if (mse==5 && Size) //If root
{
//Building sectMiniFats_FatPointers
int32u Pointers_Pos=SectStart;
while (Pointers_Pos<Pointers.size())
{
Param_Info1(Ztring::ToZtring(Pointers_Pos<<SectorShift));
sectsMiniStream.push_back(Pointers_Pos);
Pointers_Pos=Pointers[Pointers_Pos];
}
}
else if (mse==2 && Size) //If stream
{
Param_Info1("StreamOffset");
stream* Stream = new stream(
ab,
Directory_Pos,
Size
);
if (Size<MiniSectorCutoff) //MiniFAT
{
int32u Pointers_Pos=SectStart;
while (Pointers_Pos<MiniPointers.size())
{
int32u SectPos=Pointers_Pos>>(SectorShift-MiniSectorShift);
int32u MiniSectPos=Pointers_Pos&((((size_t)1)<<(SectorShift-MiniSectorShift))-1);
Stream->StreamOffsets.push_back(((1+sectsMiniStream[SectPos])<<SectorShift)+(MiniSectPos<<MiniSectorShift));
Param_Info1(Ztring::ToZtring(((1+sectsMiniStream[SectPos])<<SectorShift)+(MiniSectPos<<MiniSectorShift)));
Pointers_Pos=MiniPointers[Pointers_Pos];
}
}
else //FAT
{
int32u Pointers_Pos=SectStart;
while (Pointers_Pos<Pointers.size())
{
Stream->StreamOffsets.push_back((1+Pointers_Pos)<<SectorShift);
Param_Info1(Ztring::ToZtring((1+Pointers_Pos)<<SectorShift));
Pointers_Pos=Pointers[Pointers_Pos];
}
}
Streams.push_back(Stream);
}
Element_End0();
Directory_Pos++;
}
//---------------------------------------------------------------------------
void File_Aaf::StreamElement()
{
if (Streams_Pos>=Streams.size() || Streams[Streams_Pos]->Size>=0x1000000) //TODO: more serious test about size
return; //Incoherancy
//Saving data
if (Streams[Streams_Pos]->StreamOffsets.size()!=1)
{
Skip_XX(Element_Size, "Stream data");
int16u Shift=(Streams[Streams_Pos]->Size<MiniSectorCutoff?MiniSectorShift:SectorShift);
if (Streams[Streams_Pos]->Buffer==NULL)
Streams[Streams_Pos]->Buffer=new int8u[(size_t)((1+(Streams[Streams_Pos]->Size>>Shift))<<Shift)];
memcpy(Streams[Streams_Pos]->Buffer+Streams_Pos2*(((int64u)1)<<Shift), Buffer+Buffer_Offset, (size_t)Element_Size);
}
//Next Element
Streams_Pos2++;
if (Streams_Pos2>=Streams[Streams_Pos]->StreamOffsets.size())
{
Element_Offset=0;
StreamElement_Parse();
Streams_Pos++;
Streams_Pos2=0;
}
if (Streams_Pos<Streams.size())
GoTo(Streams[Streams_Pos]->StreamOffsets[Streams_Pos2]);
else
Finish();
}
//---------------------------------------------------------------------------
void File_Aaf::StreamElement_Parse()
{
//Searching emulation_prevention_three_byte
const int8u* Save_Buffer=Buffer;
int64u Save_File_Offset=File_Offset;
size_t Save_Buffer_Offset=Buffer_Offset;
int64u Save_Element_Size=Element_Size;
if (Streams[Streams_Pos]->Buffer)
{
//We must change the buffer for keeping out
Element_Size=Streams[Streams_Pos]->Size;
File_Offset=Streams[Streams_Pos]->StreamOffsets[0];
Buffer_Offset=0;
Buffer=Streams[Streams_Pos]->Buffer;
}
//Parsing
Element_Info1(Streams[Streams_Pos]->Directory_Pos);
Element_Info1(Streams[Streams_Pos]->Name);
int16u Count;
Skip_L2( "0x204C?");
Get_L2 (Count, "Count");
vector<int16u> Sizes;
vector<int16u> Keys;
for (int16u Pos=0; Pos<Count; Pos++)
{
int16u Key, Size;
Get_L2 (Key, "Key");
Skip_L2( "Flags?");
Get_L2 (Size, "Size");
Sizes.push_back(Size);
Keys.push_back(Key);
}
#define ELEMENT(_ELEMENT, _NAME) \
for (int16u Pos=0; Pos<Count; Pos++)
{
Element_Begin0();
xxxSize=Sizes[Pos];
switch (Keys[Pos])
{
case 0x0001 : Element_Name("MetaDictionary"); MetaDictionary(); break;
case 0x0002 : Element_Name("Header"); Header(); break;
case 0x0003 : Element_Name("ClassDefinitions"); ClassDefinitions(); break;
case 0x0004 : Element_Name("TypeDefinitions"); TypeDefinitions(); break;
case 0x0005 : Element_Name("Identification"); Identification(); break;
case 0x0006 : Element_Name("Name"); Name(); break;
case 0x0007 : Element_Name("MetaDefinition"); MetaDefinition(); break;
case 0x0008 : Element_Name("ParentClass"); ParentClass(); break;
case 0x0009 : Element_Name("Properties"); Properties(); break;
case 0x000A : Element_Name("IsConcrete"); IsConcrete(); break;
case 0x000B : Element_Name("Type"); Type(); break;
case 0x000C : Element_Name("IsOptional"); IsOptional(); break;
case 0x000D : Element_Name("LocalIdentification"); LocalIdentification(); break;
case 0x000E : Element_Name("IsUniqueIdentifier"); IsUniqueIdentifier(); break;
case 0x000F : Element_Name("Size"); Size(); break;
case 0x3D02 : Element_Name("Locked"); Locked(); break;
case 0x4001 : Element_Name("NetworkLocator"); NetworkLocator(); break;
default : Skip_XX(xxxSize, "Unknown");
}
Element_End0();
}
//
if (Streams[Streams_Pos]->Buffer)
{
//We must change the buffer for keeping out
Element_Size=Save_Element_Size;
File_Offset=Save_File_Offset;
Buffer_Offset=Save_Buffer_Offset;
delete[] Buffer; Buffer=Save_Buffer;
Element_Offset=Element_Size;
}
}
//---------------------------------------------------------------------------
void File_Aaf::MetaDictionary()
{
Skip_UTF16L(xxxSize, "Data");
}
//---------------------------------------------------------------------------
void File_Aaf::Header()
{
Skip_UTF16L(xxxSize, "Data");
}
//---------------------------------------------------------------------------
void File_Aaf::ClassDefinitions()
{
Skip_UTF16L(xxxSize, "Data");
}
//---------------------------------------------------------------------------
void File_Aaf::TypeDefinitions()
{
Skip_UTF16L(xxxSize, "Data");
}
//---------------------------------------------------------------------------
void File_Aaf::Identification()
{
Skip_B8( "Part2");
Skip_B8( "Part1");
}
//---------------------------------------------------------------------------
void File_Aaf::Name()
{
Skip_UTF16L(xxxSize, "Data");
}
//---------------------------------------------------------------------------
void File_Aaf::MetaDefinition()
{
Skip_UTF16L(xxxSize, "Data");
}
//---------------------------------------------------------------------------
void File_Aaf::ParentClass()
{
Skip_B5( "WeakReference");
Skip_B8( "Part2");
Skip_B8( "Part1");
}
//---------------------------------------------------------------------------
void File_Aaf::Properties()
{
Skip_UTF16L(xxxSize, "Data");
}
//---------------------------------------------------------------------------
void File_Aaf::IsConcrete()
{
Skip_L1( "Data");
}
//---------------------------------------------------------------------------
void File_Aaf::Type()
{
Skip_B8( "Part2");
Skip_B8( "Part1");
}
//---------------------------------------------------------------------------
void File_Aaf::IsOptional()
{
Skip_L1( "Data");
}
//---------------------------------------------------------------------------
void File_Aaf::LocalIdentification()
{
Skip_L2( "Data");
}
//---------------------------------------------------------------------------
void File_Aaf::IsUniqueIdentifier()
{
Skip_L1( "Data");
}
//---------------------------------------------------------------------------
void File_Aaf::Size()
{
Skip_L1( "Data");
}
//---------------------------------------------------------------------------
void File_Aaf::Locked()
{
Skip_L1( "Data");
//Descriptors[Streams[Streams_Pos]->Directory_Pos].StreamKind=Stream_Audio;
}
//---------------------------------------------------------------------------
void File_Aaf::NetworkLocator()
{
Ztring Data;
Get_UTF16L(xxxSize, Data, "Data");
#if defined(MEDIAINFO_REFERENCES_YES)
sequence* Sequence=new sequence;
Sequence->AddFileName(Data);
ReferenceFiles->AddSequence(Sequence);
#endif //MEDIAINFO_REFERENCES_YES
//Locators[Streams[Streams_Pos]->Directory_Pos].EssenceLocator=Data;
}
} //NameSpace
#endif //MEDIAINFO_AAF_YES
↑ V524 It is odd that the body of 'Type' function is fully equivalent to the body of 'Identification' function.
↑ V525 The code contains the collection of similar blocks. Check items '2', '4', '4' in lines 166, 167, 168.
↑ V525 The code contains the collection of similar blocks. Check items '5', '8', '8' in lines 554, 555, 556.
↑ V688 The 'Stream' local variable possesses the same name as one of the class members, which can result in a confusion.
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: xxxSize, SectorShift, MiniSectorShift, sectMiniFatStart, sectDirStart, MiniSectorCutoff, ...