Skip to content

Commit

Permalink
add base64 module
Browse files Browse the repository at this point in the history
  • Loading branch information
aarkegz committed Mar 6, 2018
1 parent 9e01971 commit a0bed84
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 21 deletions.
101 changes: 101 additions & 0 deletions GeminiLab.Core2/Base64Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace GeminiLab.Core2 {
public static class Base64Extensions {
public static string Base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

private static byte[] decodeTable = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
};

public static string ToBase64(this byte[] source) {
var tail = source.Length % 3;
var groups = source.Length / 3;
var outputLen = groups * 4 + (tail > 0 ? 4 : 0);

var sb = new StringBuilder(outputLen);

for (int i = 0; i < groups; ++i) {
int val = source[i * 3] << 16 | source[i * 3 + 1] << 8 | source[i * 3 + 2];

sb.Append(Base64Chars[(val >> 18)]);
sb.Append(Base64Chars[(val >> 12) & 0x3F]);
sb.Append(Base64Chars[(val >> 6) & 0x3F]);
sb.Append(Base64Chars[val & 0x3F]);
}

if (tail == 1) {
int val = source[source.Length - 1];
sb.Append(Base64Chars[val >> 2]);
sb.Append(Base64Chars[(val & 0x03) << 4]);
sb.Append("==");
} else if (tail == 2) {
int val = source[source.Length - 2] << 8 | source[source.Length - 1];
sb.Append(Base64Chars[val >> 10]);
sb.Append(Base64Chars[(val >> 4) & 0x3F]);
sb.Append(Base64Chars[(val & 0x0F) << 2]);
sb.Append("=");
}

return sb.ToString();
}

public static string ToBase64(this string source) => source.ToBase64(Encoding.UTF8);

public static string ToBase64(this string source, Encoding encoding) => encoding.GetBytes(source).ToBase64();

public static byte[] AsBase64(this string source) {
int len = source.Length;

if (len % 4 != 0) throw new ArgumentException(nameof(source));
if (len == 0) return new byte[0];

int sp = source[len - 1] == '=' ? (source[len - 2] == '=' ? 2 : 1) : 0;
int groups = len / 4;
int outputLen = groups * 3 - sp;

byte[] rv = new byte[outputLen];

for (int i = 0; i < groups; ++i) {
int val = 0;
for (int j = 0; j < 4; ++j) {
int chr;
if ((chr = source[i * 4 + j]) >= 0x80 || chr < 0 || decodeTable[chr] >= 0x40) throw new ArgumentException(nameof(source));

val = (val << 6) | decodeTable[chr];
}

if (i == groups - 1) {
byte[] v = { (byte)(val >> 16), (byte)((val >> 8) & 0xFF), (byte)(val & 0xFF) };

for (int j = 0; j < 3; ++j) {
if (j + sp >= 3) {
if (v[j] != 0) throw new ArgumentException(nameof(source));
} else {
rv[i * 3 + j] = v[j];
}
}
} else {
rv[i * 3] = (byte)(val >> 16);
rv[i * 3 + 1] = (byte)((val >> 8) & 0xFF);
rv[i * 3 + 2] = (byte)(val & 0xFF);
}
}

return rv;
}

public static string DecodeBase64EncodedString(this string source) => source.DecodeBase64EncodedString(Encoding.UTF8);

public static string DecodeBase64EncodedString(this string source, Encoding encoding) => encoding.GetString(source.AsBase64());
}
}
9 changes: 7 additions & 2 deletions GeminiLab.Core2/GeminiLab.Core2.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@
<Authors>Gemini Laboratory</Authors>
<Company>Gemini Laboratory</Company>
<Product>GeminiLab.Core2</Product>
<AssemblyVersion>0.9.0.0</AssemblyVersion>
<AssemblyVersion>0.9.2.0</AssemblyVersion>
<Copyright>Copyright © Gemini Laboratory 2017 - 2018</Copyright>
<FileVersion>0.9.0.0</FileVersion>
<FileVersion>0.9.2.0</FileVersion>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<Version>0.9.2</Version>
<PackageLicenseUrl>https://github.com/GeminiLab/GeminiLab.Core2/blob/master/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>https://github.com/GeminiLab/GeminiLab.Core2/</PackageProjectUrl>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
Expand Down
3 changes: 1 addition & 2 deletions GeminiLab.Core2/InfiniteEnumerable.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace GeminiLab.Core2 {
Expand Down Expand Up @@ -135,7 +134,7 @@ public T GetNext() {

public void Reset() {
_first = true;
_accumulator = default(T);
_accumulator = default;
_en = _source.GetEnumerator();
}

Expand Down
94 changes: 84 additions & 10 deletions GeminiLab.Core2/ML/Json/JsonObjects.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
Expand All @@ -7,7 +8,7 @@ public abstract class JsonValue {
internal abstract void Stringify(JsonStringifyConfig config, int indent, StringBuilder target);

internal static void MakeIndent(StringBuilder sb, int cnt) => sb.Append(' ', cnt * 4);

public sealed override string ToString() {
var sb = new StringBuilder();

Expand Down Expand Up @@ -39,19 +40,86 @@ public string ToStringForNetwork() {
}

public sealed class JsonObject : JsonValue {
public IEnumerable<JsonObjectKeyValuePair> Values { get; }
private struct JsonObjectKeyComparer : IComparer<string> {
public JsonObject Father;

public int Compare(string x, string y) {
int xv = Father._keyOrder.ContainsKey(x) ? Father._keyOrder[x] : -1;
int yv = Father._keyOrder.ContainsKey(y) ? Father._keyOrder[y] : -1;

return xv.CompareTo(yv);
}
}

private readonly Dictionary<string, int> _keyOrder;
private readonly SortedDictionary<string, JsonValue> _values;

public IEnumerable<JsonObjectKeyValuePair> Values {
get {
foreach (var i in _values) yield return new JsonObjectKeyValuePair(new JsonString(i.Key), i.Value);
}
}

public JsonValue this[JsonString str] {
get => this[str?.Value ?? throw new ArgumentNullException(nameof(str))];
set => this[str?.Value ?? throw new ArgumentNullException(nameof(str))] = value;
}

public JsonValue this[string str] {
get {
if (str == null) throw new ArgumentNullException(nameof(str));
if (!_values.ContainsKey(str)) throw new KeyNotFoundException();

return _values[str];
}
set {
if (str == null) throw new ArgumentNullException(nameof(str));
if (value == null) throw new ArgumentNullException(nameof(value));

if (!_values.ContainsKey(str)) {
_keyOrder[str] = _keyOrder.Count;
}

_values[str] = value;
}
}

public void Append(JsonString key, JsonValue value) {
if (key == null) throw new ArgumentNullException(nameof(key));
if (value == null) throw new ArgumentNullException(nameof(value));

if (_values.ContainsKey(key.Value)) throw new ArgumentOutOfRangeException(nameof(key));
this[key] = value;
}

public void Remove(JsonString key) {
if (key == null) throw new ArgumentNullException(nameof(key));

if (!_values.ContainsKey(key.Value)) throw new KeyNotFoundException();
_keyOrder[key.Value] = -1;
_values.Remove(key.Value);
}

public JsonObject() {
_keyOrder = new Dictionary<string, int>();
_values = new SortedDictionary<string, JsonValue>(new JsonObjectKeyComparer { Father = this });
}

// some (and clr) don't like tuples, make them happy
public JsonObject(IEnumerable<JsonObjectKeyValuePair> values) {
Values = values;
_keyOrder = new Dictionary<string, int>();
_values = new SortedDictionary<string, JsonValue>(new JsonObjectKeyComparer { Father = this });

foreach (var i in values) {
Append(i.Key, i.Value);
}
}

internal override void Stringify(JsonStringifyConfig config, int indent, StringBuilder target) {
if (!Values.Any()) {
target.Append("{}");
return;
}

bool compact = config.Contains(JsonStringifyConfig.Compact);
bool expandObjects = config.Contains(JsonStringifyConfig.ExpandObjects);

Expand All @@ -61,7 +129,7 @@ internal override void Stringify(JsonStringifyConfig config, int indent, StringB
string tail = compact ? "}" : " }";

target.Append(expandObjects ? "{\n" : head);

bool first = true;
foreach (var i in Values) {
if (!first) {
Expand All @@ -88,10 +156,14 @@ internal override void Stringify(JsonStringifyConfig config, int indent, StringB
}

public sealed class JsonArray : JsonValue {
public IEnumerable<JsonValue> Values { get; }
public List<JsonValue> Values { get; }

public JsonArray() {
Values = new List<JsonValue>();
}

public JsonArray(IEnumerable<JsonValue> values) {
Values = values;
Values = new List<JsonValue>(values);
}

internal override void Stringify(JsonStringifyConfig config, int indent, StringBuilder target) {
Expand Down Expand Up @@ -162,9 +234,11 @@ internal JsonNumber(string value) {
if (int.TryParse(value, out int vint)) {
IsFloat = false;
ValueInt = vint;
} else {
} else if (double.TryParse(value, out double vfloat)) {
IsFloat = true;
ValueFloat = double.Parse(value);
ValueFloat = vfloat;
} else {
throw new ArgumentOutOfRangeException(nameof(value));
}
}

Expand Down
9 changes: 2 additions & 7 deletions TestConsole/Program.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
using System;
using GeminiLab.Core2;
using GeminiLab.Core2.ML.Json;

namespace TestConsole {
class Program {
public static void Main(string[] args) {
var str = Console.In.ReadToEnd();

var jsonValue = JsonParser.Parse(str);
Console.WriteLine(jsonValue.ToString());
Console.WriteLine(jsonValue.ToStringMinimized());
Console.WriteLine(jsonValue.ToStringForNetwork());
Console.WriteLine(jsonValue.ToStringPrettified());
Console.WriteLine("6Iuf5Yip5Zu95a6255Sf5q275Lul".DecodeBase64EncodedString());
}
}
}

0 comments on commit a0bed84

Please sign in to comment.