summary refs log tree commit diff
path: root/LibGit/Extensions
diff options
context:
space:
mode:
authorTheArcaneBrony <myrainbowdash949@gmail.com>2023-06-05 03:25:53 +0200
committerTheArcaneBrony <myrainbowdash949@gmail.com>2023-06-05 03:25:53 +0200
commit51d820e22a4517dbb06d38a4f07f7c48522ef811 (patch)
tree4a7749cf77223dff2414fd4b73cb17df43d7449e /LibGit/Extensions
downloadGitTools-51d820e22a4517dbb06d38a4f07f7c48522ef811.tar.xz
Initial commit HEAD master
Diffstat (limited to 'LibGit/Extensions')
-rw-r--r--LibGit/Extensions/DictionaryExtensions.cs15
-rw-r--r--LibGit/Extensions/HttpClientExtensions.cs19
-rw-r--r--LibGit/Extensions/IEnumerableExtensions.cs45
-rw-r--r--LibGit/Extensions/JsonElementExtensions.cs22
-rw-r--r--LibGit/Extensions/ObjectExtensions.cs15
-rw-r--r--LibGit/Extensions/QueueExtensions.cs26
-rw-r--r--LibGit/Extensions/StreamExtensions.cs211
-rw-r--r--LibGit/Extensions/StringExtensions.cs8
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