internal virtual void Load(ArchiveBinaryReader reader) { var nodeCount = reader.ReadInt32(); var typeTableBufferSize = reader.ReadInt32(); var nodeBuffer = reader.ReadBytes(24 * nodeCount); byte[] stringTable = reader.ReadBytes(typeTableBufferSize); using (var nodeReader = new ArchiveBinaryReader(new MemoryStream(nodeBuffer))) { var stack = new Stack <TypeNode>(); stack.Push(this); this.Version = nodeReader.ReadUInt16(); this.Depth = nodeReader.ReadByte(); this.IsArray = nodeReader.ReadBoolean(); ushort position = nodeReader.ReadUInt16(); ushort flag = nodeReader.ReadUInt16(); this.TypeName = flag == 0 ? stringTable.GetString(position) : baseStringTable.GetString(position); position = nodeReader.ReadUInt16(); flag = nodeReader.ReadUInt16(); this.FieldName = flag == 0 ? stringTable.GetString(position) : baseStringTable.GetString(position); this.Size = nodeReader.ReadInt32(); this.Index = nodeReader.ReadInt32(); this.Flags = nodeReader.ReadInt32(); for (var i = 1; i < nodeCount; i++) { var current = new TypeNode(this); current.Version = nodeReader.ReadUInt16(); current.Depth = nodeReader.ReadByte(); current.IsArray = nodeReader.ReadBoolean(); position = nodeReader.ReadUInt16(); flag = nodeReader.ReadUInt16(); current.TypeName = flag == 0 ? stringTable.GetString(position) : baseStringTable.GetString(position); position = nodeReader.ReadUInt16(); flag = nodeReader.ReadUInt16(); current.FieldName = flag == 0 ? stringTable.GetString(position) : baseStringTable.GetString(position); current.Size = nodeReader.ReadInt32(); current.Index = nodeReader.ReadInt32(); current.Flags = nodeReader.ReadInt32(); while (stack.Count > current.Depth) { stack.Pop(); } stack.Peek().Children.Add(current); stack.Push(current); } } }
protected virtual void ReadArrayNode(TypeNode typeNode, int size, ArchiveBinaryReader reader, ObjectArchive archive, Stream output, FeatureInfo data) { if (size <= 0) { return; } Stream src = reader.BaseStream; switch (typeNode.TypeFlag) { case "bool": case "SInt8": case "char": case "UInt8": case "short": case "SInt16": case "unsigned short": case "UInt16": case "int": case "SInt32": case "unsigned int": case "UInt32": case "Type*": case "long long": case "SInt64": case "unsigned long long": case "UInt64": case "float": case "double": case "Quaternionf": case "float4": case "Vector4f": case "float3": case "Vector3f": case "float2": case "Vector2f": case "ColorRGBA": case "Matrix4x4f": case "Hash128": { this.CopyTo(src, output, typeNode.Size * size); break; } default: { for (int i = 0; i < size; i++) { this.ReadNode(typeNode, reader, archive, output, data); } break; } } }
public ObjectArchive(AssetBundleArchive bundle, string name, long fileStreamOffset, long fileStreamSize, ArchiveType type) : base(bundle, name, fileStreamOffset, fileStreamSize, type) { this.archiveRefs.Add(new ArchiveRef(0, this.Name, 0, new Hash128(new byte[16]), this.Name)); this.extractor = new FeatureExtractor(); using (Stream stream = this.GetDataStream()) { using (ArchiveBinaryReader reader = new ArchiveBinaryReader(stream)) { this.Load(reader); } } }
public FeatureInfo Extract(ObjectInfo info, ArchiveBinaryReader reader) { FeatureInfo data = new FeatureInfo(); using (MemoryStream output = new MemoryStream()) { this.ReadNode(info.TypeTree, reader, info.Archive, output, data); output.Seek(0, SeekOrigin.Begin); var hash = ArchiveUtil.Hash(output); data.PropertyHash = hash; } return(data); }
public virtual object Create(ObjectInfo info) { if (info == null) { return(null); } lock (info) { using (var reader = new ArchiveBinaryReader(new MemoryStream(info.Data))) { var typeTree = info.TypeTree; var value = Parse(typeTree, reader); if (value is UnityDynamicObject) { UnityDynamicObject uo = value as UnityDynamicObject; uo.ID = info.ID; uo.Size = info.Size; uo.ObjectInfo = info; } return(value); } } }
public static AssetBundleArchive Load(Stream stream) { using (var reader = new ArchiveBinaryReader(stream)) { var signature = reader.ReadCString(); var formatVersion = reader.ReadInt32(true); var mainVersion = reader.ReadCString(); var buildVersion = reader.ReadCString(); if (signature != SIGNATURE_FS && signature != SIGNATURE_WEB) { throw new NotSupportedException("Not supported signature : " + signature); } if (formatVersion != 6) { throw new NotSupportedException("Not supported format version : " + formatVersion); } AssetBundleArchive bundle = new AssetBundleArchive(formatVersion, mainVersion, buildVersion); bundle.FileSize = reader.ReadInt64(true); var compressedBlockSize = reader.ReadInt32(true); var uncompressedBlockSize = reader.ReadInt32(true); var flags = reader.ReadInt32(true); var compressionType = (CompressionType)(flags & 0x3f); byte[] buffer = null; if ((flags & 0x80) > 0) { var currentPos = reader.BaseStream.Position; reader.BaseStream.Seek(-compressedBlockSize, SeekOrigin.End); buffer = reader.ReadBytes(compressedBlockSize); reader.BaseStream.Seek(currentPos, SeekOrigin.Begin); } else { buffer = reader.ReadBytes(compressedBlockSize); } switch (compressionType) { case CompressionType.NONE: break; case CompressionType.LZ4: case CompressionType.LZ4HC: buffer = LZ4.LZ4Codec.Decode(buffer, 0, compressedBlockSize, uncompressedBlockSize); break; default: throw new NotSupportedException("Not supported compression type : " + compressionType); } List <BlockInfo> blocks = new List <BlockInfo>(); List <AssetInfo> assets = new List <AssetInfo>(); using (var metaReader = new ArchiveBinaryReader(new MemoryStream(buffer))) { bundle.GUID = metaReader.ReadHash128(); int blockCount = metaReader.ReadInt32(true); for (int i = 0; i < blockCount; i++) { BlockInfo block; block.uncompressedSize = metaReader.ReadUInt32(true); block.compressedSize = metaReader.ReadUInt32(true); block.flag = metaReader.ReadInt16(true); blocks.Add(block); } var assetCount = metaReader.ReadInt32(true); for (int i = 0; i < assetCount; i++) { AssetInfo asset; asset.offset = metaReader.ReadInt64(true); asset.size = metaReader.ReadInt64(true); asset.flag = metaReader.ReadInt32(true); var name = metaReader.ReadCString(); name = string.IsNullOrEmpty(name) ? "" : name.ToLower(); asset.name = name; assets.Add(asset); } } var totalDataSize = blocks.Sum(b => b.uncompressedSize); var dataFilename = string.Format("{0}/{1}", ArchiveUtil.GetTemporaryCachePath(), Guid.NewGuid().ToString()); FileInfo file = new FileInfo(dataFilename); if (!file.Directory.Exists) { file.Directory.Create(); } bundle.dataFilename = file.FullName; using (Stream dataStream = new FileStream(file.FullName, FileMode.Create, FileAccess.ReadWrite, FileShare.Read, 8192)) { foreach (var block in blocks) { switch (block.CompressionType) { case CompressionType.NONE: { buffer = reader.ReadBytes((int)block.compressedSize); dataStream.Write(buffer, 0, buffer.Length); break; } case CompressionType.LZMA: { var properties = reader.ReadBytes(5); var decoder = new SevenZip.Compression.LZMA.Decoder(); decoder.SetDecoderProperties(properties); decoder.Code(reader.BaseStream, dataStream, block.compressedSize - 5, block.uncompressedSize, null); break; } case CompressionType.LZ4: case CompressionType.LZ4HC: { buffer = reader.ReadBytes((int)block.compressedSize); var data = LZ4.LZ4Codec.Decode(buffer, 0, (int)block.compressedSize, (int)block.uncompressedSize); dataStream.Write(data, 0, data.Length); break; } default: throw new NotSupportedException("Not supported compression type : " + block.CompressionType); } } } foreach (var assetInfo in assets) { switch (assetInfo.flag) { case 4: { ObjectArchive asset = new ObjectArchive(bundle, assetInfo.name, assetInfo.offset, assetInfo.size, assetInfo.Type); bundle.AddAssetArchive(asset); break; } default: { ResourceArchive asset = new ResourceArchive(bundle, assetInfo.name, assetInfo.offset, assetInfo.size, assetInfo.Type); bundle.AddAssetArchive(asset); break; } } //switch (assetInfo.Type) //{ // case ArchiveType.CAB: // case ArchiveType.BUILD_PLAYER: // case ArchiveType.SHARED_DATA: // { // ObjectArchive asset = new ObjectArchive(bundle, assetInfo.name, assetInfo.offset, assetInfo.size, assetInfo.Type); // bundle.AddAssetArchive(asset); // break; // } // default: // { // ResourceArchive asset = new ResourceArchive(bundle, assetInfo.name, assetInfo.offset, assetInfo.size, assetInfo.Type); // bundle.AddAssetArchive(asset); // break; // } //} } return(bundle); } }
public object Parse(TypeNode typeNode, ArchiveBinaryReader reader) { object result = null; switch (typeNode.TypeFlag) { case "bool": result = reader.ReadBoolean(); break; case "SInt8": result = reader.ReadSByte(); break; case "char": case "UInt8": result = reader.ReadByte(); break; case "short": case "SInt16": result = reader.ReadInt16(); break; case "unsigned short": case "UInt16": result = reader.ReadUInt16(); break; case "int": case "SInt32": result = reader.ReadInt32(); break; case "unsigned int": case "UInt32": case "Type*": result = reader.ReadUInt32(); break; case "long long": case "SInt64": result = reader.ReadInt64(); break; case "unsigned long long": case "UInt64": result = reader.ReadUInt64(); break; case "float": result = reader.ReadSingle(); break; case "double": result = reader.ReadDouble(); break; case "Quaternionf": { result = reader.ReadQuaternion(); break; } case "float4": case "Vector4f": { result = reader.ReadVector4(); break; } case "float3": case "Vector3f": { result = reader.ReadVector3(); break; } case "float2": case "Vector2f": { result = reader.ReadVector2(); break; } case "ColorRGBA": { if (typeNode.Version == 2) { result = reader.ReadColor32(); } else { result = reader.ReadColor(); } break; } case "Matrix4x4f": { result = reader.ReadMatrix4x4(); break; } case "Hash128": { result = reader.ReadHash128(); break; } case "string": { result = reader.ReadString(); break; } case "vector": case "staticvector": case "set": { var valueTypeNode = typeNode.Children[0]; result = this.Parse(valueTypeNode, reader); break; } case "map": { var pairTypeNode = typeNode.Children[0].Children[1]; var keyTypeNode = pairTypeNode.Children[0]; var valueTypeNode = pairTypeNode.Children[1]; var size = reader.ReadInt32(); Map map = new Map(typeNode); for (int i = 0; i < size; i++) { var key = this.Parse(keyTypeNode, reader); var value = this.Parse(valueTypeNode, reader); map.Add(key, value); } result = map; break; } case "Array": { var valueTypeNode = typeNode.Children[1]; var size = reader.ReadInt32(); result = this.ParseArray(valueTypeNode, size, reader); break; } case "PPtr": { var fileID = reader.ReadInt32(); var pathID = reader.ReadInt64(); result = new PPtr(fileID, pathID, typeNode.TypeName); break; } case "TypelessData": { var size = reader.ReadInt32(); result = new TypelessData(reader.ReadBytes(size)); break; } case "StreamedResource": { var source = reader.ReadString(); var offset = reader.ReadUInt64(); var size = reader.ReadUInt64(); var streamedResource = new StreamedResource(source, offset, size); result = streamedResource; break; } case "AssetBundle": { AssetBundle bundle = new AssetBundle(((TypeTree)typeNode).Archive); bundle.FullName = reader.ReadString(); var size = reader.ReadInt32(); List <PPtr> preloadTable = new List <PPtr>(size); for (int i = 0; i < size; i++) { PPtr pptr = new PPtr(reader.ReadInt32(), reader.ReadInt64(), "PPtr<Object>"); preloadTable.Add(pptr); } bundle.Preloads.AddRange(preloadTable); size = reader.ReadInt32(); List <AssetPair> container = new List <AssetPair>(size); for (int i = 0; i < size; i++) { var first = reader.ReadString(); var preloadIndex = reader.ReadInt32(); var preloadSize = reader.ReadInt32(); var pptr = new PPtr(reader.ReadInt32(), reader.ReadInt64(), "PPtr<Object>"); var pair = new AssetPair(first, new Objects.AssetInfo(preloadIndex, preloadSize, pptr)); container.Add(pair); } bundle.Container.AddRange(container); bundle.MainAsset = new Objects.AssetInfo(reader.ReadInt32(), reader.ReadInt32(), new PPtr(reader.ReadInt32(), reader.ReadInt64(), "PPtr<Object>")); bundle.RuntimeCompatibility = reader.ReadUInt32(); bundle.Name = reader.ReadString(); size = reader.ReadInt32(); List <string> dependencies = new List <string>(size); for (int i = 0; i < size; i++) { dependencies.Add(reader.ReadString()); } bundle.Dependencies.AddRange(dependencies); bundle.IsStreamed = reader.ReadBoolean(); result = bundle; break; } case "PreloadData": { PreloadData preloadData = new PreloadData(((TypeTree)typeNode).Archive); preloadData.Name = reader.ReadString(); var size = reader.ReadInt32(); List <PPtr> preloadTable = new List <PPtr>(size); for (int i = 0; i < size; i++) { PPtr pptr = new PPtr(reader.ReadInt32(), reader.ReadInt64(), "PPtr<Object>"); preloadTable.Add(pptr); } preloadData.Preloads.AddRange(preloadTable); size = reader.ReadInt32(); List <string> dependencies = new List <string>(size); for (int i = 0; i < size; i++) { dependencies.Add(reader.ReadString()); } preloadData.Dependencies.AddRange(dependencies); result = preloadData; break; } case "AssetBundleManifest": { Objects.AssetBundleManifest obj = new Objects.AssetBundleManifest((TypeTree)typeNode); foreach (TypeNode childNode in typeNode.Children) { var key = childNode.FieldName; var childValue = this.Parse(childNode, reader); obj[key] = childValue; } result = obj; break; } default: { DynamicObject obj = typeNode is TypeTree ? new UnityDynamicObject((TypeTree)typeNode) : new DynamicObject(typeNode); foreach (TypeNode childNode in typeNode.Children) { var key = childNode.FieldName; var childValue = this.Parse(childNode, reader); obj[key] = childValue; } result = obj; break; } } if (typeNode.IsAlign) { reader.Align(4); } return(result); }
protected virtual IList ParseArray(TypeNode typeNode, int size, ArchiveBinaryReader reader) { switch (typeNode.TypeFlag) { case "bool": { bool[] result = new bool[size]; for (int i = 0; i < size; i++) { result[i] = reader.ReadBoolean(); if (typeNode.IsAlign) { reader.Align(4); } } return(result); } case "SInt8": { sbyte[] result = new sbyte[size]; for (int i = 0; i < size; i++) { result[i] = reader.ReadSByte(); } return(result); } case "char": case "UInt8": { if (size <= 0) { return(new byte[0]); } return(reader.ReadBytes(size)); } case "short": case "SInt16": { short[] result = new short[size]; for (int i = 0; i < size; i++) { result[i] = reader.ReadInt16(); } return(result); } case "unsigned short": case "UInt16": { ushort[] result = new ushort[size]; for (int i = 0; i < size; i++) { result[i] = reader.ReadUInt16(); } return(result); } case "int": case "SInt32": { int[] result = new int[size]; for (int i = 0; i < size; i++) { result[i] = reader.ReadInt32(); } return(result); } case "unsigned int": case "UInt32": case "Type*": { uint[] result = new uint[size]; for (int i = 0; i < size; i++) { result[i] = reader.ReadUInt32(); } return(result); } case "long long": case "SInt64": { long[] result = new long[size]; for (int i = 0; i < size; i++) { result[i] = reader.ReadInt64(); } return(result); } case "unsigned long long": case "UInt64": { ulong[] result = new ulong[size]; for (int i = 0; i < size; i++) { result[i] = reader.ReadUInt64(); } return(result); } case "float": { float[] result = new float[size]; for (int i = 0; i < size; i++) { result[i] = reader.ReadSingle(); } return(result); } case "double": { double[] result = new double[size]; for (int i = 0; i < size; i++) { result[i] = reader.ReadDouble(); } return(result); } case "Quaternionf": { Quaternion[] result = new Quaternion[size]; for (int i = 0; i < size; i++) { result[i] = reader.ReadQuaternion(); } return(result); } case "float4": case "Vector4f": { Vector4[] result = new Vector4[size]; for (int i = 0; i < size; i++) { result[i] = reader.ReadVector4(); } return(result); } case "float3": case "Vector3f": { Vector3[] result = new Vector3[size]; for (int i = 0; i < size; i++) { result[i] = reader.ReadVector3(); } return(result); } case "float2": case "Vector2f": { Vector2[] result = new Vector2[size]; for (int i = 0; i < size; i++) { result[i] = reader.ReadVector2(); } return(result); } case "ColorRGBA": { Color[] result = new Color[size]; for (int i = 0; i < size; i++) { result[i] = reader.ReadColor(); } return(result); } case "Matrix4x4f": { Matrix4x4[] result = new Matrix4x4[size]; for (int i = 0; i < size; i++) { result[i] = reader.ReadMatrix4x4(); } return(result); } case "Hash128": { Hash128[] result = new Hash128[size]; for (int i = 0; i < size; i++) { result[i] = reader.ReadHash128(); } return(result); } case "string": { string[] result = new string[size]; for (int i = 0; i < size; i++) { result[i] = reader.ReadString(); } return(result); } default: { object[] result = new object[size]; for (int i = 0; i < size; i++) { result[i] = this.Parse(typeNode, reader); } return(result); } } }
protected virtual void Load(ArchiveBinaryReader reader) { try { long startPos = reader.BaseStream.Position; int headerSize = reader.ReadInt32(true); var fileSize = reader.ReadInt32(true); this.Format = reader.ReadInt32(true); this.assetDataOffset = reader.ReadUInt32(true); if (this.Format < 17) { throw new NotSupportedException(string.Format("The AssetBundle's format not supported,format:{0}", this.Format)); } bool bigEndian = reader.ReadBoolean(); reader.IsBigEndian = bigEndian; reader.ReadBytes(3); this.Version = reader.ReadCString(); this.TargetPlatform = reader.ReadUInt32(); //读取类型树 var hasTypeTree = reader.ReadBoolean(); if (!hasTypeTree) { throw new NotSupportedException("Missing type tree, not supported"); } Hash128 zero = new Hash128(new byte[16]); var typeTreeCount = reader.ReadInt32(); for (var i = 0; i < typeTreeCount; i++) { var typeId = reader.ReadInt32(); reader.ReadByte(); var scriptIndex = reader.ReadInt16(); var hash = reader.ReadHash128(); var propertiesHash = typeId == 114 ? reader.ReadHash128() : zero; var tree = new TypeTree(this, i, Enum.IsDefined(typeof(TypeID), typeId) ? (TypeID)typeId : TypeID.UnknownType, scriptIndex, hash, propertiesHash); tree.Load(reader); this.trees.Add(tree); } //读取对象信息 var objectCount = reader.ReadInt32(); List <ObjectItem> objectItems = new List <ObjectItem>(); for (var i = 0; i < objectCount; i++) { reader.Align(4); var id = reader.ReadInt64(); var offset = reader.ReadInt32(); var size = reader.ReadInt32(); var index = reader.ReadInt32(); var typeTree = trees[index]; var item = new ObjectItem(id, offset, size, typeTree); objectItems.Add(item); } //自定义脚本预载表 var scriptCount = reader.ReadInt32(); for (int i = 0; i < scriptCount; i++) { var fileID = reader.ReadInt32(); var pathID = reader.ReadInt64(); var pptr = new PPtr(fileID, pathID, "PPtr<MonoScript>"); this.preloadScripts.Add(pptr); } //读取共享对象 int refCount = reader.ReadInt32(); for (int i = 1; i <= refCount; i++) { var name = reader.ReadCString(); var guid = reader.ReadHash128(); var type = reader.ReadInt32(); var fileName = reader.ReadCString(); fileName = string.IsNullOrEmpty(fileName) ? "" : fileName.ToLower(); var assetRef = new ArchiveRef(i, name, type, guid, fileName); this.archiveRefs.Add(assetRef); } foreach (var item in objectItems) { TypeID typeId = item.TypeTree.TypeID; if (typeId != TypeID.AssetBundle && typeId != TypeID.PreloadData) { continue; } ObjectInfo info = new ObjectInfo(this, item.ID, item.TypeTree, item.Offset, item.Size, false); if (info.TypeID == TypeID.AssetBundle) { AssetBundle assetBundle = info.GetObject <AssetBundle>(); this.AssetBundle = assetBundle; Bundle.AssetBundle = assetBundle; } else if (info.TypeID == TypeID.PreloadData) { PreloadData preloadData = info.GetObject <PreloadData>(); this.PreloadData = preloadData; } } foreach (var item in objectItems) { TypeID typeId = item.TypeTree.TypeID; if (typeId == TypeID.AssetBundle || typeId == TypeID.PreloadData) { continue; } bool isPublic = !this.Bundle.IsStreamed && this.AssetBundle != null && this.AssetBundle.IsPublic(item.ID); ObjectInfo info = new ObjectInfo(this, item.ID, item.TypeTree, item.Offset, item.Size, isPublic); this.objects.Add(info.ID, info); if (info.IsPotentialRedundancy) { reader.BaseStream.Seek(this.assetDataOffset + item.Offset, SeekOrigin.Begin); FeatureInfo featureInfo = this.extractor.Extract(info, reader); info.Fingerprint = new PropertiesFingerprint(info, featureInfo.References, featureInfo.PropertyHash); info.Name = featureInfo.Name; info.Resources = featureInfo.Resources; } else { info.Fingerprint = new IdentifierFingerprint(info.ID, this.Name); } } } catch (Exception e) { Debug.LogErrorFormat("{0}", e); } }
protected virtual void ReadNode(TypeNode typeNode, ArchiveBinaryReader reader, ObjectArchive archive, Stream output, FeatureInfo data) { Stream src = reader.BaseStream; switch (typeNode.TypeFlag) { case "bool": case "SInt8": case "char": case "UInt8": case "short": case "SInt16": case "unsigned short": case "UInt16": case "int": case "SInt32": case "unsigned int": case "UInt32": case "Type*": case "long long": case "SInt64": case "unsigned long long": case "UInt64": case "float": case "double": case "Quaternionf": case "float4": case "Vector4f": case "float3": case "Vector3f": case "float2": case "Vector2f": case "ColorRGBA": case "Matrix4x4f": case "Hash128": { this.CopyTo(src, output, typeNode.Size); break; } case "string": { if ((typeNode.Depth == 1 || (typeNode.Depth == 2 && typeNode.Root.TypeID == TypeID.Shader)) && typeNode.FieldName.Equals("m_Name")) { var position = reader.BaseStream.Position; data.Name = reader.ReadString(); reader.BaseStream.Position = position; } int size = reader.ReadInt32(); if (size > 0) { this.CopyTo(src, output, size); } reader.Align(4); break; } case "Array": { var valueTypeNode = typeNode.Children[1]; var size = reader.ReadInt32(); if (size <= 0) { break; } this.ReadArrayNode(valueTypeNode, size, reader, archive, output, data); break; } case "TypelessData": { var size = reader.ReadInt32(); if (size > 0) { this.CopyTo(src, output, size); } break; } case "PPtr": { var fileID = reader.ReadInt32(); var pathID = reader.ReadInt64(); var pptr = new PPtr(fileID, pathID, typeNode.TypeName); data.Add(pptr); break; } case "StreamedResource": { var source = reader.ReadString(); var offset = reader.ReadUInt64(); var size = reader.ReadUInt64(); var streamedResource = new StreamedResource(source, offset, size); data.Resources = streamedResource; if (size <= 0) { break; } using (Stream dataStream = archive.GetResourceStream(streamedResource)) { if (dataStream == null) { break; } byte[] buffer = ArchiveUtil.HashBytes(dataStream); output.Write(buffer, 0, buffer.Length); } break; } default: { foreach (TypeNode childNode in typeNode.Children) { ReadNode(childNode, reader, archive, output, data); } break; } } if (typeNode.IsAlign) { reader.Align(4); } }