protected override void DoOpen() { using (CustomBinaryReader reader = new CustomBinaryReader(new FileStream(ArchivePath, FileMode.Open, FileAccess.Read))) { uint signature = reader.ReadUInt32(); if (signature != 0x415342) { throw new InvalidDataException("File is not BSA"); } uint version = reader.ReadUInt32(); uint folderOffset = reader.ReadUInt32(); flags = (ArchiveFlags)reader.ReadUInt32(); uint folderCount = reader.ReadUInt32(); uint fileCount = reader.ReadUInt32(); uint totalFolderNameLength = reader.ReadUInt32(); uint totalFileNameLength = reader.ReadUInt32(); uint fileExtensions = reader.ReadUInt32(); FolderInfo[] folders = new FolderInfo[(int)folderCount]; // Read folders reader.BaseStream.Position = folderOffset; for (int i = 0; i < folderCount; i++) { ulong hash = reader.ReadUInt64(); uint count = reader.ReadUInt32(); uint unknown = reader.ReadUInt32(); ulong offset = reader.ReadUInt64() - totalFileNameLength; folders[i] = new FolderInfo() { FileCount = count, ContentOffset = offset }; } // Read folder content (name and files) foreach (var folder in folders) { byte folderNameLength = reader.ReadByte(); folder.Path = Encoding.UTF8.GetString(reader.ReadBytes(folderNameLength - 1)); byte zero = reader.ReadByte(); folder.Files = new FileInfo[folder.FileCount]; for (ulong i = 0; i < folder.FileCount; i++) { ulong hash = reader.ReadUInt64(); uint size = reader.ReadUInt32(); bool compressed = flags.HasFlag(ArchiveFlags.DefaultCompressed); if ((size & 0xf0000000) != 0) { size &= 0xfffffff; compressed = !compressed; } uint offset = reader.ReadUInt32(); folder.Files[i] = new FileInfo() { Size = size, DataOffset = offset, IsCompressed = compressed }; } } long total = fileCount; long loaded = 0; string filename = Path.GetFileName(ArchivePath); // Read file names foreach (var folder in folders) { foreach (var file in folder.Files) { file.Filename = reader.ReadStringZeroTerminated(); loaded++; } } // Convert to nested sorted dictionary for fast search for (int i = 0; i < folderCount; i++) { var files = new SortedDictionary <string, FileInfo>(); for (ulong j = 0; j < folders[i].FileCount; j++) { files.Add(folders[i].Files[j].Filename, folders[i].Files[j]); } sorted.Add(folders[i].Path, files); } return; } }