Download as txt, pdf, or txt
Download as txt, pdf, or txt
You are on page 1of 2

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]
}
}
}

You might also like