766 lines
24 KiB
C#
Raw Normal View History

2023-11-21 23:05:03 +08:00
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
namespace CPF.Windows.Json.Deserialize
{
internal unsafe class JsonReader
{
#region pregenerated metas
internal static FieldInfo _Json =
typeof(JsonReader).GetField(nameof(Json), BindingFlags.NonPublic | BindingFlags.Instance);
internal static FieldInfo _Buffer =
typeof(JsonReader).GetField(nameof(Buffer), BindingFlags.NonPublic | BindingFlags.Instance);
internal static FieldInfo _Length =
typeof(JsonReader).GetField(nameof(Length), BindingFlags.NonPublic | BindingFlags.Instance);
internal static FieldInfo _Remaining =
typeof(JsonReader).GetField(nameof(Remaining), BindingFlags.NonPublic | BindingFlags.Instance);
internal static MethodInfo _RollbackChar = GetMethodInfo(nameof(RollbackChar));
internal static MethodInfo _Rollback = GetMethodInfo(nameof(Rollback));
internal static MethodInfo _ReadObjLeft = GetMethodInfo(nameof(ReadObjLeft));
internal static MethodInfo _ReadNullOrObjLeft = GetMethodInfo(nameof(ReadNullOrObjLeft));
internal static MethodInfo _ReadObjRight = GetMethodInfo(nameof(ReadObjRight));
internal static MethodInfo _ReadBoolObjRight = GetMethodInfo(nameof(ReadBoolObjRight));
internal static MethodInfo _ReadBoolComma = GetMethodInfo(nameof(ReadBoolComma));
internal static MethodInfo _ReadComma = GetMethodInfo(nameof(ReadComma));
internal static MethodInfo _ReadColon = GetMethodInfo(nameof(ReadColon));
internal static MethodInfo _ReadQuotes = GetMethodInfo(nameof(ReadQuotes));
internal static MethodInfo _ReadArrayLeft = GetMethodInfo(nameof(ReadArrayLeft));
internal static MethodInfo _ReadNullOrArrayLeft = GetMethodInfo(nameof(ReadNullOrArrayLeft));
internal static MethodInfo _ReadArrayRight = GetMethodInfo(nameof(ReadArrayRight));
internal static MethodInfo _ReadBoolArrayRight = GetMethodInfo(nameof(ReadBoolArrayRight));
internal static MethodInfo _ReadEnd = GetMethodInfo(nameof(ReadEnd));
internal static MethodInfo _BeforAnnotation = GetMethodInfo(nameof(BeforAnnotation));
internal static MethodInfo _ReadAnnotation = GetMethodInfo(nameof(ReadAnnotation));
internal static MethodInfo _ReadString = GetMethodInfo(nameof(ReadString));
internal static MethodInfo _ReadBoolNull = GetMethodInfo(nameof(ReadBoolNull));
internal static MethodInfo _SkipObj = GetMethodInfo(nameof(SkipObj));
internal static MethodInfo _GetArrayLength = GetMethodInfo(nameof(GetArrayLength));
internal static MethodInfo _RemoveQuoteAndSubString = GetMethodInfo(nameof(RemoveQuoteAndSubString));
internal static MethodInfo _GetChar = GetMethodInfo(nameof(GetChar));
#endregion
internal StringBuilder CharBufferSb;
internal string Json;
internal char[] Buffer;
internal int Length;
internal char* Pointer;
internal int Remaining;
internal JsonReader(string json, char* c)
{
Json = json;
Length = json.Length;
Pointer = c;
Remaining = Length;
CharBufferSb = null;
Buffer = null;
}
internal JsonReader(char[] buffer,int length, char* c)
{
Buffer = buffer;
Length = length;
Pointer = c;
Remaining = Length;
CharBufferSb = null;
Json = null;
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal string SubString(int start, int length)
{
if (Json != null)
return Json.Substring(start, length);
else//char[]
return new string(Buffer, start, length);
}
internal char this[int idx]
{
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
get
{
if (Json != null)
return Json[idx];
else
return Buffer[idx];
}
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal char GetChar()
{
var c = *Pointer;
Pointer++;
Remaining--;
return c;
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal int GetInt()
{
var i = *(int*)Pointer;
Pointer += 2;
Remaining -= 2;
return i;
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal long GetLong()
{
var i = *(long*)Pointer;
Pointer += 4;
Remaining -= 4;
return i;
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal void RollbackChar()
{
Pointer--;
Remaining++;
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal void RollbackInt()
{
Pointer -= 2;
Remaining += 2;
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal void Rollback(int num)
{
Pointer -= num;
Remaining += num;
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal void ReadObjLeft()
{
var c = BeforAnnotation();
if (c != '{')
throw new JsonWrongCharacterException(this, '{');
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal bool ReadNullOrObjLeft()
{
var c = BeforAnnotation();
if (c == 'n' && StrCompair("ull"))
return true;
if (c == '{')
return false;
throw new JsonWrongCharacterException(this, '{');
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal void ReadObjRight()
{
var c = BeforAnnotation();
if (c != '}')
throw new JsonWrongCharacterException(this, '}');
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal bool ReadBoolObjRight()
{
var c = BeforAnnotation();
if (c == '}') return true;
RollbackChar();
return false;
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal bool ReadBoolComma()
{
var c = BeforAnnotation();
if (c == ',') return true;
RollbackChar();
return false;
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal void ReadComma()
{
var c = BeforAnnotation();
if (c != ',')
throw new JsonWrongCharacterException(this, ',');
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal void ReadColon()
{
var c = BeforAnnotation();
if (c != ':')
throw new JsonWrongCharacterException(this, ':');
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal void ReadQuotes()
{
var c = BeforAnnotation();
if (c != '"')
throw new JsonWrongCharacterException(this, '"');
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal void ReadArrayLeft()
{
var c = BeforAnnotation();
if (c != '[')
throw new JsonWrongCharacterException(this, '[');
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal bool ReadNullOrArrayLeft()
{
var c = BeforAnnotation();
if (c == 'n' && StrCompair("ull"))
return true;
if (c == '[')
return false;
throw new JsonWrongCharacterException(this, '[');
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal void ReadArrayRight()
{
var c = BeforAnnotation();
if (c != ']')
throw new JsonWrongCharacterException(this, ']');
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal bool ReadBoolArrayRight()
{
var c = BeforAnnotation();
if (c == ']') return true;
RollbackChar();
return false;
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal bool ReadBoolNull()
{
var c = BeforAnnotation();
if (c == 'n' && StrCompair("ull"))
return true;
else
{
RollbackChar();
return false;
}
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal void ReadEnd()
{
if (Remaining > 0)
ReadAnnotation();
else if (Remaining < 0)
throw new JsonWrongCharacterException();
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal char BeforAnnotation()
{
var c = GetChar();
switch (c)
{
case '/':
{
if (Remaining == 0)
throw new JsonWrongCharacterException();
c = GetChar();
if (c == '*')
{
var lastChar = ' ';
while (Remaining > 0)
{
lastChar = c;
c = GetChar();
if (c == '/') // /* * */ /* ***/////
if (lastChar == '*')
{
if (Remaining > 0)
{
c = GetChar();
if (c == '\r' || c == '\n' || c == ' ' || c == '\t')
return BeforAnnotation();
return c;
}
throw new JsonWrongCharacterException("Json is incomplete"); //json不完整
}
}
}
else if (c == '/')
{
while (Remaining > 0)
{
c = GetChar();
if (c == '\r' || c == '\n')
{
if (Remaining > 0)
{
c = GetChar();
if (c == '\r' || c == '\n' || c == ' ' || c == '\t')
return BeforAnnotation();
return c;
}
throw new JsonWrongCharacterException("Json is incomplete"); //json不完整
}
}
}
throw new JsonWrongCharacterException();
}
case '\r':
case '\n':
case '\t':
case ' ':
if (Remaining > 0)
return BeforAnnotation();
else
throw new JsonWrongCharacterException("Json is incomplete"); //json不完整
}
return c;
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal void ReadAnnotation()
{
var c = GetChar();
switch (c)
{
case '/':
{
if (Remaining == 0)
throw new JsonWrongCharacterException();
c = GetChar();
if (c == '*')
{
var lastChar = ' ';
while (Remaining > 0)
{
lastChar = c;
c = GetChar();
if (c == '/') // /* * */ /* ***/////
if (lastChar == '*')
{
if (Remaining > 0)
ReadAnnotation();
return;
}
}
}
else if (c == '/')
{
while (Remaining > 0)
{
c = GetChar();
if (c == '\r' || c == '\n')
{
if (Remaining > 0)
ReadAnnotation();
return;
}
}
return;
}
break;
}
case '\r':
case '\n':
case '\t':
case ' ':
if (Remaining > 0)
ReadAnnotation();
return;
}
throw new JsonWrongCharacterException();
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal string ReadString()
{
//Currently, this method is only used for dynamic read keys and enums because it does not allow special characters
var c = BeforAnnotation();
if (c == '"')
{
var idx = Length - Remaining;
var leng = 0;
var isCorrectFormat = false;
while (Remaining > 0)
{
c = GetChar();
if (c == '"')
{
isCorrectFormat = true;
break;
}
leng++;
}
if (isCorrectFormat)
if (leng == 0)
return string.Empty;
else
return this.SubString(idx, leng);
}
else if (c == 'n' && StrCompair("ull"))
{
return null;
}
throw new JsonDeserializationTypeResolutionException(this, typeof(string));
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal int SkipObj(JsonDeserializeHandler handler)
{
var c = BeforAnnotation();
var start = Remaining;
switch (c)
{
case 'f':
if (Remaining > 3)
if (StrCompair("alse"))
goto Return;
break;
case 't':
if (Remaining > 2)
if (StrCompair("rue"))
goto Return;
break;
case 'n':
if (Remaining > 2)
if (StrCompair("ull"))
goto Return;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '-':
{
SkipNumber();
goto Return;
}
case '[':
{
if (ReadBoolArrayRight())
goto Return;
var moveNext = 1;
while (moveNext-- > 0)
{
SkipObj(handler);
if (ReadBoolComma())
moveNext++;
}
ReadArrayRight();
goto Return;
}
case '{':
{
if (ReadBoolObjRight())
goto Return;
var moveNext = 1;
while (moveNext-- > 0)
{
SkipString();
ReadColon();
SkipObj(handler);
if (ReadBoolComma())
moveNext++;
}
ReadObjRight();
goto Return;
}
case '"':
{
RollbackChar();
SkipString();
goto Return;
}
}
throw new JsonWrongCharacterException(this);
Return:
return start + 1 - Remaining;
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal void SkipString()
{
var c = BeforAnnotation();
if (c == '"')
while (Remaining > 0)
{
c = GetChar();
if (c == '"')
return;
if (c != '\\')
continue;
c = GetChar();
switch (c)
{
case '"': continue;
case '\\': continue;
case '/': continue;
case 'b': continue;
case 'f': continue;
case 'n': continue;
case 'r': continue;
case 't': continue;
case 'u':
{
c = GetChar();
if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))) throw new JsonDeserializationTypeResolutionException(this, typeof(string));
c = GetChar();
if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))) throw new JsonDeserializationTypeResolutionException(this, typeof(string));
c = GetChar();
if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))) throw new JsonDeserializationTypeResolutionException(this, typeof(string));
c = GetChar();
if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))) throw new JsonDeserializationTypeResolutionException(this, typeof(string));
continue;
}
}
}
else if (c == 'n' && StrCompair("ull")) return;
throw new JsonDeserializationTypeResolutionException(this, typeof(string));
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal void SkipNumber()
{
var seenDecimal = false;
var seenExponent = false;
char c;
while (Remaining > 0)
{
c = GetChar();
if (c >= '0' && c <= '9') continue;
if (c == '.' && !seenDecimal)
{
seenDecimal = true;
continue;
}
if ((c == 'e' || c == 'E') && !seenExponent)
{
c = GetChar();
seenExponent = true;
seenDecimal = true;
c = GetChar();
if (c == '-' || c == '+' || c >= '0' && c <= '9') continue;
throw new JsonWrongCharacterException(this, "Expected -, or a digit");
}
RollbackChar();
return;
}
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal int GetArrayLength(JsonDeserializeHandler handler)
{
//ReadObjLeft();
if (ReadBoolArrayRight())
{
RollbackChar();
return 0;
}
var start = Remaining;
var elements = 0;
var moveNext = 1;
while (moveNext-- > 0)
{
++elements;
SkipObj(handler);
if (ReadBoolComma())
moveNext++;
}
ReadArrayRight();
Rollback(start - Remaining);
return elements;
throw new JsonWrongCharacterException("Array character error");
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal bool StrCompair(string str)
{
if (Remaining < str.Length)
return false;
//2,3,4,5,6,7,8,9
fixed (char* p = str)
{
var o = p;
switch (str.Length)
{
case 2:
if (*(int*)Pointer != *(int*)o) return false;
goto True;
case 3:
if (*(int*)Pointer != *(int*)o) return false;
if (*(Pointer + 2) != *(o + 2)) return false;
goto True;
case 4:
if (*(long*)Pointer != *(long*)o) return false;
goto True;
case 5:
if (*(long*)Pointer != *(long*)o) return false;
if (*(Pointer + 4) != *(o + 4)) return false;
goto True;
case 6:
if (*(long*)Pointer != *(long*)o) return false;
if (*(int*)(Pointer + 4) != *(int*)(o + 4)) return false;
goto True;
case 7:
if (*(long*)Pointer != *(long*)o) return false;
if (*(int*)(Pointer + 4) != *(int*)(o + 4)) return false;
if (*(Pointer + 6) != *(o + 6)) return false;
goto True;
case 8:
if (*(long*)Pointer != *(long*)o) return false;
if (*(long*)(Pointer + 4) != *(long*)(o + 4)) return false;
goto True;
case 9:
if (*(long*)Pointer != *(long*)o) return false;
if (*(long*)(Pointer + 4) != *(long*)(o + 4)) return false;
if (*(Pointer + 8) != *(o + 8)) return false;
goto True;
default:
throw new Exception("Check the code,StrCompair no current length ");
}
}
True:
Remaining -= str.Length;
Pointer += str.Length;
return true;
}
#if !Net4
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal string RemoveQuoteAndSubString(int idx, int length)
{
if (this[idx] == 'n')
return null;
return this.SubString(idx + 1, length - 2); //remove \" \"
}
private static MethodInfo GetMethodInfo(string name)
{
return typeof(JsonReader).GetMethod(name, BindingFlags.NonPublic | BindingFlags.Instance);
}
}
}