2023-11-21 23:05:03 +08:00

766 lines
24 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}
}