Example #1
0
        public static ExtractedFile Extract(BND4 bndfile, int ID, string filePath)
        {
            var file = new ExtractedFile(bndfile.Files.First(f => f.ID == ID), filePath);

            System.IO.File.WriteAllBytes(file.Path, file.File.Bytes);
            return(file);
        }
Example #2
0
        public IExtractedFile ExtractDat()
        {
            var length     = ExtractedFile.GetIntAtOffset(0);
            var gpt1Length = ExtractedFile.GetIntAtOffset(8);

            var startOffset = Start;

            if (gpt1Length > 0 && ExtractedFile.GetIntAtOffset(Start) == GPT1MagicNumber) /*GPT1 magic*/
            {
                startOffset += gpt1Length + 4;
            }
            var fileName = FileName.RemoveFileExtensions() + ".dat";
            var datFile  = $"{Path}/{fileName}".GetNewStream();

            ExtractedFile.CopySubStream(datFile, startOffset, length);
            datFile.Flush();

            return(new DAT
            {
                FileName = fileName,
                Path = Path,
                FileType = FileTypes.DAT,
                ExtractedFile = datFile
            });
        }
Example #3
0
        public DOL(string pathToExtractDirectory, ISOExtractor extractor)
        {
            Path = pathToExtractDirectory;
            var fileName = $"{Path}/{FileName}";

            ExtractedFile = fileName.GetNewStream();
            Offset        = (int)extractor.ISOStream.GetUIntAtOffset(DOLStartOffsetLocation);

            var size = DolHeaderSize;

            for (int i = 0; i < DolSectionSizesCount; i++)
            {
                var offset = Offset + (i * 4) + DolSectionSizesStart;
                size += (int)extractor.ISOStream.GetUIntAtOffset(offset);
            }
            Size = size;

            if (Configuration.Verbose)
            {
                Console.WriteLine($"DOL Size: {Size:X}");
            }

            extractor.ISOStream.CopySubStream(ExtractedFile, Offset, Size);
            ExtractedFile.Flush();
        }
Example #4
0
        public override Stream Encode(bool isCompressed)
        {
            Stream entryStream;

            ExtractedFile.Seek(0, SeekOrigin.Begin);

            if (isCompressed)
            {
                var tempStream = $"{Path}/{FileName}.lzss".GetNewStream();
                ExtractedFile.CopyTo(tempStream);
                tempStream.Flush();
                tempStream.Seek(0, SeekOrigin.Begin);

                var encoder = new LZSSEncoder();
                entryStream = encoder.Encode(tempStream);
            }
            else
            {
                entryStream = $"{Path}/{FileName}.lzss".GetNewStream();
                ExtractedFile.CopyTo(entryStream);
            }

            entryStream.AlignStream(0x10);
            entryStream.Flush();
            entryStream.Seek(0, SeekOrigin.Begin);
            return(entryStream);
        }
Example #5
0
        public void ReplacePointer(int index, int newValue)
        {
            var pointerStart1 = GetPointerOffset(index);
            var pointerStart2 = (uint)(firstPointer + (index * RELSizeOfPointer) + RELPointerDataPointer2Offset);

            ExtractedFile.WriteBytesAtOffset(pointerStart1, ((uint)(newValue - dataStart)).GetBytes());
            ExtractedFile.WriteBytesAtOffset(pointerStart2, ((uint)(newValue - dataStart)).GetBytes());
            ExtractedFile.Flush();
        }
Example #6
0
        public override Stream Encode(bool _ = false)
        {
            var streamCopy = new MemoryStream();

            ExtractedFile.Seek(0, SeekOrigin.Begin);
            ExtractedFile.CopyTo(streamCopy);
            streamCopy.Seek(0, SeekOrigin.Begin);
            return(streamCopy);
        }
Example #7
0
        /// <summary>
        /// Recreates FST.bin from the current directory state. I.e. recreate the underlying stream.
        /// </summary>
        public void RebuildFST()
        {
            ExtractedFile.Dispose();
            ExtractedFile = $"{Path}/{FileName}".GetNewStream();

            var entries = GetFlattenedFST();

            // write root dir
            ExtractedFile.WriteByte(1);
            ExtractedFile.WriteByte(0);
            ExtractedFile.WriteByte(0);
            ExtractedFile.WriteByte(0);
            ExtractedFile.Write(0.GetBytes());
            ExtractedFile.Write((entries.Count + 1).GetBytes());

            // instead of seeking back and forth, store name bytes as they come and write it at the end.
            var nameBytes = new List <byte>();

            for (int i = 0; i < entries.Count; i++)
            {
                var entry = entries[i];
                if (entry is FSTFileEntry fileEntry)
                {
                    ExtractedFile.Write(fileEntry.NameOffset.GetBytes());
                    ExtractedFile.Write(fileEntry.FileDataOffset.GetBytes());
                    ExtractedFile.Write(fileEntry.Size.GetBytes());
                }
                else if (entry is FSTDirectory dir)
                {
                    var nameOffsetBytes = dir.NameOffset.GetBytes();
                    nameOffsetBytes[0] = 1;

                    ExtractedFile.Write(nameOffsetBytes);
                    ExtractedFile.Write(dir.ParentEntry.GetBytes());
                    ExtractedFile.Write(dir.EndEntry.GetBytes());
                }

                var nameByteArray = entry.Name.ToByteArray();
                if (nameByteArray.Length > 0)
                {
                    nameBytes.AddRange(nameByteArray);
                    nameBytes.Add(0);
                }
            }
            ExtractedFile.Write(nameBytes.ToArray());

            // fst.bin is aligned to the nearest 4 bytes
            var m = ExtractedFile.Length % 4;

            if (m > 0)
            {
                ExtractedFile.Write(new byte[4 - m]);
            }

            ExtractedFile.Flush();
        }
Example #8
0
        public void AdjustPointerStart(int byAmount)
        {
            var newPointerStart       = (uint)(ExtractedFile.GetUIntAtOffset(RELPointersStartOffsetLocation) + byAmount);
            var pointerHeaderStart    = ExtractedFile.GetUIntAtOffset(RELPointersHeaderPointer1Offset);
            var newPointerHeaderStart = (uint)(pointerHeaderStart + byAmount);
            var newPointerHeaderEnd   = (uint)(ExtractedFile.GetUIntAtOffset(pointerHeaderStart + 0xC) + byAmount);

            ExtractedFile.WriteBytesAtOffset(RELPointersStartOffsetLocation, newPointerStart.GetBytes());
            ExtractedFile.WriteBytesAtOffset(RELPointersHeaderPointer1Offset, newPointerHeaderStart.GetBytes());
            ExtractedFile.WriteBytesAtOffset(RELPointersHeaderPointer2Offset, newPointerStart.GetBytes());
            ExtractedFile.WriteBytesAtOffset(pointerHeaderStart + 0x4, newPointerStart.GetBytes());
            ExtractedFile.WriteBytesAtOffset(pointerHeaderStart + 0xC, newPointerHeaderEnd.GetBytes());
            firstPointer = newPointerStart + RELPointersFirstPointerOffset;
        }
        void GetOffsets()
        {
            var currentOffset = kEndOfHeader;

            for (int i = 0; i < NumberOfEntries; i++)
            {
                var id     = ExtractedFile.GetIntAtOffset(currentOffset) & 0xFFFFF;
                var offset = ExtractedFile.GetIntAtOffset(currentOffset + 4);
                if (!stringOffsets.ContainsKey(id))
                {
                    stringOffsets.Add(id, offset);
                }
                currentOffset += 8;
            }
        }
Example #10
0
        public GSWTexture()
        {
            FileType = FileTypes.GSW;
            var numberOfIds = ExtractedFile.GetUShortAtOffset(0x18);

            metadata = new List <GSWMetadata>();

            for (int i = 1; i < numberOfIds && i <= 0xFF; i++)
            {
                var search = SearchForID(i);
                if (search.HasValue)
                {
                    metadata.Add(search.Value);
                }
            }
        }
Example #11
0
        public int ExtraChracters()
        {
            var currentChar   = 0;
            var currentOffset = (int)ExtractedFile.Length - 3;
            var length        = 0;

            while (currentChar == 0)
            {
                currentChar = ExtractedFile.GetByteAtOffset(currentOffset);
                if (currentChar == 0)
                {
                    length++;
                }
                currentOffset--;
            }
            return(length);
        }
Example #12
0
        public void Load()
        {
            if (Configuration.Verbose)
            {
                Console.WriteLine($"Extracting TOC.");
            }

            rootDirectory = new FSTDirectory(0, 0, 0);
            var numberOfEntries = ExtractedFile.GetIntAtOffset(TOCNumberEntriesOffset);

            LoadFST(rootDirectory, numberOfEntries);

            if (Configuration.Verbose)
            {
                Console.WriteLine($"Finished reading FST.");
            }
        }
Example #13
0
        void LoadFST(FSTDirectory root, int endEntryIndex, int firstEntryIndex = 1)
        {
            int index = firstEntryIndex;

            while (index < endEntryIndex)
            {
                var entryOffset = index * 12;
                var folder      = ExtractedFile.GetByteAtOffset(entryOffset) == 1;

                FSTEntry fileEntry;
                uint     nameOffset;
                if (folder)
                {
                    nameOffset = (ExtractedFile.GetUIntAtOffset(entryOffset) & 0x00FFFFFF);
                    var parentEntry = ExtractedFile.GetIntAtOffset(entryOffset + 4);
                    var endDirEntry = ExtractedFile.GetIntAtOffset(entryOffset + 8);
                    var directory   = new FSTDirectory(index, nameOffset, parentEntry);

                    LoadFST(directory, endDirEntry, index + 1);
                    fileEntry = directory;
                    index    += endDirEntry - index;
                }
                else
                {
                    nameOffset = ExtractedFile.GetUIntAtOffset(entryOffset);
                    var fileOffset = ExtractedFile.GetUIntAtOffset(entryOffset + 4);
                    var fileSize   = ExtractedFile.GetUIntAtOffset(entryOffset + 8);
                    fileEntry = new FSTFileEntry(index, nameOffset, fileOffset, fileSize);
                    index++;
                    if (fileOffset < StartDataOffset)
                    {
                        StartDataOffset = fileOffset;
                    }
                }

                if (nameOffset > LastNameOffset)
                {
                    LastNameOffset = nameOffset;
                }

                var fileName = ExtractedFile.GetStringAtOffset(nameOffset + TOCFirstStringOffset);
                fileEntry.Name = fileName;
                root.Children.Add(fileEntry);
            }
        }
Example #14
0
        void LoadFileDetails()
        {
            for (int i = 0; i < NumberOfEntries; i++)
            {
                var start       = GetStartOffsetForFileDetails(i);
                var fileDetails = new FSysDetailsHeader
                {
                    Identifier            = ExtractedFile.GetUShortAtOffset(start),
                    Filetype              = (FileTypes)ExtractedFile.GetByteAtOffset(start + FileFormatOffset),
                    StartOffset           = ExtractedFile.GetUIntAtOffset(start + FileStartPointerOffset),
                    UncompressedSize      = ExtractedFile.GetUIntAtOffset(start + UncompressedSizeOffset),
                    CompressedSize        = ExtractedFile.GetUIntAtOffset(start + CompressedSizeOffset),
                    FileFormatIndexOffset = ExtractedFile.GetUIntAtOffset(start + FileFormatIndexOffset),
                    NameOffset            = ExtractedFile.GetUIntAtOffset(start + FileDetailsFilenameOffset)
                };

                fileDetails.FileName = ExtractedFile.GetStringAtOffset(fileDetails.NameOffset);
                fSysDetailsHeaders.Add(fileDetails);
            }
        }
Example #15
0
        public FST(string pathToExtractDirectory, ISOExtractor extractor)
        {
            Path          = pathToExtractDirectory;
            FileName      = "Game.toc";
            ExtractedFile = $"{Path}/{FileName}".GetNewStream();

            // load toc
            Offset = (int)extractor.ISOStream.GetUIntAtOffset(TOCStartOffsetLocation);
            Size   = (int)extractor.ISOStream.GetUIntAtOffset(TOCFileSizeLocation);

            if (Configuration.Verbose)
            {
                Console.WriteLine("Reading TOC from ISO");
                Console.WriteLine($"TOC Start: {Offset:X}");
                Console.WriteLine($"TOC Length: {Size:X}");
            }

            // write to disk
            extractor.ISOStream.CopySubStream(ExtractedFile, Offset, Size);
            ExtractedFile.Flush();
            Load();
        }
Example #16
0
        public IEnumerable <Texture> ExtractTextureData()
        {
            var textures = new List <Texture>();

            foreach (var info in metadata)
            {
                var filename      = $"{Path}/{FileName.RemoveFileExtensions()}{info.Id}.gtx";
                var extractedFile = File.Open(filename, FileMode.Create, FileAccess.ReadWrite);
                ExtractedFile.CopySubStream(extractedFile, info.StartOffset, info.DataSize);
                extractedFile.Flush();

                var entry = new Texture
                {
                    Path          = Path,
                    FileName      = filename,
                    FileType      = FileTypes.GTX,
                    ExtractedFile = extractedFile
                };
                textures.Add(entry);
            }
            return(textures);
        }
Example #17
0
        GSWMetadata?SearchForID(int id)
        {
            var headerMarker = new byte[] { 3, 0, 0, (byte)id };
            var offsets      = ExtractedFile.OccurencesOfBytes(BitConverter.ToInt32(headerMarker));

            foreach (var offset in offsets)
            {
                if (ExtractedFile.GetUShortAtOffset(offset + 0x24) == 0x0801)
                {
                    var formatID = ExtractedFile.GetIntAtOffset(offset + 0x28);

                    var palletteSize = ExtractedFile.GetIntAtOffset(offset + 0x68);
                    var textureSize  = palletteSize + 0x200;
                    var textureStart = offset + 0x20;
                    return(new GSWMetadata
                    {
                        Id = id,
                        StartOffset = textureSize,
                        DataSize = textureStart
                    });
                }
            }
            return(null);
        }
Example #18
0
        public UnicodeString GetStringAtOffset(int offset)
        {
            var currentOffset = offset;
            var currChar      = 0x0;
            var nextChar      = 0x1;
            var str           = new UnicodeString();

            while (nextChar != 0)
            {
                if (currentOffset + 2 > ExtractedFile.Length)
                {
                    break;
                }
                currChar       = ExtractedFile.GetUShortAtOffset(currentOffset);
                currentOffset += 2;

                if (currChar == 0xFFFF)
                {
                    var specChar = (SpecialCharacters)ExtractedFile.GetByteAtOffset(currentOffset);
                    currentOffset += 1;

                    var extra = specChar.ExtraBytes();
                    var bytes = new byte[extra];
                    ExtractedFile.Seek(currentOffset, SeekOrigin.Begin);
                    currentOffset += ExtractedFile.Read(bytes);

                    str.Add(new SpecialUnicodeCharacters(specChar, bytes));
                }
                else
                {
                    str.Add(new UnicodeCharacters(currChar));
                }
                nextChar = ExtractedFile.GetUShortAtOffset(currentOffset);
            }
            return(str);
        }
Example #19
0
        public uint GetPointer(int index)
        {
            var offset = GetPointerOffset(index);

            return(ExtractedFile.GetUIntAtOffset(offset) + dataStart);
        }
Example #20
0
        public uint GetValueAtPointer(int index)
        {
            var offset = GetPointer(index);

            return(ExtractedFile.GetUIntAtOffset(offset));
        }
Example #21
0
        public override Stream Encode(bool _ = false)
        {
            Stream fSysStream = $"{Path}/{FileName}.repak".GetNewStream();

            if (ExtractedEntries.Count == 0)
            {
                // nothing extracted, nothing changed
                // just copy the existing stream back
                ExtractedFile.Seek(0, SeekOrigin.Begin);
                ExtractedFile.CopyTo(fSysStream);
                return(fSysStream);
            }

            // unpack the entire fsys archive for easier repacking
            if (ExtractedEntries.Count < NumberOfEntries)
            {
                FSysExtractor.ExtractFSys(this, false);
            }


            // copy the header back, we'll update the sizes later
            NumberOfEntries = ExtractedEntries.Count;
            ExtractedFile.Seek(0, SeekOrigin.Begin);
            ExtractedFile.CopySubStream(fSysStream, 0, 0x60);

            var sizeOfDetailsPointers = (fSysDetailsHeaders.Count * 4);
            var startNameOffset       = 0x60 + sizeOfDetailsPointers + sizeOfDetailsPointers.GetAlignBytesCount(16);

            fSysStream.Seek(startNameOffset, SeekOrigin.Begin);

            // write the name table
            var startDataOffset = uint.MaxValue;

            foreach (var detailHeader in fSysDetailsHeaders)
            {
                fSysStream.Write(detailHeader.FileName.ToByteArray());
                fSysStream.WriteByte(0);

                if (detailHeader.StartOffset < startDataOffset)
                {
                    startDataOffset = detailHeader.StartOffset;
                }
            }

            // align names
            fSysStream.AlignStream(0x10);
            var lastNameOffset      = (int)fSysStream.Position;
            var startDetailsOffsewt = 0x60;

            // write pointers to details offset
            fSysStream.Seek(startDetailsOffsewt, SeekOrigin.Begin);
            for (int x = 0; x < fSysDetailsHeaders.Count; x++)
            {
                fSysStream.Write((lastNameOffset + (x * 0x70)).GetBytes());
            }

            // write our data, update offsets along the way if we find mismatches
            for (int i = 0; i < fSysDetailsHeaders.Count; i++)
            {
                var detailHeader = fSysDetailsHeaders[i];

                var entryFileName = detailHeader.FileName.ToString();
                if (!entryFileName.EndsWith(detailHeader.Filetype.FileTypeName()))
                {
                    entryFileName = $"{entryFileName}{detailHeader.Filetype.FileTypeName()}";
                }

                var entry = ExtractedEntries[entryFileName];

                using var encodeStream = entry.Encode(detailHeader.IsCompressed);
                fSysStream.Seek(detailHeader.StartOffset, SeekOrigin.Begin);
                encodeStream.CopyTo(fSysStream);
                fSysStream.Flush();

                detailHeader.UncompressedSize = (uint)entry.ExtractedFile.Length;
                if (encodeStream.Length != detailHeader.CompressedSize)
                {
                    var adjustedSize = (int)(encodeStream.Length - detailHeader.CompressedSize);
                    detailHeader.CompressedSize = (uint)encodeStream.Length;

                    if (adjustedSize < 0)
                    {
                        continue; // probably wasteful, but meh
                    }
                    for (int j = i + 1; j < fSysDetailsHeaders.Count; j++)
                    {
                        var adjDetailsHeader = fSysDetailsHeaders[j];
                        adjDetailsHeader.StartOffset += (uint)adjustedSize;
                        adjDetailsHeader.StartOffset += adjDetailsHeader.StartOffset.GetAlignBytesCount(0x10);
                    }
                }
            }

            fSysStream.AlignStream(0x10);
            fSysStream.Write(new byte[0x10]);
            fSysStream.Seek(-4, SeekOrigin.Current);
            fSysStream.Write(FSYSbytes.GetBytes());
            fSysStream.Flush();

            fSysStream.WriteBytesAtOffset(FSYSFileSizeOffset, ((int)fSysStream.Length).GetBytes());

            // go back and re-write our file details table
            fSysStream.Seek(lastNameOffset, SeekOrigin.Begin);
            foreach (var detailHeader in fSysDetailsHeaders)
            {
                fSysStream.Write(detailHeader.Encode());
            }

            fSysStream.Flush();
            fSysStream.Seek(0, SeekOrigin.Begin);
            return(fSysStream);
        }
Example #22
0
 public int GetStartOffsetForFileDetails(int index)
 {
     return(ExtractedFile.GetIntAtOffset(FirstFileDetailsPointerOffset + (index * 4)));
 }
Example #23
0
        public void SetValueAtPointer(int index, int newValue)
        {
            var offset = GetPointer(index);

            ExtractedFile.WriteBytesAtOffset(offset, newValue.GetBytes());
        }