ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

json.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 /*
00024  * Files JSON.cpp and JSONValue.cpp part of the SimpleJSON Library - https://github.com/MJPA/SimpleJSON
00025  *
00026  * Copyright (C) 2010 Mike Anchor
00027  *
00028  * Permission is hereby granted, free of charge, to any person obtaining a copy
00029  * of this software and associated documentation files (the "Software"), to deal
00030  * in the Software without restriction, including without limitation the rights
00031  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00032  * copies of the Software, and to permit persons to whom the Software is
00033  * furnished to do so, subject to the following conditions:
00034  *
00035  * The above copyright notice and this permission notice shall be included in
00036  * all copies or substantial portions of the Software.
00037  *
00038  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00039  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00040  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00041  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00042  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00043  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00044  * THE SOFTWARE.
00045  */
00046 
00047 #include "common/json.h"
00048 
00049 #ifdef __MINGW32__
00050 #define wcsncasecmp wcsnicmp
00051 #endif
00052 
00053 // Macros to free an array/object
00054 #define FREE_ARRAY(x) { JSONArray::iterator iter; for (iter = x.begin(); iter != x.end(); iter++) { delete *iter; } }
00055 #define FREE_OBJECT(x) { JSONObject::iterator iter; for (iter = x.begin(); iter != x.end(); iter++) { delete (*iter)._value; } }
00056 
00057 namespace Common {
00058 
00065 JSON::JSON() {}
00066 
00076 JSONValue *JSON::parse(const char *data) {
00077     // Skip any preceding whitespace, end of data = no JSON = fail
00078     if (!skipWhitespace(&data))
00079         return nullptr;
00080 
00081     // We need the start of a value here now...
00082     JSONValue *value = JSONValue::parse(&data);
00083     if (value == nullptr)
00084         return nullptr;
00085 
00086     // Can be white space now and should be at the end of the string then...
00087     if (skipWhitespace(&data)) {
00088         delete value;
00089         return nullptr;
00090     }
00091 
00092     // We're now at the end of the string
00093     return value;
00094 }
00095 
00105 String JSON::stringify(const JSONValue *value) {
00106     if (value != nullptr)
00107         return value->stringify();
00108     else
00109         return "";
00110 }
00111 
00121 bool JSON::skipWhitespace(const char **data) {
00122     while (**data != 0 && (**data == ' ' || **data == '\t' || **data == '\r' || **data == '\n'))
00123         (*data)++;
00124 
00125     return **data != 0;
00126 }
00127 
00139 bool JSON::extractString(const char **data, String &str) {
00140     str = "";
00141 
00142     while (**data != 0) {
00143         // Save the char so we can change it if need be
00144         char next_char = **data;
00145         uint32 next_uchar = 0;
00146 
00147         // Escaping something?
00148         if (next_char == '\\') {
00149             // Move over the escape char
00150             (*data)++;
00151 
00152             // Deal with the escaped char
00153             switch (**data) {
00154             case '"': next_char = '"';
00155                 break;
00156             case '\\': next_char = '\\';
00157                 break;
00158             case '/': next_char = '/';
00159                 break;
00160             case 'b': next_char = '\b';
00161                 break;
00162             case 'f': next_char = '\f';
00163                 break;
00164             case 'n': next_char = '\n';
00165                 break;
00166             case 'r': next_char = '\r';
00167                 break;
00168             case 't': next_char = '\t';
00169                 break;
00170             case 'u': {
00171                 next_char = 0;
00172                 next_uchar = parseUnicode(data);
00173                 // If the codepoint is a high surrogate, we should have a low surrogate now
00174                 if (next_uchar >= 0xD800 && next_uchar <= 0xDBFF) {
00175                     (*data)++;
00176                     if (**data != '\\')
00177                         return false;
00178                     (*data)++;
00179                     uint32 low_surrogate = parseUnicode(data);
00180                     if (low_surrogate < 0xDC00 || low_surrogate > 0xDFFF)
00181                         return false;
00182                     //next_uchar = 0x10000 + (next_uchar - 0xD800) * 0x400 + (low_surrogate - 0xDC00);
00183                     next_uchar = (next_uchar << 10) + low_surrogate - 0x35FDC00u;
00184                 } else if (next_uchar >= 0xDC00 && next_uchar <= 0xDFFF)
00185                     return false; // low surrogate, which should only follow a high surrogate
00186                 // Check this is a valid code point
00187                 if (next_uchar > 0x10FFFF)
00188                     return false;
00189                 break;
00190             }
00191 
00192                 // By the spec, only the above cases are allowed
00193             default:
00194                 return false;
00195             }
00196         }
00197 
00198         // End of the string?
00199         else if (next_char == '"') {
00200             (*data)++;
00201             //str.reserve(); // Remove unused capacity //TODO
00202             return true;
00203         }
00204 
00205         // Disallowed char?
00206         else if (next_char < ' ' && next_char != '\t') {
00207             // SPEC Violation: Allow tabs due to real world cases
00208             return false;
00209         }
00210 
00211         // Add the next char
00212         if (next_char != 0)
00213             str += next_char;
00214         else {
00215             if (next_uchar < 0x80)
00216                 // 1-byte character (ASCII)
00217                 str += (char)next_uchar;
00218             else if (next_uchar <= 0x7FF) {
00219                 // 2-byte characters: 110xxxxx 10xxxxxx
00220                 str += (char)(0xC0 | (next_uchar >> 6));
00221                 str += (char)(0x80 | (next_uchar & 0x3F));
00222             } else if (next_uchar <= 0xFFFF) {
00223                 // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
00224                 str += (char)(0xE0 | (next_uchar >> 12));
00225                 str += (char)(0x80 | ((next_uchar >> 6) & 0x3F));
00226                 str += (char)(0x80 | (next_uchar & 0x3F));
00227             } else {
00228                 // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
00229                 str += (char)(0xF0 | (next_uchar >> 18));
00230                 str += (char)(0x80 | ((next_uchar >> 12) & 0x3F));
00231                 str += (char)(0x80 | ((next_uchar >> 6) & 0x3F));
00232                 str += (char)(0x80 | (next_uchar & 0x3F));
00233             }
00234         }
00235 
00236         // Move on
00237         (*data)++;
00238     }
00239 
00240     // If we're here, the string ended incorrectly
00241     return false;
00242 }
00243 
00255 uint32 JSON::parseUnicode(const char **data) {
00256     if (**data != 'u')
00257         return 0xFFFFFFFF;
00258     // We need 5 chars (4 hex + the 'u') or its not valid
00259     if (!simplejson_wcsnlen(*data, 5))
00260         return 0xFFFFFFFF;
00261 
00262     // Deal with the chars
00263     uint32 codepoint = 0;
00264     for (int i = 0; i < 4; i++) {
00265         // Do it first to move off the 'u' and leave us on the
00266         // final hex digit as we move on by one later on
00267         (*data)++;
00268 
00269         codepoint <<= 4;
00270 
00271         // Parse the hex digit
00272         if (**data >= '0' && **data <= '9')
00273             codepoint |= (**data - '0');
00274         else if (**data >= 'A' && **data <= 'F')
00275             codepoint |= (10 + (**data - 'A'));
00276         else if (**data >= 'a' && **data <= 'f')
00277             codepoint |= (10 + (**data - 'a'));
00278         else {
00279             // Invalid hex digit
00280             return 0xFFFFFFFF;
00281         }
00282     }
00283     return codepoint;
00284 }
00285 
00295 double JSON::parseInt(const char **data) {
00296     double integer = 0;
00297     while (**data != 0 && **data >= '0' && **data <= '9')
00298         integer = integer * 10 + (*(*data)++ - '0');
00299 
00300     return integer;
00301 }
00302 
00312 double JSON::parseDecimal(const char **data) {
00313     double decimal = 0.0;
00314     double factor = 0.1;
00315     while (**data != 0 && **data >= '0' && **data <= '9') {
00316         int digit = (*(*data)++ - '0');
00317         decimal = decimal + digit * factor;
00318         factor *= 0.1;
00319     }
00320     return decimal;
00321 }
00322 
00332 JSONValue *JSONValue::parse(const char **data) {
00333     // Is it a string?
00334     if (**data == '"') {
00335         String str;
00336         if (!JSON::extractString(&(++(*data)), str))
00337             return nullptr;
00338         else
00339             return new JSONValue(str);
00340     }
00341 
00342     // Is it a boolean?
00343     else if ((simplejson_wcsnlen(*data, 4) && scumm_strnicmp(*data, "true", 4) == 0) || (simplejson_wcsnlen(*data, 5) && scumm_strnicmp(*data, "false", 5) == 0)) {
00344         bool value = scumm_strnicmp(*data, "true", 4) == 0;
00345         (*data) += value ? 4 : 5;
00346         return new JSONValue(value);
00347     }
00348 
00349     // Is it a null?
00350     else if (simplejson_wcsnlen(*data, 4) && scumm_strnicmp(*data, "null", 4) == 0) {
00351         (*data) += 4;
00352         return new JSONValue();
00353     }
00354 
00355     // Is it a number?
00356     else if (**data == '-' || (**data >= '0' && **data <= '9')) {
00357         // Negative?
00358         bool neg = **data == '-';
00359         if (neg) (*data)++;
00360 
00361         long long int integer = 0;
00362         double number = 0.0;
00363         bool onlyInteger = true;
00364 
00365         // Parse the whole part of the number - only if it wasn't 0
00366         if (**data == '0')
00367             (*data)++;
00368         else if (**data >= '1' && **data <= '9')
00369             number = integer = JSON::parseInt(data);
00370         else
00371             return nullptr;
00372 
00373         // Could be a decimal now...
00374         if (**data == '.') {
00375             (*data)++;
00376 
00377             // Not get any digits?
00378             if (!(**data >= '0' && **data <= '9'))
00379                 return nullptr;
00380 
00381             // Find the decimal and sort the decimal place out
00382             // Use ParseDecimal as ParseInt won't work with decimals less than 0.1
00383             // thanks to Javier Abadia for the report & fix
00384             double decimal = JSON::parseDecimal(data);
00385 
00386             // Save the number
00387             number += decimal;
00388             onlyInteger = false;
00389         }
00390 
00391         // Could be an exponent now...
00392         if (**data == 'E' || **data == 'e') {
00393             (*data)++;
00394 
00395             // Check signage of expo
00396             bool neg_expo = false;
00397             if (**data == '-' || **data == '+') {
00398                 neg_expo = **data == '-';
00399                 (*data)++;
00400             }
00401 
00402             // Not get any digits?
00403             if (!(**data >= '0' && **data <= '9'))
00404                 return nullptr;
00405 
00406             // Sort the expo out
00407             double expo = JSON::parseInt(data);
00408             for (double i = 0.0; i < expo; i++)
00409                 number = neg_expo ? (number / 10.0) : (number * 10.0);
00410             onlyInteger = false;
00411         }
00412 
00413         // Was it neg?
00414         if (neg) number *= -1;
00415 
00416         if (onlyInteger)
00417             return new JSONValue(neg ? -integer : integer);
00418 
00419         return new JSONValue(number);
00420     }
00421 
00422     // An object?
00423     else if (**data == '{') {
00424         JSONObject object;
00425 
00426         (*data)++;
00427 
00428         while (**data != 0) {
00429             // Whitespace at the start?
00430             if (!JSON::skipWhitespace(data)) {
00431                 FREE_OBJECT(object);
00432                 return nullptr;
00433             }
00434 
00435             // Special case - empty object
00436             if (object.size() == 0 && **data == '}') {
00437                 (*data)++;
00438                 return new JSONValue(object);
00439             }
00440 
00441             // We want a string now...
00442             String name;
00443             if (!JSON::extractString(&(++(*data)), name)) {
00444                 FREE_OBJECT(object);
00445                 return nullptr;
00446             }
00447 
00448             // More whitespace?
00449             if (!JSON::skipWhitespace(data)) {
00450                 FREE_OBJECT(object);
00451                 return nullptr;
00452             }
00453 
00454             // Need a : now
00455             if (*((*data)++) != ':') {
00456                 FREE_OBJECT(object);
00457                 return nullptr;
00458             }
00459 
00460             // More whitespace?
00461             if (!JSON::skipWhitespace(data)) {
00462                 FREE_OBJECT(object);
00463                 return nullptr;
00464             }
00465 
00466             // The value is here
00467             JSONValue *value = parse(data);
00468             if (value == nullptr) {
00469                 FREE_OBJECT(object);
00470                 return nullptr;
00471             }
00472 
00473             // Add the name:value
00474             if (object.find(name) != object.end())
00475                 delete object[name];
00476             object[name] = value;
00477 
00478             // More whitespace?
00479             if (!JSON::skipWhitespace(data)) {
00480                 FREE_OBJECT(object);
00481                 return nullptr;
00482             }
00483 
00484             // End of object?
00485             if (**data == '}') {
00486                 (*data)++;
00487                 return new JSONValue(object);
00488             }
00489 
00490             // Want a , now
00491             if (**data != ',') {
00492                 FREE_OBJECT(object);
00493                 return nullptr;
00494             }
00495 
00496             (*data)++;
00497         }
00498 
00499         // Only here if we ran out of data
00500         FREE_OBJECT(object);
00501         return nullptr;
00502     }
00503 
00504     // An array?
00505     else if (**data == '[') {
00506         JSONArray array;
00507 
00508         (*data)++;
00509 
00510         while (**data != 0) {
00511             // Whitespace at the start?
00512             if (!JSON::skipWhitespace(data)) {
00513                 FREE_ARRAY(array);
00514                 return nullptr;
00515             }
00516 
00517             // Special case - empty array
00518             if (array.size() == 0 && **data == ']') {
00519                 (*data)++;
00520                 return new JSONValue(array);
00521             }
00522 
00523             // Get the value
00524             JSONValue *value = parse(data);
00525             if (value == nullptr) {
00526                 FREE_ARRAY(array);
00527                 return nullptr;
00528             }
00529 
00530             // Add the value
00531             array.push_back(value);
00532 
00533             // More whitespace?
00534             if (!JSON::skipWhitespace(data)) {
00535                 FREE_ARRAY(array);
00536                 return nullptr;
00537             }
00538 
00539             // End of array?
00540             if (**data == ']') {
00541                 (*data)++;
00542                 return new JSONValue(array);
00543             }
00544 
00545             // Want a , now
00546             if (**data != ',') {
00547                 FREE_ARRAY(array);
00548                 return nullptr;
00549             }
00550 
00551             (*data)++;
00552         }
00553 
00554         // Only here if we ran out of data
00555         FREE_ARRAY(array);
00556         return nullptr;
00557     }
00558 
00559     // Ran out of possibilites, it's bad!
00560     else {
00561         return nullptr;
00562     }
00563 }
00564 
00570 JSONValue::JSONValue(/*NULL*/) {
00571     _type = JSONType_Null;
00572 }
00573 
00581 JSONValue::JSONValue(const char *charValue) {
00582     _type = JSONType_String;
00583     _stringValue = new String(String(charValue));
00584 }
00585 
00593 JSONValue::JSONValue(const String &stringValue) {
00594     _type = JSONType_String;
00595     _stringValue = new String(stringValue);
00596 }
00597 
00605 JSONValue::JSONValue(bool boolValue) {
00606     _type = JSONType_Bool;
00607     _boolValue = boolValue;
00608 }
00609 
00617 JSONValue::JSONValue(double numberValue) {
00618     _type = JSONType_Number;
00619     _numberValue = numberValue;
00620 }
00621 
00629 JSONValue::JSONValue(long long int numberValue) {
00630     _type = JSONType_IntegerNumber;
00631     _integerValue = numberValue;
00632 }
00633 
00641 JSONValue::JSONValue(const JSONArray &arrayValue) {
00642     _type = JSONType_Array;
00643     _arrayValue = new JSONArray(arrayValue);
00644 }
00645 
00653 JSONValue::JSONValue(const JSONObject &objectValue) {
00654     _type = JSONType_Object;
00655     _objectValue = new JSONObject(objectValue);
00656 }
00657 
00665 JSONValue::JSONValue(const JSONValue &source) {
00666     _type = source._type;
00667 
00668     switch (_type) {
00669     case JSONType_String:
00670         _stringValue = new String(*source._stringValue);
00671         break;
00672 
00673     case JSONType_Bool:
00674         _boolValue = source._boolValue;
00675         break;
00676 
00677     case JSONType_Number:
00678         _numberValue = source._numberValue;
00679         break;
00680 
00681     case JSONType_IntegerNumber:
00682         _integerValue = source._integerValue;
00683         break;
00684 
00685     case JSONType_Array: {
00686         JSONArray source_array = *source._arrayValue;
00687         JSONArray::iterator iter;
00688         _arrayValue = new JSONArray();
00689         for (iter = source_array.begin(); iter != source_array.end(); iter++)
00690             _arrayValue->push_back(new JSONValue(**iter));
00691         break;
00692     }
00693 
00694     case JSONType_Object: {
00695         JSONObject source_object = *source._objectValue;
00696         _objectValue = new JSONObject();
00697         JSONObject::iterator iter;
00698         for (iter = source_object.begin(); iter != source_object.end(); iter++) {
00699             String name = (*iter)._key;
00700             (*_objectValue)[name] = new JSONValue(*((*iter)._value));
00701         }
00702         break;
00703     }
00704 
00705     default:
00706         // fallthrough intended
00707     case JSONType_Null:
00708         // Nothing to do.
00709         break;
00710     }
00711 }
00712 
00719 JSONValue::~JSONValue() {
00720     if (_type == JSONType_Array) {
00721         JSONArray::iterator iter;
00722         for (iter = _arrayValue->begin(); iter != _arrayValue->end(); iter++)
00723             delete *iter;
00724         delete _arrayValue;
00725     } else if (_type == JSONType_Object) {
00726         JSONObject::iterator iter;
00727         for (iter = _objectValue->begin(); iter != _objectValue->end(); iter++) {
00728             delete (*iter)._value;
00729         }
00730         delete _objectValue;
00731     } else if (_type == JSONType_String) {
00732         delete _stringValue;
00733     }
00734 }
00735 
00743 bool JSONValue::isNull() const {
00744     return _type == JSONType_Null;
00745 }
00746 
00754 bool JSONValue::isString() const {
00755     return _type == JSONType_String;
00756 }
00757 
00765 bool JSONValue::isBool() const {
00766     return _type == JSONType_Bool;
00767 }
00768 
00776 bool JSONValue::isNumber() const {
00777     return _type == JSONType_Number;
00778 }
00779 
00787 bool JSONValue::isIntegerNumber() const {
00788     return _type == JSONType_IntegerNumber;
00789 }
00790 
00798 bool JSONValue::isArray() const {
00799     return _type == JSONType_Array;
00800 }
00801 
00809 bool JSONValue::isObject() const {
00810     return _type == JSONType_Object;
00811 }
00812 
00821 const String &JSONValue::asString() const {
00822     return (*_stringValue);
00823 }
00824 
00833 bool JSONValue::asBool() const {
00834     return _boolValue;
00835 }
00836 
00845 double JSONValue::asNumber() const {
00846     return _numberValue;
00847 }
00848 
00857 long long int JSONValue::asIntegerNumber() const {
00858     return _integerValue;
00859 }
00860 
00869 const JSONArray &JSONValue::asArray() const {
00870     return (*_arrayValue);
00871 }
00872 
00881 const JSONObject &JSONValue::asObject() const {
00882     return (*_objectValue);
00883 }
00884 
00894 std::size_t JSONValue::countChildren() const {
00895     switch (_type) {
00896     case JSONType_Array:
00897         return _arrayValue->size();
00898     case JSONType_Object:
00899         return _objectValue->size();
00900     default:
00901         return 0;
00902     }
00903 }
00904 
00913 bool JSONValue::hasChild(std::size_t index) const {
00914     if (_type == JSONType_Array) {
00915         return index < _arrayValue->size();
00916     } else {
00917         return false;
00918     }
00919 }
00920 
00930 JSONValue *JSONValue::child(std::size_t index) {
00931     if (index < _arrayValue->size()) {
00932         return (*_arrayValue)[index];
00933     } else {
00934         return nullptr;
00935     }
00936 }
00937 
00946 bool JSONValue::hasChild(const char *name) const {
00947     if (_type == JSONType_Object) {
00948         return _objectValue->find(name) != _objectValue->end();
00949     } else {
00950         return false;
00951     }
00952 }
00953 
00963 JSONValue *JSONValue::child(const char *name) {
00964     JSONObject::const_iterator it = _objectValue->find(name);
00965     if (it != _objectValue->end()) {
00966         return it->_value;
00967     } else {
00968         return nullptr;
00969     }
00970 }
00971 
00980 Array<String> JSONValue::objectKeys() const {
00981     Array<String> keys;
00982 
00983     if (_type == JSONType_Object) {
00984         JSONObject::const_iterator iter = _objectValue->begin();
00985         while (iter != _objectValue->end()) {
00986             keys.push_back(iter->_key);
00987 
00988             iter++;
00989         }
00990     }
00991 
00992     return keys;
00993 }
00994 
01004 String JSONValue::stringify(bool const prettyprint) const {
01005     size_t const indentDepth = prettyprint ? 1 : 0;
01006     return stringifyImpl(indentDepth);
01007 }
01008 
01009 
01019 String JSONValue::stringifyImpl(size_t const indentDepth) const {
01020     String ret_string;
01021     size_t const indentDepth1 = indentDepth ? indentDepth + 1 : 0;
01022     String const indentStr = indent(indentDepth);
01023     String const indentStr1 = indent(indentDepth1);
01024 
01025     switch (_type) {
01026     default:
01027         // fallthrough intended
01028     case JSONType_Null:
01029         ret_string = "null";
01030         break;
01031 
01032     case JSONType_String:
01033         ret_string = stringifyString(*_stringValue);
01034         break;
01035 
01036     case JSONType_Bool:
01037         ret_string = _boolValue ? "true" : "false";
01038         break;
01039 
01040     case JSONType_Number: {
01041         if (isinf(_numberValue) || isnan(_numberValue))
01042             ret_string = "null";
01043         else {
01044             ret_string = String::format("%g", _numberValue);
01045         }
01046         break;
01047     }
01048 
01049     case JSONType_IntegerNumber: {
01050         ret_string = String::format("%lld", _integerValue);
01051         break;
01052     }
01053 
01054     case JSONType_Array: {
01055         ret_string = indentDepth ? "[\n" + indentStr1 : "[";
01056         JSONArray::const_iterator iter = _arrayValue->begin();
01057         while (iter != _arrayValue->end()) {
01058             ret_string += (*iter)->stringifyImpl(indentDepth1);
01059 
01060             // Not at the end - add a separator
01061             if (++iter != _arrayValue->end())
01062                 ret_string += ",";
01063         }
01064         ret_string += indentDepth ? "\n" + indentStr + "]" : "]";
01065         break;
01066     }
01067 
01068     case JSONType_Object: {
01069         ret_string = indentDepth ? "{\n" + indentStr1 : "{";
01070         JSONObject::const_iterator iter = _objectValue->begin();
01071         while (iter != _objectValue->end()) {
01072             ret_string += stringifyString((*iter)._key);
01073             ret_string += ":";
01074             ret_string += (*iter)._value->stringifyImpl(indentDepth1);
01075 
01076             // Not at the end - add a separator
01077             if (++iter != _objectValue->end())
01078                 ret_string += ",";
01079         }
01080         ret_string += indentDepth ? "\n" + indentStr + "}" : "}";
01081         break;
01082     }
01083     }
01084 
01085     return ret_string;
01086 }
01087 
01099 String JSONValue::stringifyString(const String &str) {
01100     String str_out = "\"";
01101 
01102     String::const_iterator iter = str.begin();
01103     while (iter != str.end()) {
01104         uint32 uchr = decodeUtf8Char(iter, str.end());
01105         if (uchr == 0xFFFFFFFF)
01106             break; // error - truncate the result
01107 
01108         if (uchr == '"' || uchr == '\\' || uchr == '/') {
01109             str_out += '\\';
01110             str_out += (char)uchr;
01111         } else if (uchr == '\b') {
01112             str_out += "\\b";
01113         } else if (uchr == '\f') {
01114             str_out += "\\f";
01115         } else if (uchr == '\n') {
01116             str_out += "\\n";
01117         } else if (uchr == '\r') {
01118             str_out += "\\r";
01119         } else if (uchr == '\t') {
01120             str_out += "\\t";
01121         } else if (uchr >= ' ' && uchr <= 126 ) {
01122             str_out += (char)uchr;
01123         } else {
01124             if (uchr <= 0xFFFF)
01125                 str_out += String::format("\\u%04x", uchr);
01126             else
01127                 str_out += String::format("\\u%04x\\u%04x", 0xD7C0 + (uchr >> 10), 0xDC00 + (uchr & 0x3FF));
01128         }
01129 
01130         iter++;
01131     }
01132 
01133     str_out += "\"";
01134     return str_out;
01135 }
01136 
01147 uint32 JSONValue::decodeUtf8Char(String::const_iterator &iter, const String::const_iterator &end) {
01148     uint8 state = 0;
01149     uint32 codepoint = 0;
01150     int nbRead = 0;
01151     do {
01152         uint8 byte = uint8(*iter);
01153         state = decodeUtf8Byte(state, codepoint, byte);
01154         ++nbRead;
01155         if (state == 0)
01156             return codepoint;
01157     } while (state != 1 && ++iter != end);
01158     if (state == 1) {
01159         // We failed to read this as a UTF-8 character. The string might be encoded differently, which
01160         // would be invalid (since the json standard indicate the string has to be in utf-8) but rather
01161         // that return 0FFFFFFFF and truncate, try to recover from it by rewinding and returning the
01162         // raw byte.
01163         while (--nbRead > 0) { --iter; }
01164         uint8 byte = uint8(*iter);
01165         warning("Invalid UTF-8 character 0x%x in JSON string.", byte);
01166         return byte;
01167     }
01168     return 0xFFFFFFFF;
01169 }
01170 
01192 uint8 JSONValue::decodeUtf8Byte(uint8 state, uint32 &codepoint, uint8 byte) {
01193     static const uint8 utf8d[] = {
01194         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F
01195         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F
01196         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F
01197         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F
01198         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F
01199         7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF
01200         8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF
01201         0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF
01202         0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF
01203         0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0
01204         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2
01205         1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4
01206         1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6
01207         1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8
01208     };
01209 
01210     const uint8 type = utf8d[byte];
01211     codepoint = state != 0 ?
01212         (codepoint << 6) | (byte & 0x3f) :
01213         (0xFF >> type) & byte;
01214     return utf8d[256 + state * 16 + type];
01215 }
01216 
01226 String JSONValue::indent(size_t depth) {
01227     const size_t indent_step = 2;
01228     depth ? --depth : 0;
01229     String indentStr;
01230     for (size_t i = 0; i < depth * indent_step; ++i) indentStr += ' ';
01231     return indentStr;
01232 }
01233 
01234 } // End of namespace Common


Generated on Sat Feb 15 2020 05:00:47 for ResidualVM by doxygen 1.7.1
curved edge   curved edge