Skip to content

Commit

Permalink
Finished porting the core Resources infrastructure.
Browse files Browse the repository at this point in the history
  • Loading branch information
Lloyd Kinsella committed Aug 9, 2018
1 parent d3f9e4a commit d3ad642
Show file tree
Hide file tree
Showing 5 changed files with 671 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/Workshell.PE.Testbed/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ static async Task RunAsync(string[] args)
var dataDirectory = image.NTHeaders.DataDirectories[DataDirectoryType.ResourceTable];
var content = await dataDirectory.GetContentAsync().ConfigureAwait(false);


var resources = await Resources.GetAsync(image);
}
}
}
142 changes: 142 additions & 0 deletions src/Workshell.PE/Content/Resources/Resource.cs
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
}
}
241 changes: 241 additions & 0 deletions src/Workshell.PE/Content/Resources/ResourceId.cs
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
}
}
Loading

0 comments on commit d3ad642

Please sign in to comment.