Esempio n. 1
0
        /// <summary>
        /// Parses compressed texture and returns it on the output.
        /// </summary>
        /// <param name="byteptr_t">Pointer to the tpk block array.</param>
        /// <param name="offslot">Offslot of the texture to be parsed</param>
        /// <returns>Decompressed texture valid to the current support.</returns>
        protected override unsafe void ParseCompTexture(byte *byteptr_t, OffSlot offslot)
        {
            byteptr_t += offslot.AbsoluteOffset;
            if (*(uint *)byteptr_t != TPK.COMPRESSED_TEXTURE)
            {
                return;                 // if not a compressed texture
            }
            // Decompress all data excluding 0x18 byte header
            var data = new byte[offslot.CompressedSize - 0x18];

            for (int a1 = 0; a1 < data.Length; ++a1)
            {
                data[a1] = *(byteptr_t + 0x18 + a1);
            }
            data = JDLZ.Decompress(data);

            // In compressed textures, their header lies right in the end (0x7C + 0x18 bytes)
            fixed(byte *dataptr_t = &data[0])
            {
                int offset = data.Length - 0x7C - 0x18;
                var Read   = new Texture(dataptr_t, offset, 0x7C, this._collection_name, this.Database);

                Read.ReadData(dataptr_t, 0, true);
                uint compression = *(uint *)(dataptr_t + offset + 0x7C + 0xC);

                this.compressions.Add(compression);
                this.Textures.Add(Read);
            }
        }
        public override TexturePack Get()
        {
            if (ContainerSize == 0)
            {
                throw new Exception("containerSize is not set!");
            }

            var data = new byte[ContainerSize];

            BinaryReader.BaseStream.Read(data, 0, data.Length);

            var          decompressed = JDLZ.Decompress(data);
            const string newName      = "_tmpCompressedTpk.dejdlz";

            using (var stream = new FileStream(newName, FileMode.Create))
            {
                stream.Write(decompressed, 0, decompressed.Length);
            }

            var readStream = new FileStream(newName, FileMode.Open);

            readStream.Seek(8, SeekOrigin.Current);
            var tpkContainer = new TPKReadContainer(new BinaryReader(readStream), FileName, decompressed.Length, true);
            var result       = tpkContainer.Get();

            readStream.Close();

            File.Delete(newName);

            return(result);
        }
Esempio n. 3
0
        /// <summary>
        /// Check to see if the file needs to be decompressed.
        /// If so, decompress it.
        /// </summary>
        private void CheckCompression()
        {
            var flag = Reader.ReadChars(4);

            Reader.BaseStream.Position -= 4;

            if (flag[0] == 'J' && flag[1] == 'D' && flag[2] == 'L' && flag[3] == 'Z')
            {
                var allData      = Reader.ReadBytes((int)Reader.BaseStream.Length);
                var decompressed = JDLZ.Decompress(allData);

                Reader = new BinaryReader(new MemoryStream(decompressed));
            }
        }
Esempio n. 4
0
        public override FNGFile Get()
        {
            if (ContainerSize == 0)
            {
                throw new Exception("containerSize is not set!");
            }

            BinaryReader.BaseStream.Seek(4, SeekOrigin.Current);

            var test = BinaryReader.ReadChars(4);

            BinaryReader.BaseStream.Seek(-4, SeekOrigin.Current);

            if (test[0] != 'J' || test[1] != 'D' || test[2] != 'L' || test[3] != 'Z')
            {
                return(new FNGFile(ChunkID.BCHUNK_FENG_PACKAGE, ContainerSize, BinaryReader.BaseStream.Position)
                {
                    Name = "__UNSUPPORTED__",
                    HasData = false
                });
            }

            var data = new byte[ContainerSize - 4];

            BinaryReader.BaseStream.Read(data, 0, data.Length);

            var          decompressed = JDLZ.Decompress(data);
            const string newName      = "_tmpCompressedFENG.dejdlz";

            using (var stream = new FileStream(newName, FileMode.Create))
            {
                stream.Write(decompressed, 0, decompressed.Length);
            }

            var readStream   = new FileStream(newName, FileMode.Open);
            var fngContainer = new FNGReadContainer(new BinaryReader(readStream), FileName, decompressed.Length);
            var result       = fngContainer.Get();

            readStream.Close();

            File.Delete(newName);

            return(result);
        }
Esempio n. 5
0
        public override void Run(ReaderContext context)
        {
            var fileName = _fileName = $"decompress_{_random.Next()}.bin";

            Console.WriteLine($"decompressing to {_fileName}");

            context.Reader.BaseStream.Position = 0;

            var fileData = new byte[context.Reader.BaseStream.Length];

            context.Reader.Read(fileData, 0, fileData.Length);

            byte[] decompressed;

            switch (_type)
            {
            case CompressionType.JDLZ:
                decompressed = JDLZ.Decompress(fileData);
                break;

            case CompressionType.WorldBin:
                decompressed = fileData;

                for (var i = decompressed.Length - 1; i >= 1; --i)
                {
                    decompressed[i] ^= decompressed[i - 1];
                }

                break;

            default:
                decompressed = new byte[0];
                break;
            }

            using (var writer = new BinaryWriter(new FileStream(fileName, FileMode.Create)))
            {
                writer.Write(decompressed, 0, decompressed.Length);
            }

            context.Reader = new BinaryReader(File.OpenRead(fileName));
        }
Esempio n. 6
0
        /// <summary>
        /// Loads English file and disassembles its blocks
        /// </summary>
        /// <param name="Language_dir">Directory of the game.</param>
        /// <param name="db">Database of classes.</param>
        /// <returns>True if success.</returns>
        public static unsafe bool LoadLanguage(string Language_dir, Database.Underground2 db)
        {
            Language_dir += @"\LANGUAGES\";

            // Get everything from language files
            try
            {
                db._LngGlobal = File.ReadAllBytes(Language_dir + "English.bin");
                db._LngLabels = File.ReadAllBytes(Language_dir + "Labels.bin");
                Log.Write("Reading data from English.bin...");
                Log.Write("Reading data from Labels.bin...");
            }
            catch (Exception e)
            {
                while (e.InnerException != null)
                {
                    e = e.InnerException;
                }
                if (Process.MessageShow)
                {
                    MessageBox.Show($"Error occured: {e.Message}", "Failure", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else
                {
                    Console.WriteLine(e.Message);
                }
                return(false);
            }

            // Decompress if compressed
            db._LngGlobal = JDLZ.Decompress(db._LngGlobal);
            db._LngLabels = JDLZ.Decompress(db._LngLabels);

            // Use pointers to speed up process
            fixed(byte *strptr = &db._LngGlobal[0], labptr = &db._LngLabels[0])
            {
                db.STRBlocks.Collections.Add(new STRBlock(strptr, labptr, db._LngGlobal.Length, db._LngLabels.Length, db));
            }

            return(true);
        }
Esempio n. 7
0
        /// <summary>
        /// Decompresses .fng JDLZ-compressed file.
        /// </summary>
        /// <param name="fng">.fng file as a byte array.</param>
        /// <returns>Decompressed FEng file as a byte array.</returns>
        public static unsafe byte[] Decompress(byte[] fng)
        {
            if (fng[0] == 3) // return if already decompressed
            {
                return(fng);
            }

            byte[] InterData = new byte[fng.Length - 12];
            Buffer.BlockCopy(fng, 12, InterData, 0, fng.Length - 12);
            var NewData = JDLZ.Decompress(InterData);

            byte[] result = new byte[8 + NewData.Length];
            fixed(byte *byteptr_t = &result[0])
            {
                *(uint *)(byteptr_t + 0) = Global.FEngFiles;
                *(int *)(byteptr_t + 4)  = NewData.Length;
            }

            Buffer.BlockCopy(NewData, 0, result, 8, NewData.Length);
            return(result);
        }
Esempio n. 8
0
        /// <summary>
        /// Loads GlobalA file and disassembles its blocks
        /// </summary>
        /// <param name="GlobalA_dir">Directory of the game.</param>
        /// <param name="db">Database of classes.</param>
        /// <returns>True if success.</returns>
        public static unsafe bool LoadGlobalA(string GlobalA_dir, Database.Underground2 db)
        {
            GlobalA_dir += @"\GLOBAL\GlobalA.bun";

            // Get everything from GlobalA.bun
            try
            {
                db._GlobalABUN = File.ReadAllBytes(GlobalA_dir);
                Log.Write("Reading data from GlobalA.bun...");
            }
            catch (Exception e)
            {
                while (e.InnerException != null)
                {
                    e = e.InnerException;
                }
                if (Process.MessageShow)
                {
                    MessageBox.Show($"Error occured: {e.Message}", "Failure", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else
                {
                    Console.WriteLine(e.Message);
                }
                return(false);
            }

            // Decompress if compressed
            db._GlobalABUN = JDLZ.Decompress(db._GlobalABUN);

            // Use pointers to speed up process
            fixed(byte *byteptr_t = &db._GlobalABUN[0])
            {
                uint offset = 0; // to calculate current offset
                uint ID     = 0; // to get the ID of the block being read
                uint size   = 0; // to get the size of the block being read

                while (offset < db._GlobalABUN.Length)
                {
                    ID   = *(uint *)(byteptr_t + offset);     // read ID
                    size = *(uint *)(byteptr_t + offset + 4); // read size
                    if (offset + size > db._GlobalABUN.Length)
                    {
                        if (Process.MessageShow)
                        {
                            MessageBox.Show("GlobalA: unable to read beyond the stream.", "Failure");
                        }
                        else
                        {
                            Console.WriteLine("GlobalA: unable to read beyond the stream.");
                        }
                        return(false);
                    }

                    switch (ID)
                    {
                    case Global.TPKBlocks:
                        int count = db.TPKBlocks.Length;
                        db.TPKBlocks.Collections.Add(new TPKBlock(byteptr_t + offset, count, db));
                        db.TPKBlocks[count].InGlobalA = true;
                        break;

                    case Global.FEngFiles:
                    case Global.FNGCompress:
                        E_FNGroup(byteptr_t + offset, size + 8, db);
                        break;

                    default:
                        break;
                    }
                    offset += 8 + size; // advance in offset
                }
            }

            return(true);
        }
Esempio n. 9
0
        protected override void ReadChunks(long totalSize)
        {
            var runTo = (_compressed
                            ? BinaryReader.BaseStream.Position - 8
                            : BinaryReader.BaseStream.Position) + totalSize;

            for (var i = 0; i < 0xFFFF && BinaryReader.BaseStream.Position < runTo; i++)
            {
                var chunkId    = BinaryReader.ReadUInt32();
                var chunkSize  = BinaryReader.ReadUInt32();
                var chunkRunTo = BinaryReader.BaseStream.Position + chunkSize;

                var normalizedId = (long)(chunkId & 0xffffffff);

                BinaryUtil.ReadPadding(BinaryReader, ref chunkSize);
                BinaryUtil.PrintID(BinaryReader, chunkId, normalizedId, chunkSize, GetType(), _logLevel,
                                   typeof(TPKChunks));

                switch (normalizedId)
                {
                case (long)TPKChunks.TPKRoot:      // TPK root
                case (long)TPKChunks.TPKDataRoot:  // TPK data root
                    _logLevel = 2;
                    ReadChunks(chunkSize);
                    _logLevel = 1;
                    break;

                case (long)TPKChunks.TPKInfo:      // TPK info
                {
                    var header = BinaryUtil.ReadStruct <TpkInfoHeader>(BinaryReader);

                    _texturePack.Name = header.Name;
                    _texturePack.Path = header.Path;
                    _texturePack.Hash = header.Hash;

                    break;
                }

                case (long)TPKChunks.TPKTextureHashes:      // Texture hashes
                {
                    // Every entry is 8 bytes; a 4-byte hash and 4 bytes of 0x00.
                    var numTextures = chunkSize / 8;

                    for (var j = 0; j < numTextures; j++)
                    {
                        var hash = BinaryReader.ReadUInt32();
                        BinaryReader.BaseStream.Seek(4, SeekOrigin.Current);
                        _texturePack.Hashes.Add(hash);
                    }

                    break;
                }

                case (long)TPKChunks.TPKTextureHeaders:      // Texture headers
                {
                    for (var j = 0; j < _texturePack.Hashes.Count; j++)
                    {
                        var textureHeader = BinaryUtil.ReadStruct <TpkTextureHeader>(BinaryReader);
                        var texture       = new Texture
                        {
                            TextureHash = textureHeader.TextureHash,
                            TypeHash    = textureHeader.TypeHash,
                            Name        = textureHeader.Name,
                            Width       = textureHeader.Width,
                            Height      = textureHeader.Height,
                            MipMap      = textureHeader.MipMap,
                            DataOffset  = textureHeader.DataOffset,
                            DataSize    = textureHeader.DataSize
                        };

                        _texturePack.Textures.Add(texture);
                    }

                    break;
                }

                case (long)TPKChunks.TPKDXTHeaders:      // DXT headers
                {
                    foreach (var texture in _texturePack.Textures)
                    {
                        BinaryReader.BaseStream.Seek(20, SeekOrigin.Current);
                        texture.CompressionType = BinaryReader.ReadInt32();
                        BinaryReader.BaseStream.Seek(0x08, SeekOrigin.Current);
                    }

                    break;
                }

                case (long)TPKChunks.TPKData:
                {
                    if (_texturePack.Hashes.Any() && !_texturePack.Textures.Any())
                    {
                        // Probably compressed?
#if DEBUG
                        Console.WriteLine("Seems to be a compressed TPK");
#endif
                        var jdlzPositions = new List <long>();

                        while (BinaryReader.BaseStream.Position < chunkRunTo)
                        {
                            var tmpCompressionFlag = BinaryReader.ReadBytes(4);

                            if (tmpCompressionFlag[0] == 'J' && tmpCompressionFlag[1] == 'D' &&
                                tmpCompressionFlag[2] == 'L' && tmpCompressionFlag[3] == 'Z')
                            {
#if DEBUG
                                Console.WriteLine("JDLZ!");
#endif
                                var headerPos = BinaryReader.BaseStream.Position - 4;

                                jdlzPositions.Add(headerPos);
                            }
                        }

                        foreach (var jdlzPos in jdlzPositions)
                        {
                            BinaryReader.BaseStream.Seek(jdlzPos, SeekOrigin.Begin);

                            var header = BinaryUtil.ReadStruct <CommonStructs.JDLZHeader>(BinaryReader);

#if DEBUG
                            Console.WriteLine(
                                $"JDLZ: {header.CompressedLength} bytes compressed, {header.UncompressedLength} uncompressed | header pos 0x{jdlzPos:X8}");
#endif
                            var compressedData = new byte[header.CompressedLength];
                            BinaryReader.BaseStream.Position = jdlzPos;

                            BinaryReader.Read(compressedData, 0, compressedData.Length);
                            var uncompressedData = JDLZ.Decompress(compressedData);

#if DEBUG
                            Console.WriteLine(BinaryUtil.HexDump(uncompressedData));
#endif
                        }
                    }
                    else if (_texturePack.Hashes.Count != _texturePack.Textures.Count)
                    {
                        // What?
                        throw new NFSException(
                                  $"Expected {_texturePack.Hashes.Count} textures, only got {_texturePack.Textures.Count}");
                    }
                    else
                    {
                    }

                    break;
                }
                }

                BinaryUtil.ValidatePosition(BinaryReader, chunkRunTo, GetType());
                BinaryReader.BaseStream.Seek(chunkRunTo - BinaryReader.BaseStream.Position, SeekOrigin.Current);
            }
        }
Esempio n. 10
0
        protected override void ReadChunks(long totalSize)
        {
            if (BinaryReader.BaseStream.Length == 0)
            {
                return;
            }

            var curPos = BinaryReader.BaseStream.Position;

            if (BinaryReader.ReadChar() == 'J' &&
                BinaryReader.ReadChar() == 'D' &&
                BinaryReader.ReadChar() == 'L' &&
                BinaryReader.ReadChar() == 'Z')
            {
#if DEBUG
                Console.WriteLine("JDLZ compressed!");
#endif
                BinaryReader.BaseStream.Seek(curPos, SeekOrigin.Begin);

                var data = new byte[BinaryReader.BaseStream.Length];

                BinaryReader.BaseStream.Read(data, 0, data.Length);

                var decompressed = JDLZ.Decompress(data);
                var newName      = _fileName + ".dejdlz";

                var stream = new FileStream(newName, FileMode.CreateNew);
                stream.Write(decompressed, 0, decompressed.Length);
                stream.Close();
                BinaryReader = new BinaryReader(new FileStream(newName, FileMode.Open));
                File.Delete(newName);
            }
            else
            {
                BinaryReader.BaseStream.Seek(curPos, SeekOrigin.Begin);
            }

            var runTo = BinaryReader.BaseStream.Position + totalSize;

            for (var i = 0;
                 i < 0xFFFF && BinaryReader.BaseStream.Position < runTo;
                 i++
                 )
            {
                var chunkId    = BinaryReader.ReadUInt32();
                var chunkSize  = BinaryReader.ReadUInt32();
                var chunkRunTo = BinaryReader.BaseStream.Position + chunkSize;

                var normalizedId = (int)chunkId & 0xffffffff;
                var endChecks    = true;

                BinaryUtil.PrintID(BinaryReader, chunkId, normalizedId, chunkSize, GetType());

                switch (normalizedId)
                {
                case (long)ChunkID.BCHUNK_TRACKSTREAMER_SECTIONS:
                    _dataModels.Add(new SectionListReadContainer(BinaryReader, FileName, chunkSize).Get());
                    break;

                case (long)ChunkID.BCHUNK_SPEED_TEXTURE_PACK_LIST_CHUNKS:
                    _dataModels.Add(new TpkReadContainer(BinaryReader, FileName, chunkSize).Get());
                    break;

                case (long)ChunkID.BCHUNK_SPEED_ESOLID_LIST_CHUNKS:
                    var solidList = new SolidListReadContainer(BinaryReader, FileName, chunkSize).Get();
                    _dataModels.Add(solidList);

                    if (solidList.Compressed)
                    {
                        endChecks = false;
                    }

                    break;

                default:
                    _dataModels.Add(new NullModel(normalizedId, chunkSize, BinaryReader.BaseStream.Position));

                    break;
                }

                if (endChecks)
                {
                    BinaryUtil.ValidatePosition(BinaryReader, chunkRunTo, GetType());
                    BinaryReader.BaseStream.Seek(chunkRunTo - BinaryReader.BaseStream.Position, SeekOrigin.Current);
                }
                else
                {
                    BinaryReader.BaseStream.Seek(chunkRunTo, SeekOrigin.Begin);
                }
            }
        }
Esempio n. 11
0
        /// <summary>
        /// Loads GlobalB file and disassembles its blocks
        /// </summary>
        /// <param name="GlobalB_dir">Directory of the game.</param>
        /// <param name="db">Database of classes.</param>
        /// <returns>True if success.</returns>
        public static unsafe bool LoadGlobalB(string GlobalB_dir, Database.MostWanted db)
        {
            LibColBlockExists = false;
            GlobalB_dir      += @"\GLOBAL\GlobalB.lzc";

            // Get everything from GlobalB.lzc
            try
            {
                db._GlobalBLZC = File.ReadAllBytes(GlobalB_dir);
                Log.Write("Reading data from GlobalB.lzc...");
            }
            catch (Exception e)
            {
                while (e.InnerException != null)
                {
                    e = e.InnerException;
                }
                if (Process.MessageShow)
                {
                    MessageBox.Show($"Error occured: {e.Message}", "Failure", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else
                {
                    Console.WriteLine(e.Message);
                }
                return(false);
            }

            // Decompress if compressed
            db._GlobalBLZC = JDLZ.Decompress(db._GlobalBLZC);

            // Use pointers to speed up process
            fixed(byte *byteptr_t = &db._GlobalBLZC[0])
            {
                uint offset = 0; // to calculate current offset
                uint ID     = 0; // to get the ID of the block being read
                uint size   = 0; // to get the size of the block being read

                uint proff  = 0; // offset of the preset rides block
                uint prsize = 0; // size of the preset rides block

                uint cpoff  = 0; // offset of the carparts block
                uint cpsize = 0; // size of the carparts block

                uint cooff  = 0; // offset of the collision block
                uint cosize = 0; // size of the collision block

                while (offset < db._GlobalBLZC.Length)
                {
                    ID   = *(uint *)(byteptr_t + offset);     // read ID
                    size = *(uint *)(byteptr_t + offset + 4); // read size
                    if (offset + size > db._GlobalBLZC.Length)
                    {
                        if (Process.MessageShow)
                        {
                            MessageBox.Show("GlobalB: unable to read beyond the stream.", "Failure");
                        }
                        else
                        {
                            Console.WriteLine("GlobalB: unable to read beyond the stream.");
                        }
                        return(false);
                    }

                    switch (ID)
                    {
                    case 0:
                        if (*(uint *)(byteptr_t + offset + 8) == Global.GlobalLib)
                        {
                            E_GlobalLibBlock(byteptr_t + offset, size + 8);
                        }
                        break;

                    case Global.Materials:
                        E_Material(byteptr_t + offset, db);
                        break;

                    case Global.TPKBlocks:
                        int count = db.TPKBlocks.Length;
                        db.TPKBlocks.Collections.Add(new TPKBlock(byteptr_t + offset, count, db));
                        break;

                    case Global.CarTypeInfo:
                        E_CarTypeInfo(byteptr_t + offset + 8, size, db);
                        break;

                    case Global.PresetRides:
                        proff  = offset + 8;
                        prsize = size;
                        break;

                    case Global.CarParts:
                        cpoff  = offset + 8;
                        cpsize = size;
                        break;

                    case Global.SlotTypes:
                        E_SlotType(byteptr_t + offset, size + 8, db);
                        break;

                    case Global.Collisions:
                        cooff  = offset + 8;
                        cosize = size;
                        break;

                    case Global.FEngFiles:
                    case Global.FNGCompress:
                        E_FNGroup(byteptr_t + offset, size + 8, db);
                        break;

                    default:
                        break;
                    }
                    offset += 8 + size; // advance in offset
                }

                // CarParts and Collisions blocks are the last ones to disassemble
                E_CarParts(byteptr_t + cpoff, cpsize, db);
                E_Collisions(byteptr_t + cooff, cosize, db);
                E_PresetRides(byteptr_t + proff, prsize, db);
            }

            // Disperse spoilers across cartypeinfo
            E_Spoilers(db);
            return(true);
        }
Esempio n. 12
0
        private void ReadCompressed()
        {
            foreach (var compHeader in _compressionHeaders)
            {
#if DEBUG
                Console.WriteLine($"0x{compHeader.TextureHash:X8} @ 0x{compHeader.AbsoluteOffset:X8}");
#endif
                var skip = false;

                if (compHeader.AbsoluteOffset != 0)
                {
                    BinaryReader.BaseStream.Position =
                        compHeader.AbsoluteOffset; // relative to the beginning of the chunk or file
                    var readBytes = 0L;
                    var blocks    = new List <byte[]>();
                    var partSizes = new uint[0xFFFF];

                    while (readBytes < compHeader.Size)
                    {
                        if (BinaryReader.ReadInt32() == 0x55441122)
                        {
                            BinaryReader.BaseStream.Position -= 4;
                            var cbh  = BinaryUtil.ReadStruct <CommonStructs.CompressBlockHead>(BinaryReader);
                            var flag = BinaryReader.ReadChars(4);
                            BinaryReader.BaseStream.Position -= 4;
                            var data = BinaryReader.ReadBytes((int)(cbh.TotalBlockSize - 24));

                            if (flag[0] == 'J' && flag[1] == 'D' && flag[2] == 'L' && flag[3] == 'Z')
                            {
                                blocks.Add(JDLZ.Decompress(data));
                            }
                            else if (_compLibEnabled)
                            {
                                var decompressed = new byte[cbh.OutSize];
                                Compression.Decompress(data, decompressed);
                                blocks.Add(decompressed);
                            }
                            else
                            {
#if DEBUG
                                Console.WriteLine("CompLib disabled, can't decompress");
#endif
                                skip = true;
                                break;
                            }

                            data       = null;
                            readBytes += cbh.TotalBlockSize;
                            partSizes[blocks.Count - 1] = cbh.OutSize;
                        }
                    }

                    if (skip)
                    {
                        continue;
                    }

                    if (blocks.Count == 1)
                    {
                        var infoBlock   = blocks[0];
                        var blockReader = new BinaryReader(new MemoryStream(infoBlock));
                        blockReader.BaseStream.Position = blockReader.BaseStream.Length - 212;

                        // 12 0x00 at the beginning of each header
                        blockReader.BaseStream.Seek(12, SeekOrigin.Current);

                        var textureHash = blockReader.ReadUInt32();
                        var typeHash    = blockReader.ReadUInt32();
                        blockReader.ReadInt32();
                        var dataSize = blockReader.ReadUInt32();
                        blockReader.ReadInt32();
                        var width  = blockReader.ReadInt32();
                        var height = blockReader.ReadInt32();
                        var mipMap = blockReader.ReadInt32();
                        blockReader.ReadUInt32();
                        blockReader.ReadUInt32();
                        blockReader.BaseStream.Seek(24, SeekOrigin.Current);
                        blockReader.ReadUInt32();
                        var dataOffset = blockReader.ReadUInt32();
                        blockReader.BaseStream.Seek(60, SeekOrigin.Current);
                        var nameLength = (int)blockReader.ReadByte();
                        var name       = new string(blockReader.ReadChars(nameLength).Where(c => c != '\0').ToArray());

#if DEBUG
                        Console.WriteLine(
                            $"{name} (0x{textureHash:X8}/0x{typeHash:X8}) - {width}x{height}, {dataSize} bytes, @ {dataOffset}");
#endif
                        blockReader.BaseStream.Position = 0;
                        var data = blockReader.ReadBytes((int)(blockReader.BaseStream.Length - 212));
                        blockReader.BaseStream.Position = blockReader.BaseStream.Length - 20;

                        var texture = new Texture
                        {
                            TextureHash     = textureHash,
                            TypeHash        = typeHash,
                            Name            = name,
                            Width           = width,
                            Height          = height,
                            MipMap          = mipMap,
                            DataOffset      = dataOffset,
                            DataSize        = (uint)(infoBlock.Length - 212),
                            CompressionType = blockReader.ReadInt32(),
                            Data            = data
                        };

                        _texturePack.Textures.Add(texture);

                        infoBlock = null;
                        data      = null;
                        blockReader.Dispose();
                        blocks.Clear();
                    }
                    else
                    {
                        var infoBlock   = blocks[blocks.Count - 2];
                        var blockReader = new BinaryReader(new MemoryStream(infoBlock));
                        blockReader.BaseStream.Position = blockReader.BaseStream.Length - 212;

                        // 12 0x00 at the beginning of each header
                        blockReader.BaseStream.Seek(12, SeekOrigin.Current);

                        var textureHash = blockReader.ReadUInt32();
                        var typeHash    = blockReader.ReadUInt32();
                        blockReader.ReadInt32();
                        var dataSize = blockReader.ReadUInt32();
                        blockReader.ReadInt32();
                        var width  = blockReader.ReadInt32();
                        var height = blockReader.ReadInt32();
                        var mipMap = blockReader.ReadInt32();
                        blockReader.ReadUInt32();
                        blockReader.ReadUInt32();
                        blockReader.BaseStream.Seek(24, SeekOrigin.Current);
                        blockReader.ReadUInt32();
                        var dataOffset = blockReader.ReadUInt32();
                        blockReader.BaseStream.Seek(60, SeekOrigin.Current);
                        var nameLength = (int)blockReader.ReadByte();
                        var name       = new string(blockReader.ReadChars(nameLength).Where(c => c != '\0').ToArray());

#if DEBUG
                        Console.WriteLine(
                            $"{name} (0x{textureHash:X8}/0x{typeHash:X8}) - {width}x{height}, {dataSize} bytes, @ {dataOffset}");
#endif
                        blockReader.BaseStream.Position = blockReader.BaseStream.Length - 20;

                        var texture = new Texture
                        {
                            TextureHash     = textureHash,
                            TypeHash        = typeHash,
                            Name            = name,
                            Width           = width,
                            Height          = height,
                            MipMap          = mipMap,
                            DataOffset      = dataOffset,
                            DataSize        = 0,
                            CompressionType = blockReader.ReadInt32()
                        };

#if DEBUG
                        Console.WriteLine($"0x{texture.CompressionType:X8}");
#endif
                        var data = new List <byte>();

                        foreach (var block in blocks)
                        {
                            if (blocks.IndexOf(block) == blocks.Count - 2)
                            {
                                continue;
                            }

                            data.AddRange(block);
                            texture.DataSize = (uint)data.Count;
                        }

                        texture.Data = data.ToArray();
                        _texturePack.Textures.Add(texture);

                        infoBlock = null;
                        blockReader.Dispose();
                        blocks.Clear();
                        data.Clear();
                    }

                    partSizes = null;
                }
                else
                {
                    // Files are located in a folder with the same name as the texture pack.
                    var baseDir = Path.Combine(Path.GetDirectoryName(FileName) ?? throw new InvalidOperationException(), _texturePack.Name);

                    using (var textureReader =
                               new BinaryReader(File.OpenRead(Path.Combine(baseDir, $"{compHeader.TextureHash:X8}.stp"))))
                    {
                        var readBytes = 0L;
                        var blocks    = new List <byte[]>();
                        var partSizes = new uint[0xFFFF];

                        while (readBytes < compHeader.Size)
                        {
                            if (textureReader.ReadInt32() == 0x55441122)
                            {
                                textureReader.BaseStream.Position -= 4;
                                var cbh  = BinaryUtil.ReadStruct <CommonStructs.CompressBlockHead>(textureReader);
                                var flag = textureReader.ReadChars(4);
                                textureReader.BaseStream.Position -= 4;
                                var data = textureReader.ReadBytes((int)(cbh.TotalBlockSize - 24));

                                if (flag[0] == 'J' && flag[1] == 'D' && flag[2] == 'L' && flag[3] == 'Z')
                                {
                                    blocks.Add(JDLZ.Decompress(data));
                                }
                                else if (_compLibEnabled)
                                {
                                    var decompressed = new byte[cbh.OutSize];
                                    Compression.Decompress(data, decompressed);
                                    blocks.Add(decompressed);
                                }
                                else
                                {
#if DEBUG
                                    Console.WriteLine("CompLib disabled, can't decompress");
#endif
                                    skip = true;
                                    break;
                                }

                                readBytes += cbh.TotalBlockSize;
                                partSizes[blocks.Count - 1] = cbh.OutSize;
                                data = null;
                            }
                        }

                        if (skip)
                        {
                            continue;
                        }

                        if (blocks.Count == 1)
                        {
                            var infoBlock   = blocks[0];
                            var blockReader = new BinaryReader(new MemoryStream(infoBlock));
                            blockReader.BaseStream.Position = blockReader.BaseStream.Length - 212;

                            // 12 0x00 at the beginning of each header
                            blockReader.BaseStream.Seek(12, SeekOrigin.Current);

                            var textureHash = blockReader.ReadUInt32();
                            var typeHash    = blockReader.ReadUInt32();
                            blockReader.ReadInt32();
                            var dataSize = blockReader.ReadUInt32();
                            blockReader.ReadInt32();
                            var width  = blockReader.ReadInt32();
                            var height = blockReader.ReadInt32();
                            var mipMap = blockReader.ReadInt32();
                            blockReader.ReadUInt32();
                            blockReader.ReadUInt32();
                            blockReader.BaseStream.Seek(24, SeekOrigin.Current);
                            blockReader.ReadUInt32();
                            var dataOffset = blockReader.ReadUInt32();
                            blockReader.BaseStream.Seek(60, SeekOrigin.Current);
                            var nameLength = (int)blockReader.ReadByte();
                            var name       = new string(blockReader.ReadChars(nameLength).Where(c => c != '\0').ToArray());

#if DEBUG
                            Console.WriteLine(
                                $"{name} (0x{textureHash:X8}/0x{typeHash:X8}) - {width}x{height}, {dataSize} bytes, @ {dataOffset}");
#endif
                            blockReader.BaseStream.Position = 0;
                            var data = blockReader.ReadBytes((int)(blockReader.BaseStream.Length - 212));
                            blockReader.BaseStream.Position = blockReader.BaseStream.Length - 20;

                            var texture = new Texture
                            {
                                TextureHash     = textureHash,
                                TypeHash        = typeHash,
                                Name            = name,
                                Width           = width,
                                Height          = height,
                                MipMap          = mipMap,
                                DataOffset      = dataOffset,
                                DataSize        = (uint)(infoBlock.Length - 212),
                                CompressionType = blockReader.ReadInt32(),
                                Data            = data
                            };

                            _texturePack.Textures.Add(texture);

                            infoBlock = null;
                            blockReader.Dispose();
                            blocks.Clear();
                            data = null;
                        }
                        else
                        {
                            var infoBlock   = blocks[blocks.Count - 2];
                            var blockReader = new BinaryReader(new MemoryStream(infoBlock));
                            blockReader.BaseStream.Position = blockReader.BaseStream.Length - 212;

                            // 12 0x00 at the beginning of each header
                            blockReader.BaseStream.Seek(12, SeekOrigin.Current);

                            var textureHash = blockReader.ReadUInt32();
                            var typeHash    = blockReader.ReadUInt32();
                            blockReader.ReadInt32();
                            var dataSize = blockReader.ReadUInt32();
                            blockReader.ReadInt32();
                            var width  = blockReader.ReadInt32();
                            var height = blockReader.ReadInt32();
                            var mipMap = blockReader.ReadInt32();
                            blockReader.ReadUInt32();
                            blockReader.ReadUInt32();
                            blockReader.BaseStream.Seek(24, SeekOrigin.Current);
                            blockReader.ReadUInt32();
                            var dataOffset = blockReader.ReadUInt32();
                            blockReader.BaseStream.Seek(60, SeekOrigin.Current);
                            var nameLength = (int)blockReader.ReadByte();
                            var name       = new string(blockReader.ReadChars(nameLength).Where(c => c != '\0').ToArray());

#if DEBUG
                            Console.WriteLine(
                                $"{name} (0x{textureHash:X8}/0x{typeHash:X8}) - {width}x{height}, {dataSize} bytes, @ {dataOffset}");
#endif
                            blockReader.BaseStream.Position = blockReader.BaseStream.Length - 20;

                            var texture = new Texture
                            {
                                TextureHash     = textureHash,
                                TypeHash        = typeHash,
                                Name            = name,
                                Width           = width,
                                Height          = height,
                                MipMap          = mipMap,
                                DataOffset      = dataOffset,
                                DataSize        = 0,
                                CompressionType = blockReader.ReadInt32()
                            };

#if DEBUG
                            Console.WriteLine($"0x{texture.CompressionType:X8}");
#endif
                            var data = new List <byte>();

                            foreach (var block in blocks)
                            {
                                if (blocks.IndexOf(block) == blocks.Count - 2)
                                {
                                    continue;
                                }

                                data.AddRange(block);
                                texture.DataSize = (uint)data.Count;
                            }

                            texture.Data = data.ToArray();
                            _texturePack.Textures.Add(texture);

                            data.Clear();
                            blocks.Clear();
                            infoBlock = null;
                            blockReader.Dispose();
                        }

                        partSizes = null;
                    }
                }
            }

            GC.Collect();
        }
Esempio n. 13
0
        /// <summary>
        /// Loads GlobalB file and disassembles its blocks
        /// </summary>
        /// <param name="GlobalB_dir">Directory of the game.</param>
        /// <param name="db">Database of classes.</param>
        /// <returns>True if success.</returns>
        public static unsafe bool LoadGlobalB(string GlobalB_dir, Database.Underground2 db)
        {
            GlobalB_dir += @"\GLOBAL\GlobalB.lzc";

            // Get everything from GlobalB.lzc
            try
            {
                db._GlobalBLZC = File.ReadAllBytes(GlobalB_dir);
                Log.Write("Reading data from GlobalB.lzc...");
            }
            catch (Exception e)
            {
                while (e.InnerException != null)
                {
                    e = e.InnerException;
                }
                if (Process.MessageShow)
                {
                    MessageBox.Show($"Error occured: {e.Message}", "Failure", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else
                {
                    Console.WriteLine(e.Message);
                }
                return(false);
            }

            // Decompress if compressed
            db._GlobalBLZC = JDLZ.Decompress(db._GlobalBLZC);

            // Use pointers to speed up process
            fixed(byte *byteptr_t = &db._GlobalBLZC[0])
            {
                uint offset = 0;         // to calculate current offset
                uint ID     = 0;         // to get the ID of the block being read
                uint size   = 0;         // to get the size of the block being read

                uint proff  = 0;         // offset of the preset rides block
                uint prsize = 0;         // size of the preset rides block

                uint troff  = 0;         // offset of the tracks block
                uint trsize = 0;         // size of the tracks block

                uint csoff  = 0;         // offset of the carskins block
                uint cssize = 0;         // size of the carskins block

                uint gcoff = 0xFFFFFFFF; // offset of the gcareerinfo block

                while (offset < db._GlobalBLZC.Length)
                {
                    ID   = *(uint *)(byteptr_t + offset);     // read ID
                    size = *(uint *)(byteptr_t + offset + 4); // read size
                    if (offset + size > db._GlobalBLZC.Length)
                    {
                        if (Process.MessageShow)
                        {
                            MessageBox.Show("GlobalB: unable to read beyond the stream.", "Failure");
                        }
                        else
                        {
                            Console.WriteLine("GlobalB: unable to read beyond the stream.");
                        }
                        return(false);
                    }

                    switch (ID)
                    {
                    case Global.Materials:
                        E_Material(byteptr_t + offset, db);
                        break;

                    case Global.TPKBlocks:
                        int count = db.TPKBlocks.Length;
                        db.TPKBlocks.Collections.Add(new TPKBlock(byteptr_t + offset, count, db));
                        break;

                    case Global.CarTypeInfo:
                        E_CarTypeInfo(byteptr_t + offset + 8, size, db);
                        break;

                    case Global.PresetRides:
                        proff  = offset + 8;
                        prsize = size;
                        break;

                    case Global.CarParts:
                        E_CarParts(byteptr_t + offset + 8, size, db);
                        break;

                    case Global.SunInfos:
                        E_SunInfo(byteptr_t + offset + 8, size, db);
                        break;

                    case Global.Tracks:
                        troff  = offset + 8;
                        trsize = size;
                        break;

                    case Global.CarSkins:
                        csoff  = offset + 8;
                        cssize = size;
                        break;

                    case Global.SlotTypes:
                        E_SlotType(byteptr_t + offset, size + 8, db);
                        break;


                    case Global.CareerInfo:
                        if (gcoff == 0xFFFFFFFF)
                        {
                            gcoff = offset;
                        }
                        break;

                    case Global.AcidEffects:
                        E_AcidEffects(byteptr_t + offset + 8, size, db);
                        break;

                    case Global.FEngFiles:
                    case Global.FNGCompress:
                        E_FNGroup(byteptr_t + offset, size + 8, db);
                        break;

                    default:
                        break;
                    }
                    offset += 8 + size; // advance in offset
                }

                // Track, Presets and CarSkins are last one to disperse
                E_Tracks(byteptr_t + troff, trsize, db);
                E_PresetRides(byteptr_t + proff, prsize, db);
                E_CarSkins(byteptr_t + csoff, cssize, db);
                CareerManager.Disassemble(byteptr_t + gcoff, db);
            }

            // Disperse spoilers across cartypeinfo
            E_SpoilMirrs(db);
            return(true);
        }
Esempio n. 14
0
        protected override void ReadChunks(long totalSize)
        {
            if (BinaryReader.BaseStream.Length == 0)
            {
                return;
            }

            var curPos = BinaryReader.BaseStream.Position;

            if (BinaryReader.ReadChar() == 'J' &&
                BinaryReader.ReadChar() == 'D' &&
                BinaryReader.ReadChar() == 'L' &&
                BinaryReader.ReadChar() == 'Z')
            {
#if DEBUG
                Console.WriteLine("JDLZ compressed!");
#endif
                BinaryReader.BaseStream.Seek(curPos, SeekOrigin.Begin);

                var data = new byte[BinaryReader.BaseStream.Length];

                BinaryReader.BaseStream.Read(data, 0, data.Length);

                var decompressed = JDLZ.Decompress(data);
                var newName      = _fileName + ".dejdlz";

                var stream = new FileStream(newName, FileMode.CreateNew);
                stream.Write(decompressed, 0, decompressed.Length);
                stream.Close();
                BinaryReader = new BinaryReader(new FileStream(newName, FileMode.Open));
                File.Delete(newName);
            }
            else
            {
                BinaryReader.BaseStream.Seek(curPos, SeekOrigin.Begin);
            }

            var runTo = BinaryReader.BaseStream.Position + totalSize;

            for (var i = 0;
                 i < 0xFFFF && BinaryReader.BaseStream.Position < runTo;
                 i++
                 )
            {
                var chunkId    = BinaryReader.ReadUInt32();
                var chunkSize  = BinaryReader.ReadUInt32();
                var chunkRunTo = BinaryReader.BaseStream.Position + chunkSize;

                var normalizedId = (int)chunkId & 0xffffffff;

                BinaryUtil.PrintID(BinaryReader, chunkId, normalizedId, chunkSize, GetType());

                switch (normalizedId)
                {
                default:
                    _dataModels.Add(new NullModel(normalizedId, chunkSize, BinaryReader.BaseStream.Position));

                    if (DebugUtil.IsContainerChunk(chunkId))
                    {
                        ReadChunks(chunkSize);
                    }

                    break;
                }

                BinaryUtil.ValidatePosition(BinaryReader, chunkRunTo, GetType());
                BinaryReader.BaseStream.Seek(chunkRunTo - BinaryReader.BaseStream.Position, SeekOrigin.Current);
            }
        }
Esempio n. 15
0
        protected override void ReadChunks(long totalSize)
        {
            if (BinaryReader.BaseStream.Length == 0)
            {
                return;
            }

            var curPos = BinaryReader.BaseStream.Position;

            if (BinaryReader.ReadChar() == 'J' &&
                BinaryReader.ReadChar() == 'D' &&
                BinaryReader.ReadChar() == 'L' &&
                BinaryReader.ReadChar() == 'Z')
            {
#if DEBUG
                Console.WriteLine("JDLZ compressed!");
#endif
                BinaryReader.BaseStream.Seek(curPos, SeekOrigin.Begin);

                var data = new byte[BinaryReader.BaseStream.Length];

                BinaryReader.BaseStream.Read(data, 0, data.Length);

                var decompressed = JDLZ.Decompress(data);
                var newName      = _fileName + ".dejdlz";

                var stream = new FileStream(newName, FileMode.CreateNew);
                stream.Write(decompressed, 0, decompressed.Length);
                stream.Close();
                BinaryReader = new BinaryReader(new FileStream(newName, FileMode.Open));
                File.Delete(newName);
            }
            else
            {
                BinaryReader.BaseStream.Seek(curPos, SeekOrigin.Begin);
            }

            var runTo = BinaryReader.BaseStream.Position + totalSize;

            for (var i = 0;
                 i < 0xFFFF && BinaryReader.BaseStream.Position < runTo;
                 i++
                 )
            {
                var chunkId    = BinaryReader.ReadUInt32();
                var chunkSize  = BinaryReader.ReadUInt32();
                var chunkRunTo = BinaryReader.BaseStream.Position + chunkSize;

                var normalizedId = (int)chunkId & 0xffffffff;

#if DEBUG
                BinaryUtil.PrintID(BinaryReader, chunkId, normalizedId, chunkSize, GetType());
#endif

                switch (normalizedId)
                {
                case (long)ChunkID.BCHUNK_CARINFO_ARRAY:
                    var carListContainer = new MWCarListReadContainer(BinaryReader, _fileName, chunkSize);
                    _dataModels.Add(carListContainer.Get());
                    break;

                case (long)ChunkID.BCHUNK_SPEED_TEXTURE_PACK_LIST_CHUNKS:
                {
                    var tpkContainer = new TPKReadContainer(BinaryReader, _fileName, chunkSize, false);
                    _dataModels.Add(tpkContainer.Get());
                    break;
                }

                case (long)ChunkID.BCHUNK_SPEED_TEXTURE_PACK_LIST_CHUNKS_ANIM:
                {
                    var tpkContainer = new AnimatedTPKReadContainer(BinaryReader, _fileName, chunkSize);
                    _dataModels.Add(tpkContainer.Get());
                    break;
                }

                case (long)ChunkID.BCHUNK_SPEED_TEXTURE_PACK_LIST_CHUNKS_COMPRESSED:
                {
                    var tpkContainer = new CompressedTPKReadContainer(BinaryReader, _fileName, chunkSize);
                    _dataModels.Add(tpkContainer.Get());
                    break;
                }

                case (long)ChunkID.BCHUNK_LANGUAGE:
                    var languageContainer = new LanguageReadContainer(BinaryReader, _fileName, chunkSize);
                    _dataModels.Add(languageContainer.Get());
                    break;

                case (long)ChunkID.BCHUNK_TRACKINFO:
                    var trackListContainer = new TrackListReadContainer(BinaryReader, _fileName, chunkSize);
                    _dataModels.Add(trackListContainer.Get());
                    break;

                case (long)ChunkID.BCHUNK_TRACKSTREAMER_SECTIONS:
                    var sectionsContainer = new SectionListReadContainer(BinaryReader, _fileName, chunkSize);
                    _dataModels.Add(sectionsContainer.Get());
                    break;

                case (long)ChunkID.BCHUNK_SPEED_ESOLID_LIST_CHUNKS:
                    var solidListContainer = new SolidListReadContainer(BinaryReader, _fileName, chunkSize);
                    _dataModels.Add(solidListContainer.Get());
                    break;

                case (long)ChunkID.BCHUNK_FENG_PACKAGE:
                {
                    var fngContainer = new FNGReadContainer(BinaryReader, _fileName, chunkSize);
                    _dataModels.Add(fngContainer.Get());
                    break;
                }

                case (long)ChunkID.BCHUNK_FENG_PACKAGE_COMPRESSED:
                {
                    var fngContainer = new CompressedFNGReadContainer(BinaryReader, _fileName, chunkSize);
                    _dataModels.Add(fngContainer.Get());
                    break;
                }

                default:
                    _dataModels.Add(new NullModel(normalizedId, chunkSize, BinaryReader.BaseStream.Position));
                    break;
                }

                BinaryUtil.ValidatePosition(BinaryReader, chunkRunTo, GetType());
                BinaryReader.BaseStream.Seek(chunkRunTo - BinaryReader.BaseStream.Position, SeekOrigin.Current);
            }
        }