/* * call-seq: * length() * * Returns the number of entries in the JavaScript array, or the number * of properties on the JavaScript object. */ static VALUE length(VALUE self) { RubyLandProxy* proxy; Data_Get_Struct(self, RubyLandProxy, proxy); JSContext * context = johnson_get_current_context(proxy->runtime); PREPARE_RUBY_JROOTS(context, 2); jsval proxy_value; JCHECK(get_jsval_for_proxy(proxy, &proxy_value)); JROOT(proxy_value); JSObject* value = JSVAL_TO_OBJECT(proxy_value); JROOT(value); if (JS_IsArrayObject(context, value)) { jsuint length; JCHECK(JS_GetArrayLength(context, value, &length)); JRETURN_RUBY(INT2FIX(length)); } else { JSIdArray* ids = JS_Enumerate(context, value); JCHECK(ids); VALUE length = INT2FIX(ids->length); JS_DestroyIdArray(context, ids); JRETURN_RUBY(length); } }
static void add_multiopt(JSContext *cx, js_setting_t *jss, JSObject *optlist, const char *vdef) { JSIdArray *opts, *opt; int i; if((opts = JS_Enumerate(cx, optlist)) == NULL) return; for(i = 0; i < opts->length; i++) { jsval name, value; if(!JS_IdToValue(cx, opts->vector[i], &name) || !JSVAL_IS_INT(name) || !JS_GetElement(cx, optlist, JSVAL_TO_INT(name), &value) || !JSVAL_IS_OBJECT(value) || (opt = JS_Enumerate(cx, JSVAL_TO_OBJECT(value))) == NULL) continue; if(opt->length >= 2) { jsval id, title, def; if(JS_GetElement(cx, JSVAL_TO_OBJECT(value), 0, &id) && JS_GetElement(cx, JSVAL_TO_OBJECT(value), 1, &title)) { if(opt->length < 3 || !JS_GetElement(cx, JSVAL_TO_OBJECT(value), 2, &def)) def = JSVAL_FALSE; const char *k = JS_GetStringBytes(JS_ValueToString(cx, id)); if(vdef) def = !strcmp(k, vdef) ? JSVAL_TRUE : JSVAL_FALSE; settings_multiopt_add_opt_cstr(jss->jss_s, k, JS_GetStringBytes(JS_ValueToString(cx, title)), def == JSVAL_TRUE); } } JS_DestroyIdArray(cx, opt); } JS_DestroyIdArray(cx, opts); }
/** * Convert a JavaScript Object to a map * * @param cx the JavaScript context * @param t the JavaScript Object to convert * @return a new map containing the JavaScript Object */ map* mapFromJSObject(JSContext *cx,jsval t){ map *res=NULL; JSIdArray *idp=JS_Enumerate(cx,JSVAL_TO_OBJECT(t)); #ifdef JS_DEBUG fprintf(stderr,"Properties %p\n",(void*)t); #endif if(idp!=NULL) { int index; jsdouble argNum; #ifdef JS_DEBUG fprintf(stderr,"Properties length : %d \n",idp->length); #endif for (index=0,argNum=idp->length;index<argNum;index++) { jsval id = idp->vector[index]; jsval vp; JS_IdToValue(cx,id,&vp); char *tmp, *tmp1; JSString *jsmsg,*jsmsg1; size_t len,len1; jsmsg = JS_ValueToString(cx,vp); len = JS_GetStringLength(jsmsg); jsval nvp; tmp=JS_EncodeString(cx,jsmsg); JS_GetProperty(cx, JSVAL_TO_OBJECT(t), tmp, &nvp); jsmsg1 = JS_ValueToString(cx,nvp); len1 = JS_GetStringLength(jsmsg1); tmp1=JS_EncodeString(cx,jsmsg1); #ifdef JS_DEBUG fprintf(stderr,"Enumerate id : %d [ %s => %s ]\n",index,tmp,tmp1); #endif if(strcasecmp(tmp,"child")!=0){ if(res!=NULL){ #ifdef JS_DEBUG fprintf(stderr,"%s - %s\n",tmp,tmp1); #endif addToMap(res,tmp,tmp1); } else{ res=createMap(tmp,tmp1); res->next=NULL; } } free(tmp); free(tmp1); #ifdef JS_DEBUG dumpMap(res); #endif } JS_DestroyIdArray(cx,idp); } #ifdef JS_DEBUG dumpMap(res); #endif return res; }
BSONObj toObject( JSObject * o , int depth = 0) { if ( ! o ) return BSONObj(); if ( JS_InstanceOf( _context , o , &bson_ro_class , 0 ) ) { BSONHolder * holder = GETHOLDER( _context , o ); assert( holder ); return holder->_obj.getOwned(); } BSONObj orig; if ( JS_InstanceOf( _context , o , &bson_class , 0 ) ) { BSONHolder * holder = GETHOLDER(_context,o); assert( holder ); if ( ! holder->_modified ) { return holder->_obj; } orig = holder->_obj; } BSONObjBuilder b; if ( ! appendSpecialDBObject( this , b , "value" , OBJECT_TO_JSVAL( o ) , o ) ) { if ( depth == 0 ) { jsval theid = getProperty( o , "_id" ); if ( ! JSVAL_IS_VOID( theid ) ) { append( b , "_id" , theid , EOO , depth + 1 ); } } JSIdArray * properties = JS_Enumerate( _context , o ); assert( properties ); for ( jsint i=0; i<properties->length; i++ ) { jsid id = properties->vector[i]; jsval nameval; assert( JS_IdToValue( _context ,id , &nameval ) ); string name = toString( nameval ); if ( depth == 0 && name == "_id" ) continue; append( b , name , getProperty( o , name.c_str() ) , orig[name].type() , depth + 1 ); } JS_DestroyIdArray( _context , properties ); } return b.obj(); }
XPCDispJSPropertyInfo::XPCDispJSPropertyInfo(JSContext* cx, PRUint32 memid, JSObject* obj, jsval val) : mPropertyType(INVALID), mMemID(memid) { PRUint32 len; jschar * chars = xpc_JSString2String(cx, val, &len); if(!chars) return; mName = nsString(reinterpret_cast<const PRUnichar *>(chars), len); JSBool found; uintN attr; // Get the property's attributes, and make sure it's found and enumerable if(!JS_GetUCPropertyAttributes(cx, obj, chars, len, &attr, &found) || !found || (attr & JSPROP_ENUMERATE) == 0) return; // Retrieve the property if(!chars || !JS_GetUCProperty(cx, obj, chars, len, &mProperty) || JSVAL_IS_NULL(mProperty)) return; // If this is a function if(JSVAL_IS_OBJECT(mProperty) && JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(mProperty))) { mPropertyType = FUNCTION; JSObject * funcObj = JSVAL_TO_OBJECT(mProperty); JSIdArray * funcObjArray = JS_Enumerate(cx, funcObj); if(funcObjArray) { mParamCount = funcObjArray->length; } } else // It's a property { mParamCount = 0; if((attr & JSPROP_READONLY) != 0) { mPropertyType = READONLY_PROPERTY; } else { mPropertyType = PROPERTY; } } }
static JSBool jsExec( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ) { if( ( 1 <= argc ) && JSVAL_IS_STRING( argv[0] ) ){ execCalled_ = true ; abortCodeQueue(); execCmd_ = JS_GetStringBytes( JS_ValueToString( cx, argv[0] ) ); execCmdArgs_.clear(); execCmdArgs_.push_back(execCmd_); } else if( (1 == argc) && JSVAL_IS_OBJECT(argv[0]) ){ JSObject *obj ; JSIdArray *elements ; if( JS_ValueToObject(cx, argv[0], &obj) && ( 0 != ( elements = JS_Enumerate(cx,obj ) ) ) ){ for( int i = 0 ; i < elements->length ; i++ ) { jsval rv ; JSString *s ; if( JS_LookupElement( cx, obj, i, &rv ) //look up each element && (0 != (s=JS_ValueToString(cx, rv))) ) { execCmdArgs_.push_back(std::string(JS_GetStringBytes(s))); } } } else JS_ReportError(cx, "Error parsing exec() array parameter\n" ); if( 0 < execCmdArgs_.size() ){ execCmd_ = execCmdArgs_[0]; execCalled_ = true ; } } else JS_ReportError( cx, "Usage: exec( 'cmdline' ) || exec( ['/path/to/exe','param1' ...] )\n" ); *rval = JSVAL_TRUE ; return JS_TRUE ; }
XPCDispTypeInfo * XPCDispTypeInfo::New(XPCCallContext& ccx, JSObject* obj) { XPCDispTypeInfo * pTypeInfo = 0; JSIdArray * jsArray = JS_Enumerate(ccx, obj); if(!jsArray) return nsnull; XPCDispIDArray* array = new XPCDispIDArray(ccx, jsArray); if(!array) return nsnull; pTypeInfo = new XPCDispTypeInfo(ccx, obj, array); if(!pTypeInfo) { delete array; return nsnull; } NS_ADDREF(pTypeInfo); return pTypeInfo; }
ObjectWrapper::WriteFieldRecursionFrame::WriteFieldRecursionFrame(JSContext* cx, JSObject* obj, BSONObjBuilder* parent, StringData sd) : thisv(cx, obj), ids(cx, JS::IdVector(cx)) { bool isArray = false; if (parent) { if (!JS_IsArrayObject(cx, thisv, &isArray)) { throwCurrentJSException( cx, ErrorCodes::JSInterpreterFailure, "Failure to check object is an array"); } subbob.emplace(isArray ? parent->subarrayStart(sd) : parent->subobjStart(sd)); } if (isArray) { uint32_t length; if (!JS_GetArrayLength(cx, thisv, &length)) { throwCurrentJSException( cx, ErrorCodes::JSInterpreterFailure, "Failure to get array length"); } if (!ids.reserve(length)) { throwCurrentJSException( cx, ErrorCodes::JSInterpreterFailure, "Failure to reserve array"); } JS::RootedId rid(cx); for (uint32_t i = 0; i < length; i++) { rid.set(INT_TO_JSID(i)); ids.infallibleAppend(rid); } } else { if (!JS_Enumerate(cx, thisv, &ids)) { throwCurrentJSException( cx, ErrorCodes::JSInterpreterFailure, "Failure to enumerate object"); } } if (getScope(cx)->getProto<BSONInfo>().instanceOf(thisv)) { std::tie(originalBSON, altered) = BSONInfo::originalBSON(cx, thisv); } }
int js_prop_from_object(JSContext *cx, JSObject *obj, prop_t *p) { JSIdArray *ida; int i, r = 0; const char *n; int array_zapped = 0; if((ida = JS_Enumerate(cx, obj)) == NULL) return -1; for(i = 0; i < ida->length; i++) { jsval name, value; if(!JS_IdToValue(cx, ida->vector[i], &name)) continue; if(JSVAL_IS_STRING(name)) { n = JS_GetStringBytes(JSVAL_TO_STRING(name)); if(!JS_GetProperty(cx, obj, n, &value)) continue; } else if(JSVAL_IS_INT(name)) { if(!JS_GetElement(cx, obj, JSVAL_TO_INT(name), &value) || JSVAL_IS_VOID(value)) continue; if(!array_zapped) { array_zapped = 1; prop_destroy_by_name(p, NULL); } n = NULL; } else { continue; } if(JSVAL_TO_OBJECT(value) == obj) continue; js_prop_set_from_jsval(cx, prop_create(p, n), value); } JS_DestroyIdArray(cx, ida); return r; }
bool ScriptInterface::EnumeratePropertyNamesWithPrefix(JS::HandleValue objVal, const char* prefix, std::vector<std::string>& out) { JSAutoRequest rq(m->m_cx); if (!objVal.isObjectOrNull()) { LOGERROR("EnumeratePropertyNamesWithPrefix expected object type!"); return false; } if (objVal.isNull()) return true; // reached the end of the prototype chain JS::RootedObject obj(m->m_cx, &objVal.toObject()); JS::AutoIdArray props(m->m_cx, JS_Enumerate(m->m_cx, obj)); if (!props) return false; for (size_t i = 0; i < props.length(); ++i) { JS::RootedId id(m->m_cx, props[i]); JS::RootedValue val(m->m_cx); if (!JS_IdToValue(m->m_cx, id, &val)) return false; if (!val.isString()) continue; // ignore integer properties JS::RootedString name(m->m_cx, val.toString()); size_t len = strlen(prefix)+1; std::vector<char> buf(len); size_t prefixLen = strlen(prefix) * sizeof(char); JS_EncodeStringToBuffer(m->m_cx, name, &buf[0], prefixLen); buf[len-1]= '\0'; if (0 == strcmp(&buf[0], prefix)) { if (JS_StringHasLatin1Chars(name)) { size_t length; JS::AutoCheckCannotGC nogc; const JS::Latin1Char* chars = JS_GetLatin1StringCharsAndLength(m->m_cx, nogc, name, &length); if (chars) out.push_back(std::string(chars, chars+length)); } else { size_t length; JS::AutoCheckCannotGC nogc; const char16_t* chars = JS_GetTwoByteStringCharsAndLength(m->m_cx, nogc, name, &length); if (chars) out.push_back(std::string(chars, chars+length)); } } } // Recurse up the prototype chain JS::RootedObject prototype(m->m_cx); if (JS_GetPrototype(m->m_cx, obj, &prototype)) { JS::RootedValue prototypeVal(m->m_cx, JS::ObjectOrNullValue(prototype)); if (!EnumeratePropertyNamesWithPrefix(prototypeVal, prefix, out)) return false; } return true; }
/** * Convert a JavaScript Object to a maps * * @param cx the JavaScript context * @param t the JavaScript Object to convert * @return a new maps containing the JavaScript Object */ maps* mapsFromJSObject(JSContext *cx,jsval t){ maps *res=NULL; maps *tres=NULL; jsint oi=0; JSObject* tt=JSVAL_TO_OBJECT(t); if(JS_IsArrayObject(cx,tt)){ #ifdef JS_DEBUG fprintf(stderr,"Is finally an array !\n"); #endif } else{ #ifdef JS_DEBUG fprintf(stderr,"Is not an array !\n"); #endif JSIdArray *idp=JS_Enumerate(cx,tt); if(idp!=NULL) { int index; jsdouble argNum; #ifdef JS_DEBUG fprintf(stderr,"Properties length : %d \n",idp->length); #endif for (index=0,argNum=idp->length;index<argNum;index++) { jsval id = idp->vector[index]; jsval vp; JS_IdToValue(cx,id,&vp); char *tmp; JSString *jsmsg; size_t len1; jsmsg = JS_ValueToString(cx,vp); len1 = JS_GetStringLength(jsmsg); tmp=JS_EncodeString(cx,jsmsg); tres=createMaps(tmp); jsval nvp=JSVAL_NULL; if((JS_GetProperty(cx, tt, tmp, &nvp)==JS_FALSE)){ #ifdef JS_DEBUG fprintf(stderr,"Enumerate id : %d => %s => No more value\n",oi,tmp); #endif } free(tmp); JSObject *nvp1=JSVAL_TO_OBJECT(JSVAL_NULL); JS_ValueToObject(cx,nvp,&nvp1); jsval nvp1j=OBJECT_TO_JSVAL(nvp1); if(JSVAL_IS_OBJECT(nvp1j)){ tres->content=mapFromJSObject(cx,nvp1j); } jsval nvp0=JSVAL_NULL; JSObject *nvp01=JSVAL_TO_OBJECT(JSVAL_NULL); if((JS_GetProperty(cx, nvp1, "child", &nvp0)==JS_FALSE)){ #ifdef JS_DEBUG fprintf(stderr,"Enumerate id : %d => %s => No more value\n",oi,tmp); #endif } JS_ValueToObject(cx,nvp0,&nvp01); jsval nvp01j=OBJECT_TO_JSVAL(nvp01); if(!JSVAL_IS_NULL(nvp01j)){ tres->child=mapsFromJSObject(cx,nvp01j); } if(res==NULL) res=dupMaps(&tres); else addMapsToMaps(&res,tres); freeMaps(&tres); free(tres); tres=NULL; } JS_DestroyIdArray(cx,idp); } } jsuint len; JSBool hasLen=JS_GetArrayLength(cx, tt, &len); #ifdef JS_DEBUG if(hasLen==JS_FALSE){ fprintf(stderr,"outputs array is empty\n"); } fprintf(stderr,"outputs array length : %d\n",len); #endif for(oi=0;hasLen && oi < len;oi++){ #ifdef JS_DEBUG fprintf(stderr,"outputs array length : %d step %d \n",len,oi); #endif jsval tmp1; JSBool hasElement=JS_GetElement(cx,tt,oi,&tmp1); JSObject *otmp1=JSVAL_TO_OBJECT(tmp1); JSIdArray *idp=JS_Enumerate(cx,otmp1); if(idp!=NULL) { int index; jsdouble argNum; #ifdef JS_DEBUG fprintf(stderr,"Properties length : %d \n",idp->length); #endif tres=(maps*)malloc(MAPS_SIZE); tres->name=NULL; tres->content=NULL; tres->next=NULL; for (index=0,argNum=idp->length;index<argNum;index++) { jsval id = idp->vector[index]; jsval vp; JS_IdToValue(cx,id,&vp); char *tmp; JSString *jsmsg; size_t len1; jsmsg = JS_ValueToString(cx,vp); len1 = JS_GetStringLength(jsmsg); tmp=JS_EncodeString(cx,jsmsg); #ifdef JS_DEBUG fprintf(stderr,"Enumerate id : %d => %s\n",oi,tmp); #endif jsval nvp=JSVAL_NULL; if((JS_GetProperty(cx, JSVAL_TO_OBJECT(tmp1), tmp, &nvp)==JS_FALSE)){ #ifdef JS_DEBUG fprintf(stderr,"Enumerate id : %d => %s => No more value\n",oi,tmp); #endif } free(tmp); if(JSVAL_IS_OBJECT(nvp)){ #ifdef JS_DEBUG fprintf(stderr,"JSVAL NVP IS OBJECT\n"); #endif } JSObject *nvp1=JSVAL_TO_OBJECT(JSVAL_NULL); JS_ValueToObject(cx,nvp,&nvp1); jsval nvp1j=OBJECT_TO_JSVAL(nvp1); if(JSVAL_IS_OBJECT(nvp1j)){ JSString *jsmsg1; char *tmp1, *tmp2; JSObject *nvp2=JSVAL_TO_OBJECT(JSVAL_NULL); jsmsg1 = JS_ValueToString(cx,nvp1j); len1 = JS_GetStringLength(jsmsg1); tmp1=JS_EncodeString(cx,jsmsg1); tmp2=JS_EncodeString(cx,jsmsg); #ifdef JS_DEBUG fprintf(stderr,"JSVAL NVP1J IS OBJECT %s = %s\n",JS_EncodeString(cx,jsmsg),tmp1); #endif if(strcasecmp(tmp1,"[object Object]")==0){ tres->name=zStrdup(tmp2); tres->content=mapFromJSObject(cx,nvp1j); } else if(strcasecmp(tmp2,"name")==0){ tres->name=zStrdup(tmp1); } else{ if(tres->content==NULL) tres->content=createMap(tmp2,tmp1); else addToMap(tres->content,tmp2,tmp1); } free(tmp1); free(tmp2); } #ifdef JS_DEBUG else fprintf(stderr,"JSVAL NVP1J IS NOT OBJECT !!\n"); #endif } #ifdef JS_DEBUG dumpMaps(tres); #endif if(res==NULL) res=dupMaps(&tres); else addMapsToMaps(&res,tres); freeMaps(&tres); free(tres); tres=NULL; JS_DestroyIdArray(cx,idp); } } #ifdef JS_DEBUG dumpMaps(res); #endif return res; }
void Server::invokeCallback( const JSCallback & theCallback, const request & theRequest, reply & theReply) { std::string myResponseString; try { jsval argv[4], rval; argv[0] = jslib::as_jsval(theCallback.context, theRequest.method); argv[1] = jslib::as_jsval(theCallback.context, theRequest.body); argv[2] = jslib::as_jsval(theCallback.context, theRequest.uri ); argv[3] = jslib::as_jsval(theCallback.context, theRequest.headers ); jslib::JSA_CallFunctionValue(theCallback.context, theCallback.object, theCallback.functionValue, 4, argv, &rval); if (JSVAL_IS_VOID(rval)) { theReply.status = reply::no_content; return; } // changed to adhere to industry standard: // the callback must return either: // body // [statuscode, body] // [statucode, headers, body] // // where body is a string, statuscode an integer and headers a hash. if (JSVAL_IS_OBJECT(rval)) { JSObject * myJsObject; jsuint arrayLength; if(JS_ValueToObject(theCallback.context, rval, &myJsObject)) { if (JS_IsArrayObject(theCallback.context, myJsObject) && JS_GetArrayLength(theCallback.context, myJsObject, &arrayLength)) { jsval curElement; // first element: status JS_GetElement(theCallback.context, myJsObject, 0, &curElement); if (!JSVAL_IS_VOID(curElement)) { int myStatusCode; jslib::convertFrom(theCallback.context, curElement, myStatusCode); theReply.status = static_cast<reply::status_type>(myStatusCode); } else { theReply.status = reply::ok; } // 2nd element (if array has three elements) headers if (arrayLength == 3) { JS_GetElement(theCallback.context, myJsObject, 1, &curElement); if (JSVAL_IS_OBJECT(curElement)) { JSObject *headers = JSVAL_TO_OBJECT(curElement); JSIdArray *props = JS_Enumerate(theCallback.context, headers); for (int i = 0; props && i < props->length; ++i) { jsid propid = props->vector[i]; jsval propname; if (!JS_IdToValue(theCallback.context, propid, &propname)) { AC_WARNING << "Weird case"; continue; } std::string header_name; if (!jslib::convertFrom(theCallback.context, propname, header_name)) { JS_ReportError(theCallback.context, "Server::handleRequest: header_name is not a string!"); } jsval propval; if (!JS_GetProperty(theCallback.context, headers, header_name.c_str(), &propval)) { AC_WARNING << "Weird case"; continue; } std::string header_value; if (!jslib::convertFrom(theCallback.context, propval, header_value)) { JS_ReportError(theCallback.context, "Server::handleRequest: header_value is not a a string!"); } theReply.headers.insert(make_pair(header_name, header_value)); } } } // last element: Body JS_GetElement(theCallback.context, myJsObject, arrayLength-1, &curElement); if (!JSVAL_IS_VOID(curElement)) { jslib::convertFrom(theCallback.context, curElement, theReply.content); } return; } } } // default (backwards-compatible): treat jsval as string... if (!jslib::convertFrom(theCallback.context, rval, myResponseString)) { JS_ReportError(theCallback.context, "Server::handleRequest: Callback does not return a string!"); } theReply.content = myResponseString; theReply.status = reply::ok; theReply.headers.insert(make_pair("Content-Type", theCallback.contentType)); return; } catch (Exception e) { theReply.status = reply::internal_server_error; theReply.content = std::string("An internal error occured: ") + asl::compose_message(e); AC_ERROR << e; return; }; }
void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val) { JSContext* cx = m_ScriptInterface.GetContext(); JSAutoRequest rq(cx); switch (JS_TypeOfValue(cx, val)) { case JSTYPE_VOID: { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_VOID); break; } case JSTYPE_NULL: // This type is never actually returned (it's a JS2 feature) { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_NULL); break; } case JSTYPE_OBJECT: { if (val.isNull()) { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_NULL); break; } JS::RootedObject obj(cx, &val.toObject()); // If we've already serialized this object, just output a reference to it u32 tag = GetScriptBackrefTag(obj); if (tag) { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_BACKREF); m_Serializer.NumberU32_Unbounded("tag", tag); break; } // Arrays are special cases of Object if (JS_IsArrayObject(cx, obj)) { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_ARRAY); // TODO: probably should have a more efficient storage format // Arrays like [1, 2, ] have an 'undefined' at the end which is part of the // length but seemingly isn't enumerated, so store the length explicitly uint length = 0; if (!JS_GetArrayLength(cx, obj, &length)) throw PSERROR_Serialize_ScriptError("JS_GetArrayLength failed"); m_Serializer.NumberU32_Unbounded("array length", length); } else if (JS_IsTypedArrayObject(obj)) { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_TYPED_ARRAY); m_Serializer.NumberU8_Unbounded("array type", GetArrayType(JS_GetArrayBufferViewType(obj))); m_Serializer.NumberU32_Unbounded("byte offset", JS_GetTypedArrayByteOffset(obj)); m_Serializer.NumberU32_Unbounded("length", JS_GetTypedArrayLength(obj)); // Now handle its array buffer // this may be a backref, since ArrayBuffers can be shared by multiple views JS::RootedValue bufferVal(cx, JS::ObjectValue(*JS_GetArrayBufferViewBuffer(cx, obj))); HandleScriptVal(bufferVal); break; } else if (JS_IsArrayBufferObject(obj)) { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_ARRAY_BUFFER); #if BYTE_ORDER != LITTLE_ENDIAN #error TODO: need to convert JS ArrayBuffer data to little-endian #endif u32 length = JS_GetArrayBufferByteLength(obj); m_Serializer.NumberU32_Unbounded("buffer length", length); JS::AutoCheckCannotGC nogc; m_Serializer.RawBytes("buffer data", (const u8*)JS_GetArrayBufferData(obj, nogc), length); break; } else { // Find type of object const JSClass* jsclass = JS_GetClass(obj); if (!jsclass) throw PSERROR_Serialize_ScriptError("JS_GetClass failed"); // TODO: Remove this workaround for upstream API breakage when updating SpiderMonkey // See https://bugzilla.mozilla.org/show_bug.cgi?id=1236373 #define JSCLASS_CACHED_PROTO_WIDTH js::JSCLASS_CACHED_PROTO_WIDTH JSProtoKey protokey = JSCLASS_CACHED_PROTO_KEY(jsclass); #undef JSCLASS_CACHED_PROTO_WIDTH if (protokey == JSProto_Object) { // Object class - check for user-defined prototype JS::RootedObject proto(cx); JS_GetPrototype(cx, obj, &proto); if (!proto) throw PSERROR_Serialize_ScriptError("JS_GetPrototype failed"); if (m_SerializablePrototypes->empty() || !IsSerializablePrototype(proto)) { // Standard Object prototype m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT); // TODO: maybe we should throw an error for unrecognized non-Object prototypes? // (requires fixing AI serialization first and excluding component scripts) } else { // User-defined custom prototype m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_PROTOTYPE); const std::wstring prototypeName = GetPrototypeName(proto); m_Serializer.String("proto name", prototypeName, 0, 256); // Does it have custom Serialize function? // if so, we serialize the data it returns, rather than the object's properties directly bool hasCustomSerialize; if (!JS_HasProperty(cx, obj, "Serialize", &hasCustomSerialize)) throw PSERROR_Serialize_ScriptError("JS_HasProperty failed"); if (hasCustomSerialize) { JS::RootedValue serialize(cx); if (!JS_GetProperty(cx, obj, "Serialize", &serialize)) throw PSERROR_Serialize_ScriptError("JS_GetProperty failed"); // If serialize is null, so don't serialize anything more if (!serialize.isNull()) { JS::RootedValue data(cx); if (!m_ScriptInterface.CallFunction(val, "Serialize", &data)) throw PSERROR_Serialize_ScriptError("Prototype Serialize function failed"); HandleScriptVal(data); } break; } } } else if (protokey == JSProto_Number) { // Standard Number object m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_NUMBER); // Get primitive value double d; if (!JS::ToNumber(cx, val, &d)) throw PSERROR_Serialize_ScriptError("JS::ToNumber failed"); m_Serializer.NumberDouble_Unbounded("value", d); break; } else if (protokey == JSProto_String) { // Standard String object m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_STRING); // Get primitive value JS::RootedString str(cx, JS::ToString(cx, val)); if (!str) throw PSERROR_Serialize_ScriptError("JS_ValueToString failed"); ScriptString("value", str); break; } else if (protokey == JSProto_Boolean) { // Standard Boolean object m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_BOOLEAN); // Get primitive value bool b = JS::ToBoolean(val); m_Serializer.Bool("value", b); break; } // TODO: Follow upstream progresses about a JS::IsMapObject // https://bugzilla.mozilla.org/show_bug.cgi?id=1285909 else if (protokey == JSProto_Map) { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_MAP); m_Serializer.NumberU32_Unbounded("map size", JS::MapSize(cx, obj)); JS::RootedValue keyValueIterator(cx); if (!JS::MapEntries(cx, obj, &keyValueIterator)) throw PSERROR_Serialize_ScriptError("JS::MapEntries failed"); JS::ForOfIterator it(cx); if (!it.init(keyValueIterator)) throw PSERROR_Serialize_ScriptError("JS::ForOfIterator::init failed"); JS::RootedValue keyValuePair(cx); bool done; while (true) { if (!it.next(&keyValuePair, &done)) throw PSERROR_Serialize_ScriptError("JS::ForOfIterator::next failed"); if (done) break; JS::RootedObject keyValuePairObj(cx, &keyValuePair.toObject()); JS::RootedValue key(cx); JS::RootedValue value(cx); ENSURE(JS_GetElement(cx, keyValuePairObj, 0, &key)); ENSURE(JS_GetElement(cx, keyValuePairObj, 1, &value)); HandleScriptVal(key); HandleScriptVal(value); } break; } // TODO: Follow upstream progresses about a JS::IsSetObject // https://bugzilla.mozilla.org/show_bug.cgi?id=1285909 else if (protokey == JSProto_Set) { // TODO: When updating SpiderMonkey to a release after 38 use the C++ API for Sets. // https://bugzilla.mozilla.org/show_bug.cgi?id=1159469 u32 setSize; m_ScriptInterface.GetProperty(val, "size", setSize); m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_SET); m_Serializer.NumberU32_Unbounded("set size", setSize); JS::RootedValue valueIterator(cx); m_ScriptInterface.CallFunction(val, "values", &valueIterator); for (u32 i=0; i<setSize; ++i) { JS::RootedValue currentIterator(cx); JS::RootedValue value(cx); ENSURE(m_ScriptInterface.CallFunction(valueIterator, "next", ¤tIterator)); m_ScriptInterface.GetProperty(currentIterator, "value", &value); HandleScriptVal(value); } break; } else { // Unrecognized class LOGERROR("Cannot serialise JS objects with unrecognized class '%s'", jsclass->name); throw PSERROR_Serialize_InvalidScriptValue(); } } // Find all properties (ordered by insertion time) JS::AutoIdArray ida (cx, JS_Enumerate(cx, obj)); if (!ida) throw PSERROR_Serialize_ScriptError("JS_Enumerate failed"); m_Serializer.NumberU32_Unbounded("num props", (u32)ida.length()); for (size_t i = 0; i < ida.length(); ++i) { JS::RootedId id(cx, ida[i]); JS::RootedValue idval(cx); JS::RootedValue propval(cx); // Forbid getters, which might delete values and mess things up. JS::Rooted<JSPropertyDescriptor> desc(cx); if (!JS_GetPropertyDescriptorById(cx, obj, id, &desc)) throw PSERROR_Serialize_ScriptError("JS_GetPropertyDescriptorById failed"); if (desc.hasGetterObject()) throw PSERROR_Serialize_ScriptError("Cannot serialize property getters"); // Get the property name as a string if (!JS_IdToValue(cx, id, &idval)) throw PSERROR_Serialize_ScriptError("JS_IdToValue failed"); JS::RootedString idstr(cx, JS::ToString(cx, idval)); if (!idstr) throw PSERROR_Serialize_ScriptError("JS_ValueToString failed"); ScriptString("prop name", idstr); if (!JS_GetPropertyById(cx, obj, id, &propval)) throw PSERROR_Serialize_ScriptError("JS_GetPropertyById failed"); HandleScriptVal(propval); } break; } case JSTYPE_FUNCTION: { // We can't serialise functions, but we can at least name the offender (hopefully) std::wstring funcname(L"(unnamed)"); JS::RootedFunction func(cx, JS_ValueToFunction(cx, val)); if (func) { JS::RootedString string(cx, JS_GetFunctionId(func)); if (string) { if (JS_StringHasLatin1Chars(string)) { size_t length; JS::AutoCheckCannotGC nogc; const JS::Latin1Char* ch = JS_GetLatin1StringCharsAndLength(cx, nogc, string, &length); if (ch && length > 0) funcname.assign(ch, ch + length); } else { size_t length; JS::AutoCheckCannotGC nogc; const char16_t* ch = JS_GetTwoByteStringCharsAndLength(cx, nogc, string, &length); if (ch && length > 0) funcname.assign(ch, ch + length); } } } LOGERROR("Cannot serialise JS objects of type 'function': %s", utf8_from_wstring(funcname)); throw PSERROR_Serialize_InvalidScriptValue(); } case JSTYPE_STRING: { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_STRING); JS::RootedString stringVal(cx, val.toString()); ScriptString("string", stringVal); break; } case JSTYPE_NUMBER: { // To reduce the size of the serialized data, we handle integers and doubles separately. // We can't check for val.isInt32 and val.isDouble directly, because integer numbers are not guaranteed // to be represented as integers. A number like 33 could be stored as integer on the computer of one player // and as double on the other player's computer. That would cause out of sync errors in multiplayer games because // their binary representation and thus the hash would be different. double d; d = val.toNumber(); i32 integer; if (JS_DoubleIsInt32(d, &integer)) { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_INT); m_Serializer.NumberI32_Unbounded("value", integer); } else { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_DOUBLE); m_Serializer.NumberDouble_Unbounded("value", d); } break; } case JSTYPE_BOOLEAN: { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_BOOLEAN); bool b = val.toBoolean(); m_Serializer.NumberU8_Unbounded("value", b ? 1 : 0); break; } default: { debug_warn(L"Invalid TypeOfValue"); throw PSERROR_Serialize_InvalidScriptValue(); } } }
/* * call-seq: * each {| element | block } * each {| name, value | block } * * Calls <em>block</em> with each item in this JavaScript array, or with * each +name+/+value+ pair (like a Hash) for any other JavaScript * object. */ static VALUE each(VALUE self) { RubyLandProxy* proxy; Data_Get_Struct(self, RubyLandProxy, proxy); JSContext * context = johnson_get_current_context(proxy->runtime); PREPARE_RUBY_JROOTS(context, 5); jsval proxy_value; JCHECK(get_jsval_for_proxy(proxy, &proxy_value)); JROOT(proxy_value); JSObject* value = JSVAL_TO_OBJECT(proxy_value); JROOT(value); // arrays behave like you'd expect, indexes in order if (JS_IsArrayObject(context, value)) { jsuint length; JCHECK(JS_GetArrayLength(context, value, &length)); jsuint i = 0; for (i = 0; i < length; ++i) { jsval element; JCHECK(JS_GetElement(context, value, (signed) i, &element)); CALL_RUBY_WRAPPER(rb_yield, CONVERT_TO_RUBY(proxy->runtime, element)); } } else { // not an array? behave like each on Hash; yield [key, value] JSIdArray* ids = JS_Enumerate(context, value); JCHECK(ids); JCLEANUP(destroy_id_array, ids); int i; for (i = 0; i < ids->length; ++i) { jsval js_key, js_value; JCHECK(JS_IdToValue(context, ids->vector[i], &js_key)); JROOT(js_key); if (JSVAL_IS_STRING(js_key)) { // regular properties have string keys JCHECK(JS_GetProperty(context, value, JS_GetStringBytes(JSVAL_TO_STRING(js_key)), &js_value)); } else { // it's a numeric property, use array access JCHECK(JS_GetElement(context, value, JSVAL_TO_INT(js_key), &js_value)); } JROOT(js_value); VALUE key = CONVERT_TO_RUBY(proxy->runtime, js_key); VALUE value = CONVERT_TO_RUBY(proxy->runtime, js_value); CALL_RUBY_WRAPPER(rb_yield, rb_ary_new3(2L, key, value)); JUNROOT(js_value); JUNROOT(js_key); } } JRETURN_RUBY(self); }
// Clone a new value (and root it and add it to the mapping) jsval Clone(jsval val) { if (JSVAL_IS_DOUBLE(val)) { jsval rval; CLONE_REQUIRE(JS_NewNumberValue(cxTo, JSVAL_TO_DOUBLE(val), &rval), L"JS_NewNumberValue"); m_RooterTo.Push(rval); return rval; } if (JSVAL_IS_STRING(val)) { size_t len; const jschar* chars = JS_GetStringCharsAndLength(cxFrom, JSVAL_TO_STRING(val), &len); CLONE_REQUIRE(chars, L"JS_GetStringCharsAndLength"); JSString* str = JS_NewUCStringCopyN(cxTo, chars, len); CLONE_REQUIRE(str, L"JS_NewUCStringCopyN"); jsval rval = STRING_TO_JSVAL(str); m_Mapping[JSVAL_TO_GCTHING(val)] = rval; m_RooterTo.Push(rval); return rval; } ENSURE(JSVAL_IS_OBJECT(val)); JSObject* newObj; if (JS_IsArrayObject(cxFrom, JSVAL_TO_OBJECT(val))) { jsuint length; CLONE_REQUIRE(JS_GetArrayLength(cxFrom, JSVAL_TO_OBJECT(val), &length), L"JS_GetArrayLength"); newObj = JS_NewArrayObject(cxTo, length, NULL); CLONE_REQUIRE(newObj, L"JS_NewArrayObject"); } else { newObj = JS_NewObject(cxTo, NULL, NULL, NULL); CLONE_REQUIRE(newObj, L"JS_NewObject"); } m_Mapping[JSVAL_TO_GCTHING(val)] = OBJECT_TO_JSVAL(newObj); m_RooterTo.Push(newObj); AutoJSIdArray ida (cxFrom, JS_Enumerate(cxFrom, JSVAL_TO_OBJECT(val))); CLONE_REQUIRE(ida.get(), L"JS_Enumerate"); AutoGCRooter idaRooter(scriptInterfaceFrom); idaRooter.Push(ida.get()); for (size_t i = 0; i < ida.length(); ++i) { jsid id = ida[i]; jsval idval, propval; CLONE_REQUIRE(JS_IdToValue(cxFrom, id, &idval), L"JS_IdToValue"); CLONE_REQUIRE(JS_GetPropertyById(cxFrom, JSVAL_TO_OBJECT(val), id, &propval), L"JS_GetPropertyById"); jsval newPropval = GetOrClone(propval); if (JSVAL_IS_INT(idval)) { // int jsids are portable across runtimes CLONE_REQUIRE(JS_SetPropertyById(cxTo, newObj, id, &newPropval), L"JS_SetPropertyById"); } else if (JSVAL_IS_STRING(idval)) { // string jsids are runtime-specific, so we need to copy the string content JSString* idstr = JS_ValueToString(cxFrom, idval); CLONE_REQUIRE(idstr, L"JS_ValueToString (id)"); size_t len; const jschar* chars = JS_GetStringCharsAndLength(cxFrom, idstr, &len); CLONE_REQUIRE(idstr, L"JS_GetStringCharsAndLength (id)"); CLONE_REQUIRE(JS_SetUCProperty(cxTo, newObj, chars, len, &newPropval), L"JS_SetUCProperty"); } else { // this apparently could be an XML object; ignore it } } return OBJECT_TO_JSVAL(newObj); }
static JSBool js_createMultiOpt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { js_setting_group_t *jsg = JS_GetPrivate(cx, obj); const char *id; const char *title; JSObject *func; JSObject *optlist; JSBool persistent = JS_FALSE; if(!JS_ConvertArguments(cx, argc, argv, "ssoo/b", &id, &title, &optlist, &func, &persistent)) return JS_FALSE; js_setting_t *jss = jss_create(cx, obj, id, rval, func, jsg, persistent); if(jss == NULL) return JS_FALSE; char **options = NULL; JSIdArray *opts, *opt; int i; char *defvalue = NULL; if((opts = JS_Enumerate(cx, optlist)) != NULL) { for(i = 0; i < opts->length; i++) { jsval name, value, id, title, def; if(!JS_IdToValue(cx, opts->vector[i], &name) || !JSVAL_IS_INT(name) || !JS_GetElement(cx, optlist, JSVAL_TO_INT(name), &value) || !JSVAL_IS_OBJECT(value) || (opt = JS_Enumerate(cx, JSVAL_TO_OBJECT(value))) == NULL) continue; if(opt->length >= 2 && JS_GetElement(cx, JSVAL_TO_OBJECT(value), 0, &id) && JS_GetElement(cx, JSVAL_TO_OBJECT(value), 1, &title)) { if(opt->length < 3 || !JS_GetElement(cx, JSVAL_TO_OBJECT(value), 2, &def)) def = JSVAL_FALSE; const char *k = JS_GetStringBytes(JS_ValueToString(cx, id)); if(def == JSVAL_TRUE) mystrset(&defvalue, k); strvec_addp(&options, k); strvec_addp(&options, JS_GetStringBytes(JS_ValueToString(cx, title))); } JS_DestroyIdArray(cx, opt); } JS_DestroyIdArray(cx, opts); } rstr_t *r = NULL; if(persistent && jsg->jsg_kv_url) r = kv_url_opt_get_rstr(jsg->jsg_kv_url, KVSTORE_DOMAIN_PLUGIN, id); jss->jss_s = setting_create(SETTING_MULTIOPT, jsg->jsg_root, SETTINGS_INITIAL_UPDATE | jsg->jsg_settings_flags, SETTING_TITLE_CSTR(title), SETTING_COURIER(js_global_pc), SETTING_CALLBACK(js_store_update_string, jss), SETTING_VALUE(r ? rstr_get(r) : defvalue), SETTING_OPTION_LIST(options), SETTING_HTSMSG_CUSTOM_SAVER(id, jsg->jsg_store, js_setting_group_save, jsg), NULL); strvec_free(options); rstr_release(r); jss->jss_cx = NULL; return JS_TRUE; }
static int json_encode_from_object(JSContext *cx, JSObject *obj, htsbuf_queue_t *out) { int objtype = 0; JSIdArray *ida; int i; const char *n; if((ida = JS_Enumerate(cx, obj)) == NULL) return -1; for(i = 0; i < ida->length; i++) { jsval name, value; if(!JS_IdToValue(cx, ida->vector[i], &name)) continue; if(JSVAL_IS_STRING(name)) { JSString *str = JSVAL_TO_STRING(name); n = JS_GetStringBytes(str); if(!JS_GetProperty(cx, obj, n, &value)) continue; if(objtype == 0) { htsbuf_append(out, "{", 1); objtype = OBJTYPE_MAP; } else if(objtype != OBJTYPE_MAP) continue; else htsbuf_append(out, ",", 1); htsbuf_append_and_escape_jsonstr(out, n); htsbuf_append(out, ":", 1); } else if(JSVAL_IS_INT(name)) { if(!JS_GetElement(cx, obj, JSVAL_TO_INT(name), &value) || JSVAL_IS_VOID(value)) continue; if(objtype == 0) { htsbuf_append(out, "[", 1); objtype = OBJTYPE_LIST; } else if(objtype != OBJTYPE_LIST) continue; else htsbuf_append(out, ",", 1); } else { continue; } js_json_emit_jsval(cx, value, out); } JS_DestroyIdArray(cx, ida); switch(objtype) { case OBJTYPE_LIST: htsbuf_append(out, "]", 1); break; case OBJTYPE_MAP: htsbuf_append(out, "}", 1); break; default: return -1; } return 0; }
// // Native method Install // static JSBool InstallTriggerGlobalInstall(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { nsIDOMInstallTriggerGlobal *nativeThis = getTriggerNative(cx, obj); if (!nativeThis) return JS_FALSE; *rval = JSVAL_FALSE; // make sure XPInstall is enabled, return false if not nsIScriptGlobalObject *globalObject = nsnull; nsIScriptContext *scriptContext = GetScriptContextFromJSContext(cx); if (scriptContext) globalObject = scriptContext->GetGlobalObject(); if (!globalObject) return JS_TRUE; nsCOMPtr<nsIScriptSecurityManager> secman(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID)); if (!secman) { JS_ReportError(cx, "Could not the script security manager service."); return JS_FALSE; } // get the principal. if it doesn't exist, die. nsCOMPtr<nsIPrincipal> principal; secman->GetSubjectPrincipal(getter_AddRefs(principal)); if (!principal) { JS_ReportError(cx, "Could not get the Subject Principal during InstallTrigger.Install()"); return JS_FALSE; } // get window.location to construct relative URLs nsCOMPtr<nsIURI> baseURL; JSObject* global = JS_GetGlobalObject(cx); if (global) { jsval v; if (JS_GetProperty(cx,global,"location",&v)) { nsAutoString location; ConvertJSValToStr( location, cx, v ); NS_NewURI(getter_AddRefs(baseURL), location); } } PRBool abortLoad = PR_FALSE; // parse associative array of installs if ( argc >= 1 && JSVAL_IS_OBJECT(argv[0]) && JSVAL_TO_OBJECT(argv[0]) ) { nsXPITriggerInfo *trigger = new nsXPITriggerInfo(); if (!trigger) return JS_FALSE; trigger->SetPrincipal(principal); JSIdArray *ida = JS_Enumerate( cx, JSVAL_TO_OBJECT(argv[0]) ); if ( ida ) { jsval v; const PRUnichar *name, *URL; const PRUnichar *iconURL = nsnull; for (int i = 0; i < ida->length && !abortLoad; i++ ) { JS_IdToValue( cx, ida->vector[i], &v ); JSString * str = JS_ValueToString( cx, v ); if (!str) { abortLoad = PR_TRUE; break; } name = reinterpret_cast<const PRUnichar*>(JS_GetStringChars( str )); URL = iconURL = nsnull; JSAutoByteString hash; JS_GetUCProperty( cx, JSVAL_TO_OBJECT(argv[0]), reinterpret_cast<const jschar*>(name), nsCRT::strlen(name), &v ); if ( JSVAL_IS_OBJECT(v) && JSVAL_TO_OBJECT(v) ) { jsval v2; if (JS_GetProperty( cx, JSVAL_TO_OBJECT(v), "URL", &v2 ) && !JSVAL_IS_VOID(v2)) { JSString *str = JS_ValueToString(cx, v2); if (!str) { abortLoad = PR_TRUE; break; } URL = reinterpret_cast<const PRUnichar*>(JS_GetStringChars(str)); } if (JS_GetProperty( cx, JSVAL_TO_OBJECT(v), "IconURL", &v2 ) && !JSVAL_IS_VOID(v2)) { JSString *str = JS_ValueToString(cx, v2); if (!str) { abortLoad = PR_TRUE; break; } iconURL = reinterpret_cast<const PRUnichar*>(JS_GetStringChars(str)); } if (JS_GetProperty( cx, JSVAL_TO_OBJECT(v), "Hash", &v2) && !JSVAL_IS_VOID(v2)) { JSString *str = JS_ValueToString(cx, v2); if (!str || !hash.encode(cx, str)) { abortLoad = PR_TRUE; break; } } } else { JSString *str = JS_ValueToString(cx, v); if (!str) { abortLoad = PR_TRUE; break; } URL = reinterpret_cast<const PRUnichar*>(JS_GetStringChars(str)); } if ( URL ) { // Get relative URL to load nsAutoString xpiURL(URL); if (baseURL) { nsCAutoString resolvedURL; baseURL->Resolve(NS_ConvertUTF16toUTF8(xpiURL), resolvedURL); xpiURL = NS_ConvertUTF8toUTF16(resolvedURL); } nsAutoString icon(iconURL); if (iconURL && baseURL) { nsCAutoString resolvedIcon; baseURL->Resolve(NS_ConvertUTF16toUTF8(icon), resolvedIcon); icon = NS_ConvertUTF8toUTF16(resolvedIcon); } // Make sure we're allowed to load this URL and the icon URL nsresult rv = InstallTriggerCheckLoadURIFromScript(cx, xpiURL); if (NS_FAILED(rv)) abortLoad = PR_TRUE; if (!abortLoad && iconURL) { rv = InstallTriggerCheckLoadURIFromScript(cx, icon); if (NS_FAILED(rv)) abortLoad = PR_TRUE; } if (!abortLoad) { // Add the install item to the trigger collection nsXPITriggerItem *item = new nsXPITriggerItem( name, xpiURL.get(), icon.get(), hash ); if ( item ) { trigger->Add( item ); } else abortLoad = PR_TRUE; } } else abortLoad = PR_TRUE; } JS_DestroyIdArray( cx, ida ); } // pass on only if good stuff found if (!abortLoad && trigger->Size() > 0) { nsCOMPtr<nsIURI> checkuri; nsresult rv = nativeThis->GetOriginatingURI(globalObject, getter_AddRefs(checkuri)); if (NS_SUCCEEDED(rv)) { nsCOMPtr<nsIDOMWindowInternal> win(do_QueryInterface(globalObject)); nsCOMPtr<nsIXPIInstallInfo> installInfo = new nsXPIInstallInfo(win, checkuri, trigger, 0); if (installInfo) { // installInfo now owns triggers PRBool enabled = PR_FALSE; nativeThis->UpdateEnabled(checkuri, XPI_WHITELIST, &enabled); if (!enabled) { nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); if (os) os->NotifyObservers(installInfo, "xpinstall-install-blocked", nsnull); } else { // save callback function if any (ignore bad args for now) if ( argc >= 2 && JS_TypeOfValue(cx,argv[1]) == JSTYPE_FUNCTION ) { trigger->SaveCallback( cx, argv[1] ); } PRBool result; nativeThis->StartInstall(installInfo, &result); *rval = BOOLEAN_TO_JSVAL(result); } return JS_TRUE; } } } // didn't pass it on so we must delete trigger delete trigger; } JS_ReportError(cx, "Incorrect arguments to InstallTrigger.Install()"); return JS_FALSE; }