agones.dev/agones@v1.54.0/sdks/unity/third_party/MiniJSON.cs (about)

     1  /*
     2   * Copyright (c) 2013 Calvin Rien
     3   *
     4   * Based on the JSON parser by Patrick van Bergen
     5   * http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html
     6   *
     7   * Simplified it so that it doesn't throw exceptions
     8   * and can be used in Unity iPhone with maximum code stripping.
     9   *
    10   * Permission is hereby granted, free of charge, to any person obtaining
    11   * a copy of this software and associated documentation files (the
    12   * "Software"), to deal in the Software without restriction, including
    13   * without limitation the rights to use, copy, modify, merge, publish,
    14   * distribute, sublicense, and/or sell copies of the Software, and to
    15   * permit persons to whom the Software is furnished to do so, subject to
    16   * the following conditions:
    17   *
    18   * The above copyright notice and this permission notice shall be
    19   * included in all copies or substantial portions of the Software.
    20   *
    21   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    22   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    23   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    24   * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    25   * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    26   * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    27   * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    28   */
    29  using System;
    30  using System.Collections;
    31  using System.Collections.Generic;
    32  using System.IO;
    33  using System.Text;
    34  
    35  namespace MiniJSON {
    36      // Example usage:
    37      //
    38      //  using UnityEngine;
    39      //  using System.Collections;
    40      //  using System.Collections.Generic;
    41      //  using MiniJSON;
    42      //
    43      //  public class MiniJSONTest : MonoBehaviour {
    44      //      void Start () {
    45      //          var jsonString = "{ \"array\": [1.44,2,3], " +
    46      //                          "\"object\": {\"key1\":\"value1\", \"key2\":256}, " +
    47      //                          "\"string\": \"The quick brown fox \\\"jumps\\\" over the lazy dog \", " +
    48      //                          "\"unicode\": \"\\u3041 Men\u00fa sesi\u00f3n\", " +
    49      //                          "\"int\": 65536, " +
    50      //                          "\"float\": 3.1415926, " +
    51      //                          "\"bool\": true, " +
    52      //                          "\"null\": null }";
    53      //
    54      //          var dict = Json.Deserialize(jsonString) as Dictionary<string,object>;
    55      //
    56      //          Debug.Log("deserialized: " + dict.GetType());
    57      //          Debug.Log("dict['array'][0]: " + ((List<object>) dict["array"])[0]);
    58      //          Debug.Log("dict['string']: " + (string) dict["string"]);
    59      //          Debug.Log("dict['float']: " + (double) dict["float"]); // floats come out as doubles
    60      //          Debug.Log("dict['int']: " + (long) dict["int"]); // ints come out as longs
    61      //          Debug.Log("dict['unicode']: " + (string) dict["unicode"]);
    62      //
    63      //          var str = Json.Serialize(dict);
    64      //
    65      //          Debug.Log("serialized: " + str);
    66      //      }
    67      //  }
    68  
    69      /// <summary>
    70      /// This class encodes and decodes JSON strings.
    71      /// Spec. details, see http://www.json.org/
    72      ///
    73      /// JSON uses Arrays and Objects. These correspond here to the datatypes IList and IDictionary.
    74      /// All numbers are parsed to doubles.
    75      /// </summary>
    76      public static class Json {
    77          /// <summary>
    78          /// Parses the string json into a value
    79          /// </summary>
    80          /// <param name="json">A JSON string.</param>
    81          /// <returns>An List&lt;object&gt;, a Dictionary&lt;string, object&gt;, a double, an integer,a string, null, true, or false</returns>
    82          public static object Deserialize(string json) {
    83              // save the string for debug information
    84              if (json == null) {
    85                  return null;
    86              }
    87  
    88              return Parser.Parse(json);
    89          }
    90  
    91          sealed class Parser : IDisposable {
    92              const string WORD_BREAK = "{}[],:\"";
    93  
    94              public static bool IsWordBreak(char c) {
    95                  return Char.IsWhiteSpace(c) || WORD_BREAK.IndexOf(c) != -1;
    96              }
    97  
    98              enum TOKEN {
    99                  NONE,
   100                  CURLY_OPEN,
   101                  CURLY_CLOSE,
   102                  SQUARED_OPEN,
   103                  SQUARED_CLOSE,
   104                  COLON,
   105                  COMMA,
   106                  STRING,
   107                  NUMBER,
   108                  TRUE,
   109                  FALSE,
   110                  NULL
   111              };
   112  
   113              StringReader json;
   114  
   115              Parser(string jsonString) {
   116                  json = new StringReader(jsonString);
   117              }
   118  
   119              public static object Parse(string jsonString) {
   120                  using (var instance = new Parser(jsonString)) {
   121                      return instance.ParseValue();
   122                  }
   123              }
   124  
   125              public void Dispose() {
   126                  json.Dispose();
   127                  json = null;
   128              }
   129  
   130              Dictionary<string, object> ParseObject() {
   131                  Dictionary<string, object> table = new Dictionary<string, object>();
   132  
   133                  // ditch opening brace
   134                  json.Read();
   135  
   136                  // {
   137                  while (true) {
   138                      switch (NextToken) {
   139                      case TOKEN.NONE:
   140                          return null;
   141                      case TOKEN.COMMA:
   142                          continue;
   143                      case TOKEN.CURLY_CLOSE:
   144                          return table;
   145                      default:
   146                          // name
   147                          string name = ParseString();
   148                          if (name == null) {
   149                              return null;
   150                          }
   151  
   152                          // :
   153                          if (NextToken != TOKEN.COLON) {
   154                              return null;
   155                          }
   156                          // ditch the colon
   157                          json.Read();
   158  
   159                          // value
   160                          table[name] = ParseValue();
   161                          break;
   162                      }
   163                  }
   164              }
   165  
   166              List<object> ParseArray() {
   167                  List<object> array = new List<object>();
   168  
   169                  // ditch opening bracket
   170                  json.Read();
   171  
   172                  // [
   173                  var parsing = true;
   174                  while (parsing) {
   175                      TOKEN nextToken = NextToken;
   176  
   177                      switch (nextToken) {
   178                      case TOKEN.NONE:
   179                          return null;
   180                      case TOKEN.COMMA:
   181                          continue;
   182                      case TOKEN.SQUARED_CLOSE:
   183                          parsing = false;
   184                          break;
   185                      default:
   186                          object value = ParseByToken(nextToken);
   187  
   188                          array.Add(value);
   189                          break;
   190                      }
   191                  }
   192  
   193                  return array;
   194              }
   195  
   196              object ParseValue() {
   197                  TOKEN nextToken = NextToken;
   198                  return ParseByToken(nextToken);
   199              }
   200  
   201              object ParseByToken(TOKEN token) {
   202                  switch (token) {
   203                  case TOKEN.STRING:
   204                      return ParseString();
   205                  case TOKEN.NUMBER:
   206                      return ParseNumber();
   207                  case TOKEN.CURLY_OPEN:
   208                      return ParseObject();
   209                  case TOKEN.SQUARED_OPEN:
   210                      return ParseArray();
   211                  case TOKEN.TRUE:
   212                      return true;
   213                  case TOKEN.FALSE:
   214                      return false;
   215                  case TOKEN.NULL:
   216                      return null;
   217                  default:
   218                      return null;
   219                  }
   220              }
   221  
   222              string ParseString() {
   223                  StringBuilder s = new StringBuilder();
   224                  char c;
   225  
   226                  // ditch opening quote
   227                  json.Read();
   228  
   229                  bool parsing = true;
   230                  while (parsing) {
   231  
   232                      if (json.Peek() == -1) {
   233                          parsing = false;
   234                          break;
   235                      }
   236  
   237                      c = NextChar;
   238                      switch (c) {
   239                      case '"':
   240                          parsing = false;
   241                          break;
   242                      case '\\':
   243                          if (json.Peek() == -1) {
   244                              parsing = false;
   245                              break;
   246                          }
   247  
   248                          c = NextChar;
   249                          switch (c) {
   250                          case '"':
   251                          case '\\':
   252                          case '/':
   253                              s.Append(c);
   254                              break;
   255                          case 'b':
   256                              s.Append('\b');
   257                              break;
   258                          case 'f':
   259                              s.Append('\f');
   260                              break;
   261                          case 'n':
   262                              s.Append('\n');
   263                              break;
   264                          case 'r':
   265                              s.Append('\r');
   266                              break;
   267                          case 't':
   268                              s.Append('\t');
   269                              break;
   270                          case 'u':
   271                              var hex = new char[4];
   272  
   273                              for (int i=0; i< 4; i++) {
   274                                  hex[i] = NextChar;
   275                              }
   276  
   277                              s.Append((char) Convert.ToInt32(new string(hex), 16));
   278                              break;
   279                          }
   280                          break;
   281                      default:
   282                          s.Append(c);
   283                          break;
   284                      }
   285                  }
   286  
   287                  return s.ToString();
   288              }
   289  
   290              object ParseNumber() {
   291                  string number = NextWord;
   292  
   293                  if (number.IndexOf('.') == -1) {
   294                      long parsedInt;
   295                      Int64.TryParse(number, out parsedInt);
   296                      return parsedInt;
   297                  }
   298  
   299                  double parsedDouble;
   300                  Double.TryParse(number, out parsedDouble);
   301                  return parsedDouble;
   302              }
   303  
   304              void EatWhitespace() {
   305                  while (Char.IsWhiteSpace(PeekChar)) {
   306                      json.Read();
   307  
   308                      if (json.Peek() == -1) {
   309                          break;
   310                      }
   311                  }
   312              }
   313  
   314              char PeekChar {
   315                  get {
   316                      return Convert.ToChar(json.Peek());
   317                  }
   318              }
   319  
   320              char NextChar {
   321                  get {
   322                      return Convert.ToChar(json.Read());
   323                  }
   324              }
   325  
   326              string NextWord {
   327                  get {
   328                      StringBuilder word = new StringBuilder();
   329  
   330                      while (!IsWordBreak(PeekChar)) {
   331                          word.Append(NextChar);
   332  
   333                          if (json.Peek() == -1) {
   334                              break;
   335                          }
   336                      }
   337  
   338                      return word.ToString();
   339                  }
   340              }
   341  
   342              TOKEN NextToken {
   343                  get {
   344                      EatWhitespace();
   345  
   346                      if (json.Peek() == -1) {
   347                          return TOKEN.NONE;
   348                      }
   349  
   350                      switch (PeekChar) {
   351                      case '{':
   352                          return TOKEN.CURLY_OPEN;
   353                      case '}':
   354                          json.Read();
   355                          return TOKEN.CURLY_CLOSE;
   356                      case '[':
   357                          return TOKEN.SQUARED_OPEN;
   358                      case ']':
   359                          json.Read();
   360                          return TOKEN.SQUARED_CLOSE;
   361                      case ',':
   362                          json.Read();
   363                          return TOKEN.COMMA;
   364                      case '"':
   365                          return TOKEN.STRING;
   366                      case ':':
   367                          return TOKEN.COLON;
   368                      case '0':
   369                      case '1':
   370                      case '2':
   371                      case '3':
   372                      case '4':
   373                      case '5':
   374                      case '6':
   375                      case '7':
   376                      case '8':
   377                      case '9':
   378                      case '-':
   379                          return TOKEN.NUMBER;
   380                      }
   381  
   382                      switch (NextWord) {
   383                      case "false":
   384                          return TOKEN.FALSE;
   385                      case "true":
   386                          return TOKEN.TRUE;
   387                      case "null":
   388                          return TOKEN.NULL;
   389                      }
   390  
   391                      return TOKEN.NONE;
   392                  }
   393              }
   394          }
   395  
   396          /// <summary>
   397          /// Converts a IDictionary / IList object or a simple type (string, int, etc.) into a JSON string
   398          /// </summary>
   399          /// <param name="json">A Dictionary&lt;string, object&gt; / List&lt;object&gt;</param>
   400          /// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns>
   401          public static string Serialize(object obj) {
   402              return Serializer.Serialize(obj);
   403          }
   404  
   405          sealed class Serializer {
   406              StringBuilder builder;
   407  
   408              Serializer() {
   409                  builder = new StringBuilder();
   410              }
   411  
   412              public static string Serialize(object obj) {
   413                  var instance = new Serializer();
   414  
   415                  instance.SerializeValue(obj);
   416  
   417                  return instance.builder.ToString();
   418              }
   419  
   420              void SerializeValue(object value) {
   421                  IList asList;
   422                  IDictionary asDict;
   423                  string asStr;
   424  
   425                  if (value == null) {
   426                      builder.Append("null");
   427                  } else if ((asStr = value as string) != null) {
   428                      SerializeString(asStr);
   429                  } else if (value is bool) {
   430                      builder.Append((bool) value ? "true" : "false");
   431                  } else if ((asList = value as IList) != null) {
   432                      SerializeArray(asList);
   433                  } else if ((asDict = value as IDictionary) != null) {
   434                      SerializeObject(asDict);
   435                  } else if (value is char) {
   436                      SerializeString(new string((char) value, 1));
   437                  } else {
   438                      SerializeOther(value);
   439                  }
   440              }
   441  
   442              void SerializeObject(IDictionary obj) {
   443                  bool first = true;
   444  
   445                  builder.Append('{');
   446  
   447                  foreach (object e in obj.Keys) {
   448                      if (!first) {
   449                          builder.Append(',');
   450                      }
   451  
   452                      SerializeString(e.ToString());
   453                      builder.Append(':');
   454  
   455                      SerializeValue(obj[e]);
   456  
   457                      first = false;
   458                  }
   459  
   460                  builder.Append('}');
   461              }
   462  
   463              void SerializeArray(IList anArray) {
   464                  builder.Append('[');
   465  
   466                  bool first = true;
   467  
   468                  foreach (object obj in anArray) {
   469                      if (!first) {
   470                          builder.Append(',');
   471                      }
   472  
   473                      SerializeValue(obj);
   474  
   475                      first = false;
   476                  }
   477  
   478                  builder.Append(']');
   479              }
   480  
   481              void SerializeString(string str) {
   482                  builder.Append('\"');
   483  
   484                  char[] charArray = str.ToCharArray();
   485                  foreach (var c in charArray) {
   486                      switch (c) {
   487                      case '"':
   488                          builder.Append("\\\"");
   489                          break;
   490                      case '\\':
   491                          builder.Append("\\\\");
   492                          break;
   493                      case '\b':
   494                          builder.Append("\\b");
   495                          break;
   496                      case '\f':
   497                          builder.Append("\\f");
   498                          break;
   499                      case '\n':
   500                          builder.Append("\\n");
   501                          break;
   502                      case '\r':
   503                          builder.Append("\\r");
   504                          break;
   505                      case '\t':
   506                          builder.Append("\\t");
   507                          break;
   508                      default:
   509                          int codepoint = Convert.ToInt32(c);
   510                          if ((codepoint >= 32) && (codepoint <= 126)) {
   511                              builder.Append(c);
   512                          } else {
   513                              builder.Append("\\u");
   514                              builder.Append(codepoint.ToString("x4"));
   515                          }
   516                          break;
   517                      }
   518                  }
   519  
   520                  builder.Append('\"');
   521              }
   522  
   523              void SerializeOther(object value) {
   524                  // NOTE: decimals lose precision during serialization.
   525                  // They always have, I'm just letting you know.
   526                  // Previously floats and doubles lost precision too.
   527                  if (value is float) {
   528                      builder.Append(((float) value).ToString("R"));
   529                  } else if (value is int
   530                      || value is uint
   531                      || value is long
   532                      || value is sbyte
   533                      || value is byte
   534                      || value is short
   535                      || value is ushort
   536                      || value is ulong) {
   537                      builder.Append(value);
   538                  } else if (value is double
   539                      || value is decimal) {
   540                      builder.Append(Convert.ToDouble(value).ToString("R"));
   541                  } else {
   542                      SerializeString(value.ToString());
   543                  }
   544              }
   545          }
   546      }
   547  }