static nsresult ReadScriptFromStream(JSContext *cx, nsIObjectInputStream *stream, JSScript **script) { *script = nsnull; PRUint32 size; nsresult rv = stream->Read32(&size); NS_ENSURE_SUCCESS(rv, rv); char *data; rv = stream->ReadBytes(size, &data); NS_ENSURE_SUCCESS(rv, rv); JSXDRState *xdr = JS_XDRNewMem(cx, JSXDR_DECODE); NS_ENSURE_TRUE(xdr, NS_ERROR_OUT_OF_MEMORY); xdr->userdata = stream; JS_XDRMemSetData(xdr, data, size); if (!JS_XDRScript(xdr, script)) { rv = NS_ERROR_FAILURE; } // Update data in case ::JS_XDRScript called back into C++ code to // read an XPCOM object. // // In that case, the serialization process must have flushed a run // of counted bytes containing JS data at the point where the XPCOM // object starts, after which an encoding C++ callback from the JS // XDR code must have written the XPCOM object directly into the // nsIObjectOutputStream. // // The deserialization process will XDR-decode counted bytes up to // but not including the XPCOM object, then call back into C++ to // read the object, then read more counted bytes and hand them off // to the JSXDRState, so more JS data can be decoded. // // This interleaving of JS XDR data and XPCOM object data may occur // several times beneath the call to ::JS_XDRScript, above. At the // end of the day, we need to free (via nsMemory) the data owned by // the JSXDRState. So we steal it back, nulling xdr's buffer so it // doesn't get passed to ::JS_free by ::JS_XDRDestroy. uint32 length; data = static_cast<char*>(JS_XDRMemGetData(xdr, &length)); if (data) { JS_XDRMemSetData(xdr, nsnull, 0); } JS_XDRDestroy(xdr); // If data is null now, it must have been freed while deserializing an // XPCOM object (e.g., a principal) beneath ::JS_XDRScript. if (data) { nsMemory::Free(data); } return rv; }
static nsresult WriteScriptToStream(JSContext *cx, JSScript *script, nsIObjectOutputStream *stream) { JSXDRState *xdr = JS_XDRNewMem(cx, JSXDR_ENCODE); NS_ENSURE_TRUE(xdr, NS_ERROR_OUT_OF_MEMORY); xdr->userdata = stream; nsresult rv = NS_OK; if (JS_XDRScript(xdr, &script)) { // Get the encoded JSXDRState data and write it. The JSXDRState owns // this buffer memory and will free it beneath ::JS_XDRDestroy. // // If an XPCOM object needs to be written in the midst of the JS XDR // encoding process, the C++ code called back from the JS engine (e.g., // nsEncodeJSPrincipals in caps/src/nsJSPrincipals.cpp) will flush data // from the JSXDRState to aStream, then write the object, then return // to JS XDR code with xdr reset so new JS data is encoded at the front // of the xdr's data buffer. // // However many XPCOM objects are interleaved with JS XDR data in the // stream, when control returns here from ::JS_XDRScript, we'll have // one last buffer of data to write to aStream. uint32 size; const char* data = reinterpret_cast<const char*> (JS_XDRMemGetData(xdr, &size)); NS_ASSERTION(data, "no decoded JSXDRState data!"); rv = stream->Write32(size); if (NS_SUCCEEDED(rv)) { rv = stream->WriteBytes(data, size); } } else { rv = NS_ERROR_FAILURE; // likely to be a principals serialization error } JS_XDRDestroy(xdr); return rv; }
int main(int argc, char *argv[]) { JSRuntime *rt; JSContext *cx; JSObject *glob; long rtsize = 8; /* Runtime size allocated in MB */ JSBool status; JSScript *script; jsval rval; JSClass dj_Global = { "global", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 }; rt = JS_NewRuntime(1024L * 1024L * rtsize); if (rt == NULL) { printf("Cannot initialise javascript runtime\n"); return ERROR; } /* Create a javascript context and associate it with the JS runtime */ cx = JS_NewContext(rt, CONTEXT_SIZE); if (cx == NULL) { printf("Cannot initialise javascript context\n"); return ERROR; } /* Create a global object */ glob = JS_NewObject(cx, &dj_Global, NULL, NULL); if (glob == NULL) { printf("Cannot create javascript global object\n"); return ERROR; } /* Create the standard classes */ status = JS_InitStandardClasses(cx, glob); if (status == JS_FALSE) { printf("Cannot initialise javascript standard classes\n"); return ERROR; } /* XDR script */ JSXDRState *xdr = JS_XDRNewMem(cx, JSXDR_DECODE); if ((xdr != NULL)) { void* f = fopen(argv[1], "rb"); fseek(f, 0, SEEK_END); int len = ftell(f); fseek(f, 0, SEEK_SET); void* data = malloc(len); fread(data, 1, len, f); JS_XDRMemSetData(xdr, data, len); if (JS_XDRScript(xdr, &script) != JS_TRUE) { printf("Decompilation error\n"); }; } /* Decompile script */ JSString *sourcecode = JS_DecompileScript(cx, script, "proba.js", 2); char *sourcecode_str = JS_GetStringBytes(sourcecode); printf("%s", sourcecode_str); /* Destroy context */ JS_DestroyContext(cx); /* Destroy runtime */ JS_DestroyRuntime(rt); return 0; }