Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ csharp_style_inlined_variable_declaration = true:suggestion
csharp_style_throw_expression = false:none
csharp_style_conditional_delegate_call = true:suggestion

csharp_style_namespace_declarations = file_scoped:warning

# utf8 strings only clarify if it really is a string. in the case of binary data, it only obfuscates things.
csharp_style_prefer_utf8_string_literals = false:none

Expand Down
191 changes: 95 additions & 96 deletions src/MethodCheck.Core/BinaryProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,138 +2,137 @@
using System;
using System.Collections.Generic;

namespace MethodCheck.Core
namespace MethodCheck.Core;

public static class BinaryProcessor
{
public static class BinaryProcessor
public static byte[]? Parse(ReadOnlySpan<char> text)
{
public static byte[]? Parse(ReadOnlySpan<char> text)
var index = 0;
var buffer = new List<byte>();
var halfByte = false;
var readingComment = false;
byte tmp = 0;

while (index < text.Length)
{
var index = 0;
var buffer = new List<byte>();
var halfByte = false;
var readingComment = false;
byte tmp = 0;
var c = text[index++];
byte x;

while (index < text.Length)
if (c == '\r' || c == '\n')
{
var c = text[index++];
byte x;
readingComment = false;
continue;
}

if (c == '\r' || c == '\n')
{
readingComment = false;
continue;
}
if (char.IsWhiteSpace(c) || readingComment)
{
continue;
}

if (char.IsWhiteSpace(c) || readingComment)
{
continue;
}
if ((uint)(c - '0') <= 9)
{
x = unchecked((byte)(c - '0'));
}
else
{
c |= '\x20';

if ((uint)(c - '0') <= 9)
if ((uint)(c - 'a') <= 5)
{
x = unchecked((byte)(c - '0'));
x = unchecked((byte)(c - 'a' + 10));
}
else
else if (c == '/' && index < text.Length && text[index] == '/')
{
c |= '\x20';

if ((uint)(c - 'a') <= 5)
{
x = unchecked((byte)(c - 'a' + 10));
}
else if (c == '/' && index < text.Length && text[index] == '/')
{
readingComment = true;
index++;
continue;
}
else
{
return null;
}
}

if (halfByte)
{
buffer.Add(unchecked((byte)(tmp | x)));
halfByte = false;
readingComment = true;
index++;
continue;
}
else
{
tmp = unchecked((byte)(x << 4));
halfByte = true;
return null;
}
}

if (halfByte)
{
buffer.Add(tmp);
buffer.Add(unchecked((byte)(tmp | x)));
halfByte = false;
}
else
{
tmp = unchecked((byte)(x << 4));
halfByte = true;
}
}

return buffer.ToArray();
if (halfByte)
{
buffer.Add(tmp);
}

public static string Format(ReadOnlySpan<byte> blob)
return buffer.ToArray();
}

public static string Format(ReadOnlySpan<byte> blob)
{
if (blob.Length == 0)
{
if (blob.Length == 0)
{
return string.Empty;
}
return string.Empty;
}

// 2 characters per byte +
// one separator character per byte after the first +
// one additional separator character every 4 bytes after the first.
//
// After every 16 bytes, the separator will be a newline, otherwise it will be spaces.
var length = 2 + (((blob.Length - 1) * 13) >> 2);
// 2 characters per byte +
// one separator character per byte after the first +
// one additional separator character every 4 bytes after the first.
//
// After every 16 bytes, the separator will be a newline, otherwise it will be spaces.
var length = 2 + (((blob.Length - 1) * 13) >> 2);

if (Environment.NewLine.Length != 2)
{
// We calculated length based on Environment.NewLine being 2 characters.
// We need to adjust if it wasn't for some reason.
length += (Environment.NewLine.Length - 2) * ((blob.Length - 1) >> 4);
}
if (Environment.NewLine.Length != 2)
{
// We calculated length based on Environment.NewLine being 2 characters.
// We need to adjust if it wasn't for some reason.
length += (Environment.NewLine.Length - 2) * ((blob.Length - 1) >> 4);
}

return string.Create(
length,
blob,
static (target, blob) =>
{
var write = 0;
var nl = Environment.NewLine.AsSpan();
return string.Create(
length,
blob,
static (target, blob) =>
{
var write = 0;
var nl = Environment.NewLine.AsSpan();

WriteByte(target.Slice(write), blob[0]);
write += 2;
WriteByte(target.Slice(write), blob[0]);
write += 2;

for (var i = 1; i < blob.Length; i++)
for (var i = 1; i < blob.Length; i++)
{
if ((i & 0xF) == 0)
{
if ((i & 0xF) == 0)
{
nl.CopyTo(target.Slice(write));
write += nl.Length;
}
else
nl.CopyTo(target.Slice(write));
write += nl.Length;
}
else
{
if ((i & 0x3) == 0)
{
if ((i & 0x3) == 0)
{
target[write++] = ' ';
}

target[write++] = ' ';
}

WriteByte(target.Slice(write), blob[i]);
write += 2;
target[write++] = ' ';
}
});

static void WriteByte(Span<char> target, byte b)
{
const string Alphabet = "0123456789ABCDEF";
target[0] = Alphabet[b >> 4];
target[1] = Alphabet[b & 0xF];
}
WriteByte(target.Slice(write), blob[i]);
write += 2;
}
});

static void WriteByte(Span<char> target, byte b)
{
const string Alphabet = "0123456789ABCDEF";
target[0] = Alphabet[b >> 4];
target[1] = Alphabet[b & 0xF];
}
}
}
23 changes: 11 additions & 12 deletions src/MethodCheck.Core/Data/ExceptionHandler.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
// Copyright (c) Brian Reichle. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information.
using System.Reflection;

namespace MethodCheck.Core.Data
namespace MethodCheck.Core.Data;

public sealed class ExceptionHandler(
ExceptionHandlingClauseOptions type,
ILRange tryRange,
ILRange handlerRange,
int filterOrType)
{
public sealed class ExceptionHandler(
ExceptionHandlingClauseOptions type,
ILRange tryRange,
ILRange handlerRange,
int filterOrType)
{
public ExceptionHandlingClauseOptions Type { get; } = type;
public ILRange TryRange { get; } = tryRange;
public ILRange HandlerRange { get; } = handlerRange;
public int FilterOrType { get; } = filterOrType;
}
public ExceptionHandlingClauseOptions Type { get; } = type;
public ILRange TryRange { get; } = tryRange;
public ILRange HandlerRange { get; } = handlerRange;
public int FilterOrType { get; } = filterOrType;
}
55 changes: 27 additions & 28 deletions src/MethodCheck.Core/Data/Instruction.cs
Original file line number Diff line number Diff line change
@@ -1,41 +1,40 @@
// Copyright (c) Brian Reichle. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information.
using System.Reflection.Emit;

namespace MethodCheck.Core.Data
namespace MethodCheck.Core.Data;

public sealed class Instruction
{
public sealed class Instruction
public const int MaxMnemonicLength = 14;

public Instruction(ILRange range, OpCode opcode, object? argument)
{
public const int MaxMnemonicLength = 14;
Kind = InstructionKind.OpCode;
Range = range;
OpCode = opcode;
Argument = argument;
}

public Instruction(ILRange range, OpCode opcode, object? argument)
{
Kind = InstructionKind.OpCode;
Range = range;
OpCode = opcode;
Argument = argument;
}
public Instruction(ILRange range)
{
Kind = InstructionKind.Invalid;
Range = range;
}

public InstructionKind Kind { get; }
public ILRange Range { get; }
public OpCode OpCode { get; }
public object? Argument { get; }

public Instruction(ILRange range)
public override string ToString()
{
if (Argument == null)
{
Kind = InstructionKind.Invalid;
Range = range;
return Range.Offset + ": " + OpCode.Name;
}

public InstructionKind Kind { get; }
public ILRange Range { get; }
public OpCode OpCode { get; }
public object? Argument { get; }

public override string ToString()
else
{
if (Argument == null)
{
return Range.Offset + ": " + OpCode.Name;
}
else
{
return Range.Offset + ": " + OpCode.Name + " " + Argument;
}
return Range.Offset + ": " + OpCode.Name + " " + Argument;
}
}
}
11 changes: 5 additions & 6 deletions src/MethodCheck.Core/Data/InstructionKind.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
// Copyright (c) Brian Reichle. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information.
namespace MethodCheck.Core.Data
namespace MethodCheck.Core.Data;

public enum InstructionKind
{
public enum InstructionKind
{
Invalid,
OpCode,
}
Invalid,
OpCode,
}
31 changes: 15 additions & 16 deletions src/MethodCheck.Core/Data/MethodData.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
// Copyright (c) Brian Reichle. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information.
using System.Collections.Immutable;

namespace MethodCheck.Core.Data
namespace MethodCheck.Core.Data;

public sealed class MethodData(
MetadataToken localsToken,
int maxStack,
int codeSize,
MethodDataFlags flags,
ImmutableArray<Instruction> instructions,
ImmutableArray<MethodDataSection> dataSections)
{
public sealed class MethodData(
MetadataToken localsToken,
int maxStack,
int codeSize,
MethodDataFlags flags,
ImmutableArray<Instruction> instructions,
ImmutableArray<MethodDataSection> dataSections)
{
public MetadataToken LocalsToken { get; } = localsToken;
public int MaxStack { get; } = maxStack;
public int CodeSize { get; } = codeSize;
public MethodDataFlags Flags { get; } = flags;
public ImmutableArray<Instruction> Instructions { get; } = instructions;
public ImmutableArray<MethodDataSection> DataSections { get; } = dataSections;
}
public MetadataToken LocalsToken { get; } = localsToken;
public int MaxStack { get; } = maxStack;
public int CodeSize { get; } = codeSize;
public MethodDataFlags Flags { get; } = flags;
public ImmutableArray<Instruction> Instructions { get; } = instructions;
public ImmutableArray<MethodDataSection> DataSections { get; } = dataSections;
}
Loading