Skip to content

Commit 4311005

Browse files
Support archive format version 9 chunk alignment padding (#128)
A change in Unity 6.7 bumps the Unity Archive format to version 9 and introduces padding - each chunk-based (non-streamed) storage block is followed by zero padding up to the next 16-byte boundary of the data section, so that a size change in one chunk no longer shifts the position of every chunk after it (this aids binary patching). each StorageBlock now serializes a UInt64 offset giving where its stored bytes start, relative to the start of the data section. The writer is then free to change its padding policy without another format bump, and the reader no longer needs the "streamed blocks are not padded, chunk blocks are" special case. Parse that offset as the fourth field of each block record, after Flags, when the signature is UnityFS and the version is 9 or later. Version 8 and earlier store their blocks contiguously, so their offsets are still accumulated from the compressed sizes. A v9 archive whose blocks are out of order or overlapping is rejected, matching the native reader.
1 parent 110d036 commit 4311005

24 files changed

Lines changed: 529 additions & 35 deletions

‎Archive/ArchiveTool.cs‎

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,16 @@ public static int PrintSummary(FileInfo filename, OutputFormat format)
163163
uncompressedDataSize += block.UncompressedSize;
164164
}
165165

166+
// The data section can be larger than the sum of the blocks, because the writer may leave
167+
// padding between them. Only version 9 and later record where each block starts, so this is
168+
// the only version where padding is detectable (and where it is currently written).
169+
long paddingSize = 0;
170+
if (blocks.Length > 0)
171+
{
172+
var lastBlock = blocks[blocks.Length - 1];
173+
paddingSize = lastBlock.Offset + lastBlock.CompressedSize - dataSize;
174+
}
175+
166176
// Determine the compression algorithm by finding the first block that uses compression.
167177
// Individual blocks may be stored uncompressed even when compression is enabled, because
168178
// compression is skipped when it provides no size reduction. So the first compressed block
@@ -193,6 +203,7 @@ public static int PrintSummary(FileInfo filename, OutputFormat format)
193203
unityVersion = header.UnityVersion,
194204
fileSize = header.Size,
195205
dataSize = dataSize,
206+
blockPaddingSize = paddingSize,
196207
uncompressedDataSize = uncompressedDataSize,
197208
compressionRatio = Math.Round(compressionRatio, 2),
198209
compression = compression,
@@ -208,6 +219,8 @@ public static int PrintSummary(FileInfo filename, OutputFormat format)
208219
Console.WriteLine($"{"Unity Version",-30} {header.UnityVersion}");
209220
Console.WriteLine($"{"File Size",-30} {header.Size:N0} bytes");
210221
Console.WriteLine($"{"Data Size",-30} {dataSize:N0} bytes");
222+
if (paddingSize > 0)
223+
Console.WriteLine($"{"Block Padding Size",-30} {paddingSize:N0} bytes");
211224
Console.WriteLine($"{"Uncompressed Data Size",-30} {uncompressedDataSize:N0} bytes");
212225
Console.WriteLine($"{"Compression Ratio",-30} {compressionRatio:F2}x");
213226
Console.WriteLine($"{"Compression",-30} {compression}");
@@ -263,10 +276,10 @@ static string FormatCompressionType(int compressionType)
263276

264277
static readonly (uint bit, string name)[] KnownArchiveFlags =
265278
{
266-
(0x40, "BlocksAndDirectoryInfoCombined"),
267-
(0x80, "BlocksInfoAtTheEnd"),
268-
(0x100, "OldWebPluginCompatibility"),
269-
(0x200, "BlockInfoNeedPaddingAtStart"),
279+
(ArchiveFlags.BlocksAndDirectoryInfoCombined, "BlocksAndDirectoryInfoCombined"),
280+
(ArchiveFlags.BlocksInfoAtTheEnd, "BlocksInfoAtTheEnd"),
281+
(ArchiveFlags.OldWebPluginCompatibility, "OldWebPluginCompatibility"),
282+
(ArchiveFlags.BlockInfoNeedPaddingAtStart, "BlockInfoNeedPaddingAtStart"),
270283
};
271284

272285
static string[] GetArchiveFlagNames(uint flagBits)

‎TestCommon/Data/LeadingEdgeBuilds/AGENTS.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ The LeadingEdge build scripts regenerate this folder directly, so to update it,
66

77
## Layout
88

9-
* `AssetBundles/` - the AssetBundle build: one bundle per asset (named after the asset) plus the `AssetBundles` manifest bundle.
9+
* `AssetBundles/` - the AssetBundle build: one bundle per asset (named after the asset) plus the `AssetBundles` manifest bundle. LZMA compressed, so each archive has a single data block.
10+
* `AssetBundlesLz4/` - the same bundle layout built with chunk-based (LZ4) compression, giving archives with multiple data blocks. The writer leaves padding between the blocks, so these exercise the `StorageBlock.Offset` field added in archive format version 9.
1011
* `ContentDirectory/` - the Content Directory build: content (`.cf`) files, `.resource` files and the build manifest.
1112
* `BuildReport-AssetBundles/LastBuild.buildreport` - the AssetBundle build report.
1213
* `BuildReport-ContentDirectory/` - the Content Directory build report folder, including `ContentLayout.json`.
31.7 KB
Binary file not shown.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
ManifestFileVersion: 0
2+
UnityVersion: 6000.7.0b2
3+
CRC: 1943531319
4+
Hashes:
5+
AssetFileHash:
6+
serializedVersion: 2
7+
Hash: 5e3dcfafd0199141af65300e6ff5a8fb
8+
TypeTreeHash:
9+
serializedVersion: 2
10+
Hash: 9a2ca7bdbd1871f7131daf57de908e0c
11+
IncrementalBuildHash:
12+
serializedVersion: 2
13+
Hash: 929d8f9d46e767e1fc66294cd024c1fa
14+
HashAppended: 0
15+
ClassTypes:
16+
- Class: 83
17+
Script: {instanceID: 0}
18+
SerializeReferenceClassIdentifiers: []
19+
Assets:
20+
- Assets/Audio/6.mp3
21+
Dependencies: []
Binary file not shown.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
ManifestFileVersion: 0
2+
UnityVersion: 6000.7.0b2
3+
CRC: 3869125346
4+
HashAppended: 0
5+
AssetBundleManifest:
6+
AssetBundleInfos:
7+
Info_0:
8+
Name: assetbundleroot
9+
Dependencies:
10+
Dependency_0: directaudioclipreference
11+
Dependency_1: singleaudioclipdirectreference
12+
Dependency_2: serializationdemo
13+
Info_1:
14+
Name: directaudioclipreference
15+
Dependencies:
16+
Dependency_0: 6
17+
Dependency_1: a
18+
Info_2:
19+
Name: singleaudioclipdirectreference
20+
Dependencies:
21+
Dependency_0: a
22+
Info_3:
23+
Name: serializationdemo
24+
Dependencies: {}
25+
Info_4:
26+
Name: 6
27+
Dependencies: {}
28+
Info_5:
29+
Name: a
30+
Dependencies: {}
31+
Info_6:
32+
Name: scenes
33+
Dependencies: {}
48 KB
Binary file not shown.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
ManifestFileVersion: 0
2+
UnityVersion: 6000.7.0b2
3+
CRC: 1309966254
4+
Hashes:
5+
AssetFileHash:
6+
serializedVersion: 2
7+
Hash: 515b741faeaecc91b64c7a8b6504b338
8+
TypeTreeHash:
9+
serializedVersion: 2
10+
Hash: 9a2ca7bdbd1871f7131daf57de908e0c
11+
IncrementalBuildHash:
12+
serializedVersion: 2
13+
Hash: aeb2216eeb5ccfe1cb3f81e62f704746
14+
HashAppended: 0
15+
ClassTypes:
16+
- Class: 83
17+
Script: {instanceID: 0}
18+
SerializeReferenceClassIdentifiers: []
19+
Assets:
20+
- Assets/Audio/a.mp3
21+
Dependencies: []
Binary file not shown.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
ManifestFileVersion: 0
2+
UnityVersion: 6000.7.0b2
3+
CRC: 1322119296
4+
Hashes:
5+
AssetFileHash:
6+
serializedVersion: 2
7+
Hash: c174946e4bcb463b2dd90535ff0dcfe5
8+
TypeTreeHash:
9+
serializedVersion: 2
10+
Hash: 819240184df2798191fd853444ad58c4
11+
IncrementalBuildHash:
12+
serializedVersion: 2
13+
Hash: cf13ad57198a935f56c518df40c037d0
14+
HashAppended: 0
15+
ClassTypes:
16+
- Class: 114
17+
Script: {fileID: 11500000, guid: d6330d3e9b8e5a0439e4dd147cec19dd, type: 3}
18+
- Class: 114
19+
Script: {fileID: 11500000, guid: 8623c5efbb626994da80931050f0aba0, type: 3}
20+
- Class: 114
21+
Script: {fileID: 11500000, guid: f44aeb02ae06dd84bb3ef76e1df8d525, type: 3}
22+
- Class: 115
23+
Script: {instanceID: 0}
24+
SerializeReferenceClassIdentifiers:
25+
- AssemblyName: Assembly-CSharp
26+
ClassName: SerializationDemo/SerializedData
27+
- AssemblyName: UnityEngine.CoreModule
28+
ClassName: UnityEngine.DictionarySerialization/SerializedKeyValue`2
29+
Assets:
30+
- Assets/ScriptableObjects/AssetBundleRoot.asset
31+
Dependencies:
32+
- C:/UnitySrc/UnityDataTools_Cursor/UnityProjects/LeadingEdge/../../TestCommon/Data/LeadingEdgeBuilds/AssetBundlesLz4/directaudioclipreference
33+
- C:/UnitySrc/UnityDataTools_Cursor/UnityProjects/LeadingEdge/../../TestCommon/Data/LeadingEdgeBuilds/AssetBundlesLz4/serializationdemo
34+
- C:/UnitySrc/UnityDataTools_Cursor/UnityProjects/LeadingEdge/../../TestCommon/Data/LeadingEdgeBuilds/AssetBundlesLz4/singleaudioclipdirectreference

0 commit comments

Comments
 (0)