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