diff options
author | TheArcaneBrony <myrainbowdash949@gmail.com> | 2023-06-05 03:25:53 +0200 |
---|---|---|
committer | TheArcaneBrony <myrainbowdash949@gmail.com> | 2023-06-05 03:25:53 +0200 |
commit | 51d820e22a4517dbb06d38a4f07f7c48522ef811 (patch) | |
tree | 4a7749cf77223dff2414fd4b73cb17df43d7449e /LibGit/Extensions | |
download | GitTools-51d820e22a4517dbb06d38a4f07f7c48522ef811.tar.xz |
Diffstat (limited to 'LibGit/Extensions')
-rw-r--r-- | LibGit/Extensions/DictionaryExtensions.cs | 15 | ||||
-rw-r--r-- | LibGit/Extensions/HttpClientExtensions.cs | 19 | ||||
-rw-r--r-- | LibGit/Extensions/IEnumerableExtensions.cs | 45 | ||||
-rw-r--r-- | LibGit/Extensions/JsonElementExtensions.cs | 22 | ||||
-rw-r--r-- | LibGit/Extensions/ObjectExtensions.cs | 15 | ||||
-rw-r--r-- | LibGit/Extensions/QueueExtensions.cs | 26 | ||||
-rw-r--r-- | LibGit/Extensions/StreamExtensions.cs | 211 | ||||
-rw-r--r-- | LibGit/Extensions/StringExtensions.cs | 8 |
8 files changed, 361 insertions, 0 deletions
diff --git a/LibGit/Extensions/DictionaryExtensions.cs b/LibGit/Extensions/DictionaryExtensions.cs new file mode 100644 index 0000000..0e6df06 --- /dev/null +++ b/LibGit/Extensions/DictionaryExtensions.cs @@ -0,0 +1,15 @@ +namespace LibGit.Extensions; + +public static class DictionaryExtensions +{ + public static bool ChangeKey<TKey, TValue>(this IDictionary<TKey, TValue> dict, + TKey oldKey, TKey newKey) + { + TValue value; + if (!dict.Remove(oldKey, out value)) + return false; + + dict[newKey] = value; // or dict.Add(newKey, value) depending on ur comfort + return true; + } +} \ No newline at end of file diff --git a/LibGit/Extensions/HttpClientExtensions.cs b/LibGit/Extensions/HttpClientExtensions.cs new file mode 100644 index 0000000..79e3e5f --- /dev/null +++ b/LibGit/Extensions/HttpClientExtensions.cs @@ -0,0 +1,19 @@ +namespace LibGit.Extensions; + +public static class HttpClientExtensions +{ + public static async Task<bool> CheckSuccessStatus(this HttpClient hc, string url) + { + //cors causes failure, try to catch + try + { + var resp = await hc.GetAsync(url); + return resp.IsSuccessStatusCode; + } + catch (Exception e) + { + Console.WriteLine($"Failed to check success status: {e.Message}"); + return false; + } + } +} \ No newline at end of file diff --git a/LibGit/Extensions/IEnumerableExtensions.cs b/LibGit/Extensions/IEnumerableExtensions.cs new file mode 100644 index 0000000..d8fc54d --- /dev/null +++ b/LibGit/Extensions/IEnumerableExtensions.cs @@ -0,0 +1,45 @@ +using System.IO.Compression; +using System.Text; + +namespace LibGit.Extensions; + +public static class IEnumerableExtensions +{ + public static bool StartsWith<T>(this IEnumerable<T> list, IEnumerable<T> prefix) + { + return prefix.SequenceEqual(list.Take(prefix.Count())); + } + + public static void HexDump(this IEnumerable<byte> bytes, int width = 32) + { + var data = new Queue<(string hex, char utf8)>(bytes.ToArray().Select(x => ($"{x:X2}", (char)x)).ToArray()); + while (data.Count > 0) + { + var line = data.Dequeue(Math.Min(width, data.Count)).ToArray(); + Console.WriteLine( + string.Join(" ", line.Select(x => x.hex)).PadRight(width * 3) + + " | " + + string.Join("", line.Select(x => x.utf8)) + .Replace('\n', '.') + .Replace('\r', '.') + .Replace('\0', '.') + ); + } + } + + public static string AsHexString(this IEnumerable<byte> bytes) => string.Join(' ', bytes.Select(x => $"{x:X2}")); + public static string AsString(this IEnumerable<byte> bytes) => Encoding.UTF8.GetString(bytes.ToArray()); + + + //zlib decompress + public static byte[] ZlibDecompress(this IEnumerable<byte> bytes) + { + var inStream = new MemoryStream(bytes.ToArray()); + using ZLibStream stream = new ZLibStream(inStream, CompressionMode.Decompress); + using var result = new MemoryStream(); + stream.CopyTo(result); + stream.Flush(); + stream.Close(); + return result.ToArray(); + } +} \ No newline at end of file diff --git a/LibGit/Extensions/JsonElementExtensions.cs b/LibGit/Extensions/JsonElementExtensions.cs new file mode 100644 index 0000000..dd97013 --- /dev/null +++ b/LibGit/Extensions/JsonElementExtensions.cs @@ -0,0 +1,22 @@ +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace LibGit.Extensions; + +public static class JsonElementExtensions +{ + public static void FindExtraJsonFields([DisallowNull] this JsonElement? res, Type t) + { + var props = t.GetProperties(); + var unknownPropertyFound = false; + foreach (var field in res.Value.EnumerateObject()) + { + if (props.Any(x => x.GetCustomAttribute<JsonPropertyNameAttribute>()?.Name == field.Name)) continue; + Console.WriteLine($"[!!] Unknown property {field.Name} in {t.Name}!"); + unknownPropertyFound = true; + } + if(unknownPropertyFound) Console.WriteLine(res.Value.ToJson()); + } +} \ No newline at end of file diff --git a/LibGit/Extensions/ObjectExtensions.cs b/LibGit/Extensions/ObjectExtensions.cs new file mode 100644 index 0000000..2cdeccd --- /dev/null +++ b/LibGit/Extensions/ObjectExtensions.cs @@ -0,0 +1,15 @@ +using System.Text.Json; + +namespace LibGit.Extensions; + +public static class ObjectExtensions +{ + public static string ToJson(this object obj, bool indent = true, bool ignoreNull = false, bool unsafeContent = false) + { + var jso = new JsonSerializerOptions(); + if(indent) jso.WriteIndented = true; + if(ignoreNull) jso.IgnoreNullValues = true; + if(unsafeContent) jso.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping; + return JsonSerializer.Serialize(obj, jso); + } +} \ No newline at end of file diff --git a/LibGit/Extensions/QueueExtensions.cs b/LibGit/Extensions/QueueExtensions.cs new file mode 100644 index 0000000..45b8093 --- /dev/null +++ b/LibGit/Extensions/QueueExtensions.cs @@ -0,0 +1,26 @@ +namespace LibGit.Extensions; + +public static class QueueExtensions +{ +public static IEnumerable<T> Dequeue<T>(this Queue<T> queue, int count) +{ + for (int i = 0; i < count; i++) + { + yield return queue.Dequeue(); + } +} + public static IEnumerable<T> Peek<T>(this Queue<T> queue, int count) + { + for (int i = 0; i < count; i++) + { + yield return queue.ElementAt(i); + } + } + public static void Drop<T>(this Queue<T> queue, int count) + { + for (int i = 0; i < count; i++) + { + queue.Dequeue(); + } + } +} \ No newline at end of file diff --git a/LibGit/Extensions/StreamExtensions.cs b/LibGit/Extensions/StreamExtensions.cs new file mode 100644 index 0000000..6555783 --- /dev/null +++ b/LibGit/Extensions/StreamExtensions.cs @@ -0,0 +1,211 @@ +using System.IO.Compression; + +namespace LibGit.Extensions; + +public static class StreamExtensions +{ + private const bool _debug = false; + + public static long Remaining(this Stream stream) + { + //if (_debug) Console.WriteLine($"stream pos: {stream.Position}, stream len: {stream.Length}, stream rem: {stream.Length - stream.Position}"); + return stream.Length - stream.Position; + } + + public static int Peek(this Stream stream) + { + if (!stream.CanRead) + throw new InvalidOperationException("Can't peek a non-readable stream"); + if (!stream.CanSeek) + throw new InvalidOperationException("Can't peek a non-seekable stream"); + + int peek = stream.ReadByte(); + if (peek != -1) + stream.Seek(-1, SeekOrigin.Current); + + return peek; + } + + public static IEnumerable<byte> Peek(this Stream stream, long count) + { + if (!stream.CanRead) + throw new InvalidOperationException("Can't peek a non-readable stream"); + if (!stream.CanSeek) + throw new InvalidOperationException("Can't peek a non-seekable stream"); + long i; + for (i = 0; i < count; i++) + { + int peek = stream.ReadByte(); + if (peek == -1) + { + if(_debug) Console.WriteLine($"Can't peek {count} bytes, only {i} bytes remaining"); + stream.Seek(-i, SeekOrigin.Current); + yield break; + } + + yield return (byte)peek; + } + stream.Seek(-i, SeekOrigin.Current); + } + + public static IEnumerable<byte> ReadBytes(this Stream stream, long count) + { + if (!stream.CanRead) + throw new InvalidOperationException("Can't read a non-readable stream"); + if (!stream.CanSeek) + throw new InvalidOperationException("Can't read a non-seekable stream"); + + for (long i = 0; i < count; i++) + { + int read = stream.ReadByte(); + if (read == -1) + yield break; + yield return (byte)read; + } + } + + public static bool StartsWith(this Stream stream, IEnumerable<byte> sequence) + { + if (!stream.CanRead) + throw new InvalidOperationException("Can't read a non-readable stream"); + if (!stream.CanSeek) + throw new InvalidOperationException("Can't read a non-seekable stream"); + + if (_debug) + { + Console.WriteLine($"Expected: {sequence.AsHexString()} ({sequence.AsString()})"); + Console.WriteLine($"Actual: {stream.Peek(sequence.Count()).AsHexString()} ({stream.Peek(sequence.Count()).AsString()})"); + } + + int readCount = 0; + foreach (int b in sequence) + { + int read = stream.ReadByte(); + readCount++; + if (read == -1) + { + stream.Seek(-readCount, SeekOrigin.Current); + return false; + } + + if (read != b) + { + if (_debug) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("^^".PadLeft(readCount * 3 + 9)); + Console.ResetColor(); + } + + stream.Seek(-readCount, SeekOrigin.Current); + return false; + } + } + stream.Seek(-readCount, SeekOrigin.Current); + + return true; + } + + public static bool StartsWith(this Stream stream, string ascii_seq) + { + return stream.StartsWith(ascii_seq.Select(x => (byte)x)); + } + + public static Stream Skip(this Stream stream, long count = 1) + { + if (!stream.CanSeek) + throw new InvalidOperationException("Can't skip a non-seekable stream"); + stream.Seek(count, SeekOrigin.Current); + return stream; + } + + public static IEnumerable<byte> ReadNullTerminatedField(this Stream stream, IEnumerable<byte>? binaryPrefix = null, string? asciiPrefix = null) => ReadTerminatedField(stream: stream, terminator: 0x00, binaryPrefix: binaryPrefix, asciiPrefix: asciiPrefix); + public static IEnumerable<byte> ReadSpaceTerminatedField(this Stream stream, IEnumerable<byte>? binaryPrefix = null, string? asciiPrefix = null) => ReadTerminatedField(stream: stream, terminator: 0x20, binaryPrefix: binaryPrefix, asciiPrefix: asciiPrefix); + public static IEnumerable<byte> ReadTerminatedField(this Stream stream, byte terminator, IEnumerable<byte>? binaryPrefix = null, string? asciiPrefix = null) + { + if (!stream.CanRead) + throw new InvalidOperationException("Can't read a non-readable stream"); + if (binaryPrefix != null) + if (!stream.StartsWith(binaryPrefix)) + throw new InvalidDataException($"Binary prefix {stream.Peek(binaryPrefix.Count()).AsHexString()} does not match expected value of {binaryPrefix.AsHexString()}!"); + else stream.Skip(binaryPrefix.Count()); + else if (asciiPrefix != null) + if (!stream.StartsWith(asciiPrefix)) + throw new InvalidDataException($"Text prefix {stream.Peek(asciiPrefix.Length).AsHexString()} ({stream.Peek(asciiPrefix.Length).AsString()}) does not match expected value of {asciiPrefix.AsBytes().AsHexString()} ({asciiPrefix})!"); + else stream.Skip(asciiPrefix.Length); + + var read = 0; + while (stream.Peek() != terminator) + { + if (_debug) Console.WriteLine($"ReadTerminatedField -- pos: {stream.Position}/+{stream.Remaining()}/{stream.Length} | next: {(char)stream.Peek()} | Length: {read}"); + if (stream.Peek() == -1) + { + Console.WriteLine($"Warning: Reached end of stream while reading null-terminated field"); + yield break; + } + + read++; + yield return (byte)stream.ReadByte(); + } + + if (stream.Peek() == terminator) stream.Skip(); + } + + public static IEnumerable<byte> ReadToEnd(this Stream stream) + { + if (!stream.CanRead) + throw new InvalidOperationException("Can't read a non-readable stream"); + + while (stream.Peek() != -1) + yield return (byte)stream.ReadByte(); + } + + public static int ReadInt32BE(this Stream stream) + { + if (!stream.CanRead) + throw new InvalidOperationException("Can't read a non-readable stream"); + + var bytes = stream.ReadBytes(4).ToArray(); + + if (BitConverter.IsLittleEndian) + Array.Reverse(bytes); + + Console.WriteLine("ReadInt32BE: " + bytes.AsHexString() + " => " + BitConverter.ToInt32(bytes)); + return BitConverter.ToInt32(bytes); + } + + //read variable length number + public static int ReadVLQ(this Stream stream) + { + if (!stream.CanRead) + throw new InvalidOperationException("Can't read a non-readable stream"); + + int result = 0; + int shift = 0; + byte b; + do + { + b = (byte)stream.ReadByte(); + result |= (b & 0b0111_1111) << shift; + shift += 7; + } while ((b & 0b1000_0000) != 0); + + return result; + } + public static int ReadVLQBigEndian(this Stream stream) + { + if (!stream.CanRead) + throw new InvalidOperationException("Can't read a non-readable stream"); + + int result = 0; + int shift = 0; + byte b; + do + { + b = (byte)stream.ReadByte(); + result = (result << 7) | (b & 0b0111_1111); + } while ((b & 0b1000_0000) != 0); + + return result; + } +} \ No newline at end of file diff --git a/LibGit/Extensions/StringExtensions.cs b/LibGit/Extensions/StringExtensions.cs new file mode 100644 index 0000000..f33bd4e --- /dev/null +++ b/LibGit/Extensions/StringExtensions.cs @@ -0,0 +1,8 @@ +using System.Text; + +namespace LibGit.Extensions; + +public static class StringExtensions +{ + public static IEnumerable<byte> AsBytes(this string str) => Encoding.UTF8.GetBytes(str); +} \ No newline at end of file |