Пример #1
0
 internal static Asset?SearchInner(VirtualFileSystem.Directory parent, string name)
 {
     return((Asset?)FileSystem.SearchInner(parent, name));
 }
Пример #2
0
 public static Asset?Search(VirtualFileSystem.Directory parent, string name)
 {
     using var _ = ApiCallSource.StartExternalCall();
     return(SearchInner(parent, name));
 }
Пример #3
0
 internal static TAsset?SearchInner <TAsset>(VirtualFileSystem.Directory parent, string name) where TAsset : Asset
 {
     return(FileSystem.SearchInner <TAsset>(parent, name));
 }
Пример #4
0
 public static TAsset?Search <TAsset>(VirtualFileSystem.Directory parent, string name) where TAsset : Asset
 {
     using var _ = ApiCallSource.StartExternalCall();
     return(SearchInner <TAsset>(parent, name));
 }
Пример #5
0
        private void ReadMetadata()
        {
            // Read the header.
            version = reader.ReadBytes(4);
            uint hashTableOffsetFromEndOfHeader = reader.ReadLEUInt32();             // minus header size (12 bytes)
            uint fileCount = reader.ReadLEUInt32();

            // Calculate some useful values.
            var headerSize = reader.BaseStream.Position;

            hashTablePosition      = headerSize + hashTableOffsetFromEndOfHeader;
            fileDataSectionPostion = hashTablePosition + (8 * fileCount);

            // Create file metadatas.
            fileMetadatas = new FileMetadata[fileCount];

            for (int i = 0; i < fileCount; i++)
            {
                fileMetadatas[i] = new FileMetadata();
            }

            // Read file sizes/offsets.
            for (int i = 0; i < fileCount; i++)
            {
                fileMetadatas[i].size = reader.ReadLEUInt32();
                fileMetadatas[i].offsetInDataSection = reader.ReadLEUInt32();
            }

            // Read filename offsets.
            var filenameOffsets = new uint[fileCount];             // relative offset in filenames section

            for (int i = 0; i < fileCount; i++)
            {
                filenameOffsets[i] = reader.ReadLEUInt32();
            }

            // Read filenames.
            var filenamesSectionStartPos = reader.BaseStream.Position;
            var filenameBuffer           = new List <byte>(64);

            for (int i = 0; i < fileCount; i++)
            {
                reader.BaseStream.Position = filenamesSectionStartPos + filenameOffsets[i];

                filenameBuffer.Clear();
                byte curCharAsByte;

                while ((curCharAsByte = reader.ReadByte()) != 0)
                {
                    filenameBuffer.Add(curCharAsByte);
                }

                fileMetadatas[i].path = System.Text.Encoding.ASCII.GetString(filenameBuffer.ToArray());
            }

            // Read filename hashes.
            reader.BaseStream.Position = hashTablePosition;

            for (int i = 0; i < fileCount; i++)
            {
                fileMetadatas[i].pathHash.value1 = reader.ReadLEUInt32();
                fileMetadatas[i].pathHash.value2 = reader.ReadLEUInt32();
            }

            // Create the file metadata hash table.
            fileMetadataHashTable = new Dictionary <FileNameHash, FileMetadata>();

            for (int i = 0; i < fileCount; i++)
            {
                fileMetadataHashTable[fileMetadatas[i].pathHash] = fileMetadatas[i];
            }

            // Create a virtual directory tree.
            rootDir = new VirtualFileSystem.Directory();

            foreach (var fileMetadata in fileMetadatas)
            {
                rootDir.CreateDescendantFile(fileMetadata.path);
            }

            // Skip to the file data section.
            reader.BaseStream.Position = fileDataSectionPostion;
        }
Пример #6
0
        void ReadMetadata()
        {
            // Open
            Magic = _r.ReadLEUInt32();
            if (Magic == F4_BSAHEADER_FILEID)
            {
                Version = _r.ReadLEUInt32();
                if (Version != F4_BSAHEADER_VERSION)
                {
                    throw new InvalidOperationException("BAD MAGIC");
                }
                // Read the header
                var header_Type            = _r.ReadASCIIString(4); // 08 GNRL=General, DX10=Textures
                var header_NumFiles        = _r.ReadLEUInt32();     // 0C
                var header_NameTableOffset = _r.ReadLEUInt64();     // 10 - relative to start of file

                // Create file metadatas
                _r.BaseStream.Position = (long)header_NameTableOffset;
                _files = new FileMetadata[header_NumFiles];
                for (var i = 0; i < header_NumFiles; i++)
                {
                    var length = _r.ReadLEUInt16();
                    var path   = _r.ReadASCIIString(length);
                    _files[i] = new FileMetadata
                    {
                        Path     = path,
                        PathHash = Tes4HashFilePath(path),
                    };
                }
                if (header_Type == "GNRL")           // General BA2 Format
                {
                    _r.BaseStream.Position = 16 + 8; // sizeof(header) + 8
                    for (var i = 0; i < header_NumFiles; i++)
                    {
                        var info_NameHash     = _r.ReadLEUInt32();     // 00
                        var info_Ext          = _r.ReadASCIIString(4); // 04 - extension
                        var info_DirHash      = _r.ReadLEUInt32();     // 08
                        var info_Unk0C        = _r.ReadLEUInt32();     // 0C - flags? 00100100
                        var info_Offset       = _r.ReadLEUInt64();     // 10 - relative to start of file
                        var info_PackedSize   = _r.ReadLEUInt32();     // 18 - packed length (zlib)
                        var info_UnpackedSize = _r.ReadLEUInt32();     // 1C - unpacked length
                        var info_Unk20        = _r.ReadLEUInt32();     // 20 - BAADF00D
                        _files[i].PackedSize   = info_PackedSize;
                        _files[i].UnpackedSize = info_UnpackedSize;
                        _files[i].Offset       = (long)info_Offset;
                    }
                }
                else if (header_Type == "DX10")      // Texture BA2 Format
                {
                    _r.BaseStream.Position = 16 + 8; // sizeof(header) + 8
                    for (var i = 0; i < header_NumFiles; i++)
                    {
                        var fileMetadata         = _files[i];
                        var info_NameHash        = _r.ReadLEUInt32();     // 00
                        var info_Ext             = _r.ReadASCIIString(4); // 04
                        var info_DirHash         = _r.ReadLEUInt32();     // 08
                        var info_Unk0C           = _r.ReadByte();         // 0C
                        var info_NumChunks       = _r.ReadByte();         // 0D
                        var info_ChunkHeaderSize = _r.ReadLEUInt16();     // 0E - size of one chunk header
                        var info_Height          = _r.ReadLEUInt16();     // 10
                        var info_Width           = _r.ReadLEUInt16();     // 12
                        var info_NumMips         = _r.ReadByte();         // 14
                        var info_Format          = _r.ReadByte();         // 15 - DXGI_FORMAT
                        var info_Unk16           = _r.ReadLEUInt16();     // 16 - 0800
                        // read tex-chunks
                        var texChunks = new F4TexChunk[info_NumChunks];
                        for (var j = 0; j < info_NumChunks; j++)
                        {
                            texChunks[j] = new F4TexChunk
                            {
                                Offset       = _r.ReadLEUInt64(),   // 00
                                PackedSize   = _r.ReadLEUInt32(),   // 08
                                UnpackedSize = _r.ReadLEUInt32(),   // 0C
                                StartMip     = _r.ReadLEUInt16(),   // 10
                                EndMip       = _r.ReadLEUInt16(),   // 12
                                Unk14        = _r.ReadLEUInt32(),   // 14 - BAADFOOD
                            }
                        }
                        ;
                        var firstChunk = texChunks[0];
                        _files[i].PackedSize   = firstChunk.PackedSize;
                        _files[i].UnpackedSize = firstChunk.UnpackedSize;
                        _files[i].Offset       = (long)firstChunk.Offset;
                        fileMetadata.Tex       = new F4Tex
                        {
                            Height  = info_Height,
                            Width   = info_Width,
                            NumMips = info_NumMips,
                            Format  = (DXGIFormat)info_Format,
                            Unk16   = info_Unk16,
                            Chunks  = texChunks,
                        };
                    }
                }
            }
            else if (Magic == OB_BSAHEADER_FILEID)
            {
                Version = _r.ReadLEUInt32();
                if (Version != OB_BSAHEADER_VERSION && Version != F3_BSAHEADER_VERSION && Version != SSE_BSAHEADER_VERSION)
                {
                    throw new InvalidOperationException("BAD MAGIC");
                }
                // Read the header
                var header_FolderRecordOffset = _r.ReadLEUInt32(); // Offset of beginning of folder records
                var header_ArchiveFlags       = _r.ReadLEUInt32(); // Archive flags
                var header_FolderCount        = _r.ReadLEUInt32(); // Total number of folder records (OBBSAFolderInfo)
                var header_FileCount          = _r.ReadLEUInt32(); // Total number of file records (OBBSAFileInfo)
                var header_FolderNameLength   = _r.ReadLEUInt32(); // Total length of folder names
                var header_FileNameLength     = _r.ReadLEUInt32(); // Total length of file names
                var header_FileFlags          = _r.ReadLEUInt32(); // File flags

                // Calculate some useful values
                if ((header_ArchiveFlags & OB_BSAARCHIVE_PATHNAMES) == 0 || (header_ArchiveFlags & OB_BSAARCHIVE_FILENAMES) == 0)
                {
                    throw new InvalidOperationException("HEADER FLAGS");
                }
                _compressToggle = (header_ArchiveFlags & OB_BSAARCHIVE_COMPRESSFILES) != 0;
                if (Version == F3_BSAHEADER_VERSION || Version == SSE_BSAHEADER_VERSION)
                {
                    _hasNamePrefix = (header_ArchiveFlags & F3_BSAARCHIVE_PREFIXFULLFILENAMES) != 0;
                }
                var folderSize = Version != SSE_BSAHEADER_VERSION ? 16 : 24;

                // Create file metadatas
                _files = new FileMetadata[header_FileCount];
                var filenamesSectionStartPos = _r.BaseStream.Position = header_FolderRecordOffset + header_FolderNameLength + header_FolderCount * (folderSize + 1) + header_FileCount * 16;
                var buf = new List <byte>(64);
                for (var i = 0; i < header_FileCount; i++)
                {
                    buf.Clear();
                    byte curCharAsByte; while ((curCharAsByte = _r.ReadByte()) != 0)
                    {
                        buf.Add(curCharAsByte);
                    }
                    var path = Encoding.ASCII.GetString(buf.ToArray());
                    _files[i] = new FileMetadata
                    {
                        Path = path,
                    };
                }
                if (_r.BaseStream.Position != filenamesSectionStartPos + header_FileNameLength)
                {
                    throw new InvalidOperationException("HEADER FILENAMES");
                }

                // read-all folders
                _r.BaseStream.Position = header_FolderRecordOffset;
                var foldersFiles = new uint[header_FolderCount];
                for (var i = 0; i < header_FolderCount; i++)
                {
                    var folder_Hash = _r.ReadLEUInt64();      // Hash of the folder name
                    var folder_FileCount = _r.ReadLEUInt32(); // Number of files in folder
                    var folder_Unk = 0U; var folder_Offset = 0UL;
                    if (Version == SSE_BSAHEADER_VERSION)
                    {
                        folder_Unk = _r.ReadLEUInt32(); folder_Offset = _r.ReadLEUInt64();
                    }
                    else
                    {
                        folder_Offset = _r.ReadLEUInt32();
                    }
                    foldersFiles[i] = folder_FileCount;
                }

                // add file
                var fileNameIndex = 0U;
                for (var i = 0; i < header_FolderCount; i++)
                {
                    var folder_name = _r.ReadASCIIString(_r.ReadByte(), ASCIIFormat.PossiblyNullTerminated); // BSAReadSizedString
                    var folderFiles = foldersFiles[i];
                    for (var j = 0; j < folderFiles; j++)
                    {
                        var file_Hash      = _r.ReadLEUInt64(); // Hash of the filename
                        var file_SizeFlags = _r.ReadLEUInt32(); // Size of the data, possibly with OB_BSAFILE_FLAG_COMPRESS set
                        var file_Offset    = _r.ReadLEUInt32(); // Offset to raw file data
                        var fileMetadata   = _files[fileNameIndex++];
                        fileMetadata.SizeFlags = file_SizeFlags;
                        fileMetadata.Offset    = file_Offset;
                        var path = folder_name + "\\" + fileMetadata.Path;
                        fileMetadata.Path     = path;
                        fileMetadata.PathHash = Tes4HashFilePath(path);
                    }
                }
            }
            else if (Magic == MW_BSAHEADER_FILEID)
            {
                // Read the header
                var header_HashOffset = _r.ReadLEUInt32(); // Offset of hash table minus header size (12)
                var header_FileCount  = _r.ReadLEUInt32(); // Number of files in the archive

                // Calculate some useful values
                var headerSize             = _r.BaseStream.Position;
                var hashTablePosition      = headerSize + header_HashOffset;
                var fileDataSectionPostion = hashTablePosition + (8 * header_FileCount);

                // Create file metadatas
                _files = new FileMetadata[header_FileCount];
                for (var i = 0; i < header_FileCount; i++)
                {
                    _files[i] = new FileMetadata
                    {
                        // Read file sizes/offsets
                        SizeFlags = _r.ReadLEUInt32(),
                        Offset    = fileDataSectionPostion + _r.ReadLEUInt32(),
                    }
                }
                ;

                // Read filename offsets
                var filenameOffsets = new uint[header_FileCount]; // relative offset in filenames section
                for (var i = 0; i < header_FileCount; i++)
                {
                    filenameOffsets[i] = _r.ReadLEUInt32();
                }

                // Read filenames
                var filenamesSectionStartPos = _r.BaseStream.Position;
                var buf = new List <byte>(64);
                for (var i = 0; i < header_FileCount; i++)
                {
                    _r.BaseStream.Position = filenamesSectionStartPos + filenameOffsets[i];
                    buf.Clear();
                    byte curCharAsByte; while ((curCharAsByte = _r.ReadByte()) != 0)
                    {
                        buf.Add(curCharAsByte);
                    }
                    _files[i].Path = Encoding.ASCII.GetString(buf.ToArray());
                }

                // Read filename hashes
                _r.BaseStream.Position = hashTablePosition;
                for (var i = 0; i < header_FileCount; i++)
                {
                    _files[i].PathHash = _r.ReadLEUInt64();
                }
            }
            else
            {
                throw new InvalidOperationException("BAD MAGIC");
            }

            // Create the file metadata hash table
            _filesByHash = _files.ToLookup(x => x.PathHash);

            // Create a virtual directory tree.
            RootDir = new VirtualFileSystem.Directory();
            foreach (var fileMetadata in _files)
            {
                RootDir.CreateDescendantFile(fileMetadata.Path);
            }
        }

        ulong HashFilePath(string filePath)
        {
            if (Magic == MW_BSAHEADER_FILEID)
            {
                return(Tes3HashFilePath(filePath));
            }
            else
            {
                return(Tes4HashFilePath(filePath));
            }
        }