2010-12-10 04:50:08 +01:00
|
|
|
#ifndef U8_H
|
|
|
|
#define U8_H
|
|
|
|
|
|
|
|
#include "includes.h"
|
|
|
|
|
|
|
|
/*order of the names in the imet header
|
|
|
|
japanese
|
|
|
|
english
|
|
|
|
german
|
|
|
|
french
|
|
|
|
spanish
|
|
|
|
italian
|
|
|
|
dutch
|
|
|
|
simp_chinese
|
|
|
|
trad_chinese
|
|
|
|
korean
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct FEntry
|
|
|
|
{
|
2011-05-18 19:34:45 +02:00
|
|
|
union
|
|
|
|
{
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
unsigned int Type :8;
|
|
|
|
unsigned int NameOffset :24;
|
|
|
|
};
|
|
|
|
unsigned int TypeName;
|
|
|
|
};
|
|
|
|
union
|
|
|
|
{
|
|
|
|
struct // File Entry
|
|
|
|
{
|
|
|
|
unsigned int FileOffset;
|
|
|
|
unsigned int FileLength;
|
|
|
|
};
|
|
|
|
struct // Dir Entry
|
|
|
|
{
|
|
|
|
unsigned int ParentOffset;
|
|
|
|
unsigned int NextOffset;
|
|
|
|
};
|
|
|
|
unsigned int entry[ 2 ];
|
|
|
|
};
|
2010-12-10 04:50:08 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
U8_Hdr_none = 0,
|
|
|
|
U8_Hdr_IMET_app,//basically the same except the app has 0x40 bytes of padding more than the bnr
|
|
|
|
U8_Hdr_IMET_bnr,
|
|
|
|
U8_Hdr_IMD5
|
|
|
|
};
|
|
|
|
|
|
|
|
//class to handle U8 archives found in wii games & system files
|
|
|
|
// handles different header types, lz77 & ash
|
|
|
|
//! basic usage is to read an existing U8 archive into a qbytearray and pass it to this class through the second constructor or Load()
|
|
|
|
//! you can also create a brand-spankin-new U8 archive by using the first constructor
|
|
|
|
//! check IsOk() to see if that it was loaded ok
|
|
|
|
//! then call Entries() to get a list of everything that is in the archive
|
|
|
|
//! access the data in that archive with AddEntry(), RemoveEntry(), ReplaceEntry(), RenameEntry(), and GetData()
|
|
|
|
class U8
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
//creates a U8 object
|
|
|
|
//if initialize is true, it will call CreateEmptyData() in this U8
|
|
|
|
//you can also set the header type & imet names, though they dont affect the actual data in the archive
|
|
|
|
U8( bool initialize = false, int type = U8_Hdr_none, const QStringList &names = QStringList() );
|
|
|
|
U8( const QByteArray &ba );
|
|
|
|
|
|
|
|
//check if the u8 constructor finished successfully
|
|
|
|
bool IsOK();
|
|
|
|
|
|
|
|
void Load( const QByteArray &ba );
|
|
|
|
|
|
|
|
//set the variables and create an fst with only a root node
|
|
|
|
bool CreateEmptyData();
|
|
|
|
|
|
|
|
//adds an entry to this U8 with the given path, and type, and if it is a file entry, the given data
|
|
|
|
//returns the index of the created entry or -1 on error
|
|
|
|
int AddEntry( const QString &path, int type, const QByteArray &ba = QByteArray() );
|
|
|
|
|
|
|
|
//removes an entry, and all its children, from the archive
|
|
|
|
bool RemoveEntry( const QString &path );
|
|
|
|
|
|
|
|
//replace a file in the archive with different data ( only supports files, no directories )
|
|
|
|
//if autoCompress is true, it will check if the data to be replaced is ASH/LZ77 compressed and make sure the new data is LZ77'd
|
|
|
|
bool ReplaceEntry( const QString &path, const QByteArray &ba = QByteArray(), bool autoCompress = true );
|
|
|
|
|
|
|
|
//remane an entry. this expects a full path of the entry to be named, and newName is only the replacement name ( not the full path )
|
|
|
|
bool RenameEntry( const QString &path, const QString &newName );
|
|
|
|
|
|
|
|
|
|
|
|
//returns the index of an item in the archive FST, or -1 the item is not present
|
|
|
|
//it accepts names like "/arc/anim/". parent is the directory to start looking in
|
|
|
|
int FindEntry( const QString &str, int parent = 0 );
|
|
|
|
quint32 NextEntryInFolder( quint32 current, quint32 directory );
|
|
|
|
QString FstName( const FEntry *entry );
|
|
|
|
QString FstName( quint32 i );
|
|
|
|
|
|
|
|
//gets the data for a path inside the archive
|
|
|
|
//if no path is given, returns the data for the whole archive, starting at the U8 tag
|
|
|
|
//if onlyPayload is true, it will return the data unLZ77'd ( and without its IMET/IMD5 header for nested U8 archives )
|
|
|
|
const QByteArray GetData( const QString &str = QString(), bool onlyPayload = false );
|
|
|
|
|
|
|
|
//get the size of an entry in the archive
|
|
|
|
//if no path is given, returns the size for the whole archive, starting at the U8 tag
|
|
|
|
quint32 GetSize( const QString &str = QString() );
|
|
|
|
|
|
|
|
//returns a list of all the entries in the u8 archive
|
|
|
|
//directories end with "/"
|
|
|
|
const QStringList Entries();
|
|
|
|
|
|
|
|
//check the first 5000 bytes of a file for the u8 tag.
|
|
|
|
//if necessary, un-LZ77 the data before checking
|
|
|
|
//this doesnt check anything else in the archive
|
|
|
|
static bool IsU8( const QByteArray &ba );
|
|
|
|
|
|
|
|
//returns the location of the U8 tag in the first 5000 bytes of the given data
|
|
|
|
static int GetU8Offset( const QByteArray &ba );
|
|
|
|
|
|
|
|
//adds the IMD5 header to the given bytearray and returns it ( original data is modified )
|
|
|
|
static QByteArray AddIMD5( QByteArray ba );
|
|
|
|
|
|
|
|
//returns the U8 archive data with an IMD5 header added
|
|
|
|
//the actual data is not changed
|
|
|
|
const QByteArray AddIMD5();
|
|
|
|
|
|
|
|
//adds the IMET header to the given bytearray and returns it ( original data is modified )
|
|
|
|
static QByteArray AddIMET( QByteArray ba, const QStringList &names );
|
|
|
|
|
|
|
|
//get an IMET header using the given names and sizes
|
|
|
|
//padding type will add 0, 0x40, or 0x80 bytes of 0s to the beginning
|
|
|
|
static QByteArray GetIMET( const QStringList &names, int paddingType = U8_Hdr_IMET_app, quint32 iconSize = 0, quint32 bannerSize = 0, quint32 soundSize = 0 );
|
|
|
|
|
|
|
|
//returns the U8 archive data with an IMET header added
|
|
|
|
//the actual archive data is not changed
|
|
|
|
const QByteArray AddIMET( int paddingType = U8_Hdr_IMET_app );
|
|
|
|
|
|
|
|
//ruterns a list of the names as read from the imet header
|
2011-05-18 19:34:45 +02:00
|
|
|
const QStringList &IMETNames();
|
2010-12-10 04:50:08 +01:00
|
|
|
|
|
|
|
//set the imet names
|
|
|
|
//the data in the archive is not changed, but calling AddIMET() on this banner will use the new names
|
|
|
|
void SetImetNames( const QStringList &names );
|
|
|
|
|
|
|
|
//void SetHeaderType( int type );
|
|
|
|
int GetHeaderType();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//reads from the fst and makes the list of paths
|
|
|
|
void CreateEntryList();
|
|
|
|
|
2011-07-11 07:47:33 +02:00
|
|
|
// if this archive was packed by any of the wii.cs tools and it is not
|
|
|
|
// a standard banner, it will be incorrectly packed, and this will return true
|
|
|
|
bool IsBuggy(){ return wii_cs_error; }
|
2010-12-10 04:50:08 +01:00
|
|
|
|
|
|
|
private:
|
|
|
|
QByteArray data;//data starting at the U8 tag
|
|
|
|
QStringList paths;
|
|
|
|
bool ok;
|
|
|
|
|
2011-07-11 07:47:33 +02:00
|
|
|
bool wii_cs_error;
|
|
|
|
|
2010-12-10 04:50:08 +01:00
|
|
|
//if this archive as a whole is lz77 compressed
|
|
|
|
bool isLz77;
|
|
|
|
|
|
|
|
QStringList imetNames;
|
|
|
|
int headerType;
|
|
|
|
void ReadHeader( const QByteArray &ba );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//just a pointer to the fst data.
|
|
|
|
//this pointer needs to be updated any time data is changed
|
|
|
|
FEntry* fst;
|
|
|
|
|
|
|
|
//stored in host endian !
|
|
|
|
quint32 fstSize;
|
|
|
|
quint32 rootnode_offset;
|
|
|
|
quint32 data_offset;
|
|
|
|
quint32 NameOff;
|
|
|
|
|
|
|
|
//a list of the nested u8 archives
|
|
|
|
QMap<QString, U8>nestedU8s;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#endif // U8_H
|