AdblockPlus::JsValuePtr AdblockPlus::JsValue::Call(const JsValueList& params, JsValuePtr thisPtr) const { if (!IsFunction()) throw new std::runtime_error("Attempting to call a non-function"); const JsContext context(jsEngine); if (!thisPtr) { v8::Local<v8::Context> localContext = v8::Local<v8::Context>::New(jsEngine->GetIsolate(), *jsEngine->context); thisPtr = JsValuePtr(new JsValue(jsEngine, localContext->Global())); } if (!thisPtr->IsObject()) throw new std::runtime_error("`this` pointer has to be an object"); v8::Local<v8::Object> thisObj = v8::Local<v8::Object>::Cast(thisPtr->UnwrapValue()); std::vector<v8::Handle<v8::Value>> argv; for (JsValueList::const_iterator it = params.begin(); it != params.end(); ++it) argv.push_back((*it)->UnwrapValue()); const v8::TryCatch tryCatch; v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(UnwrapValue()); v8::Local<v8::Value> result = func->Call(thisObj, argv.size(), argv.size() ? &argv.front() : 0); if (tryCatch.HasCaught()) throw JsError(tryCatch.Exception(), tryCatch.Message()); return JsValuePtr(new JsValue(jsEngine, result)); }
void ProcessNextChar(char c) { if (c == '\n') { state = jsBegin; // abandon current parse (if any) and start again return; } switch (state) { case jsBegin: // initial state, expecting '{' if (c == '{') { parser_watcher::StartReceivedMessage(); state = jsExpectId; fieldVal.clear(); fieldId.clear(); arrayDepth = 0; } break; case jsExpectId: // expecting a quoted ID switch (c) { case ' ': // ignore space break; case '"': state = jsId; break; case '}': // empty object, or extra comma at end of field list RemoveLastId(); if (fieldId.size() == 0) { // TODO: should we report this to the monitor as an error? parser_watcher::EndReceivedMessage(); state = jsBegin; } else { RemoveLastIdChar(); state = jsEndVal; } break; default: state = JsError(); break; } break; case jsId: // expecting an identifier, or in the middle of one switch (c) { case '"': state = jsHadId; break; default: if (c < ' ') { state = JsError(); } else if (c != ':' && c != '^') { if (!fieldId.add(c)) { state = JsError(); } } break; } break; case jsHadId: // had a quoted identifier, expecting ':' switch (c) { case ':': state = jsVal; break; case ' ': break; default: state = JsError(); break; } break; case jsVal: // had ':' or ':[', expecting value switch (c) { case ' ': break; case '"': fieldVal.clear(); state = jsStringVal; break; case '[': if (arrayDepth < MAX_ARRAY_NESTING && fieldId.add('^')) { arrayIndices[arrayDepth] = 0; // start an array ++arrayDepth; } else { state = JsError(); } break; case ']': if (InArray()) { EndArray(); // empty array state = jsEndVal; } else { state = JsError(); // ']' received without a matching '[' first } break; case '-': fieldVal.clear(); // TODO: an report error to the watcher state = (fieldVal.add(c)) ? jsNegIntVal : JsError(); break; case '{': // start of a nested object // TODO: report an error to the watcher state = (fieldId.add(':')) ? jsExpectId : JsError(); break; default: if (c >= '0' && c <= '9') { fieldVal.clear(); fieldVal.add(c); // must succeed because we just cleared fieldVal state = jsIntVal; break; } else { state = JsError(); } } break; case jsStringVal: // just had '"' and expecting a string value switch (c) { case '"': ConvertUnicode(); ProcessField(); state = jsEndVal; break; case '\\': state = jsStringEscape; break; default: if (c < ' ') { state = JsError(); } else { fieldVal.add(c); // ignore any error so that long string parameters // just get truncated } break; } break; case jsStringEscape: // just had backslash in a string if (!fieldVal.full()) { switch (c) { case '"': case '\\': case '/': if (!fieldVal.add(c)) { state = JsError(); } break; case 'n': case 't': if (!fieldVal.add(' ')) // replace newline and tab by space { // parser_watcher::ProcessError(); state = JsError(); } break; case 'b': case 'f': case 'r': default: break; } } state = jsStringVal; break; case jsNegIntVal: // had '-' so expecting a integer value // TODO: report an error to the watcher state = (c >= '0' && c <= '9' && fieldVal.add(c)) ? jsIntVal : JsError(); break; case jsIntVal: // receiving an integer value switch (c) { case '.': state = (fieldVal.add(c)) ? jsFracVal : JsError(); break; case ',': ProcessField(); if (InArray()) { ++arrayIndices[arrayDepth - 1]; fieldVal.clear(); state = jsVal; } else { RemoveLastId(); state = jsExpectId; } break; case ']': if (InArray()) { ProcessField(); ++arrayIndices[arrayDepth - 1]; EndArray(); state = jsEndVal; } else { state = JsError(); } break; case '}': if (InArray()) { state = JsError(); } else { ProcessField(); RemoveLastId(); if (fieldId.size() == 0) { parser_watcher::EndReceivedMessage(); state = jsBegin; } else { RemoveLastIdChar(); state = jsEndVal; } } break; default: if (!(c >= '0' && c <= '9' && fieldVal.add(c))) { state = JsError(); } break; } break; case jsFracVal: // receiving a fractional value switch (c) { case ',': ProcessField(); if (InArray()) { ++arrayIndices[arrayDepth - 1]; state = jsVal; } else { RemoveLastId(); state = jsExpectId; } break; case ']': if (InArray()) { ProcessField(); ++arrayIndices[arrayDepth - 1]; EndArray(); state = jsEndVal; } else { state = JsError(); } break; case '}': if (InArray()) { state = JsError(); } else { ProcessField(); RemoveLastId(); if (fieldId.size() == 0) { parser_watcher::EndReceivedMessage(); state = jsBegin; } else { RemoveLastIdChar(); state = jsEndVal; } } break; default: if (!(c >= '0' && c <= '9' && fieldVal.add(c))) { state = JsError(); } break; } break; case jsEndVal: // had the end of a string or array value, expecting comma // or ] or } switch (c) { case ',': if (InArray()) { ++arrayIndices[arrayDepth - 1]; fieldVal.clear(); state = jsVal; } else { RemoveLastId(); state = jsExpectId; } break; case ']': if (InArray()) { ++arrayIndices[arrayDepth - 1]; EndArray(); } else { state = JsError(); } break; case '}': if (InArray()) { state = JsError(); } else { RemoveLastId(); if (fieldId.size() == 0) { parser_watcher::EndReceivedMessage(); state = jsBegin; } else { RemoveLastIdChar(); // state = jsEndVal; // not needed, state == jsEndVal already } } break; default: break; } break; case jsError: // Ignore all characters. State will be reset to jsBegin at the start of // this function when we receive a newline. break; } }