Пример #1
0
        public void Save(string path)
        {
            using (var fs = new FileStream(path, FileMode.Create))
                using (var bs = new BinaryStream(fs, ByteConverter.Big))
                {
                    bs.WriteString(MAGIC, StringCoding.Raw);
                    bs.Position += 4;
                    bs.Position += 4; // Skip prefixes offset for now
                    bs.WriteInt32(NameTrees.Count);

                    bs.Position += NameTrees.Count * sizeof(uint);
                    bs.AlignWithValue(0x10, 0x5E);

                    long lastPos = bs.Position;
                    for (int i = 0; i < NameTrees.Count; i++)
                    {
                        var currentTree = NameTrees[i];
                        bs.Position = lastPos;
                        int baseTreePos = (int)bs.Position;
                        // For now skip everything and go to the string tables
                        bs.Position += 0x10;
                        bs.Position += 0x10 * currentTree.Entries.Count;

                        OptimizedStringTable opt = NameTrees[i].GetStringTable();
                        opt.SaveStream(bs);
                        bs.AlignWithValue(0x10, 0x5E);

                        lastPos = bs.Position;

                        // Write where the tree is located
                        bs.Position = 0x10 + (i * sizeof(uint));
                        bs.WriteInt32(baseTreePos);

                        // Write its data
                        bs.Position = baseTreePos;
                        bs.WriteInt32(100);
                        bs.WriteInt32(currentTree.Entries.Count);
                        bs.AlignWithValue(0x10, 0x5E);
                        for (int j = 0; j < currentTree.Entries.Count; j++)
                        {
                            var entry = currentTree.Entries[j];
                            bs.WriteUInt32(entry.SpecDBID);
                            bs.WriteUInt32(entry.AlphabeticalID);
                            bs.WriteInt32(opt.GetStringOffset(entry.FullName));
                            bs.WriteBytes(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF });
                        }
                    }

                    // Write the prefix tree
                    bs.Position = lastPos;
                    bs.WriteInt32(Prefixes.Count); // 4 byte header

                    // Skip entries
                    bs.Position += Prefixes.Count * sizeof(uint);
                    OptimizedStringTable prefixST = GetPrefixStringTable();
                    prefixST.SaveStream(bs);
                    bs.Align(0x10, true);

                    // String table
                    bs.Position = lastPos + 4;
                    foreach (var prefix in Prefixes)
                    {
                        bs.WriteInt32(prefixST.GetStringOffset(prefix.Name));
                    }

                    // Write prefix tree offset
                    bs.Position = 0x08;
                    bs.WriteInt32((int)lastPos);
                }
        }
Пример #2
0
        public void Pack(string outputFileName, bool bigEndian = true)
        {
            Console.WriteLine($"[:] GPB: Packing {Files.Count} to -> {outputFileName}..");

            using var fs = new FileStream(outputFileName, FileMode.Create);
            using var bs = new BinaryStream(fs, bigEndian ? ByteConverter.Big : ByteConverter.Little);

            if (bigEndian)
            {
                bs.WriteString("3bpg", StringCoding.Raw);
            }
            else
            {
                bs.WriteString("gpb3", StringCoding.Raw);
            }

            bs.WriteInt32(0);
            bs.WriteInt32(HeaderSize); // Header Size
            bs.WriteInt32(Files.Count);

            // Write all file names first
            int baseFileNameOffset    = HeaderSize + (EntrySize * Files.Count);
            int currentFileNameOffset = baseFileNameOffset;

            // Game uses bsearch, important
            Files = Files.OrderBy(e => e.FileName).ToList();

            for (int i = 0; i < Files.Count; i++)
            {
                bs.Position = HeaderSize + (i * EntrySize);
                bs.WriteInt32(currentFileNameOffset);

                bs.Position = currentFileNameOffset;
                bs.WriteString(Files[i].FileName, StringCoding.ZeroTerminated);
                currentFileNameOffset = (int)bs.Position;
            }

            bs.AlignWithValue(0x80, 0x5E, true);
            int baseDataOffset        = (int)bs.Position; // Align with 0x5E todo
            int currentFileDataOffset = baseDataOffset;

            // Write the buffers
            for (int i = 0; i < Files.Count; i++)
            {
                bs.Position = HeaderSize + (i * EntrySize) + 4;
                bs.WriteInt32(currentFileDataOffset);
                bs.WriteInt32(Files[i].FileData.Length);

                bs.Position = currentFileDataOffset;
                bs.WriteBytes(Files[i].FileData);

                bs.AlignWithValue(0x80, 0x5E, true);
                currentFileDataOffset = (int)bs.Position;
            }

            bs.Position = 0x10;
            bs.WriteInt32(HeaderSize); // Offset of entries
            bs.WriteInt32(baseFileNameOffset);
            bs.WriteInt32(baseDataOffset);

            Console.WriteLine($"[:] GPB: Done packing {Files.Count} files to {outputFileName}.");
        }