DotNetMultiFileResourcesImpl(HexBufferFile file, Bit7String?resourceTypeSpan, Bit7String?resourceSetTypeSpan, HexPosition versionPosition, HexSpan paddingSpan, Bit7String[] typeNames, int numResources, HexPosition dataSectionPosition, HexPosition nameSectionPosition) : base(file) { DataSectionPosition = dataSectionPosition; var headerSpan = new HexBufferSpan(file.Buffer, HexSpan.FromBounds(file.Span.Start, nameSectionPosition)); Header = new DotNetMultiFileResourceHeaderDataImpl(headerSpan, resourceTypeSpan, resourceSetTypeSpan, versionPosition, paddingSpan, typeNames, numResources); ResourceInfo[] resourceInfos; dataArray = CreateDataArray(typeNames, numResources, paddingSpan.End, dataSectionPosition, nameSectionPosition, out resourceInfos); var files = new List <BufferFileOptions>(resourceInfos.Length); foreach (var info in resourceInfos) { var data = info.ResData; if (data == null) { continue; } if (data.NestedFileData.IsEmpty) { continue; } if (!IsNestedFile(data.TypeCode)) { continue; } var name = Encoding.Unicode.GetString(File.Buffer.ReadBytes(info.UnicodeName.StringSpan)); var filteredName = NameUtils.FilterName(name); var tags = data.TypeCode >= ResourceTypeCode.UserTypes ? tagsSerialized : tagsNonSerialized; files.Add(new BufferFileOptions(data.NestedFileData, filteredName, string.Empty, tags)); } if (files.Count > 0) { File.CreateFiles(files.ToArray()); } }
static DotNetMultiFileResourcesImpl?TryReadCore(HexBufferFile file) { if (file is null) { throw new ArgumentNullException(nameof(file)); } if (file.Span.Length < 0x1C) { return(null); } var buffer = file.Buffer; var pos = file.Span.Start; if (buffer.ReadUInt32(pos) != 0xBEEFCACE) { return(null); } int resMgrHeaderVersion = buffer.ReadInt32(pos + 4); int headerSize = buffer.ReadInt32(pos + 8); if (resMgrHeaderVersion < 0 || headerSize < 0) { return(null); } pos += 0xC; Bit7String?resourceTypeSpan = null; Bit7String?resourceSetTypeSpan = null; if (resMgrHeaderVersion > 1) { pos += headerSize; } else { resourceTypeSpan = ReadBit7String(buffer, ref pos, file.Span.End); resourceSetTypeSpan = ReadBit7String(buffer, ref pos, file.Span.End); if (resourceTypeSpan is null || resourceSetTypeSpan is null) { return(null); } var resourceType = Encoding.UTF8.GetString(buffer.ReadBytes(resourceTypeSpan.Value.StringSpan)); if (!Regex.IsMatch(resourceType, @"^System\.Resources\.ResourceReader,\s*mscorlib,")) { return(null); } } var versionPosition = pos; if (pos + 0x0C > file.Span.End) { return(null); } uint version = buffer.ReadUInt32(pos); if (version != 2) { return(null); //TODO: Support version 1 } int numResources = buffer.ReadInt32(pos + 4); int numTypes = buffer.ReadInt32(pos + 8); if (numResources < 0 || numTypes < 0) { return(null); } pos += 0x0C; var typeNames = new Bit7String[numTypes]; for (int i = 0; i < typeNames.Length; i++) { var info = ReadBit7String(buffer, ref pos, file.Span.End); if (info is null) { return(null); } typeNames[i] = info.Value; } var paddingStart = pos; pos = file.AlignUp(pos, 8); var paddingSpan = HexSpan.FromBounds(paddingStart, pos); if (pos + (ulong)numResources * 8 + 4 > file.Span.End) { return(null); } pos += (ulong)numResources * 8; int dataSectionOffset = buffer.ReadInt32(pos); pos += 4; if (dataSectionOffset < 0 || dataSectionOffset < (pos - file.Span.Start)) { return(null); } // Use > and not >= in case it's an empty resource if (dataSectionOffset > file.Span.Length) { return(null); } var dataSectionPosition = file.Span.Start + dataSectionOffset; var nameSectionPosition = pos; return(new DotNetMultiFileResourcesImpl(file, resourceTypeSpan, resourceSetTypeSpan, versionPosition, paddingSpan, typeNames, numResources, dataSectionPosition, nameSectionPosition)); }
public DotNetMultiFileResourceHeaderDataImpl(HexBufferSpan span, Bit7String?resourceTypeSpan, Bit7String?resourceSetTypeSpan, HexPosition versionPosition, HexSpan paddingSpan, Bit7String[] typeNames, int numResources) : base(span) { var buffer = span.Buffer; var pos = span.Start.Position; MagicNum = new StructField <UInt32Data>("MagicNum", new UInt32Data(buffer, pos)); ResMgrHeaderVersion = new StructField <UInt32Data>("ResMgrHeaderVersion", new UInt32Data(buffer, pos + 4)); HeaderSize = new StructField <UInt32Data>("HeaderSize", new UInt32Data(buffer, pos + 8)); if (resourceTypeSpan == null) { if (resourceSetTypeSpan != null) { throw new ArgumentException(); } UnknownHeader = new StructField <VirtualArrayData <ByteData> >("Header", ArrayData.CreateVirtualByteArray(new HexBufferSpan(buffer, HexSpan.FromBounds(pos + 0x0C, versionPosition)))); } else { if (resourceSetTypeSpan == null) { throw new ArgumentNullException(nameof(resourceSetTypeSpan)); } ReaderType = new StructField <Bit7EncodedStringData>("ReaderType", new Bit7EncodedStringData(buffer, resourceTypeSpan.Value.LengthSpan, resourceTypeSpan.Value.StringSpan, Encoding.UTF8)); ResourceSetType = new StructField <Bit7EncodedStringData>("ResourceSetType", new Bit7EncodedStringData(buffer, resourceSetTypeSpan.Value.LengthSpan, resourceSetTypeSpan.Value.StringSpan, Encoding.UTF8)); } pos = versionPosition; Version = new StructField <UInt32Data>("Version", new UInt32Data(buffer, pos)); NumResources = new StructField <UInt32Data>("NumResources", new UInt32Data(buffer, pos + 4)); NumTypes = new StructField <UInt32Data>("NumTypes", new UInt32Data(buffer, pos + 8)); pos += 0x0C; var fields = new ArrayField <Bit7EncodedStringData> [typeNames.Length]; var currPos = pos; for (int i = 0; i < fields.Length; i++) { var info = typeNames[i]; var field = new ArrayField <Bit7EncodedStringData>(new Bit7EncodedStringData(buffer, info.LengthSpan, info.StringSpan, Encoding.UTF8), (uint)i); fields[i] = field; currPos = field.Data.Span.End; } TypeNames = new StructField <VariableLengthArrayData <Bit7EncodedStringData> >("TypeNames", new VariableLengthArrayData <Bit7EncodedStringData>(string.Empty, new HexBufferSpan(buffer, HexSpan.FromBounds(pos, currPos)), fields)); Alignment8 = new StructField <ArrayData <ByteData> >("Padding", ArrayData.CreateByteArray(buffer, paddingSpan.Start, (int)paddingSpan.Length.ToUInt64())); pos = paddingSpan.End; NameHashes = new StructField <VirtualArrayData <UInt32Data> >("NameHashes", ArrayData.CreateVirtualUInt32Array(new HexBufferSpan(buffer, new HexSpan(pos, (ulong)numResources * 4)))); pos += (ulong)numResources * 4; NamePositions = new StructField <VirtualArrayData <UInt32Data> >("NamePositions", ArrayData.CreateVirtualUInt32Array(new HexBufferSpan(buffer, new HexSpan(pos, (ulong)numResources * 4)))); pos += (ulong)numResources * 4; DataSectionOffset = new StructField <FileOffsetData>("DataSectionOffset", new FileOffsetData(buffer, pos)); pos += 4; if (pos != span.Span.End) { throw new ArgumentOutOfRangeException(nameof(span)); } var list = new List <BufferField>(13); list.Add(MagicNum); list.Add(ResMgrHeaderVersion); list.Add(HeaderSize); if (UnknownHeader != null) { list.Add(UnknownHeader); } if (ReaderType != null) { list.Add(ReaderType); } if (ResourceSetType != null) { list.Add(ResourceSetType); } list.Add(Version); list.Add(NumResources); list.Add(NumTypes); list.Add(TypeNames); list.Add(Alignment8); list.Add(NameHashes); list.Add(NamePositions); list.Add(DataSectionOffset); Fields = list.ToArray(); }