public StringTableReader(Stream stream) { reader = new CustomBinaryReader(stream); uint count = reader.ReadUInt32(); uint dataSize = reader.ReadUInt32(); long dataPosition = 8 + count * 8; for (int i = 0; i < count; i++) { uint index = reader.ReadUInt32(); uint offset = reader.ReadUInt32(); table.Add(index, dataPosition + offset); } }
protected override void DoOpen() { using (CustomBinaryReader reader = new CustomBinaryReader(new FileStream(ArchivePath, FileMode.Open, FileAccess.Read))) { uint signature = reader.ReadUInt32(); if (signature != 0x58445442) { throw new InvalidDataException("File is not BA2"); } version = reader.ReadUInt32(); if (version > 1) { throw new InvalidDataException("Unsupported archive file version: " + version); } type = (ArchiveType)reader.ReadUInt32(); if (type != ArchiveType.General) { Log.Fine("Skipping archive file which is not the general purpose type."); return; } long baseOffset = reader.BaseStream.Position; uint fileCount = reader.ReadUInt32(); long fileNameTableOffset = reader.ReadInt64(); FileInfo[] files = new FileInfo[fileCount]; for (int i = 0; i < fileCount; i++) { files[i] = new FileInfo() { NameHash = reader.ReadUInt32(), Type = reader.ReadUInt32(), DirectoryNameHash = reader.ReadUInt32(), Unknown1 = reader.ReadUInt32(), DataOffset = reader.ReadInt64(), DataCompressedSize = reader.ReadUInt32(), DataUncompressedSize = reader.ReadUInt32(), Unknown2 = reader.ReadUInt32() }; } reader.BaseStream.Position = fileNameTableOffset; for (int i = 0; i < fileCount; i++) { ushort length = reader.ReadUInt16(); string path = reader.ReadStringFixedLength(length).ToLower(); string dir = Path.GetDirectoryName(path).ToLower(); string filename = Path.GetFileName(path).ToLower(); if (!sorted.ContainsKey(dir)) { sorted.Add(dir, new SortedDictionary<string, FileInfo>()); } sorted[dir].Add(filename, files[i]); } } }
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 offset = reader.ReadUInt32() - 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 (int 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 (int 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; } }