Skip to content

Commit bf5ce45

Browse files
committed
write bundle to temp file or blocks at end of file
1 parent b4b3629 commit bf5ce45

1 file changed

Lines changed: 120 additions & 77 deletions

File tree

AssetTools.NET/Standard/AssetsBundleFileFormat/AssetsBundleFile.cs

Lines changed: 120 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ public bool Unpack(AssetsFileReader reader, AssetsFileWriter writer)
380380
}
381381
return false;
382382
}
383-
public bool Pack(AssetsFileReader reader, AssetsFileWriter writer, AssetBundleCompressionType compType)
383+
public bool Pack(AssetsFileReader reader, AssetsFileWriter writer, AssetBundleCompressionType compType, bool blockDirAtEnd = true)
384384
{
385385
reader.Position = 0;
386386
writer.Position = 0;
@@ -395,7 +395,7 @@ public bool Pack(AssetsFileReader reader, AssetsFileWriter writer, AssetBundleCo
395395
totalFileSize = 0,
396396
compressedSize = 0,
397397
decompressedSize = 0,
398-
flags = 0x43
398+
flags = (uint)(0x43 | (blockDirAtEnd ? 0x80 : 0x00))
399399
};
400400

401401
AssetBundleBlockAndDirectoryList06 newBlockAndDirList = new AssetBundleBlockAndDirectoryList06()
@@ -408,128 +408,164 @@ public bool Pack(AssetsFileReader reader, AssetsFileWriter writer, AssetBundleCo
408408
dirInf = bundleInf6.dirInf
409409
};
410410

411+
//write header now and overwrite it later
412+
long startPos = writer.Position;
413+
414+
newHeader.Write(writer);
415+
if (newHeader.fileVersion >= 7)
416+
writer.Align16();
417+
418+
int headerSize = (int)(writer.Position - startPos);
419+
420+
long totalCompressedSize = 0;
411421
List<AssetBundleBlockInfo06> newBlocks = new List<AssetBundleBlockInfo06>();
422+
List<Stream> newStreams = new List<Stream>(); //used if blockDirAtEnd == false
412423

413-
reader.Position = bundleHeader6.GetFileDataOffset();
414-
int fileDataLength = (int)(bundleHeader6.totalFileSize - reader.Position);
415-
byte[] fileData = reader.ReadBytes(fileDataLength);
424+
long fileDataOffset = bundleHeader6.GetFileDataOffset();
425+
int fileDataLength = (int)(bundleHeader6.totalFileSize - fileDataOffset);
426+
427+
SegmentStream bundleDataStream = new SegmentStream(reader.BaseStream, fileDataOffset, fileDataLength);
416428

417-
//todo, we just write everything to memory and then write to file
418-
//we could calculate the blocks we need ahead of time and correctly
419-
//size the block listing before this so we can write directly to file
420-
byte[] compressedFileData;
421429
switch (compType)
422430
{
423431
case AssetBundleCompressionType.LZMA:
424432
{
425-
compressedFileData = SevenZipHelper.Compress(fileData);
426-
newBlocks.Add(new AssetBundleBlockInfo06()
433+
Stream writeStream;
434+
if (blockDirAtEnd)
435+
writeStream = writer.BaseStream;
436+
else
437+
writeStream = GetTempFileStream();
438+
439+
long writeStreamStart = writeStream.Position;
440+
SevenZipHelper.Compress(bundleDataStream, writeStream);
441+
uint writeStreamLength = (uint)(writeStream.Position - writeStreamStart);
442+
443+
AssetBundleBlockInfo06 blockInfo = new AssetBundleBlockInfo06()
427444
{
428-
compressedSize = (uint)compressedFileData.Length,
429-
decompressedSize = (uint)fileData.Length,
445+
compressedSize = writeStreamLength,
446+
decompressedSize = (uint)fileDataLength,
430447
flags = 0x41
431-
});
448+
};
449+
450+
totalCompressedSize += blockInfo.compressedSize;
451+
newBlocks.Add(blockInfo);
452+
453+
if (blockDirAtEnd)
454+
bundleDataStream.CopyToCompat(writer.BaseStream);
455+
else
456+
newStreams.Add(writeStream);
457+
432458
break;
433459
}
434460
case AssetBundleCompressionType.LZ4:
435461
{
436-
using (var memStreamCom = new MemoryStream())
437-
using (var binaryWriter = new BinaryWriter(memStreamCom))
462+
//compress into 0x20000 blocks
463+
BinaryReader bundleDataReader = new BinaryReader(bundleDataStream);
464+
byte[] uncompressedBlock = bundleDataReader.ReadBytes(0x20000);
465+
while (uncompressedBlock.Length != 0)
438466
{
439-
using (var memStreamUnc = new MemoryStream(fileData))
440-
using (var binaryReader = new BinaryReader(memStreamUnc))
467+
Stream writeStream;
468+
if (blockDirAtEnd)
469+
writeStream = writer.BaseStream;
470+
else
471+
writeStream = GetTempFileStream();
472+
473+
byte[] compressedBlock = LZ4Codec.Encode32HC(uncompressedBlock, 0, uncompressedBlock.Length);
474+
writeStream.Write(compressedBlock, 0, compressedBlock.Length);
475+
476+
if (compressedBlock.Length > uncompressedBlock.Length)
441477
{
442-
//compress into 0x20000 blocks
443-
byte[] uncompressedBlock = binaryReader.ReadBytes(131072);
444-
while (uncompressedBlock.Length != 0)
478+
AssetBundleBlockInfo06 blockInfo = new AssetBundleBlockInfo06()
445479
{
446-
byte[] compressedBlock = LZ4Codec.Encode32HC(uncompressedBlock, 0, uncompressedBlock.Length);
447-
448-
if (compressedBlock.Length > uncompressedBlock.Length)
449-
{
450-
newBlocks.Add(new AssetBundleBlockInfo06()
451-
{
452-
compressedSize = (uint)uncompressedBlock.Length,
453-
decompressedSize = (uint)uncompressedBlock.Length,
454-
flags = 0x0
455-
});
456-
binaryWriter.Write(uncompressedBlock);
457-
}
458-
else
459-
{
460-
newBlocks.Add(new AssetBundleBlockInfo06()
461-
{
462-
compressedSize = (uint)compressedBlock.Length,
463-
decompressedSize = (uint)uncompressedBlock.Length,
464-
flags = 0x3
465-
});
466-
binaryWriter.Write(compressedBlock);
467-
}
468-
469-
uncompressedBlock = binaryReader.ReadBytes(131072);
470-
}
480+
compressedSize = (uint)uncompressedBlock.Length,
481+
decompressedSize = (uint)uncompressedBlock.Length,
482+
flags = 0x0
483+
};
484+
485+
totalCompressedSize += blockInfo.compressedSize;
486+
487+
newBlocks.Add(blockInfo);
471488
}
489+
else
490+
{
491+
AssetBundleBlockInfo06 blockInfo = new AssetBundleBlockInfo06()
492+
{
493+
compressedSize = (uint)compressedBlock.Length,
494+
decompressedSize = (uint)uncompressedBlock.Length,
495+
flags = 0x3
496+
};
497+
498+
totalCompressedSize += blockInfo.compressedSize;
499+
500+
newBlocks.Add(blockInfo);
501+
}
502+
503+
if (blockDirAtEnd)
504+
bundleDataStream.CopyToCompat(writer.BaseStream);
505+
else
506+
newStreams.Add(writeStream);
472507

473-
compressedFileData = memStreamCom.ToArray();
508+
uncompressedBlock = bundleDataReader.ReadBytes(0x20000);
474509
}
475510
break;
476511
}
477512
case AssetBundleCompressionType.NONE:
478513
{
479-
compressedFileData = fileData;
480-
newBlocks.Add(new AssetBundleBlockInfo06()
514+
AssetBundleBlockInfo06 blockInfo = new AssetBundleBlockInfo06()
481515
{
482-
compressedSize = (uint)fileData.Length,
483-
decompressedSize = (uint)fileData.Length,
516+
compressedSize = (uint)fileDataLength,
517+
decompressedSize = (uint)fileDataLength,
484518
flags = 0x00
485-
});
519+
};
520+
521+
totalCompressedSize += blockInfo.compressedSize;
522+
523+
newBlocks.Add(blockInfo);
524+
525+
if (blockDirAtEnd)
526+
bundleDataStream.CopyToCompat(writer.BaseStream);
527+
else
528+
newStreams.Add(bundleDataStream);
529+
486530
break;
487531
}
488-
default:
489-
{
490-
return false;
491-
}
492532
}
493533

494534
newBlockAndDirList.blockInf = newBlocks.ToArray();
495535

496536
byte[] bundleInfoBytes;
497-
using (var memStream = new MemoryStream())
537+
using (MemoryStream memStream = new MemoryStream())
498538
{
499-
var afw = new AssetsFileWriter(memStream);
500-
newBlockAndDirList.Write(afw);
539+
AssetsFileWriter infoWriter = new AssetsFileWriter(memStream);
540+
newBlockAndDirList.Write(infoWriter);
501541
bundleInfoBytes = memStream.ToArray();
502542
}
503543

504-
if (bundleInfoBytes == null || bundleInfoBytes.Length == 0)
505-
return false;
506-
507544
//listing is usually lz4 even if the data blocks are lzma
508545
byte[] bundleInfoBytesCom = LZ4Codec.Encode32HC(bundleInfoBytes, 0, bundleInfoBytes.Length);
509546

510-
byte[] bundleHeaderBytes = null;
511-
using (var memStream = new MemoryStream())
512-
{
513-
var afw = new AssetsFileWriter(memStream);
514-
newHeader.Write(afw);
515-
bundleHeaderBytes = memStream.ToArray();
516-
}
517-
518-
if (bundleHeaderBytes == null || bundleHeaderBytes.Length == 0)
519-
return false;
520-
521-
uint totalFileSize = (uint)(bundleHeaderBytes.Length + bundleInfoBytesCom.Length + compressedFileData.Length);
547+
uint totalFileSize = (uint)(headerSize + bundleInfoBytesCom.Length + totalCompressedSize);
522548
newHeader.totalFileSize = totalFileSize;
523549
newHeader.decompressedSize = (uint)bundleInfoBytes.Length;
524550
newHeader.compressedSize = (uint)bundleInfoBytesCom.Length;
525551

552+
writer.Write(bundleInfoBytesCom);
553+
554+
if (!blockDirAtEnd)
555+
{
556+
foreach (Stream newStream in newStreams)
557+
{
558+
newStream.Position = 0;
559+
newStream.CopyToCompat(writer.BaseStream);
560+
newStream.Close();
561+
}
562+
}
563+
564+
writer.Position = 0;
526565
newHeader.Write(writer);
527566
if (newHeader.fileVersion >= 7)
528567
writer.Align16();
529568

530-
writer.Write(bundleInfoBytesCom);
531-
writer.Write(compressedFileData);
532-
533569
return true;
534570
}
535571
return false;
@@ -614,6 +650,13 @@ internal void GetFileRange(int index, out long offset, out long length)
614650
throw new NotSupportedException();
615651
}
616652
}
653+
654+
private FileStream GetTempFileStream()
655+
{
656+
string tempFilePath = Path.GetTempFileName();
657+
FileStream tempFileStream = new FileStream(tempFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.DeleteOnClose);
658+
return tempFileStream;
659+
}
617660
}
618661

619662
public enum AssetBundleCompressionType

0 commit comments

Comments
 (0)