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() ) ) + "'." );
     }
 }
Пример #2
0
        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 );
        }
Пример #3
0
        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 ) );
            }
        }
Пример #4
0
        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;
        }
Пример #5
0
        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;
        }
Пример #6
0
        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;
        }