From e48e9d67e0af892922f325047d61d30c0bb187cf Mon Sep 17 00:00:00 2001 From: giantpune Date: Sat, 29 Jan 2011 08:44:22 +0000 Subject: [PATCH] *ash class: slightly better error handling & memory management. should help fix/avoid some issues with buffer overflowing using the hardcoded buffer size from crediar's original code git-svn-id: http://wiiqt.googlecode.com/svn/trunk@71 389f4c8b-5dfe-645f-db0e-df882bc27289 --- WiiQt/ash.cpp | 164 +++--- WiiQt/u8.cpp | 1116 ++++++++++++++++++++--------------------- nandBinCheck/main.cpp | 444 ++++++++-------- 3 files changed, 873 insertions(+), 851 deletions(-) diff --git a/WiiQt/ash.cpp b/WiiQt/ash.cpp index 1d4ec86..f3bf0c0 100644 --- a/WiiQt/ash.cpp +++ b/WiiQt/ash.cpp @@ -1,4 +1,8 @@ #include "ash.h" + +//this is large enough for all the system menu ash0 files, and thats all i need it for +#define BUFFER_SIZE 0x600000 + bool IsAshCompressed( const QByteArray ba ) { return ba.startsWith( "ASH" ); @@ -6,37 +10,49 @@ bool IsAshCompressed( const QByteArray ba ) QByteArray DecryptAsh( const QByteArray ba ) { + //qDebug() << "DecryptAsh()"; if( !IsAshCompressed( ba ) ) { - qWarning() << "DecryptAsh -> wrong magic"; - return QByteArray(); + qWarning() << "DecryptAsh -> wrong magic"; + return QByteArray(); } quint32 r[ 32 ]; quint32 count=0; quint32 t; quint64 memAddr = (quint64)( ba.data() );//in - r[4] = 0x80000000; + r[4] = 0x8000000; qint64 inDiff = memAddr - r[ 4 ];//difference in r[ 4 ] and the real address. hack to support higher memory addresses than crediar's version r[5] = 0x415348; r[6] = 0x415348; -//Rvl_decode_ash: + //Rvl_decode_ash: r[5] = qFromBigEndian(*(quint32 *)( r[4] + inDiff + 4 ) ); r[5] = r[5] & 0x00FFFFFF; quint32 size = r[5]; //qDebug() << "Decompressed size:" << hex << size; + if( size > BUFFER_SIZE ) + { + qWarning() << "DecryptAsh(): this file was built with a buffer to small to deal with this archive. Build it with a bigger one and try again." + << hex << size << ">" << BUFFER_SIZE; + return QByteArray(); + } - char crap2[ size ]; - quint64 memAddr2 = (quint64)( crap2 );//outbuf - r[3] = 0x90000000; + QByteArray crap2( size, '\0' ); + if( (quint32)crap2.size() != size ) + { + qWarning() << "DecryptAsh(): out of memory 1"; + return QByteArray(); + } + //char crap2[ size ]; + quint64 memAddr2 = (quint64)( crap2.data() );//outbuf + r[3] = 0x9000000; qint64 outDiff = memAddr2 - r[ 3 ];//difference in r[ 3 ] and the real address quint32 o = r[ 3 ]; - memset( (void*)( r[ 3 ] + outDiff ), 0, size ); r[24] = 0x10; r[28] = qFromBigEndian(*(quint32 *)(r[4]+8 + inDiff)); @@ -48,12 +64,18 @@ QByteArray DecryptAsh( const QByteArray ba ) //r[8] = 0x8108<<16; //HACK, pointer to RAM - char crap3[ 0x100000 ]; - quint64 memAddr3 = (quint64)( crap3 );//outbuf + QByteArray crap3( BUFFER_SIZE, '\0' ); + if( crap3.size() != BUFFER_SIZE ) + { + qWarning() << "DecryptAsh(): out of memory 1"; + return QByteArray(); + } + + //char crap3[ 0x100000 ]; + quint64 memAddr3 = (quint64)( crap3.data() );//outbuf r[8] = 0x84000000; qint64 outDiff2 = memAddr3 - r[ 8 ];//difference in r[ 3 ] and the real address memset( (void*)( r[8] + outDiff2 ), 0, 0x100000 ); - r[8] = r[8]; r[9] = r[8] + 0x07FE; r[10] = r[9] + 0x07FE; @@ -63,10 +85,10 @@ QByteArray DecryptAsh( const QByteArray ba ) r[22] = 0x200; r[27] = 0; -loc_81332124: + loc_81332124: if( r[25] != 0x1F ) - goto loc_81332140; + goto loc_81332140; r[0] = r[26] >> 31; r[26]= qFromBigEndian(*(quint32 *)(r[4] + r[24] + inDiff)); @@ -74,16 +96,16 @@ loc_81332124: r[24]= r[24] + 4; goto loc_8133214C; -loc_81332140: + loc_81332140: r[0] = r[26] >> 31; r[25]= r[25] + 1; r[26]= r[26] << 1; -loc_8133214C: + loc_8133214C: if( r[0] == 0 ) - goto loc_81332174; + goto loc_81332174; r[0] = r[23] | 0x8000; *(quint16 *)(r[31] + outDiff2) = (quint16)qFromBigEndian((quint16)r[0]); @@ -97,31 +119,31 @@ loc_8133214C: goto loc_81332124; -loc_81332174: + loc_81332174: r[12] = 9; r[21] = r[25] + r[12]; t = r[21]; if( r[21] > 0x20 ) - goto loc_813321AC; + goto loc_813321AC; r[21] = (~(r[12] - 0x20))+1; r[6] = r[26] >> r[21]; if( t == 0x20 ) - goto loc_8133219C; + goto loc_8133219C; r[26] = r[26] << r[12]; r[25] = r[25] + r[12]; goto loc_813321D0; -loc_8133219C: + loc_8133219C: r[26]= qFromBigEndian(*(quint32 *)(r[4] + r[24] + inDiff)); r[25]= 0; r[24]= r[24] + 4; goto loc_813321D0; -loc_813321AC: + loc_813321AC: r[0] = (~(r[12] - 0x20))+1; r[6] = r[26] >> r[0]; @@ -133,7 +155,7 @@ loc_813321AC: r[25] = r[21] - 0x20; r[26] = r[26] << r[25]; -loc_813321D0: + loc_813321D0: r[12]= (quint16)qFromBigEndian((quint16)(*(quint16 *)(( r[31] + outDiff2 ) - 2))); r[31] -= 2; @@ -141,30 +163,30 @@ loc_813321D0: r[0] = r[12] & 0x8000; r[12]= (r[12] & 0x1FFF) << 1; if( r[0] == 0 ) - goto loc_813321F8; + goto loc_813321F8; *(quint16 *)(r[9]+r[12] + outDiff2 ) = (quint16)qFromBigEndian((quint16)r[6]);//????? r[6] = (r[12] & 0x3FFF)>>1;//extrwi %r6, %r12, 14,17 if( r[27] != 0 ) - goto loc_813321D0; + goto loc_813321D0; goto loc_81332204; -loc_813321F8: + loc_813321F8: *(quint16 *)(r[8]+r[12] + outDiff2) = (quint16)qFromBigEndian((quint16)r[6]); r[23] = r[22]; goto loc_81332124; -loc_81332204: + loc_81332204: r[23] = 0x800; r[22] = 0x800; -loc_8133220C: + loc_8133220C: if( r[29] != 0x1F ) - goto loc_81332228; + goto loc_81332228; r[0] = r[30] >> 31; r[30]= qFromBigEndian(*(quint32 *)(r[4] + r[28] + inDiff)); @@ -172,16 +194,16 @@ loc_8133220C: r[28]= r[28] + 4; goto loc_81332234; -loc_81332228: + loc_81332228: r[0] = r[30] >> 31; r[29]= r[29] + 1; r[30]= r[30] << 1; -loc_81332234: + loc_81332234: if( r[0] == 0 ) - goto loc_8133225C; + goto loc_8133225C; r[0] = r[23] | 0x8000; *(quint16 *)(r[31] + outDiff2) = (quint16)qFromBigEndian((quint16)r[0]); @@ -195,31 +217,31 @@ loc_81332234: goto loc_8133220C; -loc_8133225C: + loc_8133225C: r[12] = 0xB; r[21] = r[29] + r[12]; t = r[21]; if( r[21] > 0x20 ) - goto loc_81332294; + goto loc_81332294; r[21] = (~(r[12] - 0x20))+1; r[7] = r[30] >> r[21]; if( t == 0x20 ) - goto loc_81332284; + goto loc_81332284; r[30] = r[30] << r[12]; r[29] = r[29] + r[12]; goto loc_813322B8; -loc_81332284: + loc_81332284: r[30]= qFromBigEndian(*(quint32 *)(r[4] + r[28] + inDiff)); r[29]= 0; r[28]= r[28] + 4; goto loc_813322B8; -loc_81332294: + loc_81332294: r[0] = (~(r[12] - 0x20))+1; r[7] = r[30] >> r[0]; @@ -231,7 +253,7 @@ loc_81332294: r[29]= r[21] - 0x20; r[30]= r[30] << r[29]; -loc_813322B8: + loc_813322B8: r[12]= (quint16)qFromBigEndian((quint16)(*(quint16 *)((r[31] + outDiff2 ) - 2))); r[31] -= 2; @@ -239,36 +261,36 @@ loc_813322B8: r[0] = r[12] & 0x8000; r[12]= (r[12] & 0x1FFF) << 1; if( r[0] == 0 ) - goto loc_813322E0; + goto loc_813322E0; *(quint16 *)(r[11]+r[12] + outDiff2 ) = (quint16)qFromBigEndian((quint16)r[7]);//???? r[7] = (r[12] & 0x3FFF)>>1;// extrwi %r7, %r12, 14,17 if( r[27] != 0 ) - goto loc_813322B8; + goto loc_813322B8; goto loc_813322EC; -loc_813322E0: + loc_813322E0: *(quint16 *)(r[10]+r[12] + outDiff2 ) = (quint16)qFromBigEndian((quint16)r[7]); r[23] = r[22]; goto loc_8133220C; -loc_813322EC: + loc_813322EC: r[0] = r[5]; -loc_813322F0: + loc_813322F0: r[12]= r[6]; -loc_813322F4: + loc_813322F4: if( r[12] < 0x200 ) - goto loc_8133233C; + goto loc_8133233C; if( r[25] != 0x1F ) - goto loc_81332318; + goto loc_81332318; r[31] = r[26] >> 31; r[26] = qFromBigEndian(*(quint32 *)(r[4] + r[24] + inDiff)); @@ -276,50 +298,50 @@ loc_813322F4: r[25] = 0; goto loc_81332324; -loc_81332318: + loc_81332318: r[31] = r[26] >> 31; r[25] = r[25] + 1; r[26] = r[26] << 1; -loc_81332324: + loc_81332324: r[27] = r[12] << 1; if( r[31] != 0 ) - goto loc_81332334; + goto loc_81332334; r[12] = (quint16)qFromBigEndian((quint16)(*(quint16 *)(r[8] + r[27] + outDiff2 ))); goto loc_813322F4; -loc_81332334: + loc_81332334: r[12] = (quint16)qFromBigEndian((quint16)(*(quint16 *)(r[9] + r[27] + outDiff2 ))); goto loc_813322F4; -loc_8133233C: + loc_8133233C: if( r[12] >= 0x100 ) - goto loc_8133235C; + goto loc_8133235C; *(quint8 *)(r[3] + outDiff) = r[12]; r[3] = r[3] + 1; r[5] = r[5] - 1; if( r[5] != 0 ) - goto loc_813322F0; + goto loc_813322F0; goto loc_81332434; -loc_8133235C: + loc_8133235C: r[23] = r[7]; -loc_81332360: + loc_81332360: if( r[23] < 0x800 ) - goto loc_813323A8; + goto loc_813323A8; if( r[29] != 0x1F ) - goto loc_81332384; + goto loc_81332384; r[31] = r[30] >> 31; r[30] = qFromBigEndian(*(quint32 *)(r[4] + r[28] + inDiff)); @@ -327,27 +349,27 @@ loc_81332360: r[29] = 0; goto loc_81332390; -loc_81332384: + loc_81332384: r[31] = r[30] >> 31; r[29] = r[29] + 1; r[30] = r[30] << 1; -loc_81332390: + loc_81332390: r[27] = r[23] << 1; if( r[31] != 0 ) - goto loc_813323A0; + goto loc_813323A0; r[23] = (quint16)qFromBigEndian((quint16)(*(quint16 *)(r[10] + r[27] + outDiff2 ))); goto loc_81332360; -loc_813323A0: + loc_813323A0: r[23] = (quint16)qFromBigEndian((quint16)(*(quint16 *)(r[11] + r[27] + outDiff2 ))); goto loc_81332360; -loc_813323A8: + loc_813323A8: r[12] = r[12] - 0xFD; r[23] = ~r[23] + r[3] + 1; @@ -355,11 +377,11 @@ loc_813323A8: r[31] = r[12] >> 3; if( r[31] == 0 ) - goto loc_81332414; + goto loc_81332414; count = r[31]; -loc_813323C0: + loc_813323C0: r[31] = *(quint8 *)(( r[23] + outDiff ) - 1); *(quint8 *)(r[3] + outDiff) = r[31]; @@ -389,17 +411,17 @@ loc_813323C0: r[3] = r[3] + 8; if( --count ) - goto loc_813323C0; + goto loc_813323C0; r[12] = r[12] & 7; if( r[12] == 0 ) - goto loc_8133242C; + goto loc_8133242C; -loc_81332414: + loc_81332414: count = r[12]; -loc_81332418: + loc_81332418: r[31] = *(quint8 *)(( r[23] + outDiff ) - 1); r[23] = r[23] + 1; @@ -407,14 +429,14 @@ loc_81332418: r[3] = r[3] + 1; if( --count ) - goto loc_81332418; + goto loc_81332418; -loc_8133242C: + loc_8133242C: if( r[5] != 0 ) - goto loc_813322F0; + goto loc_813322F0; -loc_81332434: + loc_81332434: r[3] = r[0]; diff --git a/WiiQt/u8.cpp b/WiiQt/u8.cpp index c632e0e..139023f 100644 --- a/WiiQt/u8.cpp +++ b/WiiQt/u8.cpp @@ -26,7 +26,7 @@ U8::U8( bool initialize, int type, const QStringList &names ) headerType = type; imetNames = names; if( !initialize ) - return; + return; //headerType = type; //imetNames = names; @@ -44,9 +44,9 @@ bool U8::CreateEmptyData() QBuffer buf( &data ); if( !buf.open( QBuffer::WriteOnly ) ) { - qWarning() << "Can't create buffer"; - data.clear(); - return false; + qWarning() << "Can't create buffer"; + data.clear(); + return false; } buf.putChar( 'U' ); buf.putChar( '\xAA' ); @@ -88,64 +88,64 @@ bool U8::RenameEntry( const QString &path, const QString &newName ) qDebug() << "U8::RenameEntry(" << path << "," << newName << ")"; if( !ok ) { - qWarning() << "U8::RenameEntry -> archive has no data"; - return false; + qWarning() << "U8::RenameEntry -> archive has no data"; + return false; } if( newName.contains( "/" ) ) { - qWarning() << "U8::RenameEntry -> newName cannot contain \'/\'"; - return false; + qWarning() << "U8::RenameEntry -> newName cannot contain \'/\'"; + return false; } //check if this is a path to a file in a nested archive QMap::iterator i = nestedU8s.begin(); while( i != nestedU8s.constEnd() ) { - if( path.startsWith( i.key() ) && path != i.key() ) - { - QString subPath = path; - subPath.remove( 0, i.key().size() + 1 );//remove the path of the archive itself + the slash + if( path.startsWith( i.key() ) && path != i.key() ) + { + QString subPath = path; + subPath.remove( 0, i.key().size() + 1 );//remove the path of the archive itself + the slash - bool ret = i.value().RenameEntry( subPath, newName ); - if( !ret ) - { - qWarning() << "U8::RenameEntry -> error replacing data in child U8 archive"; - return false; - } - //qDebug() << "child entry updated, now replacing child archive in this one"; - return ReplaceEntry( i.key(),i.value().GetData() ); - //NOTE - after replacing the entry, "i" is no longer valid. keep that in mind when changing this code. its a bitch to track down this bug - } - i++; + bool ret = i.value().RenameEntry( subPath, newName ); + if( !ret ) + { + qWarning() << "U8::RenameEntry -> error replacing data in child U8 archive"; + return false; + } + //qDebug() << "child entry updated, now replacing child archive in this one"; + return ReplaceEntry( i.key(),i.value().GetData() ); + //NOTE - after replacing the entry, "i" is no longer valid. keep that in mind when changing this code. its a bitch to track down this bug + } + i++; } //make sure the new filename doesnt already exist QString parentPath = path; while( parentPath.startsWith( "/") )//remove leading "/"s - parentPath.remove( 0, 1 ); + parentPath.remove( 0, 1 ); while( parentPath.endsWith( "/") )//remove trailing "/"s - parentPath.resize( parentPath.size() - 1 ); + parentPath.resize( parentPath.size() - 1 ); int slash = parentPath.lastIndexOf( "/" ); if( slash != -1 ) { - parentPath.chop( ( parentPath.size() - slash ) ); - parentPath += "/" + newName; + parentPath.chop( ( parentPath.size() - slash ) ); + parentPath += "/" + newName; } else - parentPath = newName; + parentPath = newName; if( FindEntry( parentPath ) != -1 ) { - qWarning() << "U8::RenameEntry ->" << parentPath << "already exists in the archive"; - return false; + qWarning() << "U8::RenameEntry ->" << parentPath << "already exists in the archive"; + return false; } //find the entry to rename int entryToRename = FindEntry( path ); if( entryToRename == -1 ) { - qWarning() << "U8::RenameEntry" << path << "doesn\'t exists in the archive"; - qWarning() << "choices are" << paths; - return false; + qWarning() << "U8::RenameEntry" << path << "doesn\'t exists in the archive"; + qWarning() << "choices are" << paths; + return false; } quint32 newNameLen = newName.size(); @@ -155,16 +155,16 @@ bool U8::RenameEntry( const QString &path, const QString &newName ) quint32 nFstSize = fstSize + difference; int dataAdjustment = 0; - if( RU( nFstSize, U8_HEADER_ALIGNMENT ) < RU( fstSize, U8_HEADER_ALIGNMENT ) ) - dataAdjustment = - RU( ( fstSize - nFstSize ), U8_HEADER_ALIGNMENT ); + if( RU( nFstSize, U8_HEADER_ALIGNMENT ) < RU( fstSize, U8_HEADER_ALIGNMENT ) ) + dataAdjustment = - RU( ( fstSize - nFstSize ), U8_HEADER_ALIGNMENT ); - else if( RU( nFstSize, U8_HEADER_ALIGNMENT ) > RU( fstSize, U8_HEADER_ALIGNMENT ) ) - dataAdjustment = RU( ( nFstSize - fstSize ), U8_HEADER_ALIGNMENT ); + else if( RU( nFstSize, U8_HEADER_ALIGNMENT ) > RU( fstSize, U8_HEADER_ALIGNMENT ) ) + dataAdjustment = RU( ( nFstSize - fstSize ), U8_HEADER_ALIGNMENT ); qDebug() << "old size:" << hex << oldNameLen\ - << "new size:" << hex << newNameLen\ - << "difference:" << hex << difference - << "dataAdjustment:" << hex << dataAdjustment; + << "new size:" << hex << newNameLen\ + << "difference:" << hex << difference + << "dataAdjustment:" << hex << dataAdjustment; QByteArray nFstData( ( qFromBigEndian( fst[ 0 ].FileLength ) ) * 0xc, '\0' ); FEntry *nfst = (FEntry*)( nFstData.data() ); //make the new root entry @@ -182,34 +182,34 @@ bool U8::RenameEntry( const QString &path, const QString &newName ) for( quint32 i = 1; i < cnt; i++ ) { - FEntry *e = &fst[ i ];//old entry - FEntry *ne = &nfst[ i ];//new entry + FEntry *e = &fst[ i ];//old entry + FEntry *ne = &nfst[ i ];//new entry - ne->NameOffset = swap24( nNameTable.size() );//offset to the new entry's name in the string table + ne->NameOffset = swap24( nNameTable.size() );//offset to the new entry's name in the string table - //add the name to the new name table - if( i == (quint32)entryToRename ) - { - nNameTable.append( newName.toLatin1() ); - } - else - nNameTable.append( FstName( e ).toLatin1() ); + //add the name to the new name table + if( i == (quint32)entryToRename ) + { + nNameTable.append( newName.toLatin1() ); + } + else + nNameTable.append( FstName( e ).toLatin1() ); - nNameTable.append( '\0' ); - if( e->Type )//nothing special to change for directories except the name offset - { - ne->Type = 1; - ne->ParentOffset = e->ParentOffset; - ne->NextOffset = e->NextOffset; - } - else//only need to change the name offset & the data offset for files - { - ne->Type = 0; - ne->FileOffset = qFromBigEndian( qFromBigEndian( e->FileOffset ) + dataAdjustment );// + qFromBigEndian( dataAdjustment ); - //qFromBigEndian( (quint32)( 0x20 + RU( U8_HEADER_ALIGNMENT, nFstSize ) + nPayload.size() ) ); - ne->FileLength = e->FileLength; - qDebug() << "old offset" << hex << qFromBigEndian( e->FileOffset ) << "new offset" << hex << qFromBigEndian( e->FileOffset ) + dataAdjustment; - } + nNameTable.append( '\0' ); + if( e->Type )//nothing special to change for directories except the name offset + { + ne->Type = 1; + ne->ParentOffset = e->ParentOffset; + ne->NextOffset = e->NextOffset; + } + else//only need to change the name offset & the data offset for files + { + ne->Type = 0; + ne->FileOffset = qFromBigEndian( qFromBigEndian( e->FileOffset ) + dataAdjustment );// + qFromBigEndian( dataAdjustment ); + //qFromBigEndian( (quint32)( 0x20 + RU( U8_HEADER_ALIGNMENT, nFstSize ) + nPayload.size() ) ); + ne->FileLength = e->FileLength; + qDebug() << "old offset" << hex << qFromBigEndian( e->FileOffset ) << "new offset" << hex << qFromBigEndian( e->FileOffset ) + dataAdjustment; + } } //now put all the parts together to make a new U8 archive @@ -219,8 +219,8 @@ bool U8::RenameEntry( const QString &path, const QString &newName ) QBuffer buf( &data ); if( !buf.open( QBuffer::WriteOnly ) ) { - qWarning() << "U8::AddEntry -> Can't create buffer"; - return -1; + qWarning() << "U8::AddEntry -> Can't create buffer"; + return -1; } buf.putChar( 'U' ); buf.putChar( '\xAA' ); @@ -235,7 +235,7 @@ bool U8::RenameEntry( const QString &path, const QString &newName ) t = qFromBigEndian( fstSize ); buf.write( (const char*)&t, 4 ); - data_offset = RU( ( 0x20 + fstSize ), U8_HEADER_ALIGNMENT ); + data_offset = RU( ( 0x20 + fstSize ), U8_HEADER_ALIGNMENT ); t = qFromBigEndian( data_offset ); buf.write( (const char*)&t, 4 ); buf.close(); @@ -244,14 +244,14 @@ bool U8::RenameEntry( const QString &path, const QString &newName ) int padding = data_offset - data.size();//pad to 'data_offset' after the fst if( padding ) { - data.append( QByteArray( padding, '\0' ) ); + data.append( QByteArray( padding, '\0' ) ); } data.append( nPayload );//add the actual file data - padding = RU( data.size(), 0x20 ) - data.size();//pad the entire thing to 0x20 bytes TOTO: should probably already be done, and this step is not really necessary + padding = RU( data.size(), 0x20 ) - data.size();//pad the entire thing to 0x20 bytes TOTO: should probably already be done, and this step is not really necessary if( padding ) { - data.append( QByteArray( padding, '\0' ) ); + data.append( QByteArray( padding, '\0' ) ); } @@ -268,77 +268,77 @@ bool U8::ReplaceEntry( const QString &path, const QByteArray &nba, bool autoComp //qDebug() << "U8::ReplaceEntry(" << path << ")"; if( !ok ) { - qWarning() << "U8::ReplaceEntry -> archive has no data"; - return false; + qWarning() << "U8::ReplaceEntry -> archive has no data"; + return false; } //check if this is a path to a file in a nested archive QMap::iterator i = nestedU8s.begin(); while( i != nestedU8s.constEnd() ) { - if( path.startsWith( i.key() ) && path != i.key() ) - { - QString subPath = path; - subPath.remove( 0, i.key().size() + 1 );//remove the path of the archive itself + the slash - //qDebug() << "replacing file" << subPath << "in child U8" << i.key(); + if( path.startsWith( i.key() ) && path != i.key() ) + { + QString subPath = path; + subPath.remove( 0, i.key().size() + 1 );//remove the path of the archive itself + the slash + //qDebug() << "replacing file" << subPath << "in child U8" << i.key(); - U8 ch = i.value(); - QString chPath = i.key(); - //qDebug() << "replacing" << subPath << "in child archive"; - bool ret = ch.ReplaceEntry( subPath, nba, autoCompress ); - if( !ret ) - { - qWarning() << "U8::ReplaceEntry -> error replacing data in child U8 archive"; - return false; - } - //qDebug() << "child entry updated, now replacing child archive in this one"; - return ReplaceEntry( chPath, ch.GetData() ); - //NOTE - after replacing the entry, "i" is no longer valid. keep that in mind when changing this code. its a bitch to track down this bug - } - i++; + U8 ch = i.value(); + QString chPath = i.key(); + //qDebug() << "replacing" << subPath << "in child archive"; + bool ret = ch.ReplaceEntry( subPath, nba, autoCompress ); + if( !ret ) + { + qWarning() << "U8::ReplaceEntry -> error replacing data in child U8 archive"; + return false; + } + //qDebug() << "child entry updated, now replacing child archive in this one"; + return ReplaceEntry( chPath, ch.GetData() ); + //NOTE - after replacing the entry, "i" is no longer valid. keep that in mind when changing this code. its a bitch to track down this bug + } + i++; } //find the entry to replace int entryToReplace = FindEntry( path ); if( entryToReplace == -1 ) { - qWarning() << "U8::ReplaceEntry" << path << "doesn\'t exists in the archive"; - qWarning() << "choices are" << paths; - return false; + qWarning() << "U8::ReplaceEntry" << path << "doesn\'t exists in the archive"; + qWarning() << "choices are" << paths; + return false; } if( qFromBigEndian( fst[ entryToReplace ].Type ) ) { - qWarning() << "U8::ReplaceEntry -> replacing a directory is not supported" << path; - return false; + qWarning() << "U8::ReplaceEntry -> replacing a directory is not supported" << path; + return false; } /*qDebug() << "old size:" << hex << oldSizePadded\ - << "new size:" << hex << newSizePadded\ - << "difference:" << hex << difference;*/ + << "new size:" << hex << newSizePadded\ + << "difference:" << hex << difference;*/ QByteArray newData = nba; if( autoCompress ) { - QByteArray oldData = data.mid( qFromBigEndian( fst[ entryToReplace ].FileOffset ), qFromBigEndian( fst[ entryToReplace ].FileLength ) ); - bool oldCompressed = ( LZ77::GetLz77Offset( oldData ) > -1 || IsAshCompressed( oldData ) ); - if( oldCompressed && LZ77::GetLz77Offset( newData ) == -1 && !IsAshCompressed( newData ) ) - { - newData = LZ77::Compress( newData ); - } + QByteArray oldData = data.mid( qFromBigEndian( fst[ entryToReplace ].FileOffset ), qFromBigEndian( fst[ entryToReplace ].FileLength ) ); + bool oldCompressed = ( LZ77::GetLz77Offset( oldData ) > -1 || IsAshCompressed( oldData ) ); + if( oldCompressed && LZ77::GetLz77Offset( newData ) == -1 && !IsAshCompressed( newData ) ) + { + newData = LZ77::Compress( newData ); + } } - quint32 newSizePadded = RU( newData.size(), 0x20 ); - quint32 oldSizePadded = RU( qFromBigEndian( fst[ entryToReplace ].FileLength ), 0x20 ); + quint32 newSizePadded = RU( newData.size(), 0x20 ); + quint32 oldSizePadded = RU( qFromBigEndian( fst[ entryToReplace ].FileLength ), 0x20 ); int difference = newSizePadded - oldSizePadded; data.remove( qFromBigEndian( fst[ entryToReplace ].FileOffset ), oldSizePadded ); QByteArray newPaddedData = newData; if( newSizePadded > (quint32)newPaddedData.size() ) { - newPaddedData.append( QByteArray( newSizePadded - newPaddedData.size(), '\0' ) ); + newPaddedData.append( QByteArray( newSizePadded - newPaddedData.size(), '\0' ) ); } data.insert( qFromBigEndian( fst[ entryToReplace ].FileOffset ), newPaddedData ); if( newSizePadded == oldSizePadded )//the sized match, so nothing else to change - return true; + return true; //point the fst to the new data fst = (FEntry*)( data.data() + rootnode_offset ); @@ -352,12 +352,12 @@ bool U8::ReplaceEntry( const QString &path, const QByteArray &nba, bool autoComp quint32 cnt = qFromBigEndian( fst[ 0 ].FileLength ); for( quint32 i = entryToReplace + 1; i < cnt; i++ ) { - FEntry *e = &fst[ i ];//old entry - if( e->Type )//nothing changes for directories - continue; + FEntry *e = &fst[ i ];//old entry + if( e->Type )//nothing changes for directories + continue; - //qDebug() << "changed" << FstName( e ) << "offset from" << hex << qFromBigEndian( fst[ i ].FileOffset ) << "to" << qFromBigEndian( fst[ i ].FileOffset ) + difference; - e->FileOffset = qFromBigEndian( qFromBigEndian( fst[ i ].FileOffset ) + difference ); + //qDebug() << "changed" << FstName( e ) << "offset from" << hex << qFromBigEndian( fst[ i ].FileOffset ) << "to" << qFromBigEndian( fst[ i ].FileOffset ) + difference; + e->FileOffset = qFromBigEndian( qFromBigEndian( fst[ i ].FileOffset ) + difference ); } CreateEntryList(); @@ -372,39 +372,39 @@ bool U8::RemoveEntry( const QString &path ) //qDebug() << "U8::RemoveEntry(" << path << ")"; if( !ok ) { - qWarning() << "U8::RemoveEntry -> archive has no data"; - return false; + qWarning() << "U8::RemoveEntry -> archive has no data"; + return false; } //check if this is a path to a file in a nested archive QMap::iterator i = nestedU8s.begin(); while( i != nestedU8s.constEnd() ) { - if( path.startsWith( i.key() ) && path != i.key() ) - { - QString subPath = path; - subPath.remove( 0, i.key().size() + 1 );//remove the path of the archive itself + the slash + if( path.startsWith( i.key() ) && path != i.key() ) + { + QString subPath = path; + subPath.remove( 0, i.key().size() + 1 );//remove the path of the archive itself + the slash - U8 ch = i.value(); - QString chPath = i.key(); - //qDebug() << "deleting" << subPath << "in child archive"; + U8 ch = i.value(); + QString chPath = i.key(); + //qDebug() << "deleting" << subPath << "in child archive"; - bool ret = ch.RemoveEntry( subPath ); - if( !ret ) - { - qWarning() << "U8::RemoveEntry -> error replacing data in child U8 archive"; - return false; - } - return ReplaceEntry( chPath, ch.GetData() );//insert the new nested archive in this one - //NOTE - after replacing the entry, "i" is no longer valid. keep that in mind when changing this code. its a bitch to track down this bug - } - i++; + bool ret = ch.RemoveEntry( subPath ); + if( !ret ) + { + qWarning() << "U8::RemoveEntry -> error replacing data in child U8 archive"; + return false; + } + return ReplaceEntry( chPath, ch.GetData() );//insert the new nested archive in this one + //NOTE - after replacing the entry, "i" is no longer valid. keep that in mind when changing this code. its a bitch to track down this bug + } + i++; } //find the entry to delete int entryToDelete = FindEntry( path ); if( entryToDelete == -1 ) { - qWarning() << "U8::RemoveEntry" << path << "doesn\'t exists in the archive"; - return false; + qWarning() << "U8::RemoveEntry" << path << "doesn\'t exists in the archive"; + return false; } //create a list of all the directory indexes that my have their size changed @@ -414,35 +414,35 @@ bool U8::RemoveEntry( const QString &path ) quint32 fstLenToDelete; if( fst[ entryToDelete ].Type )//deleting a directory { - parent = qFromBigEndian( fst[ entryToDelete ].ParentOffset ); - while( parent ) - { - parents << parent; - parent = qFromBigEndian( fst[ parent ].ParentOffset ); - } - numDeletedEntries = qFromBigEndian( fst[ entryToDelete ].NextOffset ) - entryToDelete; - fstLenToDelete = 0; - for( quint32 i = entryToDelete; i < qFromBigEndian( fst[ entryToDelete ].NextOffset ); i ++ ) - { - fstLenToDelete += FstName( i ).size() + 1 + 0xc; - } + parent = qFromBigEndian( fst[ entryToDelete ].ParentOffset ); + while( parent ) + { + parents << parent; + parent = qFromBigEndian( fst[ parent ].ParentOffset ); + } + numDeletedEntries = qFromBigEndian( fst[ entryToDelete ].NextOffset ) - entryToDelete; + fstLenToDelete = 0; + for( quint32 i = entryToDelete; i < qFromBigEndian( fst[ entryToDelete ].NextOffset ); i ++ ) + { + fstLenToDelete += FstName( i ).size() + 1 + 0xc; + } } else//deleting a file { - parent = entryToDelete - 1; - while( parent ) - { - if( fst[ parent ].Type && qFromBigEndian( fst[ parent ].NextOffset ) > (quint32)entryToDelete ) - { - parents << parent; - parent = qFromBigEndian( fst[ parent ].ParentOffset ); - } - else - parent--; - } - numDeletedEntries = 1; - fstLenToDelete = FstName( entryToDelete ).size() + 1 + 0xc; + parent = entryToDelete - 1; + while( parent ) + { + if( fst[ parent ].Type && qFromBigEndian( fst[ parent ].NextOffset ) > (quint32)entryToDelete ) + { + parents << parent; + parent = qFromBigEndian( fst[ parent ].ParentOffset ); + } + else + parent--; + } + numDeletedEntries = 1; + fstLenToDelete = FstName( entryToDelete ).size() + 1 + 0xc; } @@ -468,63 +468,63 @@ bool U8::RemoveEntry( const QString &path ) QList movedDirs;//keep a list of the directories that are shifted back so their children can be shifted too for( quint32 i = 1; i < cnt; i++ ) { - if( i >= (quint32)entryToDelete && i < (quint32)( entryToDelete + numDeletedEntries ) )//skip deleted entries - continue; + if( i >= (quint32)entryToDelete && i < (quint32)( entryToDelete + numDeletedEntries ) )//skip deleted entries + continue; - //copy old entries and adjust as needed - quint8 adj = i < (quint32)entryToDelete ? 0 : numDeletedEntries; - quint32 ni = i - adj; + //copy old entries and adjust as needed + quint8 adj = i < (quint32)entryToDelete ? 0 : numDeletedEntries; + quint32 ni = i - adj; - //qDebug() << "keeping" << FstName( i ) << "in the new archive ( moved from" << hex << i << "to" << hex << ni << ")"; - //if( parents.contains( i ) ) - //qDebug() << "\tthis is a parent of the deleted item"; + //qDebug() << "keeping" << FstName( i ) << "in the new archive ( moved from" << hex << i << "to" << hex << ni << ")"; + //if( parents.contains( i ) ) + //qDebug() << "\tthis is a parent of the deleted item"; - FEntry *e = &fst[ i ];//old entry - FEntry *ne = &nfst[ ni ];//new entry + FEntry *e = &fst[ i ];//old entry + FEntry *ne = &nfst[ ni ];//new entry - nfst[ ni ].NameOffset = swap24( nNameTable.size() );//offset to the new entry's name in the string table + nfst[ ni ].NameOffset = swap24( nNameTable.size() );//offset to the new entry's name in the string table - //add the name to the new name table - nNameTable.append( FstName( e ).toLatin1() ); - nNameTable.append( '\0' ); + //add the name to the new name table + nNameTable.append( FstName( e ).toLatin1() ); + nNameTable.append( '\0' ); - if( e->Type )//directory - { - ne->Type = 1; - if( !adj )//directories before the new entry - { - ne->ParentOffset = e->ParentOffset; - ne->NextOffset = qFromBigEndian( qFromBigEndian( e->NextOffset ) \ - - ( parents.contains( i ) ? numDeletedEntries : 0 ) ); - } - else//directories after the new entry - { - ne->ParentOffset = qFromBigEndian( qFromBigEndian( e->ParentOffset ) \ - - ( movedDirs.contains( qFromBigEndian( e->ParentOffset ) ) ? numDeletedEntries : 0 ) ); - ne->NextOffset = qFromBigEndian( qFromBigEndian( e->NextOffset ) - numDeletedEntries ); + if( e->Type )//directory + { + ne->Type = 1; + if( !adj )//directories before the new entry + { + ne->ParentOffset = e->ParentOffset; + ne->NextOffset = qFromBigEndian( qFromBigEndian( e->NextOffset ) \ + - ( parents.contains( i ) ? numDeletedEntries : 0 ) ); + } + else//directories after the new entry + { + ne->ParentOffset = qFromBigEndian( qFromBigEndian( e->ParentOffset ) \ + - ( movedDirs.contains( qFromBigEndian( e->ParentOffset ) ) ? numDeletedEntries : 0 ) ); + ne->NextOffset = qFromBigEndian( qFromBigEndian( e->NextOffset ) - numDeletedEntries ); - movedDirs << i; + movedDirs << i; - //qDebug() << "e.parent:" << hex << qFromBigEndian( e->ParentOffset ) << "movedDirs:" << movedDirs; - //hexdump( (const void*)ne, sizeof( FEntry) ); - } - } - else//file - { - ne->Type = 0; - ne->FileOffset = \ - qFromBigEndian( (quint32)( 0x20 + RU( nFstSize, U8_HEADER_ALIGNMENT ) + nPayload.size() ) ); - ne->FileLength = e->FileLength; - nPayload.append( data.mid( qFromBigEndian( e->FileOffset ), qFromBigEndian( e->FileLength ) ) ); - int padding = RU( nPayload.size(), 0x20 ) - nPayload.size();//pad to 0x20 bytes between files - if( padding ) - { - nPayload.append( QByteArray( padding, '\0' ) ); - } - //qDebug() << "writing fileOffset of" << hex << ni << hex << (quint32)( 0x20 + RU( U8_HEADER_ALIGNMENT, nFstSize ) + nPayload.size() ); - } - //hexdump( (const void*)ne, sizeof( FEntry) ); + //qDebug() << "e.parent:" << hex << qFromBigEndian( e->ParentOffset ) << "movedDirs:" << movedDirs; + //hexdump( (const void*)ne, sizeof( FEntry) ); + } + } + else//file + { + ne->Type = 0; + ne->FileOffset = \ + qFromBigEndian( (quint32)( 0x20 + RU( nFstSize, U8_HEADER_ALIGNMENT ) + nPayload.size() ) ); + ne->FileLength = e->FileLength; + nPayload.append( data.mid( qFromBigEndian( e->FileOffset ), qFromBigEndian( e->FileLength ) ) ); + int padding = RU( nPayload.size(), 0x20 ) - nPayload.size();//pad to 0x20 bytes between files + if( padding ) + { + nPayload.append( QByteArray( padding, '\0' ) ); + } + //qDebug() << "writing fileOffset of" << hex << ni << hex << (quint32)( 0x20 + RU( U8_HEADER_ALIGNMENT, nFstSize ) + nPayload.size() ); + } + //hexdump( (const void*)ne, sizeof( FEntry) ); } //hexdump( nFstData ); @@ -536,8 +536,8 @@ bool U8::RemoveEntry( const QString &path ) QBuffer buf( &data ); if( !buf.open( QBuffer::WriteOnly ) ) { - qWarning() << "U8::AddEntry -> Can't create buffer"; - return -1; + qWarning() << "U8::AddEntry -> Can't create buffer"; + return -1; } buf.putChar( 'U' ); buf.putChar( '\xAA' ); @@ -552,7 +552,7 @@ bool U8::RemoveEntry( const QString &path ) t = qFromBigEndian( fstSize ); buf.write( (const char*)&t, 4 ); - data_offset = RU( ( 0x20 + fstSize ), U8_HEADER_ALIGNMENT ); + data_offset = RU( ( 0x20 + fstSize ), U8_HEADER_ALIGNMENT ); t = qFromBigEndian( data_offset ); buf.write( (const char*)&t, 4 ); buf.close(); @@ -561,14 +561,14 @@ bool U8::RemoveEntry( const QString &path ) int padding = data_offset - data.size();//pad to 'data_offset' after the fst if( padding ) { - data.append( QByteArray( padding, '\0' ) ); + data.append( QByteArray( padding, '\0' ) ); } data.append( nPayload );//add the actual file data - padding = RU( data.size(), 0x20 ) - data.size();//pad the entire thing to 0x20 bytes TOTO: should probably already be done, and this step is not really necessary + padding = RU( data.size(), 0x20 ) - data.size();//pad the entire thing to 0x20 bytes TOTO: should probably already be done, and this step is not really necessary if( padding ) { - data.append( QByteArray( padding, '\0' ) ); + data.append( QByteArray( padding, '\0' ) ); } //make sure the pirvate variables are correct @@ -590,70 +590,70 @@ int U8::AddEntry( const QString &path, int type, const QByteArray &newData ) //make sure there is actually data to manipulate if( !ok && !CreateEmptyData() ) { - return -1; + return -1; } //check if this is a path to a file in a nested archive QMap::iterator i = nestedU8s.begin(); while( i != nestedU8s.constEnd() ) { - if( path.startsWith( i.key() ) && path != i.key() ) - { - QString subPath = path; - //make a copy of the string, as "i" will become invalid on replace entry, and create a crash that is a bitch to track down - QString thisPath = i.key(); - U8 chVal = i.value(); - //qDebug() << "adding entry" << subPath << "in child U8" << thisPath; - subPath.remove( 0, thisPath.size() + 1 );//remove the path of the archive itself + the slash - bool ret = chVal.AddEntry( subPath, type, newData ); - if( !ret ) - { - qWarning() << "U8::AddEntry -> error replacing data in child U8 archive"; - return false; - } + if( path.startsWith( i.key() ) && path != i.key() ) + { + QString subPath = path; + //make a copy of the string, as "i" will become invalid on replace entry, and create a crash that is a bitch to track down + QString thisPath = i.key(); + U8 chVal = i.value(); + //qDebug() << "adding entry" << subPath << "in child U8" << thisPath; + subPath.remove( 0, thisPath.size() + 1 );//remove the path of the archive itself + the slash + bool ret = chVal.AddEntry( subPath, type, newData ); + if( !ret ) + { + qWarning() << "U8::AddEntry -> error replacing data in child U8 archive"; + return false; + } - if( !ReplaceEntry( thisPath, chVal.GetData() ) )//insert the new nested archive in this one - return -1; + if( !ReplaceEntry( thisPath, chVal.GetData() ) )//insert the new nested archive in this one + return -1; - //qDebug() << "done replacing the child entry in this archive, finding the index to return (" << thisPath << ")"; - return FindEntry( thisPath );//just return the index of the nested archive - } - i++; + //qDebug() << "done replacing the child entry in this archive, finding the index to return (" << thisPath << ")"; + return FindEntry( thisPath );//just return the index of the nested archive + } + i++; } //make sure this path doesnt already exist if( FindEntry( path ) != -1 ) { - qWarning() << "U8::AddEntry" << path << "already exists in the archive"; - return -1; + qWarning() << "U8::AddEntry" << path << "already exists in the archive"; + return -1; } //find the parent for this new entry QString parentPath = path; while( parentPath.startsWith( "/") )//remove leading "/"s - parentPath.remove( 0, 1 ); + parentPath.remove( 0, 1 ); while( parentPath.endsWith( "/") )//remove trailing "/"s - parentPath.resize( parentPath.size() - 1 ); + parentPath.resize( parentPath.size() - 1 ); int parent = 0; int slash = parentPath.lastIndexOf( "/" ); if( slash != -1 ) { - //parentPath.resize( ( parentPath.size() - slash ) - 2 ); - parentPath.chop( ( parentPath.size() - slash ) ); - parent = FindEntry( parentPath ); - if( parent == -1 )//need to create subfolders for this fucker - { - parent = AddEntry( parentPath, 1 ); - if( parent == -1 ) - { - qWarning() << "U8::AddEntry -> could not create subfolders for" << path; - return -1; - } - } - if( !fst[ parent ].Type )//parent maps to a file, not folder - { - qWarning() << "U8::AddEntry -> can't add child entry to a file"; - return -1; - } + //parentPath.resize( ( parentPath.size() - slash ) - 2 ); + parentPath.chop( ( parentPath.size() - slash ) ); + parent = FindEntry( parentPath ); + if( parent == -1 )//need to create subfolders for this fucker + { + parent = AddEntry( parentPath, 1 ); + if( parent == -1 ) + { + qWarning() << "U8::AddEntry -> could not create subfolders for" << path; + return -1; + } + } + if( !fst[ parent ].Type )//parent maps to a file, not folder + { + qWarning() << "U8::AddEntry -> can't add child entry to a file"; + return -1; + } } //qDebug() << "adding entry to" << FstName( parent ); @@ -664,9 +664,9 @@ int U8::AddEntry( const QString &path, int type, const QByteArray &newData ) QList parents; while( parentPath.contains( "/" ) ) { - parents << FindEntry( parentPath ); - int slash = parentPath.lastIndexOf( "/" ); - parentPath.chop( ( parentPath.size() - slash ) ); + parents << FindEntry( parentPath ); + int slash = parentPath.lastIndexOf( "/" ); + parentPath.chop( ( parentPath.size() - slash ) ); } parents << FindEntry( parentPath ); //qDebug() << "parents" << parents; @@ -678,7 +678,7 @@ int U8::AddEntry( const QString &path, int type, const QByteArray &newData ) int sl = name.lastIndexOf( "/" ); if( sl != -1 ) { - name.remove( 0, sl + 1 ); + name.remove( 0, sl + 1 ); } quint32 nFstSize = fstSize + 0x0C + name.size() + 1;//old fst size + 0xc bytes for the new entry + room for the new name in the string table @@ -699,74 +699,74 @@ int U8::AddEntry( const QString &path, int type, const QByteArray &newData ) QList movedDirs;//keep a list of the directories that are shifted back so their children can be shifted too for( quint32 i = 1; i < cnt; i++ ) { - nfst[ i ].NameOffset = swap24( nNameTable.size() );//offset to the new entry's name in the string table - if( i == (quint32)newEntry )//add the new entry - { - FEntry *ne = &nfst[ i ]; - if( type ) - { - ne->Type = 1; - ne->ParentOffset = qFromBigEndian( parent ); - ne->NextOffset = qFromBigEndian( i + 1 ); - } - else - { - ne->Type = 0; - ne->FileLength = qFromBigEndian( (quint32)newData.size() ); - ne->FileOffset =\ - qFromBigEndian( (quint32)( 0x20 + RU( nFstSize, U8_HEADER_ALIGNMENT ) + nPayload.size() ) ); - nPayload.append( newData ); - int padding = RU( nPayload.size(), 0x20 ) - nPayload.size();//pad to 0x20 bytes between files - if( padding ) - { - nPayload.append( QByteArray( padding, '\0' ) ); - } - } - nNameTable.append( name.toLatin1() );//add this entry's name to the table - nNameTable.append( '\0' ); - continue; - } + nfst[ i ].NameOffset = swap24( nNameTable.size() );//offset to the new entry's name in the string table + if( i == (quint32)newEntry )//add the new entry + { + FEntry *ne = &nfst[ i ]; + if( type ) + { + ne->Type = 1; + ne->ParentOffset = qFromBigEndian( parent ); + ne->NextOffset = qFromBigEndian( i + 1 ); + } + else + { + ne->Type = 0; + ne->FileLength = qFromBigEndian( (quint32)newData.size() ); + ne->FileOffset =\ + qFromBigEndian( (quint32)( 0x20 + RU( nFstSize, U8_HEADER_ALIGNMENT ) + nPayload.size() ) ); + nPayload.append( newData ); + int padding = RU( nPayload.size(), 0x20 ) - nPayload.size();//pad to 0x20 bytes between files + if( padding ) + { + nPayload.append( QByteArray( padding, '\0' ) ); + } + } + nNameTable.append( name.toLatin1() );//add this entry's name to the table + nNameTable.append( '\0' ); + continue; + } - //copy old entries and adjust as needed - quint8 adj = i < (quint32)newEntry ? 0 : 1; - quint32 ni = i - adj; + //copy old entries and adjust as needed + quint8 adj = i < (quint32)newEntry ? 0 : 1; + quint32 ni = i - adj; - FEntry *e = &fst[ ni ];//old entry - FEntry *ne = &nfst[ i ];//new entry + FEntry *e = &fst[ ni ];//old entry + FEntry *ne = &nfst[ i ];//new entry - //add the name to the new name table - nNameTable.append( FstName( e ).toLatin1() ); - nNameTable.append( '\0' ); - if( e->Type ) - { - ne->Type = 1; - if( !adj )//directories before the new entry - { - ne->ParentOffset = e->ParentOffset; - ne->NextOffset = qFromBigEndian( qFromBigEndian( e->NextOffset ) \ - + ( parents.contains( i ) ? 1 : 0 ) ); - } - else//directories after the new entry - { - movedDirs << ni; - ne->ParentOffset = qFromBigEndian( qFromBigEndian( e->ParentOffset ) \ - + ( movedDirs.contains( qFromBigEndian( e->ParentOffset ) ) ? 1 : 0 ) ); - ne->NextOffset = qFromBigEndian( qFromBigEndian( e->NextOffset ) + 1 ); - } - } - else//all file entries - { - ne->Type = 0; - ne->FileOffset = \ - qFromBigEndian( (quint32)( 0x20 + RU( nFstSize, U8_HEADER_ALIGNMENT ) + nPayload.size() ) ); - ne->FileLength = e->FileLength; - nPayload.append( data.mid( qFromBigEndian( e->FileOffset ), qFromBigEndian( e->FileLength ) ) ); - int padding = RU( nPayload.size(), 0x20 ) - nPayload.size();//pad to 0x20 bytes between files - if( padding ) - { - nPayload.append( QByteArray( padding, '\0' ) ); - } - } + //add the name to the new name table + nNameTable.append( FstName( e ).toLatin1() ); + nNameTable.append( '\0' ); + if( e->Type ) + { + ne->Type = 1; + if( !adj )//directories before the new entry + { + ne->ParentOffset = e->ParentOffset; + ne->NextOffset = qFromBigEndian( qFromBigEndian( e->NextOffset ) \ + + ( parents.contains( i ) ? 1 : 0 ) ); + } + else//directories after the new entry + { + movedDirs << ni; + ne->ParentOffset = qFromBigEndian( qFromBigEndian( e->ParentOffset ) \ + + ( movedDirs.contains( qFromBigEndian( e->ParentOffset ) ) ? 1 : 0 ) ); + ne->NextOffset = qFromBigEndian( qFromBigEndian( e->NextOffset ) + 1 ); + } + } + else//all file entries + { + ne->Type = 0; + ne->FileOffset = \ + qFromBigEndian( (quint32)( 0x20 + RU( nFstSize, U8_HEADER_ALIGNMENT ) + nPayload.size() ) ); + ne->FileLength = e->FileLength; + nPayload.append( data.mid( qFromBigEndian( e->FileOffset ), qFromBigEndian( e->FileLength ) ) ); + int padding = RU( nPayload.size(), 0x20 ) - nPayload.size();//pad to 0x20 bytes between files + if( padding ) + { + nPayload.append( QByteArray( padding, '\0' ) ); + } + } } //now put all the parts together to make a new U8 archive @@ -776,8 +776,8 @@ int U8::AddEntry( const QString &path, int type, const QByteArray &newData ) QBuffer buf( &data ); if( !buf.open( QBuffer::WriteOnly ) ) { - qWarning() << "U8::AddEntry -> Can't create buffer"; - return -1; + qWarning() << "U8::AddEntry -> Can't create buffer"; + return -1; } buf.putChar( 'U' ); buf.putChar( '\xAA' ); @@ -792,7 +792,7 @@ int U8::AddEntry( const QString &path, int type, const QByteArray &newData ) t = qFromBigEndian( fstSize ); buf.write( (const char*)&t, 4 ); - data_offset = RU( ( 0x20 + fstSize ), U8_HEADER_ALIGNMENT ); + data_offset = RU( ( 0x20 + fstSize ), U8_HEADER_ALIGNMENT ); t = qFromBigEndian( data_offset ); buf.write( (const char*)&t, 4 ); buf.close(); @@ -801,14 +801,14 @@ int U8::AddEntry( const QString &path, int type, const QByteArray &newData ) int padding = data_offset - data.size();//pad to 'data_offset' after the fst if( padding ) { - data.append( QByteArray( padding, '\0' ) ); + data.append( QByteArray( padding, '\0' ) ); } data.append( nPayload );//add the actual file data - padding = RU( data.size(), 0x20 ) - data.size();//pad the entire thing to 0x20 bytes TOTO: should probably already be done, and this step is not really necessary + padding = RU( data.size(), 0x20 ) - data.size();//pad the entire thing to 0x20 bytes TOTO: should probably already be done, and this step is not really necessary if( padding ) { - data.append( QByteArray( padding, '\0' ) ); + data.append( QByteArray( padding, '\0' ) ); } //make sure the pirvate variables are correct @@ -831,12 +831,12 @@ void U8::CreateEntryList() quint32 cnt = qFromBigEndian( fst[ 0 ].FileLength ); if( ( cnt * 0x0d ) + rootnode_offset > (quint32)data.size() ) { - qWarning() << "U8::CreateEntryList -> invalid archive"; - ok = false; - data.clear(); - paths.clear(); - fst = NULL; - return; + qWarning() << "U8::CreateEntryList -> invalid archive"; + ok = false; + data.clear(); + paths.clear(); + fst = NULL; + return; } NameOff = cnt * 0x0C; bool fixWarn = false;//ony print the warning 1 time @@ -844,79 +844,79 @@ void U8::CreateEntryList() //qDebug() << "cnt" << hex << cnt; for( quint32 i = 1; i < cnt; ++i )//this is not the most effecient way to do things, but it seems to work ok and these archives are small enough that it happens fast anyways { - //start at the beginning of the fst and enter every directory whos "nextoffset" is greater than this index, - //adding the names along the way and hopefully finding "i" - QString path; - quint32 current = 1; - quint32 folder = 0; - while( 1 ) - { - if( !current ) - { - qWarning() << "U8::CreateEntryList -> error parsing the archive"; - break; - } - if( current == i ) - { - path += FstName( i ); - if( fst[ current ].Type ) - { - //sanity check: make sure the parent offset is correct - if( folder != qFromBigEndian( fst[ current ].ParentOffset ) ) - { - qWarning() << "U8::CreateEntryList -> error parsing the archive - recursion mismatch in" - << path << "expected:" << hex << folder << "got:" << hex << qFromBigEndian( fst[ current ].ParentOffset )\ - << "(" << FstName( qFromBigEndian( fst[ current ].ParentOffset ) ) << ")"; + //start at the beginning of the fst and enter every directory whos "nextoffset" is greater than this index, + //adding the names along the way and hopefully finding "i" + QString path; + quint32 current = 1; + quint32 folder = 0; + while( 1 ) + { + if( !current ) + { + qWarning() << "U8::CreateEntryList -> error parsing the archive"; + break; + } + if( current == i ) + { + path += FstName( i ); + if( fst[ current ].Type ) + { + //sanity check: make sure the parent offset is correct + if( folder != qFromBigEndian( fst[ current ].ParentOffset ) ) + { + qWarning() << "U8::CreateEntryList -> error parsing the archive - recursion mismatch in" + << path << "expected:" << hex << folder << "got:" << hex << qFromBigEndian( fst[ current ].ParentOffset )\ + << "(" << FstName( qFromBigEndian( fst[ current ].ParentOffset ) ) << ")"; - //some tools use "recursion" instead of "parent offset". - //it just coincidentally works for archives such as the opening.bnr and .app since they dont have many folders to mess up - if( qFromBigEndian( fst[ current ].ParentOffset ) == (quint32)path.count( "/" ) ) - { - if( !fixWarn ) - { - qWarning() << "This archive was made by a broken tool such as U8Mii. I'm trying to fix it, but I can't make any promises"; - fixWarn = true; - } - fst[ current ].ParentOffset = qFromBigEndian( folder ); - } - } - path += "/"; - paths << path; - } - else - { - //add this file to the list of entries - paths << path; + //some tools use "recursion" instead of "parent offset". + //it just coincidentally works for archives such as the opening.bnr and .app since they dont have many folders to mess up + if( qFromBigEndian( fst[ current ].ParentOffset ) == (quint32)path.count( "/" ) ) + { + if( !fixWarn ) + { + qWarning() << "This archive was made by a broken tool such as U8Mii. I'm trying to fix it, but I can't make any promises"; + fixWarn = true; + } + fst[ current ].ParentOffset = qFromBigEndian( folder ); + } + } + path += "/"; + paths << path; + } + else + { + //add this file to the list of entries + paths << path; - //check if this file is really a U8 archive, and add it to the list of children - QByteArray chData = data.mid( qFromBigEndian( fst[ current ].FileOffset ), qFromBigEndian( fst[ current ].FileLength ) ); - if( IsU8( chData ) ) - { - U8 child( chData ); - if( child.IsOK() ) - { - nestedU8s.insert( path, child ); - foreach( QString chPath, child.Entries() ) - { - QString newPath = path + "/" + chPath; - paths << newPath; - } - } - } - } - break; - } - if( fst[ current ].Type && i < qFromBigEndian( fst[ current ].NextOffset ) ) - { - path += FstName( current ) + "/"; - folder = current; - current++; - continue; + //check if this file is really a U8 archive, and add it to the list of children + QByteArray chData = data.mid( qFromBigEndian( fst[ current ].FileOffset ), qFromBigEndian( fst[ current ].FileLength ) ); + if( IsU8( chData ) ) + { + U8 child( chData ); + if( child.IsOK() ) + { + nestedU8s.insert( path, child ); + foreach( QString chPath, child.Entries() ) + { + QString newPath = path + "/" + chPath; + paths << newPath; + } + } + } + } + break; + } + if( fst[ current ].Type && i < qFromBigEndian( fst[ current ].NextOffset ) ) + { + path += FstName( current ) + "/"; + folder = current; + current++; + continue; - } - current = NextEntryInFolder( current, folder ); - } - //paths << path; + } + current = NextEntryInFolder( current, folder ); + } + //paths << path; } //qDebug() << "done"; //qDebug() << "paths" << paths; @@ -937,28 +937,28 @@ void U8::Load( const QByteArray &ba ) imetNames.clear(); /*if( ba.size() < 0x80 ) { - //qWarning() << "U8::Load:" << hex << ba.size(); - //qWarning() << "U8::Load -> where is the rest of the data?"; - return; + //qWarning() << "U8::Load:" << hex << ba.size(); + //qWarning() << "U8::Load -> where is the rest of the data?"; + return; }*/ data = ba; if( IsAshCompressed( data ) )//decrypt ASH0 files - data = DecryptAsh( data ); + data = DecryptAsh( data ); quint32 tmp; int off = LZ77::GetLz77Offset( data ); int off2 = GetU8Offset( data ); if( off != -1 && ( off2 == -1 || ( off2 != -1 && off < off2 ) ) ) { - isLz77 = true; - data = LZ77::Decompress( data ); - off2 = GetU8Offset( data ); + isLz77 = true; + data = LZ77::Decompress( data ); + off2 = GetU8Offset( data ); } if( off2 == -1 ) { - qDebug() << "This isnt a U8"; - return; + qDebug() << "This isnt a U8"; + return; } data = data.mid( off2 ); @@ -966,8 +966,8 @@ void U8::Load( const QByteArray &ba ) QBuffer buf( &data ); if( !buf.open( QBuffer::ReadOnly ) ) { - qWarning() << "Can't create buffer"; - return; + qWarning() << "Can't create buffer"; + return; } buf.seek( 4 ); @@ -975,9 +975,9 @@ void U8::Load( const QByteArray &ba ) rootnode_offset = qFromBigEndian( tmp ); if( rootnode_offset != 0x20 ) { - qWarning() << "rootnodeOffset" << hex << rootnode_offset; - qWarning() << hex << data.size(); - hexdump( data ); + qWarning() << "rootnodeOffset" << hex << rootnode_offset; + qWarning() << hex << data.size(); + hexdump( data ); } buf.read( ( char*)&tmp, 4 ); @@ -1005,7 +1005,7 @@ QString U8::FstName( const FEntry *entry ) { //qDebug() << "U8::FstName"; if( entry == &fst[ 0 ] ) - return QString(); + return QString(); int nameStart = swap24( entry->NameOffset ) + NameOff + rootnode_offset; return data.mid( nameStart, nameStart + 0x100 ); @@ -1015,8 +1015,8 @@ QString U8::FstName( quint32 i ) { if( i > fst[ 0 ].FileLength ) { - qWarning() << "U8::FstName -> index is out of range"; - return QString(); + qWarning() << "U8::FstName -> index is out of range"; + return QString(); } return FstName( &fst[ i ] ); } @@ -1027,7 +1027,7 @@ quint32 U8::NextEntryInFolder( quint32 current, quint32 directory ) quint32 next = ( fst[ current ].Type ? qFromBigEndian( fst[ current ].FileLength ) : current + 1 ); //qDebug() << "next" << next << "len" << hex << qFromBigEndian( fst[ directory ].FileLength ); if( next < qFromBigEndian( fst[ directory ].FileLength ) ) - return next; + return next; return 0; } @@ -1036,19 +1036,19 @@ int U8::FindEntry( const QString &str, int d ) { //qDebug() << "U8::FindEntry(" << str << "," << d << ")"; if( str.isEmpty() ) - return 0; + return 0; if( str.startsWith( "/" ) ) { - QString r = str; - r.remove( 0, 1 ); - return FindEntry( r, d ); + QString r = str; + r.remove( 0, 1 ); + return FindEntry( r, d ); } if( !fst[ d ].Type ) { - qDebug() << "ERROR!!" << FstName( &fst[ d ] ) << "is not a directory"; - return -1; + qDebug() << "ERROR!!" << FstName( &fst[ d ] ) << "is not a directory"; + return -1; } int next = d + 1; @@ -1056,25 +1056,25 @@ int U8::FindEntry( const QString &str, int d ) while( next ) { - QString item; - int sl = str.indexOf( "/" ); - if( sl > -1 ) - item = str.left( sl ); - else - item = str; + QString item; + int sl = str.indexOf( "/" ); + if( sl > -1 ) + item = str.left( sl ); + else + item = str; - if( FstName( entry ) == item ) - { - if( item == str || item + "/" == str )//this is the item we are looking for - { - return next; - } - //this item is a parent folder of one we are looking for - return FindEntry( str.right( ( str.size() - sl ) - 1 ), next ); - } - //find the next entry in this folder - next = NextEntryInFolder( next, d ); - entry = &fst[ next ]; + if( FstName( entry ) == item ) + { + if( item == str || item + "/" == str )//this is the item we are looking for + { + return next; + } + //this item is a parent folder of one we are looking for + return FindEntry( str.right( ( str.size() - sl ) - 1 ), next ); + } + //find the next entry in this folder + next = NextEntryInFolder( next, d ); + entry = &fst[ next ]; } //no entry with the given path was found @@ -1086,66 +1086,66 @@ const QByteArray U8::GetData( const QString &str, bool onlyPayload ) //qDebug() << "U8::GetData(" << str << ")"; if( str.isEmpty() )//give the data for this whole archive { - if( onlyPayload ) - return data; + if( onlyPayload ) + return data; - //qDebug() << "U8::GetData -> returning all the data for this archive. headerType:" << headerType; + //qDebug() << "U8::GetData -> returning all the data for this archive. headerType:" << headerType; - QByteArray ret = data; + QByteArray ret = data; - switch( headerType ) - { - case U8_Hdr_IMET_app: - case U8_Hdr_IMET_bnr: - ret = AddIMET( headerType );//data is lz77 compressed in this function if it needs to be - break; - case U8_Hdr_IMD5: - { - if( isLz77 ) - ret = LZ77::Compress( ret ); + switch( headerType ) + { + case U8_Hdr_IMET_app: + case U8_Hdr_IMET_bnr: + ret = AddIMET( headerType );//data is lz77 compressed in this function if it needs to be + break; + case U8_Hdr_IMD5: + { + if( isLz77 ) + ret = LZ77::Compress( ret ); - ret = AddIMD5( ret ); + ret = AddIMD5( ret ); - //hexdump( ret, 0, 0x40 ); - } - break; - default: - break; - } - return ret; + //hexdump( ret, 0, 0x40 ); + } + break; + default: + break; + } + return ret; } //check if this is a path to a file in a nested archive QMap::iterator i = nestedU8s.begin(); while( i != nestedU8s.constEnd() ) { - if( str.startsWith( i.key() ) && str != i.key() ) - { - QString subPath = str; - subPath.remove( 0, i.key().size() + 1 );//remove the path of the archive itself + the slash - return i.value().GetData( subPath, onlyPayload ); - } - i++; + if( str.startsWith( i.key() ) && str != i.key() ) + { + QString subPath = str; + subPath.remove( 0, i.key().size() + 1 );//remove the path of the archive itself + the slash + return i.value().GetData( subPath, onlyPayload ); + } + i++; } int index = FindEntry( str ); if( index < 0 ) { - qWarning() << "U8::GetData" << str << "was not found in the archive"; - return QByteArray(); + qWarning() << "U8::GetData" << str << "was not found in the archive"; + return QByteArray(); } if( fst[ index ].Type ) { - qWarning() << "U8::GetData" << str << "is a directory"; - return QByteArray(); + qWarning() << "U8::GetData" << str << "is a directory"; + return QByteArray(); } QByteArray ret = data.mid( qFromBigEndian( fst[ index ].FileOffset ), qFromBigEndian( fst[ index ].FileLength ) ); //hexdump( ret, 0, 0x40 ); if( onlyPayload ) { - if( LZ77::GetLz77Offset( ret ) != -1 ) - ret = LZ77::Decompress( ret ); + if( LZ77::GetLz77Offset( ret ) != -1 ) + ret = LZ77::Decompress( ret ); - else if( IsAshCompressed( ret ) ) - ret = DecryptAsh( ret ); + else if( IsAshCompressed( ret ) ) + ret = DecryptAsh( ret ); } return ret; } @@ -1154,18 +1154,18 @@ quint32 U8::GetSize( const QString &str ) { if( str.isEmpty() ) { - return data.size(); + return data.size(); } int index = FindEntry( str ); if( index < 0 ) { - qWarning() << "U8::GetSize" << str << "was not found in the archive"; - return 0; + qWarning() << "U8::GetSize" << str << "was not found in the archive"; + return 0; } if( fst[ index ].Type ) { - qWarning() << "U8::GetSize" << str << "is a directory"; - return 0; + qWarning() << "U8::GetSize" << str << "is a directory"; + return 0; } return qFromBigEndian( fst[ index ].FileLength ); } @@ -1185,11 +1185,11 @@ bool U8::IsU8( const QByteArray &ba ) { QByteArray data = ba; if( IsAshCompressed( data ) )//decrypt ASH0 files - data = DecryptAsh( data ); + data = DecryptAsh( data ); int off = LZ77::GetLz77Offset( data );//decrypt LZ77 if( off != -1 ) - data = LZ77::Decompress( data ); + data = LZ77::Decompress( data ); QByteArray start = data.left( 5000 ); return start.indexOf( "U\xAA\x38\x2d" ) != -1; @@ -1198,14 +1198,14 @@ bool U8::IsU8( const QByteArray &ba ) #define IMET_MAX_NAME_LEN 0x2a typedef struct { - quint32 sig; // "IMET" - quint32 unk1; - quint32 unk2; - quint32 filesizes[ 3 ]; - quint32 unk3; - quint16 names[ 10 ][ IMET_MAX_NAME_LEN ]; - quint8 zeroes2[ 0x24c ]; - quint8 md5[ 0x10 ]; + quint32 sig; // "IMET" + quint32 unk1; + quint32 unk2; + quint32 filesizes[ 3 ]; + quint32 unk3; + quint16 names[ 10 ][ IMET_MAX_NAME_LEN ]; + quint8 zeroes2[ 0x24c ]; + quint8 md5[ 0x10 ]; } IMET; void U8::ReadHeader( const QByteArray &ba ) @@ -1216,54 +1216,54 @@ void U8::ReadHeader( const QByteArray &ba ) imetNames.clear(); if( ba.startsWith( "IMD5" ) )//dont bother to read any more data { - //qDebug() << "IMD5 header"; - headerType = U8_Hdr_IMD5; - return; + //qDebug() << "IMD5 header"; + headerType = U8_Hdr_IMD5; + return; } QByteArray start = ba.left( sizeof( IMET ) + 0x80 ); QBuffer buf( &start ); if( !buf.open( QBuffer::ReadOnly ) ) { - qWarning() << "U8::ReadHeader Can't create buffer"; - return; + qWarning() << "U8::ReadHeader Can't create buffer"; + return; } int off = start.indexOf( "IMET" ); //qDebug() << "imet offset" << hex << off << "u8 offset" << hex << GetU8Offset( ba ); if( off == 0x40 || off == 0x80 )//read imet header { - if( off > GetU8Offset( ba ) )//in case somebody wants to put a IMET archive inside another U8 for whatever reason - return; + if( off > GetU8Offset( ba ) )//in case somebody wants to put a IMET archive inside another U8 for whatever reason + return; - if( off == 0x40 ) - headerType = U8_Hdr_IMET_bnr; - else - headerType = U8_Hdr_IMET_app; + if( off == 0x40 ) + headerType = U8_Hdr_IMET_bnr; + else + headerType = U8_Hdr_IMET_app; - buf.seek( off ); - IMET imet; - buf.read( (char*)&imet, sizeof( IMET ) ); - buf.close(); + buf.seek( off ); + IMET imet; + buf.read( (char*)&imet, sizeof( IMET ) ); + buf.close(); - for( int h = 0; h < 10; h ++ ) - { - QString name; - for( int i = 0; i < IMET_MAX_NAME_LEN && imet.names[ h ][ i ] != 0; i++ )//no need to switch endian, 0x0000 is a palendrome - name += QChar( qFromBigEndian( imet.names[ h ][ i ] ) ); + for( int h = 0; h < 10; h ++ ) + { + QString name; + for( int i = 0; i < IMET_MAX_NAME_LEN && imet.names[ h ][ i ] != 0; i++ )//no need to switch endian, 0x0000 is a palendrome + name += QChar( qFromBigEndian( imet.names[ h ][ i ] ) ); - imetNames << name; - } - //done - return; + imetNames << name; + } + //done + return; } } QByteArray U8::AddIMD5( QByteArray ba ) { quint32 size = ba.size(); - /*MD5 hash; + /*MD5 hash; hash.update( ba.data(), size ); - hash.finalize();*/ + hash.finalize();*/ size = qFromBigEndian( size ); @@ -1271,8 +1271,8 @@ QByteArray U8::AddIMD5( QByteArray ba ) QBuffer buf( &imd5 ); if( !buf.open( QBuffer::WriteOnly ) ) { - qWarning() << "U8::AddIMD5 Can't create buffer"; - return QByteArray(); + qWarning() << "U8::AddIMD5 Can't create buffer"; + return QByteArray(); } buf.putChar( 'I' ); buf.putChar( 'M' ); @@ -1282,8 +1282,8 @@ QByteArray U8::AddIMD5( QByteArray ba ) buf.write( (const char*)&size, 4 ); buf.seek( 0x10 ); - buf.write( GetMd5( ba ) ); - //buf.write( (const char*)hash.hexdigestChar(), 16 ); + buf.write( GetMd5( ba ) ); + //buf.write( (const char*)hash.hexdigestChar(), 16 ); buf.close(); //qDebug() << hash.hexdigest().c_str(); //hexdump( (void*)imd5.data(), 0x20 ); @@ -1306,8 +1306,8 @@ QByteArray U8::GetIMET( const QStringList &names, int paddingType, quint32 iconS QBuffer buf( &ret ); if( !buf.open( QBuffer::WriteOnly ) ) { - qWarning() << "U8::GetIMET Can't create buffer"; - return QByteArray(); + qWarning() << "U8::GetIMET Can't create buffer"; + return QByteArray(); } buf.seek( 0 + 0x40 ); buf.putChar( 'I' ); @@ -1330,35 +1330,35 @@ QByteArray U8::GetIMET( const QStringList &names, int paddingType, quint32 iconS int numNames = names.size(); for( int i = 0; i < numNames; i++ ) { - QString name = names.at( i ); - int nameLen = name.size(); - buf.seek( nameOffset + ( IMET_MAX_NAME_LEN * i * 2 ) ); - for( int j = 0; j < nameLen; j++ ) - { - quint16 letter = qFromBigEndian( name.at( j ).unicode() ); - buf.write( ( const char*)&letter, 2 ); - } + QString name = names.at( i ); + int nameLen = name.size(); + buf.seek( nameOffset + ( IMET_MAX_NAME_LEN * i * 2 ) ); + for( int j = 0; j < nameLen; j++ ) + { + quint16 letter = qFromBigEndian( name.at( j ).unicode() ); + buf.write( ( const char*)&letter, 2 ); + } } - /*MD5 hash; + /*MD5 hash; hash.update( ret.data(), sizeof( IMET ) + 0x40 ); - hash.finalize();*/ + hash.finalize();*/ buf.seek( 0x5f0 ); - buf.write( GetMd5( ret ) ); - //buf.write( (const char*)hash.hexdigestChar(), 16 ); + buf.write( GetMd5( ret ) ); + //buf.write( (const char*)hash.hexdigestChar(), 16 ); buf.close(); switch( paddingType ) { case U8_Hdr_IMET_app: - ret.prepend( QByteArray( 0x40, '\0' ) ); - break; + ret.prepend( QByteArray( 0x40, '\0' ) ); + break; case U8_Hdr_IMET_bnr: - break; + break; default: - ret.remove( 0, 0x40 ); - break; + ret.remove( 0, 0x40 ); + break; } return ret; } @@ -1386,27 +1386,27 @@ const QByteArray U8::AddIMET( int paddingType ) //otherwise write the size - 0x20 ( imd5 header size ) if( LZ77::GetLz77Offset( ret ) != -1 ) - iconSize = LZ77::GetDecompressedSize( ret ); + iconSize = LZ77::GetDecompressedSize( ret ); else - iconSize = ret.size() - 0x20; + iconSize = ret.size() - 0x20; ret = GetData( "meta/banner.bin" ); if( LZ77::GetLz77Offset( ret ) != -1 ) - bannerSize = LZ77::GetDecompressedSize( ret ); + bannerSize = LZ77::GetDecompressedSize( ret ); else - bannerSize = ret.size() - 0x20; + bannerSize = ret.size() - 0x20; ret = GetData( "meta/sound.bin" ); if( LZ77::GetLz77Offset( ret ) != -1 ) - soundSize = LZ77::GetDecompressedSize( ret ); + soundSize = LZ77::GetDecompressedSize( ret ); else - soundSize = ret.size() - 0x20; + soundSize = ret.size() - 0x20; ret = GetIMET( imetNames, paddingType, iconSize, bannerSize, soundSize ); if( isLz77 )//really? can the entire banner be lz77 compressed? - ret += LZ77::Compress( data ); + ret += LZ77::Compress( data ); else - ret += data; + ret += data; return ret; } diff --git a/nandBinCheck/main.cpp b/nandBinCheck/main.cpp index 551bd1a..c84b336 100644 --- a/nandBinCheck/main.cpp +++ b/nandBinCheck/main.cpp @@ -39,10 +39,10 @@ int GetColor() { WORD wColor = 0; - HANDLE hStdOut = GetStdHandle( STD_OUTPUT_HANDLE ); + HANDLE hStdOut = GetStdHandle( STD_OUTPUT_HANDLE ); CONSOLE_SCREEN_BUFFER_INFO csbi; //We use csbi for the wAttributes word. - if( GetConsoleScreenBufferInfo( hStdOut, &csbi ) ) + if( GetConsoleScreenBufferInfo( hStdOut, &csbi ) ) { wColor = csbi.wAttributes; } @@ -69,19 +69,19 @@ struct bin_str static struct bin_str color_indicator[] = { { LEN_STR_PAIR ("\033[") }, /* lc: Left of color sequence */ - { LEN_STR_PAIR ("m") }, /* rc: Right of color sequence */ - { 0, NULL }, /* ec: End color (replaces lc+no+rc) */ - { LEN_STR_PAIR ("0") }, /* rs: Reset to ordinary colors */ - { 0, NULL }, /* no: Normal */ - { 0, NULL }, /* fi: File: default */ + { LEN_STR_PAIR ("m") }, /* rc: Right of color sequence */ + { 0, NULL }, /* ec: End color (replaces lc+no+rc) */ + { LEN_STR_PAIR ("0") }, /* rs: Reset to ordinary colors */ + { 0, NULL }, /* no: Normal */ + { 0, NULL }, /* fi: File: default */ { LEN_STR_PAIR ("01;34") }, /* di: Directory: bright blue */ { LEN_STR_PAIR ("01;36") }, /* ln: Symlink: bright cyan */ { LEN_STR_PAIR ("33") }, /* pi: Pipe: yellow/brown */ { LEN_STR_PAIR ("01;35") }, /* so: Socket: bright magenta */ { LEN_STR_PAIR ("01;33") }, /* bd: Block device: bright yellow */ { LEN_STR_PAIR ("01;33") }, /* cd: Char device: bright yellow */ - { 0, NULL }, /* mi: Missing file: undefined */ - { 0, NULL }, /* or: Orphaned symlink: undefined */ + { 0, NULL }, /* mi: Missing file: undefined */ + { 0, NULL }, /* or: Orphaned symlink: undefined */ { LEN_STR_PAIR ("01;32") }, /* ex: Executable: bright green */ { LEN_STR_PAIR ("01;35") }, /* do: Door: bright magenta */ { LEN_STR_PAIR ("37;41") }, /* su: setuid: white on red */ @@ -90,7 +90,7 @@ static struct bin_str color_indicator[] = { LEN_STR_PAIR ("34;42") }, /* ow: other-writable: blue on green */ { LEN_STR_PAIR ("30;42") }, /* tw: ow w/ sticky: black on green */ { LEN_STR_PAIR ("30;41") }, /* ca: black on red */ - { 0, NULL }, /* mh: disabled by default */ + { 0, NULL }, /* mh: disabled by default */ { LEN_STR_PAIR ("\033[K") }, /* cl: clear to end of line */ }; @@ -107,31 +107,31 @@ void PrintColoredString( const char *msg, int highlite ) } else { - QString str( msg ); - QStringList list = str.split( "\n", QString::SkipEmptyParts ); - foreach( QString s, list ) - { - QString m = s; - QString m2 = s.trimmed(); - m.resize( m.indexOf( m2 ) ); - printf( "%s", m.toLatin1().data() ); //print all leading whitespace + QString str( msg ); + QStringList list = str.split( "\n", QString::SkipEmptyParts ); + foreach( QString s, list ) + { + QString m = s; + QString m2 = s.trimmed(); + m.resize( m.indexOf( m2 ) ); + printf( "%s", m.toLatin1().data() ); //print all leading whitespace #ifdef Q_WS_WIN - SetConsoleTextAttribute( hConsole, highlite ); + SetConsoleTextAttribute( hConsole, highlite ); #else - put_indicator( &color_indicator[ C_LEFT ] ); - put_indicator( &color_indicator[ highlite ] ); //change color - put_indicator( &color_indicator[ C_RIGHT ] ); + put_indicator( &color_indicator[ C_LEFT ] ); + put_indicator( &color_indicator[ highlite ] ); //change color + put_indicator( &color_indicator[ C_RIGHT ] ); #endif - printf( "%s", m2.toLatin1().data() ); //print text + printf( "%s", m2.toLatin1().data() ); //print text #ifdef Q_WS_WIN - SetConsoleTextAttribute( hConsole, origColor ); + SetConsoleTextAttribute( hConsole, origColor ); #else - put_indicator( &color_indicator[ C_LEFT ] ); - put_indicator( &color_indicator[ C_NORM ] ); //reset color - put_indicator( &color_indicator[ C_RIGHT ] ); + put_indicator( &color_indicator[ C_LEFT ] ); + put_indicator( &color_indicator[ C_NORM ] ); //reset color + put_indicator( &color_indicator[ C_RIGHT ] ); #endif - printf( "\n" ); - } + printf( "\n" ); + } } fflush( stdout ); } @@ -144,14 +144,14 @@ void DebugHandler( QtMsgType type, const char *msg ) case QtDebugMsg: printf( "%s\n", msg ); break; - case QtWarningMsg: - PrintColoredString( msg, C_STICKY ); + case QtWarningMsg: + PrintColoredString( msg, C_STICKY ); break; - case QtCriticalMsg: - PrintColoredString( msg, C_CAP ); + case QtCriticalMsg: + PrintColoredString( msg, C_CAP ); break; case QtFatalMsg: - fprintf( stderr, "Fatal Error: %s\n", msg ); + fprintf( stderr, "Fatal Error: %s\n", msg ); abort(); break; } @@ -165,14 +165,14 @@ void Usage() qDebug() << ""; qDebug() << " -fs verify the filesystem is in tact"; qDebug() << " verifies presence of uid & content.map & checks the hashes in the content.map"; - qDebug() << " check sha1 hashes for title private contents"; + qDebug() << " check sha1 hashes for title private contents"; qDebug() << " check all titles with a ticket titles for required IOS, proper uid & gid"; qDebug() << ""; - qDebug() << " -settingtxt check setting.txt itself and against system menu resources. this must be combined with \"-fs\""; - qDebug() << ""; - qDebug() << " -uid Look any titles in the uid.sys, check signatures and whatnot. this must be combined with \"-fs\""; - qDebug() << ""; - qDebug() << " -rsa Calculate and compare RSA signatures. this must be combined with \"-fs\""; + qDebug() << " -settingtxt check setting.txt itself and against system menu resources. this must be combined with \"-fs\""; + qDebug() << ""; + qDebug() << " -uid Look any titles in the uid.sys, check signatures and whatnot. this must be combined with \"-fs\""; + qDebug() << ""; + qDebug() << " -rsa Calculate and compare RSA signatures. this must be combined with \"-fs\""; qDebug() << ""; qDebug() << " -clInfo shows free, used, and lost ( marked used, but dont belong to any file ) clusters"; qDebug() << ""; @@ -183,24 +183,24 @@ void Usage() qDebug() << ""; qDebug() << " -v increase verbosity"; qDebug() << ""; - qDebug() << " -continue try to keep going as fas as possible on errors that should be fatal"; - qDebug() << ""; - qDebug() << " -nocolor don\'t use terminal color trickery"; - qDebug() << ""; - qDebug() << " -about info about this program"; + qDebug() << " -continue try to keep going as fas as possible on errors that should be fatal"; + qDebug() << ""; + qDebug() << " -nocolor don\'t use terminal color trickery"; + qDebug() << ""; + qDebug() << " -about info about this program"; exit( 1 ); } void About() { - qCritical() << " (c) giantpune 2010, 2011"; - qCritical() << " http://code.google.com/p/wiiqt/"; - qCritical() << " built:" << __DATE__ << __TIME__; - qWarning() << "This software is licensed under GPLv2. It comes with no guarentee that it will work,"; - qWarning() << "or that it will work well."; - qDebug() << ""; - qDebug() << "This program is designed to gather information about a nand dump for a Nintendo Wii"; - exit( 1 ); + qCritical() << " (c) giantpune 2010, 2011"; + qCritical() << " http://code.google.com/p/wiiqt/"; + qCritical() << " built:" << __DATE__ << __TIME__; + qWarning() << "This software is licensed under GPLv2. It comes with no guarentee that it will work,"; + qWarning() << "or that it will work well."; + qDebug() << ""; + qDebug() << "This program is designed to gather information about a nand dump for a Nintendo Wii"; + exit( 1 ); } void Fail( const QString& str ) @@ -241,7 +241,7 @@ void ShowBootInfo( quint8 boot1, QList boot2stuff ) qDebug() << "Boot1 D (fixed)"; break; default: - qWarning() << "unrecognized boot1 version"; + qWarning() << "unrecognized boot1 version"; break; } quint16 cnt = boot2stuff.size(); @@ -345,8 +345,8 @@ QTreeWidgetItem *ItemFromPath( const QString &path ) item = FindItem( lookingFor, item ); if( !item ) { - //if( verbose ) - // qWarning() << "ItemFromPath ->item not found" << path; + //if( verbose ) + // qWarning() << "ItemFromPath ->item not found" << path; return NULL; } slash = nextSlash + 1; @@ -390,27 +390,27 @@ QList< quint64 > InstalledTitles() for( quint16 j = 0; j < subfc2; j++ ) { QTreeWidgetItem *tikI = subF->child( j ); - QString name = tikI->text( 0 ); + QString name = tikI->text( 0 ); if( !name.endsWith( ".tik" ) ) - { + { continue; } name.resize( 8 ); quint32 lower = name.toUInt( &ok, 16 ); if( !ok ) - { + { continue; } //now see if there is a tmd QTreeWidgetItem *tmdI = ItemFromPath( "/title/" + subF->text( 0 ) + "/" + name + "/content/title.tmd" ); if( !tmdI ) - { + { continue; } - quint64 tid = ( ( (quint64)upper << 32) | lower ); + quint64 tid = ( ( (quint64)upper << 32) | lower ); ret << tid; } } @@ -461,9 +461,9 @@ void BuildGoodIosList() if( ba.isEmpty() ) continue; - Tmd t( ba ); //skip stubbzzzzz - if( !( t.Version() % 0x100 ) && //version is a nice pretty round number - t.Count() == 3 && //3 contents, 1 private and 2 shared + Tmd t( ba ); //skip stubbzzzzz + if( !( t.Version() % 0x100 ) && //version is a nice pretty round number + t.Count() == 3 && //3 contents, 1 private and 2 shared t.Type( 0 ) == 1 && t.Type( 1 ) == 0x8001 && t.Type( 2 ) == 0x8001 ) @@ -473,7 +473,7 @@ void BuildGoodIosList() if( !CheckTitleIntegrity( tid ) ) continue; - validIoses << tid; //seems good enough. add it to the list + validIoses << tid; //seems good enough. add it to the list } } @@ -530,110 +530,110 @@ void PrintName( const QByteArray &app ) bool CheckArm003( const QByteArray &stuff ) { - qint32 esTag = MAX( stuff.indexOf( "$IOSVersion: ES" ), stuff.indexOf( "$IOSVersion: ES" ) ); - if( esTag < 0 ) - { - qWarning() << "\tFailed to find the ES module in the kernel"; - return false; - } - if( stuff.contains( QByteArray::fromHex( "e2511cb1d7fbbef8d7f97db5a1d81694" ) ) //1337 buffer #1 - || stuff.contains( QByteArray::fromHex( "3f5b8cc9ea855a0afa7347d23e8d664e" ) ) //1337 buffer #2 - || stuff.contains( QByteArray::fromHex( "b570b08868851c01310c22c0005218ab681b2b00d10248bff001f852680b2b45" ) ) )//blablabla, CMP R3, #0x45 - { - if( verbose > 1 ) - qWarning() << "\tSystem menu IOS supports the Korean-key check"; - return true; - } - if( verbose > 1 ) - qDebug() << "\tSystem menu IOS does not appear to support the Korean-key check"; + qint32 esTag = MAX( stuff.indexOf( "$IOSVersion: ES" ), stuff.indexOf( "$IOSVersion: ES" ) ); + if( esTag < 0 ) + { + qWarning() << "\tFailed to find the ES module in the kernel"; + return false; + } + if( stuff.contains( QByteArray::fromHex( "e2511cb1d7fbbef8d7f97db5a1d81694" ) ) //1337 buffer #1 + || stuff.contains( QByteArray::fromHex( "3f5b8cc9ea855a0afa7347d23e8d664e" ) ) //1337 buffer #2 + || stuff.contains( QByteArray::fromHex( "b570b08868851c01310c22c0005218ab681b2b00d10248bff001f852680b2b45" ) ) )//blablabla, CMP R3, #0x45 + { + if( verbose > 1 ) + qWarning() << "\tSystem menu IOS supports the Korean-key check"; + return true; + } + if( verbose > 1 ) + qDebug() << "\tSystem menu IOS does not appear to support the Korean-key check"; - return false; + return false; } void Check003() { - qDebug() << "Checking for 003 error ..."; - if( sysMenuExe.isEmpty() ) - { - qWarning() << "can\'t check 003 error for empty data"; - return; - } - bool brick = true; + qDebug() << "Checking for 003 error ..."; + if( sysMenuExe.isEmpty() ) + { + qWarning() << "can\'t check 003 error for empty data"; + return; + } + bool brick = true; - //check the PPC half - if( !sysMenuExe.contains( QByteArray::fromHex( "3880004538A0000038C00000" ) ) ) //li %r4, 0x45 - { //li %r5, 0 - brick = false; //li %r6, 0 - if( verbose > 1 ) - qDebug() << "\tThe system menu doesn\'t appear to perform the Korean-key check"; - } - else if( verbose > 1 ) - qWarning() << "\tThe system menu performs the Korean-key check"; + //check the PPC half + if( !sysMenuExe.contains( QByteArray::fromHex( "3880004538A0000038C00000" ) ) ) //li %r4, 0x45 + { //li %r5, 0 + brick = false; //li %r6, 0 + if( verbose > 1 ) + qDebug() << "\tThe system menu doesn\'t appear to perform the Korean-key check"; + } + else if( verbose > 1 ) + qWarning() << "\tThe system menu performs the Korean-key check"; - //check the ARM half - QString iosStr = TidTxt( sysMenuIos ); - iosStr.insert( 8, "/" ); - iosStr.prepend( "/title/" ); - iosStr += "/content/"; - QByteArray tmdD = nand.GetData( iosStr + "title.tmd" ); - if( tmdD.isEmpty() ) - { - qWarning() << "\tcan\'t read systemmenu-ios's TMD"; - return; - } - Tmd t( tmdD ); - QByteArray iosKernel; - QString kernelPath; - quint16 cnt = t.Count(); - if( t.BootIndex() >= cnt ) //in case there is some really fucked up TMD - { - Fail( "\tThe system menu ios bootindex is fucked up pretty bad" ); - return; - } - if( t.Type( t.BootIndex() ) == 0x8001 ) - { - QString appname = sharedM.GetAppFromHash( t.Hash( t.BootIndex() ) ); - if( appname.isEmpty() ) - { - Fail( "\tError reading the system menu ios" ); - return; - } + //check the ARM half + QString iosStr = TidTxt( sysMenuIos ); + iosStr.insert( 8, "/" ); + iosStr.prepend( "/title/" ); + iosStr += "/content/"; + QByteArray tmdD = nand.GetData( iosStr + "title.tmd" ); + if( tmdD.isEmpty() ) + { + qWarning() << "\tcan\'t read systemmenu-ios's TMD"; + return; + } + Tmd t( tmdD ); + QByteArray iosKernel; + QString kernelPath; + quint16 cnt = t.Count(); + if( t.BootIndex() >= cnt ) //in case there is some really fucked up TMD + { + Fail( "\tThe system menu ios bootindex is fucked up pretty bad" ); + return; + } + if( t.Type( t.BootIndex() ) == 0x8001 ) + { + QString appname = sharedM.GetAppFromHash( t.Hash( t.BootIndex() ) ); + if( appname.isEmpty() ) + { + Fail( "\tError reading the system menu ios" ); + return; + } - kernelPath = "/shared1/" + appname + ".app"; - } - else - { - kernelPath = iosStr + t.Cid( t.BootIndex() ) + ".app"; - } - iosKernel = nand.GetData( kernelPath ); - if( iosKernel.isEmpty() ) - { - Fail( "\tError reading the system menu ios data" ); - return; - } - if( !CheckArm003( iosKernel ) ) - brick = false; + kernelPath = "/shared1/" + appname + ".app"; + } + else + { + kernelPath = iosStr + t.Cid( t.BootIndex() ) + ".app"; + } + iosKernel = nand.GetData( kernelPath ); + if( iosKernel.isEmpty() ) + { + Fail( "\tError reading the system menu ios data" ); + return; + } + if( !CheckArm003( iosKernel ) ) + brick = false; - //look for korean keys in keys.bin - QByteArray keys = nand.Keys(); - if( keys.size() != 0x400 ) - { - Fail( "\tError getting nand keys" ); - return; - } - quint8 k_key[ 16 ] = KOREAN_KEY; - if( !keys.contains( QByteArray( (const char*)&k_key, 16 ) ) ) - { - brick = false; - if( verbose > 1 ) - qDebug() << "\tThe korean key is not present in this wii"; - } - else if( verbose > 1 ) - qWarning() << "\tThis wii contains the korean key"; + //look for korean keys in keys.bin + QByteArray keys = nand.Keys(); + if( keys.size() != 0x400 ) + { + Fail( "\tError getting nand keys" ); + return; + } + quint8 k_key[ 16 ] = KOREAN_KEY; + if( !keys.contains( QByteArray( (const char*)&k_key, 16 ) ) ) + { + brick = false; + if( verbose > 1 ) + qDebug() << "\tThe korean key is not present in this wii"; + } + else if( verbose > 1 ) + qWarning() << "\tThis wii contains the korean key"; - if( brick ) - Fail( "\tThis wii will likely show the 003 error" ); + if( brick ) + Fail( "\tThis wii will likely show the 003 error" ); } bool CheckTitleIntegrity( quint64 tid ) @@ -668,27 +668,27 @@ bool CheckTitleIntegrity( quint64 tid ) qDebug() << "error getting" << it << "data"; return false; } - if( calcRsa ) - { - qint32 ch = check_cert_chain( ba ); - switch( ch ) - { - case ERROR_SIG_TYPE: - case ERROR_SUB_TYPE: - case ERROR_RSA_HASH: - case ERROR_RSA_TYPE_UNKNOWN: - case ERROR_RSA_TYPE_MISMATCH: - case ERROR_CERT_NOT_FOUND: - qWarning().nospace() << "\t" << qPrintable( it ) << " RSA signature isn't even close ( " << ch << " )"; - //return false; //maye in the future this will be true, but for now, this doesnt mean it wont boot - break; - case ERROR_RSA_FAKESIGNED: - qWarning().nospace() << "\t" << qPrintable( it ) << " fakesigned"; - break; - default: - break; - } - } + if( calcRsa ) + { + qint32 ch = check_cert_chain( ba ); + switch( ch ) + { + case ERROR_SIG_TYPE: + case ERROR_SUB_TYPE: + case ERROR_RSA_HASH: + case ERROR_RSA_TYPE_UNKNOWN: + case ERROR_RSA_TYPE_MISMATCH: + case ERROR_CERT_NOT_FOUND: + qWarning().nospace() << "\t" << qPrintable( it ) << " RSA signature isn't even close ( " << ch << " )"; + //return false; //maye in the future this will be true, but for now, this doesnt mean it wont boot + break; + case ERROR_RSA_FAKESIGNED: + qWarning().nospace() << "\t" << qPrintable( it ) << " fakesigned"; + break; + default: + break; + } + } if( i ) { t = Tmd( ba ); @@ -721,7 +721,7 @@ bool CheckTitleIntegrity( quint64 tid ) { qWarning() << "\tone of the shared contents is missing"; return false; - } + } } else//private { @@ -746,22 +746,22 @@ bool CheckTitleIntegrity( quint64 tid ) //if we are going to check the setting.txt stuff, we need to get the system menu resource file to compare ( check for opera bricks ) //so far, i think this file is always boot index 1, type 1 - if( tid == 0x100000002ull ) - { - if( t.Index( i ) == 1 && - ( args.contains( "-settingtxt", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) ) ) - { - sysMenuResource = ba; - } - else if( t.Index( i ) == t.BootIndex() ) - sysMenuExe = ba; - } + if( tid == 0x100000002ull ) + { + if( t.Index( i ) == 1 && + ( args.contains( "-settingtxt", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) ) ) + { + sysMenuResource = ba; + } + else if( t.Index( i ) == t.BootIndex() ) + sysMenuExe = ba; + } //print a description of this title - if( verbose > 1 && t.Index( i ) == 0 ) + if( verbose > 1 && t.Index( i ) == 0 ) { PrintName( ba ); - } + } } } @@ -782,11 +782,11 @@ bool CheckTitleIntegrity( quint64 tid ) qWarning() << "\tthe IOS for this title is not bootable\n\t" << TidTxt( ios ).insert( 8, "-" ); return false; } - if( tid == 0x100000002ull ) - sysMenuIos = ios; + if( tid == 0x100000002ull ) + sysMenuIos = ios; - if( verbose > 1 && ( upper != 1 || tid == 0x100000002ull ) ) - qDebug() << "\trequires IOS" << ((quint32)( ios & 0xffffffff )); + if( verbose > 1 && ( upper != 1 || tid == 0x100000002ull ) ) + qDebug() << "\trequires IOS" << ((quint32)( ios & 0xffffffff )); quint32 uid = uidM.GetUid( tid, false ); if( !uid ) { @@ -808,7 +808,7 @@ bool CheckTitleIntegrity( quint64 tid ) if( dataI->text( 3 ) != uidS || !dataI->text( 4 ).startsWith( gidS ) )//dont necessarily fail for this. the title will still be bootable without its data qWarning() << "\tincorrect uid/gid for data folder"; - RecurseCheckGidUid( dataI, uidS, gidS, "data/" ); + RecurseCheckGidUid( dataI, uidS, gidS, "data/" ); } dataP.resize( 25 ); dataP += "content"; @@ -835,7 +835,7 @@ void ListDeletedTitles() return; } qDebug() << "Comparing uid.sys against the filesystem..."; - //hexdump12( uidSys ); + //hexdump12( uidSys ); QBuffer buf( &uidSys ); buf.open( QIODevice::ReadWrite ); @@ -851,9 +851,9 @@ void ListDeletedTitles() tid = qFromBigEndian( tid ); quint32 upper = ( ( tid >> 32 ) & 0xffffffff ); quint32 lower = ( tid & 0xffffffff ); - if( ( upper == 0x10001 && ( ( lower >> 24 ) & 0xff ) != 0x48 ) || //a channel, not starting with 'H' - lower == 0x48415858 || //original HBC - tid == 0x100000000ull || //bannerbomb -> ATD ( or any other program that uses the SU tid ) + if( ( upper == 0x10001 && ( ( lower >> 24 ) & 0xff ) != 0x48 ) || //a channel, not starting with 'H' + lower == 0x48415858 || //original HBC + tid == 0x100000000ull || //bannerbomb -> ATD ( or any other program that uses the SU tid ) ( upper == 0x10000 && ( ( lower & 0xffffff00 ) == 0x555000 ) ) ) //a disc update partition break; if( ( verbose || upper != 0x10000 ) && !tids.contains( tid ) ) @@ -892,7 +892,7 @@ void ListDeletedTitles() qWarning() << "\tError reading TMD for" << qPrintable( TidTxt( tid ).insert( 8, "-" ) + ( upper != 1 ? " (" + AsciiTxt( lower ) + ")" : "" ) ); deleted = true; } - else if( calcRsa ) + else if( calcRsa ) { qint32 ch = check_cert_chain( ba ); switch( ch ) @@ -933,7 +933,7 @@ void ListDeletedTitles() qWarning() << "\tError reading ticket for" << qPrintable( TidTxt( tid ).insert( 8, "-" ) + ( upper != 1 ? " (" + AsciiTxt( lower ) + ")" : "" ) ); deleted = true; } - else if( calcRsa ) + else if( calcRsa ) { qint32 ch = check_cert_chain( ba ); switch( ch ) @@ -964,8 +964,8 @@ void ListDeletedTitles() void CheckLostClusters() { QList u = nand.GetFatsForEntry( 0 );//all clusters actually used for a file - if( verbose ) - qDebug() << "total used clusters" << hex << u.size() << "of 0x8000"; + if( verbose ) + qDebug() << "total used clusters" << hex << u.size() << "of 0x8000"; quint16 lost = 0; QList ffs; QList frs; @@ -1006,7 +1006,7 @@ void CheckEcc() for( quint16 i = 0; i < 0x8000; i++ ) { if( fats.at( i ) == 0xfffd || fats.at( i ) == 0xfffe ) - continue; + continue; for( quint8 j = 0; j < 8; j++, checked += 8 ) { @@ -1026,16 +1026,16 @@ void CheckEcc() { quint16 p = clustersCpy.takeFirst(); if( fats.at( p ) < 0xfff0 ) - badClustersNotSpecial++; + badClustersNotSpecial++; quint16 block = p/8; if( !blocks.contains( block ) ) blocks << block; - } + } qDebug() << bad.size() << "out of" << checked << "pages had incorrect ecc.\nthey were spread through" << clusters.size() << "clusters in" << blocks.size() << "blocks:\n" << blocks; - qDebug() << badClustersNotSpecial << "of those clusters are non-special (they belong to the fs)"; + qDebug() << badClustersNotSpecial << "of those clusters are non-special (they belong to the fs)"; } @@ -1258,17 +1258,17 @@ int main( int argc, char *argv[] ) origColor = GetColor(); hConsole = GetStdHandle( STD_OUTPUT_HANDLE ); #endif - qInstallMsgHandler( DebugHandler ); - qCritical() << "** nandBinCheck : Wii nand info tool **"; - qCritical() << " from giantpune"; - qCritical() << " built:" << __DATE__ << __TIME__; + qInstallMsgHandler( DebugHandler ); + qCritical() << "** nandBinCheck : Wii nand info tool **"; + qCritical() << " from giantpune"; + qCritical() << " built:" << __DATE__ << __TIME__; args = QCoreApplication::arguments(); - if( args.contains( "-nocolor", Qt::CaseInsensitive ) ) + if( args.contains( "-nocolor", Qt::CaseInsensitive ) ) color = false; - if( args.contains( "-about", Qt::CaseInsensitive ) ) - About(); + if( args.contains( "-about", Qt::CaseInsensitive ) ) + About(); if( args.size() < 3 ) Usage(); @@ -1281,13 +1281,13 @@ int main( int argc, char *argv[] ) root = NULL; - verbose = args.count( "-v" ); + verbose = args.count( "-v" ); - if( args.contains( "-continue", Qt::CaseInsensitive ) ) - tryToKeepGoing = true; + if( args.contains( "-continue", Qt::CaseInsensitive ) ) + tryToKeepGoing = true; - if( args.contains( "-rsa", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) ) - calcRsa = true; + if( args.contains( "-rsa", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) ) + calcRsa = true; //these only serve to show info. no action is taken if( args.contains( "-boot", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) ) @@ -1321,7 +1321,7 @@ int main( int argc, char *argv[] ) //if( !CheckTitleIntegrity( tid ) && tid == 0x100000002ull ) //well, this SHOULD be the case. but nintendo doesnt care so much about //Fail( "The System menu isnt valid" ); //checking signatures & hashes as the rest of us. } - Check003(); + Check003(); if( args.contains( "-settingtxt", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) ) { CheckSettingTxt();