static BsaFileReader() { fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); reader = new BinaryReader(fileStream); // Read the header. header = new BsaHeader(reader); // Calculate some useful values. var hashTablePosition = 12 + header.HashOffset; var fileOffset = hashTablePosition + (8 * header.FileCount); // Create file metadatas. reader.BaseStream.Position = 12; var fileMetadatas = new FileMetadata[header.FileCount]; for (var i = 0; i < header.FileCount; i++) { fileMetadatas[i] = new FileMetadata(reader, fileOffset); } // Read filename hashes. fileCache = new Dictionary <int, FileMetadata>(fileMetadatas.Length); reader.BaseStream.Position = header.HashOffset + 12; foreach (var metadata in fileMetadatas) { // Add the file metadata to the hash table var hash = reader.ReadInt64(); fileCache.Add(hash.GetHashCode(), metadata); } }
public IEnumerable<BsaFolder> Read() { using (var reader = _mmf.ToReader(0, BsaHeader.Size)) Header = new BsaHeader(reader); if (Header.Version != Bsa.FalloutVersion) throw new NotImplementedException("Unsupported BSA version"); Settings.BStringPrefixed = Header.ArchiveFlags.HasFlag(ArchiveFlags.BStringPrefixed); Settings.DefaultCompressed = Header.ArchiveFlags.HasFlag(ArchiveFlags.Compressed); long offset = BsaHeader.Size; var folderDict = ReadFolders(ref offset, Header.FolderCount); var fileNames = ReadFileNameBlocks(offset, Header.FileCount); return BuildBsaLayout(folderDict, fileNames); }
public IEnumerable <BsaFolder> Read() { using (var reader = _mmf.ToReader(0, BsaHeader.Size)) Header = new BsaHeader(reader); if (Header.Version != Bsa.FalloutVersion) { throw new NotImplementedException("Unsupported BSA version"); } Settings.BStringPrefixed = Header.ArchiveFlags.HasFlag(ArchiveFlags.BStringPrefixed); Settings.DefaultCompressed = Header.ArchiveFlags.HasFlag(ArchiveFlags.Compressed); long offset = BsaHeader.Size; var folderDict = ReadFolders(ref offset, Header.FolderCount); var fileNames = ReadFileNameBlocks(offset, Header.FileCount); return(BuildBsaLayout(folderDict, fileNames)); }
private void SaveTo(Stream stream, bool recreate) { var allFiles = this.SelectMany(fold => fold).ToList(); var allFileNames = allFiles.Select(file => file.Name).ToList(); _folderRecordOffsetsA = new Dictionary <BsaFolder, uint>(Count); _folderRecordOffsetsB = new Dictionary <BsaFolder, uint>(Count); _fileRecordOffsetsA = new Dictionary <BsaFile, uint>(allFiles.Count); _fileRecordOffsetsB = new Dictionary <BsaFile, uint>(allFiles.Count); var header = new BsaHeader(); if (!recreate && _bsaReader != null) { header = _bsaReader.Header; } if (header.Equals(default(BsaHeader))) { //this needs to be set, otherwise we won't write archive information recreate = true; } header.Field = BsaGreet; header.Version = FalloutVersion; header.Offset = BsaHeader.Size; if (recreate) { header.ArchiveFlags = ArchiveFlags.NamedDirectories | ArchiveFlags.NamedFiles; if (Settings.DefaultCompressed) { header.ArchiveFlags |= ArchiveFlags.Compressed; } if (Settings.BStringPrefixed) { header.ArchiveFlags |= ArchiveFlags.BStringPrefixed; } } header.FolderCount = (uint)Count; header.FileCount = (uint)allFileNames.Count; header.TotalFolderNameLength = (uint)this.Sum(folder => folder.Path.Length + 1); header.TotalFileNameLength = (uint)allFileNames.Sum(file => file.Length + 1); if (recreate) { header.FileFlags = CreateFileFlags(allFileNames); } using (var writer = new BinaryWriter(stream)) { header.Write(writer); foreach (var folder in this) { WriteFolderRecord(writer, folder); } #if PARALLEL //parallel pump the files, as checking RecordSize may //trigger a decompress/recompress, depending on settings allFiles.AsParallel().ForAll(file => file.Cache()); #endif foreach (var folder in this) { WriteFileRecordBlock(writer, folder, header.TotalFileNameLength); } allFileNames.ForEach(writer.WriteCString); allFiles.ForEach(file => WriteFileBlock(writer, file)); var folderRecordOffsets = _folderRecordOffsetsA.Zip(_folderRecordOffsetsB, (kvpA, kvpB) => new KeyValuePair <uint, uint>(kvpA.Value, kvpB.Value)); var fileRecordOffsets = _fileRecordOffsetsA.Zip(_fileRecordOffsetsB, (kvpA, kvpB) => new KeyValuePair <uint, uint>(kvpA.Value, kvpB.Value)); var completeOffsets = folderRecordOffsets.Concat(fileRecordOffsets).ToList(); completeOffsets.ForEach(kvp => { writer.BaseStream.Seek(kvp.Key, SeekOrigin.Begin); writer.Write(kvp.Value); }); } }