예제 #1
0
    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);
        }
    }
예제 #2
0
        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);
        }
예제 #3
0
        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));
        }
예제 #4
0
        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);
                });
            }
        }