| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- using LZ4;
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using UnityEngine;
- namespace UnityFS
- {
- public class BundleFileWriter
- {
- private readonly BundleFileInfo _bundle;
- private readonly List<Node> _files = new List<Node>();
- private readonly List<StorageBlock> _blocks = new List<StorageBlock>();
- private readonly EndianBinaryWriter _blockDirectoryMetadataStream = new EndianBinaryWriter(new MemoryStream());
- private byte[] _blockBytes;
- public BundleFileWriter(BundleFileInfo bundle)
- {
- _bundle = bundle;
- }
- public void Write(EndianBinaryWriter output)
- {
- InitBlockAndDirectories();
- output.WriteNullEndString(_bundle.signature);
- output.Write(_bundle.version);
- output.WriteNullEndString(_bundle.unityVersion);
- output.WriteNullEndString(_bundle.unityRevision);
- BuildBlockDirectoryMetadata();
- long sizePos = output.Position;
- output.Write(0L);
- output.Write((uint)_blockDirectoryMetadataStream.Length);
- output.Write((uint)_blockDirectoryMetadataStream.Length);
- ArchiveFlags flags = ArchiveFlags.BlocksAndDirectoryInfoCombined | (uint)CompressionType.None;
- output.Write((uint)flags);
- if (_bundle.version >= 7)
- {
- output.AlignStream(16);
- }
- byte[] metadataBytes = _blockDirectoryMetadataStream.BaseStream.ReadAllBytes();
- output.Write(metadataBytes, 0, metadataBytes.Length);
- byte[] dataBytes = _blockBytes;
- output.Write(dataBytes, 0, dataBytes.Length);
- output.Position = sizePos;
- output.Write(output.Length);
- }
- private void InitBlockAndDirectories()
- {
- var dataStream = new MemoryStream();
- foreach(var file in _bundle.files)
- {
- byte[] data = file.data;
- _files.Add(new Node { path = file.file, flags = 0, offset = dataStream.Length, size = data.LongLength });
- dataStream.Write(data, 0, data.Length);
- }
- byte[] dataBytes = dataStream.ToArray();
- var compressedBlockStream = new MemoryStream(dataBytes.Length / 2);
- int blockByteSize = 128 * 1024;
- long dataSize = dataBytes.Length;
- byte[] tempCompressBlock = new byte[blockByteSize * 2];
- for(long i = 0, blockNum = (dataSize + blockByteSize - 1) / blockByteSize; i < blockNum; i++)
- {
- long curBlockSize = Math.Min(dataSize, blockByteSize);
- dataSize -= curBlockSize;
- int compressedSize = LZ4Codec.Encode(dataBytes, (int)(i * blockByteSize), (int)curBlockSize, tempCompressBlock, 0, tempCompressBlock.Length);
- compressedBlockStream.Write(tempCompressBlock, 0, compressedSize);
- _blocks.Add(new StorageBlock { flags = (StorageBlockFlags)(int)CompressionType.Lz4, compressedSize = (uint)compressedSize, uncompressedSize = (uint)curBlockSize });
- //Debug.Log($"== block[{i}] uncompressedSize:{curBlockSize} compressedSize:{compressedSize} totalblocksize:{compressedBlockStream.Length}");
- }
- _blockBytes = compressedBlockStream.ToArray();
- }
- private void BuildBlockDirectoryMetadata()
- {
- var hash = new byte[16];
- _blockDirectoryMetadataStream.Write(hash, 0, 16);
- _blockDirectoryMetadataStream.Write((uint)_blocks.Count);
- foreach(var b in _blocks)
- {
- _blockDirectoryMetadataStream.Write(b.uncompressedSize);
- _blockDirectoryMetadataStream.Write(b.compressedSize);
- _blockDirectoryMetadataStream.Write((ushort)b.flags);
- }
- _blockDirectoryMetadataStream.Write((uint)_files.Count);
- foreach(var f in _files)
- {
- _blockDirectoryMetadataStream.Write(f.offset);
- _blockDirectoryMetadataStream.Write(f.size);
- _blockDirectoryMetadataStream.Write(f.flags);
- _blockDirectoryMetadataStream.WriteNullEndString(f.path);
- }
- //Debug.Log($"block and directory metadata size:{_blockDirectoryMetadataStream.Length}");
- }
- }
- }
|