2012-06-30 04:45:25 -07:00
/*
* HLLib
* Copyright ( C ) 2006 - 2010 Ryan Gregg
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later
* version .
*/
# include "HLLib.h"
# include "XZPFile.h"
# include "Streams.h"
using namespace HLLib ;
const char * CXZPFile : : lpAttributeNames [ ] = { " Version " , " Preload Bytes " } ;
const char * CXZPFile : : lpItemAttributeNames [ ] = { " Created " , " Preload Bytes " } ;
CXZPFile : : CXZPFile ( ) : CPackage ( ) , pHeaderView ( 0 ) , pDirectoryEntryView ( 0 ) , pDirectoryItemView ( 0 ) , pFooterView ( 0 ) , pHeader ( 0 ) , lpDirectoryEntries ( 0 ) , lpPreloadDirectoryEntries ( 0 ) , lpPreloadDirectoryMappings ( 0 ) , lpDirectoryItems ( 0 ) , pFooter ( 0 )
{
}
CXZPFile : : ~ CXZPFile ( )
{
this - > Close ( ) ;
}
HLPackageType CXZPFile : : GetType ( ) const
{
return HL_PACKAGE_XZP ;
}
const hlChar * CXZPFile : : GetExtension ( ) const
{
return " xzp " ;
}
const hlChar * CXZPFile : : GetDescription ( ) const
{
return " XBox Package File " ;
}
hlBool CXZPFile : : MapDataStructures ( )
{
if ( sizeof ( XZPHeader ) > this - > pMapping - > GetMappingSize ( ) )
{
LastError . SetErrorMessage ( " Invalid file: the file map is too small for it's header. " ) ;
return hlFalse ;
}
if ( ! this - > pMapping - > Map ( this - > pHeaderView , 0 , sizeof ( XZPHeader ) ) )
{
return hlFalse ;
}
this - > pHeader = ( XZPHeader * ) this - > pHeaderView - > GetView ( ) ;
if ( memcmp ( this - > pHeader - > lpSignature , " piZx " , 4 ) ! = 0 )
{
LastError . SetErrorMessage ( " Invalid file: the file's header signature does not match. " ) ;
return hlFalse ;
}
if ( this - > pHeader - > uiVersion ! = 6 )
{
LastError . SetErrorMessageFormated ( " Invalid XZP version (v%u): you have a version of a XZP file that HLLib does not know how to read. Check for product updates. " , this - > pHeader - > uiVersion ) ;
return hlFalse ;
}
if ( this - > pHeader - > uiHeaderLength ! = sizeof ( XZPHeader ) )
{
LastError . SetErrorMessage ( " Invalid file: the file's header size does not match. " ) ;
return hlFalse ;
}
if ( ! this - > pMapping - > Map ( this - > pDirectoryEntryView , sizeof ( XZPHeader ) , this - > pHeader - > uiPreloadBytes ? ( this - > pHeader - > uiDirectoryEntryCount + this - > pHeader - > uiPreloadDirectoryEntryCount ) * sizeof ( XZPDirectoryEntry ) + this - > pHeader - > uiDirectoryEntryCount * sizeof ( XZPDirectoryMapping ) : this - > pHeader - > uiDirectoryEntryCount * sizeof ( XZPDirectoryEntry ) ) )
{
return hlFalse ;
}
this - > lpDirectoryEntries = ( XZPDirectoryEntry * ) this - > pDirectoryEntryView - > GetView ( ) ;
this - > lpPreloadDirectoryEntries = this - > pHeader - > uiPreloadBytes ? this - > lpDirectoryEntries + this - > pHeader - > uiDirectoryEntryCount : 0 ;
this - > lpPreloadDirectoryMappings = this - > pHeader - > uiPreloadBytes ? ( XZPDirectoryMapping * ) ( this - > lpPreloadDirectoryEntries + this - > pHeader - > uiPreloadDirectoryEntryCount ) : 0 ;
if ( this - > pHeader - > uiDirectoryItemCount ! = 0 )
{
if ( ! this - > pMapping - > Map ( this - > pDirectoryItemView , this - > pHeader - > uiDirectoryItemOffset , this - > pHeader - > uiDirectoryItemLength ) )
{
return hlFalse ;
}
this - > lpDirectoryItems = ( XZPDirectoryItem * ) this - > pDirectoryItemView - > GetView ( ) ;
}
if ( ! this - > pMapping - > Map ( this - > pFooterView , this - > pMapping - > GetMappingSize ( ) - sizeof ( XZPFooter ) , sizeof ( XZPFooter ) ) )
{
return hlFalse ;
}
this - > pFooter = ( XZPFooter * ) this - > pFooterView - > GetView ( ) ;
if ( memcmp ( this - > pFooter - > lpSignature , " tFzX " , 4 ) ! = 0 )
{
LastError . SetErrorMessage ( " Invalid file: the file's footer signature does not match. " ) ;
return hlFalse ;
}
if ( this - > pFooter - > uiFileLength ! = this - > pMapping - > GetMappingSize ( ) )
{
LastError . SetErrorMessage ( " Invalid file: the file map is not within mapping bounds. " ) ;
return hlFalse ;
}
return hlTrue ;
}
hlVoid CXZPFile : : UnmapDataStructures ( )
{
this - > pFooter = 0 ;
this - > pMapping - > Unmap ( this - > pFooterView ) ;
this - > lpDirectoryItems = 0 ;
this - > pMapping - > Unmap ( this - > pDirectoryItemView ) ;
this - > lpDirectoryEntries = 0 ;
this - > lpPreloadDirectoryEntries = 0 ;
this - > lpPreloadDirectoryMappings = 0 ;
this - > pMapping - > Unmap ( this - > pDirectoryEntryView ) ;
this - > pHeader = 0 ;
this - > pMapping - > Unmap ( this - > pHeaderView ) ;
}
CDirectoryFolder * CXZPFile : : CreateRoot ( )
{
CDirectoryFolder * pRoot = new CDirectoryFolder ( this ) ;
if ( this - > pHeader - > uiDirectoryItemCount ! = 0 )
{
// Loop through each file in the XZP file.
for ( hlUInt i = 0 ; i < this - > pHeader - > uiDirectoryEntryCount ; i + + )
{
// Find it's info (file name).
for ( hlUInt j = 0 ; j < this - > pHeader - > uiDirectoryItemCount ; j + + )
{
if ( this - > lpDirectoryEntries [ i ] . uiFileNameCRC = = this - > lpDirectoryItems [ j ] . uiFileNameCRC )
{
hlChar lpFileName [ 256 ] ;
strncpy ( lpFileName , ( hlChar * ) this - > lpDirectoryItems + this - > lpDirectoryItems [ j ] . uiNameOffset - this - > pHeader - > uiDirectoryItemOffset , sizeof ( lpFileName ) ) ;
lpFileName [ sizeof ( lpFileName ) - 1 ] = ' \0 ' ;
// Check if we have just a file, or if the file has directories we need to create.
if ( strchr ( lpFileName , ' / ' ) = = 0 & & strchr ( lpFileName , ' \\ ' ) = = 0 )
{
pRoot - > AddFile ( lpFileName , i ) ;
}
else
{
// Tokenize the file path and create the directories.
CDirectoryFolder * pInsertFolder = pRoot ;
hlChar lpTemp [ 256 ] = " " ;
hlChar * lpToken = strtok ( lpFileName , " / \\ " ) ;
while ( lpToken ! = 0 )
{
strcpy ( lpTemp , lpToken ) ;
lpToken = strtok ( 0 , " / \\ " ) ;
if ( lpToken ! = 0 )
{
// Check if the directory exists.
CDirectoryItem * pItem = pInsertFolder - > GetItem ( lpTemp ) ;
if ( pItem = = 0 | | pItem - > GetType ( ) = = HL_ITEM_FILE )
{
// It doesn't, create it.
pInsertFolder = pInsertFolder - > AddFolder ( lpTemp ) ;
}
else
{
// It does, use it.
pInsertFolder = static_cast < CDirectoryFolder * > ( pItem ) ;
}
}
}
// The file name is the last token, add it.
pInsertFolder - > AddFile ( lpTemp , i ) ;
}
break ;
}
}
}
}
else
{
// No file name information, just file name CRCs.
for ( hlUInt i = 0 ; i < this - > pHeader - > uiDirectoryEntryCount ; i + + )
{
hlChar lpTemp [ 16 ] = " " ;
2012-06-30 04:55:49 -07:00
const hlChar * lpLookup [ ] = { " 0 " , " 1 " , " 2 " , " 3 " , " 4 " , " 5 " , " 6 " , " 7 " , " 8 " , " 9 " , " a " , " b " , " c " , " d " , " e " , " f " } ;
2012-06-30 04:45:25 -07:00
for ( hlByte * lpCRC = ( hlByte * ) & this - > lpDirectoryEntries [ i ] . uiFileNameCRC ; lpCRC < ( hlByte * ) & this - > lpDirectoryEntries [ i ] . uiFileNameCRC + sizeof ( hlUInt ) ; lpCRC + + )
{
strcat ( lpTemp , lpLookup [ ( hlByte ) ( * lpCRC > > 4 ) ] ) ;
strcat ( lpTemp , lpLookup [ ( hlByte ) ( * lpCRC & 0x0F ) ] ) ;
}
pRoot - > AddFile ( lpTemp , i ) ;
}
}
return pRoot ;
}
hlUInt CXZPFile : : GetAttributeCountInternal ( ) const
{
return HL_XZP_PACKAGE_COUNT ;
}
const hlChar * CXZPFile : : GetAttributeNameInternal ( HLPackageAttribute eAttribute ) const
{
if ( eAttribute < HL_XZP_PACKAGE_COUNT )
{
return this - > lpAttributeNames [ eAttribute ] ;
}
return 0 ;
}
hlBool CXZPFile : : GetAttributeInternal ( HLPackageAttribute eAttribute , HLAttribute & Attribute ) const
{
switch ( eAttribute )
{
case HL_XZP_PACKAGE_VERSION :
hlAttributeSetUnsignedInteger ( & Attribute , this - > lpAttributeNames [ eAttribute ] , this - > pHeader - > uiVersion , hlFalse ) ;
return hlTrue ;
case HL_XZP_PACKAGE_PRELOAD_BYTES :
hlAttributeSetUnsignedInteger ( & Attribute , this - > lpAttributeNames [ eAttribute ] , this - > pHeader - > uiPreloadBytes , hlFalse ) ;
return hlTrue ;
default :
return hlFalse ;
}
}
hlUInt CXZPFile : : GetItemAttributeCountInternal ( ) const
{
return HL_XZP_ITEM_COUNT ;
}
const hlChar * CXZPFile : : GetItemAttributeNameInternal ( HLPackageAttribute eAttribute ) const
{
if ( eAttribute < HL_XZP_ITEM_COUNT )
{
return this - > lpItemAttributeNames [ eAttribute ] ;
}
return 0 ;
}
hlBool CXZPFile : : GetItemAttributeInternal ( const CDirectoryItem * pItem , HLPackageAttribute eAttribute , HLAttribute & Attribute ) const
{
switch ( pItem - > GetType ( ) )
{
case HL_ITEM_FILE :
{
const CDirectoryFile * pFile = static_cast < const CDirectoryFile * > ( pItem ) ;
const XZPDirectoryEntry * pDirectoryEntry = this - > lpDirectoryEntries + pFile - > GetID ( ) ;
switch ( eAttribute )
{
case HL_XZP_ITEM_CREATED :
{
for ( hlUInt i = 0 ; i < this - > pHeader - > uiDirectoryItemCount ; i + + )
{
if ( this - > lpDirectoryItems [ i ] . uiFileNameCRC = = pDirectoryEntry - > uiFileNameCRC )
{
time_t Time = ( time_t ) this - > lpDirectoryItems [ i ] . uiTimeCreated ;
tm * pTime = localtime ( & Time ) ;
hlChar lpTime [ 128 ] ;
strftime ( lpTime , sizeof ( lpTime ) , " %c " , pTime ) ;
hlAttributeSetString ( & Attribute , this - > lpItemAttributeNames [ eAttribute ] , lpTime ) ;
return hlTrue ;
}
}
break ;
}
case HL_XZP_ITEM_PRELOAD_BYTES :
{
hlUInt uiSize = 0 ;
if ( this - > lpPreloadDirectoryMappings ! = 0 )
{
hlUInt16 uiIndex = this - > lpPreloadDirectoryMappings [ pFile - > GetID ( ) ] . uiPreloadDirectoryEntryIndex ;
if ( uiIndex ! = 0xffff & & this - > lpPreloadDirectoryEntries [ uiIndex ] . uiFileNameCRC = = pDirectoryEntry - > uiFileNameCRC )
{
uiSize = this - > lpPreloadDirectoryEntries [ uiIndex ] . uiEntryLength ;
}
}
hlAttributeSetUnsignedInteger ( & Attribute , this - > lpItemAttributeNames [ eAttribute ] , uiSize , hlFalse ) ;
return hlTrue ;
}
2012-06-30 05:42:31 -07:00
default :
break ;
2012-06-30 04:45:25 -07:00
}
break ;
}
2012-06-30 05:42:31 -07:00
default :
break ;
2012-06-30 04:45:25 -07:00
}
return hlFalse ;
}
hlBool CXZPFile : : GetFileSizeInternal ( const CDirectoryFile * pFile , hlUInt & uiSize ) const
{
uiSize = this - > lpDirectoryEntries [ pFile - > GetID ( ) ] . uiEntryLength ;
return hlTrue ;
}
hlBool CXZPFile : : GetFileSizeOnDiskInternal ( const CDirectoryFile * pFile , hlUInt & uiSize ) const
{
uiSize = this - > lpDirectoryEntries [ pFile - > GetID ( ) ] . uiEntryLength ;
return hlTrue ;
}
hlBool CXZPFile : : CreateStreamInternal ( const CDirectoryFile * pFile , Streams : : IStream * & pStream ) const
{
const XZPDirectoryEntry * pDirectoryEntry = this - > lpDirectoryEntries + pFile - > GetID ( ) ;
pStream = new Streams : : CMappingStream ( * this - > pMapping , pDirectoryEntry - > uiEntryOffset , pDirectoryEntry - > uiEntryLength ) ;
return hlTrue ;
}