private static DataNode ReadNode(string contents, ref int index, string name) { DataNode result = null; var state = State.Type; char c; var mode = InputMode.None; StringBuilder name_content = new StringBuilder(); StringBuilder value_content = new StringBuilder(); int rewind_index = index; bool is_escaped = false; do { bool isWhiteSpace; bool next = false; do { if (index >= contents.Length) { if (state == State.Next) { return(result); } throw new Exception($"JSON parsing exception, unexpected end of data"); } c = contents[index]; isWhiteSpace = Char.IsWhiteSpace(c); if (!isWhiteSpace) { rewind_index = index; } index++; next = (mode == InputMode.None) ? isWhiteSpace : false; } while (next); switch (state) { case State.Type: { switch (c) { case '{': { result = DataNode.CreateObject(name); state = State.Name; break; } case '[': { result = DataNode.CreateArray(name); state = State.Value; break; } default: { throw new Exception($"JSON parsing exception at, unexpected character"); //throw new Exception($"JSON parsing exception at {ParserUtils.GetOffsetError(contents, index)}, unexpected character"); } } break; } case State.Name: { if (c == '}' && result.Kind == NodeKind.Object) { return(result); } switch (c) { case '"': { if (mode == InputMode.None) { mode = InputMode.Text; name_content.Length = 0; } else { mode = InputMode.None; state = State.Colon; } break; } default: { if (mode == InputMode.Text) { name_content.Append(c); } else { throw new Exception($"JSON parsing exception at, unexpected character"); //throw new Exception($"JSON parsing exception at {ParserUtils.GetOffsetError(contents, index)}, unexpected character"); } break; } } break; } case State.Colon: { switch (c) { case ':': { state = State.Value; break; } default: { throw new Exception($"JSON parsing exception at, expected collon"); //throw new Exception($"JSON parsing exception at {ParserUtils.GetOffsetError(contents, index)}, expected collon"); } } break; } case State.Value: { if (c == '\\' && !is_escaped) { is_escaped = true; } else if (is_escaped) { is_escaped = false; if (c == 'n') // Newline { value_content.Append('\n'); } else if (c == 'r') // Carriage return { value_content.Append('\r'); } else if (c == 't') // Tab { value_content.Append('\t'); } else if (c == 'b') // Backspace { value_content.Append('\b'); } else if (c == 'f') // Form feed { value_content.Append('\f'); } else { if (c == 'u') { var hex = ""; for (int i = 0; i < 4; i++) { if (index >= contents.Length) { throw new Exception($"JSON parsing exception, unexpected end of data"); } hex += contents[index]; index++; } ushort unicode_val; unicode_val = ushort.Parse(hex, System.Globalization.NumberStyles.HexNumber); c = (char)unicode_val; } value_content.Append(c); } } else if (c == 'n' && mode == InputMode.None) { ReadString("null", contents, ref index); result.AddField(name_content.Length == 0 ? null : name_content.ToString(), null); state = State.Next; } else if (c == 'f' && mode == InputMode.None) { ReadString("false", contents, ref index); result.AddField(name_content.Length == 0 ? null : name_content.ToString(), false); state = State.Next; } else if (c == 't' && mode == InputMode.None) { ReadString("true", contents, ref index); result.AddField(name_content.Length == 0 ? null : name_content.ToString(), true); state = State.Next; } else if (c == ']' && mode == InputMode.None && result.Kind == NodeKind.Array) { return(result); } else { switch (c) { case '"': { if (mode == InputMode.None) { mode = InputMode.Text; value_content.Length = 0; } else { object value; var str = value_content.ToString(); if (mode == InputMode.Number) { if (str.Contains("e")) { // TODO } value = str; } else { value = str; } mode = InputMode.None; result.AddField(name_content.Length == 0 ? null : name_content.ToString(), value); state = State.Next; } break; } case '[': case '{': { if (mode == InputMode.Text) { value_content.Append(c); } else { index = rewind_index; var node = ReadNode(contents, ref index, name_content.Length == 0 ? null : name_content.ToString()); result.AddNode(node); state = State.Next; } break; } default: { if (mode == InputMode.Text) { value_content.Append(c); } else if (char.IsNumber(c) || (c == '.' || c == 'e' || c == 'E' || c == '-' || c == '+')) { if (mode != InputMode.Number) { value_content.Length = 0; mode = InputMode.Number; } if (c == 'E') { c = 'e'; } value_content.Append(c); } else { if (mode == InputMode.Number) { mode = InputMode.None; var numStr = value_content.ToString(); if (numStr.Contains("e")) { var num = double.Parse(numStr, NumberStyles.Any, CultureInfo.InvariantCulture); result.AddField(name_content.Length == 0 ? null : name_content.ToString(), num); } else { var num = decimal.Parse(numStr, NumberStyles.Any, CultureInfo.InvariantCulture); result.AddField(name_content.Length == 0 ? null : name_content.ToString(), num); } state = State.Next; if (c == ',' || c == ']' || c == '}') { index = rewind_index; } } else { //throw new Exception($"JSON parsing exception at {ParserUtils.GetOffsetError(contents, index)}, unexpected character"); } } break; } } } break; } case State.Next: { switch (c) { case ',': { state = result.Kind == NodeKind.Array ? State.Value : State.Name; break; } case '}': { if (result.Kind != NodeKind.Object) { //throw new Exception($"JSON parsing exception at {ParserUtils.GetOffsetError(contents, index)}, unexpected }}"); } return(result); } case ']': { if (result.Kind != NodeKind.Array) { //throw new Exception($"JSON parsing exception at {ParserUtils.GetOffsetError(contents, index)}, unexpected ]"); } return(result); } default: { throw new Exception($"JSON parsing exception at, expected collon"); //throw new Exception($"JSON parsing exception at {ParserUtils.GetOffsetError(contents, index)}, expected collon"); } } break; } } } while (true); }
public static DataNode ReadFromString(string contents) { var root = DataNode.CreateArray(null); //Console.WriteLine(contents); var header = new List <string>(); int index = 0; var state = State.Header; char c; int fieldIndex = 0; bool isEscaped = false; var content = new StringBuilder(); DataNode currentNode = null; while (index < contents.Length) { c = contents[index]; index++; switch (state) { case State.Header: { if (c == ',' || c == '\n') { header.Add(content.ToString().Trim()); content.Length = 0; } switch (c) { case ',': { break; } case '\n': { state = State.Content; break; } default: { content.Append(c); break; } } break; } case State.Content: { if (!isEscaped && (c == ',' || c == '\n')) { if (fieldIndex < header.Count) { currentNode.AddField(header[fieldIndex], content.ToString()); } content.Length = 0; fieldIndex++; if (c == '\n') { fieldIndex = 0; currentNode = null; } break; } if (c == '"') { if (isEscaped && index < contents.Length && contents[index] == '"') { index++; } else { isEscaped = !isEscaped; break; } } if (currentNode == null) { currentNode = DataNode.CreateObject(null); root.AddNode(currentNode); } content.Append(c); break; } } } if (currentNode != null && fieldIndex < header.Count) { currentNode.AddField(header[fieldIndex], content.ToString()); } return(root); }