public static IFileSection ParseNextSection( System.IO.Stream stream ) { switch ( stream.PeekUInt32().SwapEndian() ) { case 0x43464C44: return new FileSections.CFLD( stream ); case 0x44415441: return new FileSections.DATA( stream ); case 0x4D455320: return new FileSections.MES( stream ); case 0x4E414D45: return new FileSections.NAME( stream ); case 0x5441424C: return new FileSections.TABL( stream ); default: throw new Exception( "Unknown file section '" + Encoding.ASCII.GetString( BitConverter.GetBytes( stream.PeekUInt32() ) ) + "'." ); } }
public CFLD( System.IO.Stream stream ) : base(stream) { if ( SectionIdentifierHumanReadable != "CFLD" ) { throw new System.Exception( "Attempted to parse a 'CFLD' section with data from a '" + SectionIdentifierHumanReadable + "' section." ); } Subsections = new List<IFileSection>(); long PositionAtBeginning = stream.Position; stream.ReadAlign( 0x10 ); while ( stream.Position < PositionAtBeginning + _SectionSize ) { if ( stream.PeekUInt32() == 0x00000000 ) { stream.DiscardBytes( 0x10 ); continue; } IFileSection s = FileSectionFactory.ParseNextSection( stream ); Subsections.Add( s ); stream.ReadAlign( 0x10 ); } stream.ReadAlign( 0x10 ); }
public T8BTVABlock( System.IO.Stream stream, uint refStringStart ) { uint size = stream.PeekUInt32().SwapEndian(); if ( size % 4 != 0 ) { throw new Exception( "T8BTVABlock size must be divisible by 4!" ); } if ( size / 4 < 14 ) { throw new Exception( "T8BTVABlock must contain at least 14 ints!" ); } Size = stream.ReadUInt32().SwapEndian(); IndexInArray = stream.ReadUInt32().SwapEndian(); IndexInGame = stream.ReadUInt32().SwapEndian(); IdentifierLocation = stream.ReadUInt32().SwapEndian(); CharacterSpecificData = new uint[9]; for ( int i = 0; i < 9; ++i ) { CharacterSpecificData[i] = stream.ReadUInt32().SwapEndian(); } EntryCount = stream.ReadUInt32().SwapEndian(); Identifier = stream.ReadAsciiNulltermFromLocationAndReset( IdentifierLocation + refStringStart ); Entries = new List<T8BTVAEntry>( (int)EntryCount ); for ( uint i = 0; i < EntryCount; ++i ) { Entries.Add( new T8BTVAEntry( stream, refStringStart ) ); } }
public StrategySet( System.IO.Stream stream, uint refStringStart ) { uint[] Data; uint entrySize = stream.PeekUInt32().SwapEndian(); Data = new uint[entrySize / 4]; for ( int i = 0; i < Data.Length; ++i ) { Data[i] = stream.ReadUInt32().SwapEndian(); } ID = Data[1]; uint refStringLocation = Data[2]; NameStringDicID = Data[3]; DescStringDicID = Data[4]; StrategyDefaults = new uint[8, 9]; for ( uint x = 0; x < 8; ++x ) { for ( uint y = 0; y < 9; ++y ) { StrategyDefaults[x, y] = Data[x * 9 + y + 5]; } } ID2 = Data[77]; UnknownFloats1 = new float[9]; for ( int i = 0; i < UnknownFloats1.Length; ++i ) { UnknownFloats1[i] = Data[78 + i].UIntToFloat(); } UnknownFloats2 = new float[9]; for ( int i = 0; i < UnknownFloats2.Length; ++i ) { UnknownFloats2[i] = Data[87 + i].UIntToFloat(); } long pos = stream.Position; stream.Position = refStringStart + refStringLocation; RefString = stream.ReadAsciiNullterm(); stream.Position = pos; }
public EncounterGroup( System.IO.Stream stream, uint refStringStart ) { uint[] Data; uint entryLength = stream.PeekUInt32().SwapEndian(); Data = new uint[entryLength / 4]; for ( int i = 0; i < Data.Length; ++i ) { Data[i] = stream.ReadUInt32().SwapEndian(); } ID = Data[1]; StringDicID = Data[2]; InGameID = Data[3]; EnemyGroupIDs = new uint[10]; for ( int i = 0; i < 10; ++i ) { EnemyGroupIDs[i] = Data[5 + i]; } long pos = stream.Position; stream.Position = refStringStart + Data[4]; RefString = stream.ReadAsciiNullterm(); stream.Position = pos; }
static bool PatchArm9( System.IO.FileStream nds, uint pos, uint len ) { nds.Position = pos; byte[] data = new byte[len]; nds.Read( data, 0, (int)len ); // decompress size info: http://www.crackerscrap.com/docs/dsromstructure.html // TODO: Is there a better way to figure out if an ARM9 is compressed? nds.Position = nds.Position - 8; uint compressedSize = nds.ReadUInt24(); byte headerLength = (byte)nds.ReadByte(); uint additionalCompressedSize = nds.ReadUInt32(); uint decompressedSize = additionalCompressedSize + len; bool compressed = false; byte[] decData = data; #if DEBUG Console.WriteLine( "ARM9 old dec size: 0x" + decompressedSize.ToString( "X6" ) ); Console.WriteLine( "ARM9 old cmp size: 0x" + compressedSize.ToString( "X6" ) ); Console.WriteLine( "ARM9 old filesize: 0x" + len.ToString( "X6" ) ); Console.WriteLine( "ARM9 old diff: 0x" + additionalCompressedSize.ToString( "X6" ) ); System.IO.File.WriteAllBytes( "arm9-raw.bin", data ); #endif blz blz = new blz(); // if one of these isn't true then it can't be blz-compressed so don't even try bool headerLengthValid = ( headerLength >= 8 && headerLength <= 11 ); bool compressedSizeValid = ( data.Length >= compressedSize + 0x4000 && data.Length <= compressedSize + 0x400B ); if ( headerLengthValid && compressedSizeValid ) { try { blz.arm9 = 1; byte[] maybeDecData = blz.BLZ_Decode( data ); if ( maybeDecData.Length == decompressedSize ) { compressed = true; decData = maybeDecData; #if DEBUG System.IO.File.WriteAllBytes( "arm9-dec.bin", decData ); #endif } } catch ( blzDecodingException ) { compressed = false; } } byte[] decDataUnmodified = (byte[])decData.Clone(); if ( ReplaceInData( decData, 0x00, true ) ) { if ( compressed ) { Console.WriteLine( "Replacing and recompressing ARM9..." ); data = blz.BLZ_Encode( decData, 0 ); uint newCompressedSize = (uint)data.Length; if ( newCompressedSize > len ) { // new ARM is actually bigger, redo without the additional nullterm replacement decData = decDataUnmodified; ReplaceInData( decData, 0x00, false ); data = blz.BLZ_Encode( decData, 0, supressWarnings: true ); newCompressedSize = (uint)data.Length; int arm9diff = (int)len - (int)newCompressedSize; if ( arm9diff < 0 ) { // still too big, remove debug strings if ( !RemoveStringsInKnownGames( GetGamecode( nds ), decData ) ) { RemoveDebugStrings( decData ); } #if DEBUG System.IO.File.WriteAllBytes( "arm9-dec-without-debug.bin", decData ); #endif data = blz.BLZ_Encode( decData, 0, supressWarnings: true ); newCompressedSize = (uint)data.Length; arm9diff = (int)len - (int)newCompressedSize; if ( arm9diff < 0 ) { Console.WriteLine( "WARNING: Recompressed ARM9 is " + -arm9diff + " bytes bigger than original!" ); Console.WriteLine( " Patched game may be corrupted!" ); #if DEBUG System.IO.File.WriteAllBytes( "arm9-too-big-recomp.bin", data ); #endif } } } if ( newCompressedSize != len ) { // new ARM is (still) different, attempt to find the metadata in the ARM9 secure area and replace that bool foundSize = false; for ( int i = 0; i < 0x4000; i += 4 ) { uint maybeSize = BitConverter.ToUInt32( data, i ); if ( maybeSize == len + 0x02000000u || maybeSize == len + 0x02004000u ) { foundSize = true; byte[] newCmpSizeBytes; if ( maybeSize == len + 0x02004000u ) { newCmpSizeBytes = BitConverter.GetBytes( newCompressedSize + 0x02004000u ); } else { newCmpSizeBytes = BitConverter.GetBytes( newCompressedSize + 0x02000000u ); } data[i + 0] = newCmpSizeBytes[0]; data[i + 1] = newCmpSizeBytes[1]; data[i + 2] = newCmpSizeBytes[2]; data[i + 3] = newCmpSizeBytes[3]; break; } } if ( !foundSize ) { Console.WriteLine( "WARNING: Recompressed ARM9 is different size, and size could not be found in secure area!" ); Console.WriteLine( " Patched game will probably not boot!" ); } } #if DEBUG uint newDecompressedSize = (uint)decData.Length; uint newAdditionalCompressedSize = newDecompressedSize - newCompressedSize; Console.WriteLine( "ARM9 new dec size: 0x" + newDecompressedSize.ToString( "X6" ) ); Console.WriteLine( "ARM9 new cmp size: 0x" + newCompressedSize.ToString( "X6" ) ); Console.WriteLine( "ARM9 new diff: 0x" + newAdditionalCompressedSize.ToString( "X6" ) ); #endif } else { Console.WriteLine( "Replacing ARM9..." ); data = decData; } #if DEBUG System.IO.File.WriteAllBytes( "arm9-new.bin", data ); #endif nds.Position = pos; nds.Write( data, 0, data.Length ); int newSize = data.Length; int diff = (int)len - newSize; // copy back footer if ( diff > 0 ) { List<byte> footer = new List<byte>(); nds.Position = pos + len; if ( nds.PeekUInt32() == 0xDEC00621 ) { for ( int j = 0; j < 12; ++j ) { footer.Add( (byte)nds.ReadByte() ); } nds.Position = pos + newSize; nds.Write( footer.ToArray(), 0, footer.Count ); } // padding for ( int j = 0; j < diff; ++j ) { nds.WriteByte( 0xFF ); } } // write new size byte[] newSizeBytes = BitConverter.GetBytes( newSize ); nds.Position = 0x2C; nds.Write( newSizeBytes, 0, 4 ); // recalculate checksums nds.Position = pos; ushort secureChecksum = new Crc16().ComputeChecksum( nds, 0x4000, 0xFFFF ); nds.Position = 0x6C; nds.Write( BitConverter.GetBytes( secureChecksum ), 0, 2 ); nds.Position = 0; ushort headerChecksum = new Crc16().ComputeChecksum( nds, 0x15E, 0xFFFF ); nds.Write( BitConverter.GetBytes( headerChecksum ), 0, 2 ); return true; } return false; }