-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Finished porting the core Resources infrastructure.
- Loading branch information
Lloyd Kinsella
committed
Aug 9, 2018
1 parent
d3f9e4a
commit d3ad642
Showing
5 changed files
with
671 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Reflection; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Workshell.PE.Content | ||
{ | ||
public class Resource : ISupportsBytes | ||
{ | ||
public const uint DefaultLanguage = 1033; | ||
|
||
private readonly PortableExecutableImage _image; | ||
private readonly Dictionary<uint, ResourceDirectoryEntry> _languages; | ||
|
||
protected Resource(PortableExecutableImage image, ResourceType type, ResourceDirectoryEntry entry, ResourceId id) | ||
{ | ||
_image = image; | ||
_languages = BuildLanguages(entry); | ||
|
||
Type = type; | ||
Entry = entry; | ||
Id = id; | ||
Languages = _languages.Keys.OrderBy(k => k).ToArray(); | ||
} | ||
|
||
#region Static Methods | ||
|
||
internal static async Task<Resource> CreateAsync(PortableExecutableImage image, ResourceType type, ResourceDirectoryEntry entry, Type resourceType) | ||
{ | ||
ResourceId id; | ||
|
||
if (entry.NameType == NameType.ID) | ||
{ | ||
id = entry.GetId(); | ||
} | ||
else | ||
{ | ||
id = await entry.GetNameAsync().ConfigureAwait(false); | ||
} | ||
|
||
var ctors = resourceType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); | ||
var ctor = ctors.First(); | ||
var resource = (Resource)ctor.Invoke(new object[] { image, type, entry, id }); | ||
|
||
return resource; | ||
} | ||
|
||
#endregion | ||
|
||
#region Methods | ||
|
||
public override string ToString() | ||
{ | ||
if (!Id.IsNumeric) | ||
return Id.Name; | ||
|
||
return $"#{Id}"; | ||
} | ||
|
||
public ResourceData GetData(uint language = DefaultLanguage) | ||
{ | ||
return GetDataAsync(language).GetAwaiter().GetResult(); | ||
} | ||
|
||
public async Task<ResourceData> GetDataAsync(uint language = DefaultLanguage) | ||
{ | ||
if (!_languages.ContainsKey(language)) | ||
return null; | ||
|
||
var languageEntry = _languages[language]; | ||
var entry = await languageEntry.GetDataEntryAsync().ConfigureAwait(false); | ||
var data = entry.GetData(); | ||
|
||
return data; | ||
} | ||
|
||
public byte[] GetBytes() | ||
{ | ||
return GetBytes(DefaultLanguage); | ||
} | ||
|
||
public async Task<byte[]> GetBytesAsync() | ||
{ | ||
return await GetBytesAsync(DefaultLanguage); | ||
} | ||
|
||
public byte[] GetBytes(uint language) | ||
{ | ||
return GetBytesAsync(language).GetAwaiter().GetResult(); | ||
} | ||
|
||
public async Task<byte[]> GetBytesAsync(uint language) | ||
{ | ||
if (!_languages.ContainsKey(language)) | ||
throw new PortableExecutableImageException(_image, $"Cannot find specified language: {language}"); | ||
|
||
var data = await GetDataAsync(language).ConfigureAwait(false); | ||
|
||
if (data == null) | ||
throw new PortableExecutableImageException(_image, $"Cannot find resource data for language: {language}"); | ||
|
||
return await data.GetBytesAsync().ConfigureAwait(false); | ||
} | ||
|
||
public void CopyTo(Stream stream, uint language = DefaultLanguage) | ||
{ | ||
CopyToAsync(stream, language).GetAwaiter().GetResult(); | ||
} | ||
|
||
public async Task CopyToAsync(Stream stream, uint language = DefaultLanguage) | ||
{ | ||
var data = await GetDataAsync(language).ConfigureAwait(false); | ||
|
||
await data.CopyToAsync(stream).ConfigureAwait(false); | ||
} | ||
|
||
private Dictionary<uint, ResourceDirectoryEntry> BuildLanguages(ResourceDirectoryEntry parentEntry) | ||
{ | ||
var results = new Dictionary<uint, ResourceDirectoryEntry>(); | ||
var directory = parentEntry.GetDirectory(); | ||
|
||
foreach (var entry in directory) | ||
results.Add(entry.GetId(),entry); | ||
|
||
return results; | ||
} | ||
|
||
#endregion | ||
|
||
#region Properties | ||
|
||
public ResourceType Type { get; } | ||
public ResourceDirectoryEntry Entry { get; } | ||
public ResourceId Id { get; } | ||
public uint[] Languages { get; } | ||
|
||
#endregion | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Text; | ||
|
||
namespace Workshell.PE.Content | ||
{ | ||
public struct ResourceId : IEquatable<ResourceId> | ||
{ | ||
public ResourceId(uint resourceId) | ||
{ | ||
Id = resourceId; | ||
Name = resourceId.ToString(); | ||
} | ||
|
||
public ResourceId(string resourceName) | ||
{ | ||
Id = 0; | ||
Name = resourceName; | ||
} | ||
|
||
public ResourceId(uint resourceId, string resourceName) | ||
{ | ||
Id = resourceId; | ||
Name = resourceName; | ||
} | ||
|
||
#region Operators | ||
|
||
public static implicit operator ResourceId(short resourceId) | ||
{ | ||
return new ResourceId(Convert.ToUInt32(resourceId)); | ||
} | ||
|
||
public static implicit operator ResourceId(int resourceId) | ||
{ | ||
return new ResourceId(Convert.ToUInt32(resourceId)); | ||
} | ||
|
||
public static implicit operator ResourceId(long resourceId) | ||
{ | ||
return new ResourceId(Convert.ToUInt32(resourceId)); | ||
} | ||
|
||
public static implicit operator ResourceId(ushort resourceId) | ||
{ | ||
return new ResourceId(resourceId); | ||
} | ||
|
||
public static implicit operator ResourceId(uint resourceId) | ||
{ | ||
return new ResourceId(resourceId); | ||
} | ||
|
||
public static implicit operator ResourceId(ulong resourceId) | ||
{ | ||
return new ResourceId(Convert.ToUInt32(resourceId)); | ||
} | ||
|
||
public static implicit operator ResourceId(string resourceName) | ||
{ | ||
return new ResourceId(resourceName); | ||
} | ||
|
||
public static implicit operator short(ResourceId resourceId) | ||
{ | ||
return Convert.ToInt16(resourceId.Id); | ||
} | ||
|
||
public static implicit operator int(ResourceId resourceId) | ||
{ | ||
return Convert.ToInt32(resourceId.Id); | ||
} | ||
|
||
public static implicit operator long(ResourceId resourceId) | ||
{ | ||
return resourceId.Id; | ||
} | ||
|
||
public static implicit operator ushort(ResourceId resourceId) | ||
{ | ||
return Convert.ToUInt16(resourceId.Id); | ||
} | ||
|
||
public static implicit operator uint(ResourceId resourceId) | ||
{ | ||
return resourceId.Id; | ||
} | ||
|
||
public static implicit operator ulong(ResourceId resourceId) | ||
{ | ||
return resourceId.Id; | ||
} | ||
|
||
public static implicit operator string(ResourceId resourceId) | ||
{ | ||
return (resourceId.Id > 0 ? resourceId.Id.ToString() : resourceId.Name); | ||
} | ||
|
||
public static bool operator ==(ResourceId firstId, ResourceId secondId) | ||
{ | ||
return firstId.Equals(secondId); | ||
} | ||
|
||
public static bool operator !=(ResourceId firstId, ResourceId secondId) | ||
{ | ||
return !(firstId == secondId); | ||
} | ||
|
||
public static bool operator ==(ResourceId firstId, short secondId) | ||
{ | ||
return (firstId.Id == Convert.ToUInt32(secondId)); | ||
} | ||
|
||
public static bool operator !=(ResourceId firstId, short secondId) | ||
{ | ||
return !(firstId == secondId); | ||
} | ||
|
||
public static bool operator ==(ResourceId firstId, ushort secondId) | ||
{ | ||
return (firstId.Id == Convert.ToUInt32(secondId)); | ||
} | ||
|
||
public static bool operator !=(ResourceId firstId, ushort secondId) | ||
{ | ||
return !(firstId == secondId); | ||
} | ||
|
||
public static bool operator ==(ResourceId firstId, int secondId) | ||
{ | ||
return (firstId.Id == Convert.ToUInt32(secondId)); | ||
} | ||
|
||
public static bool operator !=(ResourceId firstId, int secondId) | ||
{ | ||
return !(firstId == secondId); | ||
} | ||
|
||
public static bool operator ==(ResourceId firstId, uint secondId) | ||
{ | ||
return (firstId.Id == secondId); | ||
} | ||
|
||
public static bool operator !=(ResourceId firstId, uint secondId) | ||
{ | ||
return !(firstId == secondId); | ||
} | ||
|
||
public static bool operator ==(ResourceId firstId, long secondId) | ||
{ | ||
return (firstId.Id == Convert.ToUInt32(secondId)); | ||
} | ||
|
||
public static bool operator !=(ResourceId firstId, long secondId) | ||
{ | ||
return !(firstId == secondId); | ||
} | ||
|
||
public static bool operator ==(ResourceId firstId, ulong secondId) | ||
{ | ||
return (firstId.Id == Convert.ToUInt32(secondId)); | ||
} | ||
|
||
public static bool operator !=(ResourceId firstId, ulong secondId) | ||
{ | ||
return !(firstId == secondId); | ||
} | ||
|
||
public static bool operator ==(ResourceId firstId, string secondId) | ||
{ | ||
return (String.Compare(firstId.Name, secondId, true) == 0); | ||
} | ||
|
||
public static bool operator !=(ResourceId firstId, string secondId) | ||
{ | ||
return !(firstId == secondId); | ||
} | ||
|
||
public static bool operator ==(string firstId, ResourceId secondId) | ||
{ | ||
return (string.Compare(firstId, secondId.Name, StringComparison.OrdinalIgnoreCase) == 0); | ||
} | ||
|
||
public static bool operator !=(string firstId, ResourceId secondId) | ||
{ | ||
return !(firstId == secondId); | ||
} | ||
|
||
#endregion | ||
|
||
#region Methods | ||
|
||
public override string ToString() | ||
{ | ||
if (IsEmpty) | ||
return "(Empty)"; | ||
|
||
return Name; | ||
} | ||
|
||
public override int GetHashCode() | ||
{ | ||
var hash = 13; | ||
|
||
hash = (hash * 7) + Id.GetHashCode(); | ||
hash = (hash * 7) + Name.GetHashCode(); | ||
|
||
return hash; | ||
} | ||
|
||
public override bool Equals(object obj) | ||
{ | ||
if (ReferenceEquals(obj, null)) | ||
return false; | ||
|
||
if (!(obj is ResourceId)) | ||
return false; | ||
|
||
if (ReferenceEquals(obj, this)) | ||
return true; | ||
|
||
return Equals((ResourceId)obj); | ||
} | ||
|
||
public bool Equals(ResourceId resourceId) | ||
{ | ||
return (Id == resourceId.Id && string.Compare(Name, resourceId.Name, StringComparison.OrdinalIgnoreCase) == 0); | ||
} | ||
|
||
#endregion | ||
|
||
#region Properties | ||
|
||
public uint Id { get; } | ||
public string Name { get; } | ||
public bool IsNumeric => (Id != 0); | ||
public bool IsEmpty => (Id == 0 && string.IsNullOrWhiteSpace(Name)); | ||
|
||
#endregion | ||
} | ||
} |
Oops, something went wrong.