Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions CommonShims/BinaryWriterExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Buffers;

namespace CommonShims;

#if NETSTANDARD2_0
public static class BinaryWriterExtensions
{
public static void Write(this BinaryWriter writer, ReadOnlySpan<byte> buffer)
{
if (writer.GetType() == typeof(BinaryWriter))
{
writer.BaseStream.Write(buffer);
}
else
{
var array = ArrayPool<byte>.Shared.Rent(buffer.Length);
try
{
buffer.CopyTo(array);
writer.Write(array, 0, buffer.Length);
}
finally
{
ArrayPool<byte>.Shared.Return(array);
}
}
}
}
#endif
24 changes: 24 additions & 0 deletions CommonShims/CommonShims.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>Latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>embedded</DebugType>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>embedded</DebugType>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.Memory" Version="4.6.3" />
</ItemGroup>

</Project>
16 changes: 16 additions & 0 deletions CommonShims/DictionaryExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace CommonShims;

#if NETSTANDARD2_0
public static class DictionaryExtensions
{
public static bool TryAdd<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue value)
{
if (dictionary.ContainsKey(key))
return false;

dictionary.Add(key, value);

return true;
}
}
#endif
30 changes: 30 additions & 0 deletions CommonShims/EncodingExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Text;

namespace CommonShims;

#if NETSTANDARD2_0
public static class EncodingExtensions
{
public static string GetString(this Encoding encoding, ReadOnlySpan<byte> bytes)
{
if (bytes.Length == 0)
return string.Empty;

return encoding.GetString(bytes.ToArray(), 0, bytes.Length);
}

public static int GetChars(this Encoding encoding, ReadOnlySpan<byte> bytes, Span<char> chars)
{
if (bytes.Length == 0 || chars.Length == 0)
return 0;

var src = bytes.ToArray();
var dst = new char[chars.Length];

var written = encoding.GetChars(src, 0, src.Length, dst, 0);

dst.AsSpan(0, written).CopyTo(chars);
return written;
}
}
#endif
23 changes: 23 additions & 0 deletions CommonShims/SpanExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Runtime.InteropServices;

namespace CommonShims;

public static class SpanExtensions
{
#if NETSTANDARD2_0
public static unsafe string ToStringFast(this ReadOnlySpan<char> span)
{
if (span.Length == 0)
return string.Empty;

fixed (char* p = &MemoryMarshal.GetReference(span))
{
return new string(p, 0, span.Length);
}
}

#else
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string ToStringFast(this ReadOnlySpan<char> span) => new string(span);
#endif
}
40 changes: 40 additions & 0 deletions CommonShims/StreamExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.Buffers;

namespace CommonShims;

#if NETSTANDARD2_0
public static class StreamExtensions
{
public static int Read(this Stream stream, Span<byte> buffer)
{
var sharedBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length);
try
{
var numRead = stream.Read(sharedBuffer, 0, buffer.Length);
if ((uint)numRead > (uint)buffer.Length)
throw new IOException("IOStream is too long.");

new ReadOnlySpan<byte>(sharedBuffer, 0, numRead).CopyTo(buffer);
return numRead;
}
finally
{
ArrayPool<byte>.Shared.Return(sharedBuffer);
}
}

public static void Write(this Stream stream, ReadOnlySpan<byte> buffer)
{
var sharedBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length);
try
{
buffer.CopyTo(sharedBuffer);
stream.Write(sharedBuffer, 0, buffer.Length);
}
finally
{
ArrayPool<byte>.Shared.Return(sharedBuffer);
}
}
}
#endif
31 changes: 0 additions & 31 deletions Ico.Reader.sln

This file was deleted.

5 changes: 5 additions & 0 deletions Ico.Reader.slnx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Solution>
<Project Path="CommonShims/CommonShims.csproj" />
<Project Path="Ico.Reader/Ico.Reader.csproj" />
<Project Path="PeDecoder/PeDecoder.csproj" />
</Solution>
1 change: 1 addition & 0 deletions Ico.Reader/Creator/IPngCreator.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Ico.Reader.Data;

namespace Ico.Reader.Creator;

public interface IPngCreator
{
byte[] CreatePng(ReadOnlySpan<byte> rgba, BMP_Info_Header header);
Expand Down
25 changes: 13 additions & 12 deletions Ico.Reader/Creator/PngCreator.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
using Ico.Reader.Data;
using Ico.Reader.Extensions;
using System.IO.Compression;
using System.IO.Compression;
using System.Text;

using Ico.Reader.Data;
using Ico.Reader.Extensions;

namespace Ico.Reader.Creator;

public class PngCreator : IPngCreator
{
private const uint cInit = 0xffffffff;
private const string IDAT = "IDAT";
private const string IHDR = "IHDR";
private const string IEND = "IEND";

private static readonly byte[] _header = new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
private static readonly uint[] _crcTable = Enumerable.Range(0, 256).Select(n =>
private static readonly byte[] _header = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
private static readonly uint[] _crcTable = [.. Enumerable.Range(0, 256).Select(n =>
{
var c = (uint)n;
for (var k = 0; k < 8; k++)
c = (c & 1) == 1 ? 0xedb88320 ^ c >> 1 : c >> 1;
c = (c & 1) == 1 ? 0xedb88320 ^ (c >> 1) : c >> 1;

return c;
}).ToArray();

})];

public byte[] CreatePng(ReadOnlySpan<byte> rgba, BMP_Info_Header header)
{
Expand Down Expand Up @@ -58,7 +59,7 @@ private static void WriteIdatChunks(BinaryWriter writer, ReadOnlySpan<byte> rgba
var bytesPerRow = width * 4 + 1;
var uncompressedData = new byte[height * bytesPerRow];

for (int y = 0; y < height; y++)
for (var y = 0; y < height; y++)
{
uncompressedData[y * bytesPerRow] = 0;
rgba.Slice(y * width * 4, width * 4).CopyTo(uncompressedData.AsSpan(y * bytesPerRow + 1));
Expand All @@ -73,7 +74,7 @@ private static void WriteIdatChunks(BinaryWriter writer, ReadOnlySpan<byte> rgba
compressor.Flush();
compressor.Close();

uint adler = CalculateAdler32(uncompressedData);
var adler = CalculateAdler32(uncompressedData);
using var binaryWriter = new BinaryWriter(compressedDataStream);
binaryWriter.WriteUInt32BigEndian(adler);

Expand All @@ -100,9 +101,9 @@ private static void WriteChunk(BinaryWriter writer, string type, byte[] data)

public static uint CalculateCrc32(byte[] data)
{
uint crc = cInit;
var crc = cInit;
foreach (var b in data)
crc = _crcTable[(crc ^ b) & 0xff] ^ crc >> 8;
crc = _crcTable[(crc ^ b) & 0xff] ^ (crc >> 8);

return crc ^ cInit;
}
Expand Down
7 changes: 3 additions & 4 deletions Ico.Reader/Data/BMP_Info_Header.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,14 @@ public class BMP_Info_Header
/// <returns>The number of colors in the color palette.</returns>
public int CalculatePaletteSize()
{
int maxColors = 1 << BitCount;
int paletteColors = (ClrUsed == 0 || ClrUsed > maxColors) ? maxColors : ClrUsed;
var maxColors = 1 << BitCount;
var paletteColors = (ClrUsed == 0 || ClrUsed > maxColors) ? maxColors : ClrUsed;
return paletteColors;
}


/// <summary>
/// Calculates the offset to the beginning of bitmap data, taking into account the size of the header and the color palette.
/// </summary>
/// <returns>The offset to the bitmap data in bytes.</returns>
public int CalculateDataOffset() => Size + (1 << BitCount) * 4;
public int CalculateDataOffset() => Size + ((1 << BitCount) * 4);
}
18 changes: 10 additions & 8 deletions Ico.Reader/Data/CursorGroup.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
using System.Runtime.InteropServices;

using CommonShims;

using Ico.Reader.Utils;

namespace Ico.Reader.Data;
/// <summary>
/// Represents a collection of <see cref="CursorDirectoryEntry"/> within an CUR file.
Expand Down Expand Up @@ -33,7 +37,7 @@ IIcoDirectoryEntry[] IIcoGroup<IIcoDirectoryEntry>.DirectoryEntries
{
var cursorDirectoryEntries = new CursorDirectoryEntry[value.Length];

for (int i = 0; i < value.Length; i++)
for (var i = 0; i < value.Length; i++)
{
if (value[i] is CursorDirectoryEntry entry)
cursorDirectoryEntries[i] = entry;
Expand All @@ -49,27 +53,24 @@ IIcoDirectoryEntry[] IIcoGroup<IIcoDirectoryEntry>.DirectoryEntries

public override string ToString() => $"[{nameof(CursorGroup)}] {Name} ({Size})";


public CursorDirectoryEntry[] ReadEntriesFromEXEStream(Stream stream, IcoHeader icoHeader)
{
if (icoHeader.ImageType != CursorDirectoryEntry.ImageType)
{
throw new Exception("The ico data does not contain cursor data.");
}

var positionStart = stream.Position;

int byteSize = 14 * icoHeader.ImageCount;
var byteSize = 14 * icoHeader.ImageCount;
var entries = new CursorDirectoryEntry[icoHeader.ImageCount];

Span<byte> entriesBuffer = stackalloc byte[byteSize];
stream.Read(entriesBuffer);
ReadOnlySpan<byte> entriesBufferSpan = entriesBuffer;

for (int i = 0; i < icoHeader.ImageCount; i++)
for (var i = 0; i < icoHeader.ImageCount; i++)
{
var offset = i * 14;
ushort resourceID = MemoryMarshal.Read<ushort>(entriesBufferSpan.Slice(offset + 12, 2));
var resourceID = MemoryMarshal.Read<ushort>(entriesBufferSpan.Slice(offset + 12, 2));

entries[i] = new CursorDirectoryEntry()
{
Expand All @@ -88,5 +89,6 @@ public CursorDirectoryEntry[] ReadEntriesFromEXEStream(Stream stream, IcoHeader
return entries;
}

IIcoDirectoryEntry[] IIcoGroup<IIcoDirectoryEntry>.ReadEntriesFromEXEStream(Stream stream, IcoHeader icoHeader) => IIcoGroup.ReadFromEXEStream(stream, icoHeader);
IIcoDirectoryEntry[] IIcoGroup<IIcoDirectoryEntry>.ReadEntriesFromEXEStream(Stream stream, IcoHeader icoHeader)
=> IcoGroupUtils.ReadFromEXEStream(stream, icoHeader);
}
4 changes: 2 additions & 2 deletions Ico.Reader/Data/DecodedIcoResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ public sealed class DecodedIcoResult
/// <summary>
/// An array of image references, each pointing to an image extracted from the ico file.
/// </summary>
public List<ImageReference> References { get; set; } = new List<ImageReference>();
public List<ImageReference> References { get; set; } = [];
/// <summary>
/// An array of ico groups, categorizing the extracted images into groups based on certain criteria, such as resolution or color depth.
/// </summary>
public List<IIcoGroup> IcoGroups { get; set; } = new List<IIcoGroup>();
public List<IIcoGroup> IcoGroups { get; set; } = [];
}
Loading