internal static UsmapPropertyData Deserialize(IGenericReader reader, string[] names) { var propType = reader.Read <EUsmapPropertyType>(); var data = new UsmapPropertyData(propType); switch (propType) { case EUsmapPropertyType.EnumProperty: { data.InnerType = Deserialize(reader, names); var idx = reader.Read <uint>(); data.EnumName = names[idx]; break; } case EUsmapPropertyType.StructProperty: { var idx = reader.Read <uint>(); data.StructType = names[idx]; break; } case EUsmapPropertyType.SetProperty: case EUsmapPropertyType.ArrayProperty: { data.InnerType = Deserialize(reader, names); break; } case EUsmapPropertyType.MapProperty: { data.InnerType = Deserialize(reader, names); data.ValueType = Deserialize(reader, names); break; } } return(data); }
internal Usmap(IGenericReader fileReader, UsmapOptions options) { var magic = fileReader.Read <ushort>(); if (magic != MAGIC) { throw new FileLoadException("Invalid .usmap magic constant"); } var version = fileReader.Read <EUsmapVersion>(); if (version != EUsmapVersion.LATEST) { throw new FileLoadException($"Invalid .usmap version: {(int)version}"); } var compMethod = fileReader.Read <EUsmapCompressionMethod>(); var compSize = fileReader.Read <uint>(); var decompSize = fileReader.Read <uint>(); if (fileReader.Size - fileReader.Position < compSize) { throw new FileLoadException("There is not enough data in the .usmap file"); } options ??= new UsmapOptions(); IGenericReader reader; switch (compMethod) { case EUsmapCompressionMethod.None: { if (compSize != decompSize) { throw new FileLoadException("No .usmap compression: Compression size must be equal to decompression size"); } reader = fileReader; break; } case EUsmapCompressionMethod.Oodle: { if (options.OodlePath == null) { throw new FileLoadException("Undefined oodle library path"); } if (!File.Exists(options.OodlePath)) { throw new FileLoadException($"Could not find oodle library at \"{options.OodlePath}\""); } var compData = fileReader.ReadBytes((int)compSize); fileReader.Dispose(); var data = new byte[decompSize]; using var decompressor = new OodleCompressor(options.OodlePath); unsafe { var result = decompressor.Decompress(compData, compSize, data, decompSize, OodleLZ_FuzzSafe.No, OodleLZ_CheckCRC.No, OodleLZ_Verbosity.None, 0L, 0L, 0L, 0L, 0L, 0L, OodleLZ_Decode_ThreadPhase.Unthreaded); if (result != decompSize) { throw new FileLoadException($"Invalid oodle .usmap decompress result: {result} / {decompSize}"); } } reader = new GenericBufferReader(data); break; } case EUsmapCompressionMethod.Brotli: { var compData = fileReader.ReadBytes((int)compSize); fileReader.Dispose(); var data = new byte[decompSize]; using var decoder = new BrotliDecoder(); var result = decoder.Decompress(compData, data, out var bytesConsumed, out var bytesWritten); if (result != OperationStatus.Done) { throw new FileLoadException($"Invalid brotli .usmap decompress result: {result} | {bytesWritten} / {decompSize} | {bytesConsumed} / {compSize}"); } reader = new GenericBufferReader(data); break; } default: throw new FileLoadException($"Unknown .usmap compression method: {(int)compMethod}"); } string[] names; { var size = reader.Read <uint>(); names = new string[size]; for (var i = 0; i < size; ++i) { var nameSize = reader.ReadByte(); var name = reader.ReadString(nameSize, Encoding.UTF8); names[i] = name; } } { var size = reader.Read <uint>(); Enums = new UsmapEnum[size]; for (var i = 0; i < size; ++i) { var idx = reader.Read <uint>(); var enumNamesSize = reader.ReadByte(); var enumNames = new string[enumNamesSize]; for (var j = 0; j < enumNamesSize; ++j) { var nameIdx = reader.Read <uint>(); enumNames[j] = names[nameIdx]; } Enums[i] = new UsmapEnum(names[idx], enumNames); } } { var size = reader.Read <uint>(); Schemas = new UsmapSchema[size]; for (var i = 0; i < size; ++i) { var idx = reader.Read <uint>(); var superIdx = reader.Read <uint>(); var propCount = reader.Read <ushort>(); var serializablePropCount = reader.Read <ushort>(); var props = new UsmapProperty[serializablePropCount]; for (var j = 0; j < serializablePropCount; ++j) { var schemaIdx = reader.Read <ushort>(); var arraySize = reader.Read <byte>(); var nameIdx = reader.Read <uint>(); var data = UsmapPropertyData.Deserialize(reader, names); props[j] = new UsmapProperty(names[nameIdx], schemaIdx, arraySize, data); } Schemas[i] = new UsmapSchema(names[idx], superIdx == uint.MaxValue ? null : names[superIdx], propCount, props); } } Names = options.SaveNames ? names : null; reader.Dispose(); }