File indexing completed on 2024-05-12 15:43:24

0001 /*
0002  *  This file is part of the KDE libraries
0003  *  Copyright (C) 2012 Bernd Buschinski (b.buschinski@googlemail.com)
0004  *
0005  *  This library is free software; you can redistribute it and/or
0006  *  modify it under the terms of the GNU Library General Public
0007  *  License as published by the Free Software Foundation; either
0008  *  version 2 of the License, or (at your option) any later version.
0009  *
0010  *  This library is distributed in the hope that it will be useful,
0011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013  *  Library General Public License for more details.
0014  *
0015  *  You should have received a copy of the GNU Library General Public License
0016  *  along with this library; see the file COPYING.LIB.  If not, write to
0017  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  *  Boston, MA 02110-1301, USA.
0019  *
0020  */
0021 
0022 #include "json_object.h"
0023 
0024 #include "jsonlexer.h"
0025 #include "lookup.h"
0026 #include "array_instance.h"
0027 #include "jsonstringify.h"
0028 
0029 #include "json_object.lut.h"
0030 
0031 using namespace KJS;
0032 
0033 // ------------------------------ JSONObjectImp --------------------------------
0034 
0035 const ClassInfo JSONObjectImp::info = { "JSON", nullptr, &jsonTable, nullptr };
0036 
0037 /* Source for json_object.lut.h
0038 @begin jsonTable 2
0039   parse           JSONObjectImp::Parse      DontEnum|Function 2
0040   stringify       JSONObjectImp::Stringify  DontEnum|Function 3
0041 @end
0042 */
0043 
0044 JSONObjectImp::JSONObjectImp(ExecState *, ObjectPrototype *objProto)
0045     : JSObject(objProto)
0046 {
0047 }
0048 
0049 bool JSONObjectImp::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
0050 {
0051     // As of ECMA 5.1r6 JSON only has 2 functions, so only functionSlot is needed
0052     return getStaticFunctionSlot<JSONFuncImp, JSObject>(exec, &jsonTable, this, propertyName, slot);
0053 }
0054 
0055 // ------------------------------ JSONFuncImp --------------------------------
0056 
0057 JSONFuncImp::JSONFuncImp(ExecState *exec, int i, int l, const Identifier &name)
0058     : InternalFunctionImp(static_cast<FunctionPrototype *>(exec->lexicalInterpreter()->builtinFunctionPrototype()), name),
0059       id(i)
0060 {
0061     putDirect(exec->propertyNames().length, l, DontDelete | ReadOnly | DontEnum);
0062 }
0063 
0064 static void reviver(ExecState *exec, JSValue *value, JSObject *func)
0065 {
0066     if (exec->hadException()) {
0067         return;
0068     }
0069 
0070     JSType type = JSValue::type(value);
0071     switch (type) {
0072     case ObjectType: {
0073         JSObject *obj = JSValue::getObject(value);
0074         bool isArray = obj->inherits(&ArrayInstance::info);
0075         bool validArrayIndex = false;
0076 
0077         PropertyNameArray names;
0078         obj->getOwnPropertyNames(exec, names, KJS::PropertyMap::ExcludeDontEnumProperties);
0079         const int nameSize = names.size();
0080         for (int i = 0; i < nameSize; ++i) {
0081             // For Array only take properties that are valid Array indexes
0082             if (isArray) {
0083                 names[i].toArrayIndex(&validArrayIndex);
0084                 if (!validArrayIndex) {
0085                     continue;
0086                 }
0087             }
0088 
0089             JSValue *val = obj->get(exec, names[i]);
0090 
0091             List args;
0092             args.append(jsString(names[i].ustring()));
0093             args.append(val);
0094 
0095             JSValue *ret = func->call(exec, obj, args);
0096             if (exec->hadException()) {
0097                 return;
0098             }
0099             if (JSValue::isUndefined(ret)) {
0100                 obj->deleteProperty(exec, names[i]);
0101             } else {
0102                 obj->put(exec, names[i], ret);
0103                 reviver(exec, ret, func);
0104             }
0105         }
0106         break;
0107     }
0108     case NullType:
0109     case NumberType:
0110     case BooleanType:
0111     case StringType:
0112         break;
0113     case UnspecifiedType:
0114     case GetterSetterType:
0115     case UndefinedType:
0116         // should never be reached, as JSON doesn't know them
0117         // and we only have json data here
0118         ASSERT_NOT_REACHED();
0119         break;
0120     }
0121 }
0122 
0123 JSValue *JSONFuncImp::callAsFunction(ExecState *exec, JSObject * /*thisObj*/, const List &args)
0124 {
0125     switch (id) {
0126     case JSONObjectImp::Parse: {
0127         if (args.size() < 1) {
0128             return throwError(exec, SyntaxError, "Invalid JSON Syntax");
0129         }
0130 
0131         JSONParser parser(JSValue::toString(args[0], exec));
0132         if (exec->hadException()) {
0133             return jsUndefined();
0134         }
0135         JSValue *val = parser.tryParse(exec);
0136 
0137         if (!val) {
0138             return throwError(exec, SyntaxError, "Invalid JSON Syntax");
0139         }
0140 
0141         if (args.size() < 2) {
0142             return val;
0143         }
0144 
0145         JSValue *func = args[1];
0146         if (JSValue::implementsCall(func)) {
0147             JSObject *function = JSValue::getObject(func);
0148 
0149             List args;
0150             args.append(jsString(""));
0151             args.append(val);
0152 
0153             JSObject *jsobjectArg = JSValue::toObject(val, exec);
0154             if (exec->hadException()) {
0155                 return jsUndefined();
0156             }
0157             JSValue *ret = function->call(exec, jsobjectArg, args);
0158             if (JSValue::isUndefined(ret)) {
0159                 return ret;
0160             } else {
0161                 reviver(exec, ret, function);
0162                 if (exec->hadException()) {
0163                     return jsUndefined();
0164                 }
0165             }
0166         }
0167 
0168         return val;
0169     }
0170     case JSONObjectImp::Stringify: {
0171         JSValue *object = args[0];
0172         JSONStringify stringifier(exec, args[1], args[2]);
0173 
0174         JSONStringify::StringifyState state;
0175         JSValue *ret = stringifier.stringify(exec, object, state);
0176         switch (state) {
0177         case JSONStringify::Success:
0178             return ret;
0179         case JSONStringify::FailedCyclic:
0180             return throwError(exec, TypeError, "cyclic object value");
0181         case JSONStringify::FailedStackLimitExceeded:
0182             return throwError(exec, TypeError, "object stack limit exceeded");
0183         case JSONStringify::FailedException:
0184             //stringify already got an exception
0185             return jsUndefined();
0186         }
0187     }
0188     default:
0189         ASSERT_NOT_REACHED();
0190     }
0191 
0192     return jsUndefined();
0193 }