From 76d9e87c3c8283aca67acef6a4568a37a7289e11 Mon Sep 17 00:00:00 2001 From: de4dot Date: Sat, 11 Feb 2012 16:43:53 +0100 Subject: [PATCH] Add code to write .resources files --- de4dot.code/de4dot.code.csproj | 10 + de4dot.code/resources/BuiltInResourceData.cs | 118 ++++++++++ de4dot.code/resources/IResourceData.cs | 28 +++ de4dot.code/resources/ResourceDataCreator.cs | 226 +++++++++++++++++++ de4dot.code/resources/ResourceElement.cs | 25 ++ de4dot.code/resources/ResourceElementSet.cs | 39 ++++ de4dot.code/resources/ResourceTypeCode.cs | 42 ++++ de4dot.code/resources/ResourceWriter.cs | 154 +++++++++++++ de4dot.code/resources/UserResourceData.cs | 97 ++++++++ de4dot.code/resources/UserResourceType.cs | 42 ++++ 10 files changed, 781 insertions(+) create mode 100644 de4dot.code/resources/BuiltInResourceData.cs create mode 100644 de4dot.code/resources/IResourceData.cs create mode 100644 de4dot.code/resources/ResourceDataCreator.cs create mode 100644 de4dot.code/resources/ResourceElement.cs create mode 100644 de4dot.code/resources/ResourceElementSet.cs create mode 100644 de4dot.code/resources/ResourceTypeCode.cs create mode 100644 de4dot.code/resources/ResourceWriter.cs create mode 100644 de4dot.code/resources/UserResourceData.cs create mode 100644 de4dot.code/resources/UserResourceType.cs diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index 9ce9308a..5c5ce3c5 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -44,6 +44,7 @@ ..\ICSharpCode.SharpZipLib.dll + @@ -230,6 +231,15 @@ + + + + + + + + + diff --git a/de4dot.code/resources/BuiltInResourceData.cs b/de4dot.code/resources/BuiltInResourceData.cs new file mode 100644 index 00000000..d13489fc --- /dev/null +++ b/de4dot.code/resources/BuiltInResourceData.cs @@ -0,0 +1,118 @@ +/* + Copyright (C) 2011-2012 de4dot@gmail.com + + This file is part of de4dot. + + de4dot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + de4dot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with de4dot. If not, see . +*/ + +using System; +using System.IO; +using System.Runtime.Serialization; + +namespace de4dot.code.resources { + class BuiltInResourceData : IResourceData { + readonly ResourceTypeCode code; + readonly object data; + + public ResourceTypeCode Code { + get { return code; } + } + + public BuiltInResourceData(ResourceTypeCode code, object data) { + this.code = code; + this.data = data; + } + + public void writeData(BinaryWriter writer, IFormatter formatter) { + switch (code) { + case ResourceTypeCode.Null: + return; + + case ResourceTypeCode.String: + writer.Write((string)data); + break; + + case ResourceTypeCode.Boolean: + writer.Write((bool)data); + break; + + case ResourceTypeCode.Char: + writer.Write((ushort)(char)data); + break; + + case ResourceTypeCode.Byte: + writer.Write((byte)data); + break; + + case ResourceTypeCode.SByte: + writer.Write((sbyte)data); + break; + + case ResourceTypeCode.Int16: + writer.Write((short)data); + break; + + case ResourceTypeCode.UInt16: + writer.Write((ushort)data); + break; + + case ResourceTypeCode.Int32: + writer.Write((int)data); + break; + + case ResourceTypeCode.UInt32: + writer.Write((uint)data); + break; + + case ResourceTypeCode.Int64: + writer.Write((long)data); + break; + + case ResourceTypeCode.UInt64: + writer.Write((ulong)data); + break; + + case ResourceTypeCode.Single: + writer.Write((float)data); + break; + + case ResourceTypeCode.Double: + writer.Write((double)data); + break; + + case ResourceTypeCode.Decimal: + writer.Write((decimal)data); + break; + + case ResourceTypeCode.DateTime: + writer.Write(((DateTime)data).ToBinary()); + break; + + case ResourceTypeCode.TimeSpan: + writer.Write(((TimeSpan)data).Ticks); + break; + + case ResourceTypeCode.ByteArray: + var ary = (byte[])data; + writer.Write(ary.Length); + writer.Write(ary); + break; + + default: + throw new ApplicationException("Unknown resource type code"); + } + } + } +} diff --git a/de4dot.code/resources/IResourceData.cs b/de4dot.code/resources/IResourceData.cs new file mode 100644 index 00000000..04eff9b6 --- /dev/null +++ b/de4dot.code/resources/IResourceData.cs @@ -0,0 +1,28 @@ +/* + Copyright (C) 2011-2012 de4dot@gmail.com + + This file is part of de4dot. + + de4dot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + de4dot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with de4dot. If not, see . +*/ + +using System.IO; +using System.Runtime.Serialization; + +namespace de4dot.code.resources { + interface IResourceData { + ResourceTypeCode Code { get; } + void writeData(BinaryWriter writer, IFormatter formatter); + } +} diff --git a/de4dot.code/resources/ResourceDataCreator.cs b/de4dot.code/resources/ResourceDataCreator.cs new file mode 100644 index 00000000..db832045 --- /dev/null +++ b/de4dot.code/resources/ResourceDataCreator.cs @@ -0,0 +1,226 @@ +/* + Copyright (C) 2011-2012 de4dot@gmail.com + + This file is part of de4dot. + + de4dot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + de4dot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with de4dot. If not, see . +*/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using Mono.Cecil; + +namespace de4dot.code.resources { + class ResourceDataCreator { + ModuleDefinition module; + Dictionary dict = new Dictionary(StringComparer.Ordinal); + Dictionary asmNameToAsmFullName = new Dictionary(StringComparer.Ordinal); + + public ResourceDataCreator(ModuleDefinition module) { + this.module = module; + } + + public int Count { + get { return dict.Count; } + } + + public BuiltInResourceData createNull() { + return new BuiltInResourceData(ResourceTypeCode.Null, null); + } + + public BuiltInResourceData create(string value) { + return new BuiltInResourceData(ResourceTypeCode.String, value); + } + + public BuiltInResourceData create(bool value) { + return new BuiltInResourceData(ResourceTypeCode.Boolean, value); + } + + public BuiltInResourceData create(char value) { + return new BuiltInResourceData(ResourceTypeCode.Char, value); + } + + public BuiltInResourceData create(byte value) { + return new BuiltInResourceData(ResourceTypeCode.Byte, value); + } + + public BuiltInResourceData create(sbyte value) { + return new BuiltInResourceData(ResourceTypeCode.SByte, value); + } + + public BuiltInResourceData create(short value) { + return new BuiltInResourceData(ResourceTypeCode.Int16, value); + } + + public BuiltInResourceData create(ushort value) { + return new BuiltInResourceData(ResourceTypeCode.UInt16, value); + } + + public BuiltInResourceData create(int value) { + return new BuiltInResourceData(ResourceTypeCode.Int32, value); + } + + public BuiltInResourceData create(uint value) { + return new BuiltInResourceData(ResourceTypeCode.UInt32, value); + } + + public BuiltInResourceData create(long value) { + return new BuiltInResourceData(ResourceTypeCode.Int64, value); + } + + public BuiltInResourceData create(ulong value) { + return new BuiltInResourceData(ResourceTypeCode.UInt64, value); + } + + public BuiltInResourceData create(float value) { + return new BuiltInResourceData(ResourceTypeCode.Single, value); + } + + public BuiltInResourceData create(double value) { + return new BuiltInResourceData(ResourceTypeCode.Double, value); + } + + public BuiltInResourceData create(decimal value) { + return new BuiltInResourceData(ResourceTypeCode.Decimal, value); + } + + public BuiltInResourceData create(DateTime value) { + return new BuiltInResourceData(ResourceTypeCode.DateTime, value); + } + + public BuiltInResourceData create(TimeSpan value) { + return new BuiltInResourceData(ResourceTypeCode.TimeSpan, value); + } + + public BuiltInResourceData create(byte[] value) { + return new BuiltInResourceData(ResourceTypeCode.ByteArray, value); + } + + public CharArrayResourceData create(char[] value) { + return new CharArrayResourceData(createUserResourceType(CharArrayResourceData.typeName), value); + } + + public IconResourceData createIcon(byte[] value) { + return new IconResourceData(createUserResourceType(IconResourceData.typeName), value); + } + + public ImageResourceData createImage(byte[] value) { + return new ImageResourceData(createUserResourceType(ImageResourceData.typeName), value); + } + + public BinaryResourceData createSerialized(byte[] value) { + string assemblyName, typeName; + if (!getSerializedTypeAndAssemblyName(value, out assemblyName, out typeName)) + throw new ApplicationException("Could not get serialized type name"); + string fullName = string.Format("{0},{1}", typeName, assemblyName); + return new BinaryResourceData(createUserResourceType(fullName), value); + } + + class MyBinder : SerializationBinder { + public string assemblyName; + public string typeName; + + public class OkException : Exception { + } + + public override Type BindToType(string assemblyName, string typeName) { + this.assemblyName = assemblyName; + this.typeName = typeName; + throw new OkException(); + } + } + + bool getSerializedTypeAndAssemblyName(byte[] value, out string assemblyName, out string typeName) { + var binder = new MyBinder(); + try { + var formatter = new BinaryFormatter(); + formatter.Binder = binder; + formatter.Deserialize(new MemoryStream(value)); + } + catch (MyBinder.OkException) { + assemblyName = binder.assemblyName; + typeName = binder.typeName; + return true; + } + catch { + } + + assemblyName = null; + typeName = null; + return false; + } + + public UserResourceType createUserResourceType(string fullName) { + UserResourceType type; + if (dict.TryGetValue(fullName, out type)) + return type; + + var newFullName = fullName; + string typeName, assemblyName; + splitTypeFullName(fullName, out typeName, out assemblyName); + if (!string.IsNullOrEmpty(assemblyName)) { + string newAsmName; + if (!asmNameToAsmFullName.TryGetValue(assemblyName, out newAsmName)) + asmNameToAsmFullName[assemblyName] = newAsmName = getRealAssemblyName(assemblyName); + assemblyName = newAsmName; + } + if (!string.IsNullOrEmpty(assemblyName)) + newFullName = string.Format("{0}, {1}", typeName, assemblyName); + + type = new UserResourceType(newFullName, ResourceTypeCode.UserTypes + dict.Count); + dict[fullName] = type; + dict[newFullName] = type; + return type; + } + + static void splitTypeFullName(string fullName, out string typeName, out string assemblyName) { + int index = fullName.IndexOf(','); + if (index < 0) { + typeName = fullName; + assemblyName = null; + } + else { + typeName = fullName.Substring(0, index); + assemblyName = fullName.Substring(index + 1).Trim(); + } + } + + string getRealAssemblyName(string assemblyName) { + var simpleName = Utils.getAssemblySimpleName(assemblyName); + + foreach (var asmRef in module.AssemblyReferences) { + if (asmRef.Name == simpleName) + return asmRef.FullName; + } + + try { + return AssemblyResolver.Instance.Resolve(simpleName).FullName; + } + catch (ResolutionException) { + } + catch (AssemblyResolutionException) { + } + return null; + } + + public List getSortedTypes() { + var list = new List(dict.Values); + list.Sort((a, b) => Utils.compareInt32((int)a.Code, (int)b.Code)); + return list; + } + } +} diff --git a/de4dot.code/resources/ResourceElement.cs b/de4dot.code/resources/ResourceElement.cs new file mode 100644 index 00000000..f80ed9c9 --- /dev/null +++ b/de4dot.code/resources/ResourceElement.cs @@ -0,0 +1,25 @@ +/* + Copyright (C) 2011-2012 de4dot@gmail.com + + This file is part of de4dot. + + de4dot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + de4dot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with de4dot. If not, see . +*/ + +namespace de4dot.code.resources { + class ResourceElement { + public string Name { get; set; } + public IResourceData ResourceData { get; set; } + } +} diff --git a/de4dot.code/resources/ResourceElementSet.cs b/de4dot.code/resources/ResourceElementSet.cs new file mode 100644 index 00000000..19a820c0 --- /dev/null +++ b/de4dot.code/resources/ResourceElementSet.cs @@ -0,0 +1,39 @@ +/* + Copyright (C) 2011-2012 de4dot@gmail.com + + This file is part of de4dot. + + de4dot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + de4dot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with de4dot. If not, see . +*/ + +using System; +using System.Collections.Generic; + +namespace de4dot.code.resources { + class ResourceElementSet { + Dictionary dict = new Dictionary(StringComparer.Ordinal); + + public int Count { + get { return dict.Count; } + } + + public IEnumerable ResourceElements { + get { return dict.Values; } + } + + public void add(ResourceElement elem) { + dict[elem.Name] = elem; + } + } +} diff --git a/de4dot.code/resources/ResourceTypeCode.cs b/de4dot.code/resources/ResourceTypeCode.cs new file mode 100644 index 00000000..4644074e --- /dev/null +++ b/de4dot.code/resources/ResourceTypeCode.cs @@ -0,0 +1,42 @@ +/* + Copyright (C) 2011-2012 de4dot@gmail.com + + This file is part of de4dot. + + de4dot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + de4dot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with de4dot. If not, see . +*/ + +namespace de4dot.code.resources { + enum ResourceTypeCode { + Null, + String, + Boolean, + Char, + Byte, + SByte, + Int16, + UInt16, + Int32, + UInt32, + Int64, + UInt64, + Single, + Double, + Decimal, + DateTime, + TimeSpan, + ByteArray = 0x20, + UserTypes = 0x40, + } +} diff --git a/de4dot.code/resources/ResourceWriter.cs b/de4dot.code/resources/ResourceWriter.cs new file mode 100644 index 00000000..49db069d --- /dev/null +++ b/de4dot.code/resources/ResourceWriter.cs @@ -0,0 +1,154 @@ +/* + Copyright (C) 2011-2012 de4dot@gmail.com + + This file is part of de4dot. + + de4dot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + de4dot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with de4dot. If not, see . +*/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text; +using Mono.Cecil; + +namespace de4dot.code.resources { + class ResourceWriter { + ModuleDefinition module; + BinaryWriter writer; + ResourceElementSet resources; + ResourceDataCreator typeCreator; + Dictionary dataToNewType = new Dictionary(); + + ResourceWriter(ModuleDefinition module, Stream stream, ResourceElementSet resources) { + this.module = module; + this.typeCreator = new ResourceDataCreator(module); + this.writer = new BinaryWriter(stream); + this.resources = resources; + } + + public static void write(ModuleDefinition module, Stream stream, ResourceElementSet resources) { + new ResourceWriter(module, stream, resources).write(); + } + + void write() { + initializeUserTypes(); + + writer.Write(0xBEEFCACE); + writer.Write(1); + writeReaderType(); + writer.Write(2); + writer.Write(resources.Count); + writer.Write(typeCreator.Count); + foreach (var userType in typeCreator.getSortedTypes()) + writer.Write(userType.Name); + int extraBytes = 8 - ((int)writer.BaseStream.Position & 7); + if (extraBytes != 8) { + for (int i = 0; i < extraBytes; i++) + writer.Write((byte)'X'); + } + + var nameOffsetStream = new MemoryStream(); + var nameOffsetWriter = new BinaryWriter(nameOffsetStream, Encoding.Unicode); + var dataStream = new MemoryStream(); + var dataWriter = new BinaryWriter(dataStream); + var hashes = new int[resources.Count]; + var offsets = new int[resources.Count]; + var formatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.File | StreamingContextStates.Persistence)); + int index = 0; + foreach (var info in resources.ResourceElements) { + offsets[index] = (int)nameOffsetWriter.BaseStream.Position; + hashes[index] = (int)hash(info.Name); + index++; + nameOffsetWriter.Write(info.Name); + nameOffsetWriter.Write((int)dataWriter.BaseStream.Position); + writeData(dataWriter, info, formatter); + } + + Array.Sort(hashes, offsets); + foreach (var hash in hashes) + writer.Write(hash); + foreach (var offset in offsets) + writer.Write(offset); + writer.Write((int)writer.BaseStream.Position + (int)nameOffsetStream.Length + 4); + writer.Write(nameOffsetStream.ToArray()); + writer.Write(dataStream.ToArray()); + } + + void writeData(BinaryWriter writer, ResourceElement info, IFormatter formatter) { + var code = getResourceType(info.ResourceData); + writeUInt32(writer, (uint)code); + info.ResourceData.writeData(writer, formatter); + } + + static void writeUInt32(BinaryWriter writer, uint value) { + while (value >= 0x80) { + writer.Write((byte)(value | 0x80)); + value >>= 7; + } + writer.Write((byte)value); + } + + ResourceTypeCode getResourceType(IResourceData data) { + if (data is BuiltInResourceData) + return data.Code; + + var userData = (UserResourceData)data; + return dataToNewType[userData].Code; + } + + static uint hash(string key) { + uint val = 0x1505; + foreach (var c in key) + val = ((val << 5) + val) ^ (uint)c; + return val; + } + + void initializeUserTypes() { + foreach (var resource in resources.ResourceElements) { + var data = resource.ResourceData as UserResourceData; + if (data == null) + continue; + var newType = typeCreator.createUserResourceType(data.TypeName); + dataToNewType[data] = newType; + } + } + + void writeReaderType() { + var memStream = new MemoryStream(); + var headerWriter = new BinaryWriter(memStream); + var mscorlibFullName = getMscorlibFullname(); + headerWriter.Write("System.Resources.ResourceReader, " + mscorlibFullName); + headerWriter.Write("System.Resources.RuntimeResourceSet"); + writer.Write((int)memStream.Position); + writer.Write(memStream.ToArray()); + } + + string getMscorlibFullname() { + AssemblyNameReference mscorlibRef = null; + foreach (var asmRef in module.AssemblyReferences) { + if (asmRef.Name != "mscorlib") + continue; + if (mscorlibRef == null || mscorlibRef.Version == null || asmRef.Version >= mscorlibRef.Version) + mscorlibRef = asmRef; + } + if (mscorlibRef != null) + return mscorlibRef.FullName; + + return "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; + } + } +} diff --git a/de4dot.code/resources/UserResourceData.cs b/de4dot.code/resources/UserResourceData.cs new file mode 100644 index 00000000..367ca549 --- /dev/null +++ b/de4dot.code/resources/UserResourceData.cs @@ -0,0 +1,97 @@ +/* + Copyright (C) 2011-2012 de4dot@gmail.com + + This file is part of de4dot. + + de4dot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + de4dot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with de4dot. If not, see . +*/ + +using System.Drawing; +using System.IO; +using System.Runtime.Serialization; + +namespace de4dot.code.resources { + abstract class UserResourceData : IResourceData { + readonly UserResourceType type; + + public string TypeName { + get { return type.Name; } + } + + public ResourceTypeCode Code { + get { return type.Code; } + } + + public UserResourceData(UserResourceType type) { + this.type = type; + } + + public abstract void writeData(BinaryWriter writer, IFormatter formatter); + } + + class CharArrayResourceData : UserResourceData { + public static readonly string typeName = "System.Char[],mscorlib"; + char[] data; + + public CharArrayResourceData(UserResourceType type, char[] data) + : base(type) { + this.data = data; + } + + public override void writeData(BinaryWriter writer, IFormatter formatter) { + formatter.Serialize(writer.BaseStream, data); + } + } + + class IconResourceData : UserResourceData { + public static readonly string typeName = "System.Drawing.Icon,System.Drawing"; + Icon icon; + + public IconResourceData(UserResourceType type, byte[] data) + : base(type) { + icon = new Icon(new MemoryStream(data)); + } + + public override void writeData(BinaryWriter writer, IFormatter formatter) { + formatter.Serialize(writer.BaseStream, icon); + } + } + + class ImageResourceData : UserResourceData { + public static readonly string typeName = "System.Drawing.Bitmap,System.Drawing"; + Bitmap bitmap; + + public ImageResourceData(UserResourceType type, byte[] data) + : base(type) { + bitmap = new Bitmap(Image.FromStream(new MemoryStream(data))); + } + + public override void writeData(BinaryWriter writer, IFormatter formatter) { + formatter.Serialize(writer.BaseStream, bitmap); + } + } + + class BinaryResourceData : UserResourceData { + byte[] data; + + public BinaryResourceData(UserResourceType type, byte[] data) + : base(type) { + this.data = data; + } + + public override void writeData(BinaryWriter writer, IFormatter formatter) { + writer.Write(data); + } + } +} diff --git a/de4dot.code/resources/UserResourceType.cs b/de4dot.code/resources/UserResourceType.cs new file mode 100644 index 00000000..1e38442f --- /dev/null +++ b/de4dot.code/resources/UserResourceType.cs @@ -0,0 +1,42 @@ +/* + Copyright (C) 2011-2012 de4dot@gmail.com + + This file is part of de4dot. + + de4dot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + de4dot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with de4dot. If not, see . +*/ + +namespace de4dot.code.resources { + class UserResourceType { + readonly string name; + readonly ResourceTypeCode code; + + public string Name { + get { return name; } + } + + public ResourceTypeCode Code { + get { return code; } + } + + public UserResourceType(string name, ResourceTypeCode code) { + this.name = name; + this.code = code; + } + + public override string ToString() { + return string.Format("{0:X2} {1}", (int)code, name); + } + } +}