mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
99 lines
2.9 KiB
99 lines
2.9 KiB
System.Resources.ResourceReader is unsuitable for deserializing resources in the ILSpy context, |
|
because it tries to deserialize custom resource types, which fails if the types are in a non-GAC assembly. |
|
|
|
So we are instead using our own "class ResourcesFile", which is based on the |
|
.NET Core ResourceReader implementation. |
|
|
|
struct ResourcesFileFormat { |
|
int32 magicNum; [check == ResourceManager.MagicNumber] |
|
|
|
// ResourceManager header: |
|
int32 resMgrHeaderVersion; [check >= 0] |
|
int32 numBytesToSkip; [check >= 0] |
|
if (resMgrHeaderVersion <= 1) { |
|
string readerType; |
|
string resourceSetType; |
|
} else { |
|
byte _[numBytesToSkip]; |
|
} |
|
|
|
// RuntimeResourceSet header: |
|
int32 version; [check in (1, 2)] |
|
int32 numResources; [check >=0] |
|
int32 numTypes; [check >=0] |
|
string typeName[numTypes]; |
|
.align 8; |
|
int32 nameHashes[numResources]; |
|
int32 namePositions[numResources]; [check >= 0] |
|
int32 dataSectionOffset; [check >= current position in file] |
|
byte remainderOfFile[]; |
|
} |
|
|
|
// normal strings in this file format are stored as: |
|
struct string { |
|
compressedint len; |
|
byte value[len]; // interpret as UTF-8 |
|
} |
|
|
|
// NameEntry #i is stored starting at remainderOfFile[namePositions[i]] |
|
// (that is, namePositions is interpreted relative to the start of the remainderOfFile array) |
|
struct NameEntry { |
|
compressedint len; |
|
byte name[len]; // interpret as UTF-16 |
|
int32 dataOffset; [check >= 0] |
|
} |
|
|
|
// Found at position ResourcesFileFormat.dataSectionOffset+NameEntry.dataOffset in the file. |
|
struct ValueEntry { |
|
if (version == 1) { |
|
compressedint typeIndex; |
|
if (typeIndex == -1) { |
|
// no value stored; value is implicitly null |
|
} else { |
|
switch (typeName[typeIndex]) { |
|
case string: |
|
case int, uint, long, ulong, sbyte, byte, short, ushort: |
|
case float: |
|
case double: |
|
T value; // value directly stored |
|
case DateTime: |
|
int64 value; // new DateTime(_store.ReadInt64()) |
|
case TimeSpan: |
|
int64 value; // new TimeSpan(_store.ReadInt64()) |
|
case decimal: |
|
int32 value[4]; |
|
default: |
|
byte data[...]; // BinaryFormatter-serialized data using typeName[typeIndex] |
|
} |
|
} |
|
} else if (version == 2) { |
|
compressedint typeCode; |
|
// note: unlike v1, no lookup into the typeName array! |
|
switch (typeCode) { |
|
case null: |
|
// no value stored; value is implicitly null |
|
case string: |
|
case bool: |
|
case int, uint, long, ulong, sbyte, byte, short, ushort: |
|
T value; |
|
case char: |
|
uint16 value; |
|
case float: |
|
case double: |
|
case decimal: |
|
T value; |
|
case DateTime: |
|
int64 value; // DateTime.FromBinary(_store.ReadInt64()) |
|
case TimeSpan: |
|
int64 value; // new TimeSpan(_store.ReadInt64()) |
|
case ResourceTypeCode.ByteArray: |
|
int32 len; |
|
byte value[len]; |
|
case ResourceTypeCode.Stream: |
|
int32 len; |
|
byte value[len]; |
|
case >= ResourceTypeCode.StartOfUserTypes: |
|
byte data[...]; // BinaryFormatter-serialized data using typeName[typeCode - ResourceTypeCode.StartOfUserTypes] |
|
} |
|
} |
|
} |