using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MinecraftClient { /// /// This class parses JSON data and returns an object describing that data. /// Really lightweight JSON handling by ORelio - (c) 2013 - 2014 /// public static class Json { /// /// Parse some JSON and return the corresponding JSON object /// public static JSONData ParseJson(string json) { int cursorpos = 0; return String2Data(json, ref cursorpos); } /// /// The class storing unserialized JSON data /// The data can be an object, an array or a string /// public class JSONData { public enum DataType { Object, Array, String }; private DataType type; public DataType Type { get { return type; } } public Dictionary Properties; public List DataArray; public string StringValue; public JSONData(DataType datatype) { type = datatype; Properties = new Dictionary(); DataArray = new List(); StringValue = String.Empty; } } /// /// Parse a JSON string to build a JSON object /// /// String to parse /// Cursor start (set to 0 for function init) private static JSONData String2Data(string toparse, ref int cursorpos) { try { JSONData data; switch (toparse[cursorpos]) { //Object case '{': data = new JSONData(JSONData.DataType.Object); cursorpos++; while (toparse[cursorpos] != '}') { if (toparse[cursorpos] == '"') { JSONData propertyname = String2Data(toparse, ref cursorpos); if (toparse[cursorpos] == ':') { cursorpos++; } else { /* parse error ? */ } JSONData propertyData = String2Data(toparse, ref cursorpos); data.Properties[propertyname.StringValue] = propertyData; } else cursorpos++; } cursorpos++; break; //Array case '[': data = new JSONData(JSONData.DataType.Array); cursorpos++; while (toparse[cursorpos] != ']') { if (toparse[cursorpos] == ',') { cursorpos++; } JSONData arrayItem = String2Data(toparse, ref cursorpos); data.DataArray.Add(arrayItem); } cursorpos++; break; //String case '"': data = new JSONData(JSONData.DataType.String); cursorpos++; while (toparse[cursorpos] != '"') { if (toparse[cursorpos] == '\\') { try //Unicode character \u0123 { if (toparse[cursorpos + 1] == 'u' && isHex(toparse[cursorpos + 2]) && isHex(toparse[cursorpos + 3]) && isHex(toparse[cursorpos + 4]) && isHex(toparse[cursorpos + 5])) { //"abc\u0123abc" => "0123" => 0123 => Unicode char n°0123 => Add char to string data.StringValue += char.ConvertFromUtf32(int.Parse(toparse.Substring(cursorpos + 2, 4), System.Globalization.NumberStyles.HexNumber)); cursorpos += 6; continue; } else cursorpos++; //Normal character escapement \" } catch (IndexOutOfRangeException) { cursorpos++; } // \u01 catch (ArgumentOutOfRangeException) { cursorpos++; } // Unicode index 0123 was invalid } data.StringValue += toparse[cursorpos]; cursorpos++; } cursorpos++; break; //Number case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.': data = new JSONData(JSONData.DataType.String); StringBuilder sb = new StringBuilder(); while ((toparse[cursorpos] >= '0' && toparse[cursorpos] <= '9') || toparse[cursorpos] == '.') { sb.Append(toparse[cursorpos]); cursorpos++; } data.StringValue = sb.ToString(); break; //Boolean : true case 't': data = new JSONData(JSONData.DataType.String); cursorpos++; if (toparse[cursorpos] == 'r') { cursorpos++; } if (toparse[cursorpos] == 'u') { cursorpos++; } if (toparse[cursorpos] == 'e') { cursorpos++; data.StringValue = "true"; } break; //Boolean : false case 'f': data = new JSONData(JSONData.DataType.String); cursorpos++; if (toparse[cursorpos] == 'a') { cursorpos++; } if (toparse[cursorpos] == 'l') { cursorpos++; } if (toparse[cursorpos] == 's') { cursorpos++; } if (toparse[cursorpos] == 'e') { cursorpos++; data.StringValue = "false"; } break; //Unknown data default: cursorpos++; return String2Data(toparse, ref cursorpos); } while (cursorpos < toparse.Length && (char.IsWhiteSpace(toparse[cursorpos]) || toparse[cursorpos] == '\r' || toparse[cursorpos] == '\n')) cursorpos++; return data; } catch (IndexOutOfRangeException) { return new JSONData(JSONData.DataType.String); } } /// /// Small function for checking if a char is an hexadecimal char (0-9 A-F a-f) /// /// Char to test /// True if hexadecimal private static bool isHex(char c) { return ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')); } } }