Bug 1038399. Add a ToJSON method to Web IDL dictionaries. r=bholley

This commit is contained in:
Boris Zbarsky 2014-07-31 23:50:19 -04:00
parent d77dac0580
commit 3688e8eb15
4 changed files with 52 additions and 30 deletions

View File

@ -35,6 +35,15 @@ struct DictionaryBase
protected: protected:
bool ParseJSON(JSContext* aCx, const nsAString& aJSON, bool ParseJSON(JSContext* aCx, const nsAString& aJSON,
JS::MutableHandle<JS::Value> aVal); JS::MutableHandle<JS::Value> aVal);
bool StringifyToJSON(JSContext* aCx,
JS::MutableHandle<JS::Value> aValue,
nsAString& aJSON);
private:
// aString is expected to actually be an nsAString*. Should only be
// called from StringifyToJSON.
static bool AppendJSONToString(const jschar* aJSONData, uint32_t aDataLength,
void* aString);
}; };
// Struct that serves as a base class for all typed arrays and array buffers and // Struct that serves as a base class for all typed arrays and array buffers and

View File

@ -1608,6 +1608,29 @@ DictionaryBase::ParseJSON(JSContext* aCx,
aJSON.Length(), aVal); aJSON.Length(), aVal);
} }
bool
DictionaryBase::StringifyToJSON(JSContext* aCx,
JS::MutableHandle<JS::Value> aValue,
nsAString& aJSON)
{
return JS_Stringify(aCx, aValue, JS::NullPtr(), JS::NullHandleValue,
AppendJSONToString, &aJSON);
}
/* static */
bool
DictionaryBase::AppendJSONToString(const jschar* aJSONData,
uint32_t aDataLength,
void* aString)
{
nsAString* string = static_cast<nsAString*>(aString);
string->Append(static_cast<const char16_t*>(aJSONData),
aDataLength);
return true;
}
static JSString* static JSString*
ConcatJSString(JSContext* cx, const char* pre, JS::Handle<JSString*> str, const char* post) ConcatJSString(JSContext* cx, const char* pre, JS::Handle<JSString*> str, const char* post)
{ {

View File

@ -10828,6 +10828,20 @@ class CGDictionary(CGThing):
return Init(cx, json); return Init(cx, json);
""")) """))
def toJSONMethod(self):
return ClassMethod(
"ToJSON", "bool",
[Argument('nsAString&', 'aJSON')],
body=dedent("""
MOZ_ASSERT(NS_IsMainThread());
AutoJSAPI jsapi;
jsapi.Init();
JSContext *cx = jsapi.cx();
JSAutoCompartment ac(cx, xpc::GetSafeJSContextGlobal()); // Usage approved by bholley
JS::Rooted<JS::Value> obj(cx);
return ToObjectInternal(cx, &obj) && StringifyToJSON(cx, &obj, aJSON);
"""))
def toObjectInternalMethod(self): def toObjectInternalMethod(self):
body = "" body = ""
if self.needToInitIds: if self.needToInitIds:
@ -10955,10 +10969,12 @@ class CGDictionary(CGThing):
methods.append(self.initFromJSONMethod()) methods.append(self.initFromJSONMethod())
try: try:
methods.append(self.toObjectInternalMethod()) methods.append(self.toObjectInternalMethod())
methods.append(self.toJSONMethod())
except MethodNotNewObjectError: except MethodNotNewObjectError:
# If we can't have a ToObjectInternal() because one of our members # If we can't have a ToObjectInternal() because one of our members
# can only be returned from [NewObject] methods, then just skip # can only be returned from [NewObject] methods, then just skip
# generating ToObjectInternal(). # generating ToObjectInternal() and ToJSON (since the latter depens
# on the former).
pass pass
methods.append(self.traceDictionaryMethod()) methods.append(self.traceDictionaryMethod())
@ -11546,6 +11562,8 @@ class CGBindingRoot(CGThing):
bindingHeaders["WrapperFactory.h"] = descriptors bindingHeaders["WrapperFactory.h"] = descriptors
bindingHeaders["mozilla/dom/DOMJSClass.h"] = descriptors bindingHeaders["mozilla/dom/DOMJSClass.h"] = descriptors
bindingHeaders["mozilla/dom/ScriptSettings.h"] = dictionaries # AutoJSAPI
bindingHeaders["xpcpublic.h"] = dictionaries ## xpc::GetSafeJSContextGlobal
# Do codegen for all the dictionaries. We have to be a bit careful # Do codegen for all the dictionaries. We have to be a bit careful
# here, because we have to generate these in order from least derived # here, because we have to generate these in order from least derived

View File

@ -2241,15 +2241,6 @@ private:
} }
}; };
static bool
JSONCreator(const jschar* aBuf, uint32_t aLen, void* aData)
{
nsAString* result = static_cast<nsAString*>(aData);
result->Append(static_cast<const char16_t*>(aBuf),
static_cast<uint32_t>(aLen));
return true;
}
template<class KeyEncryptTask> template<class KeyEncryptTask>
class WrapKeyTask : public ExportKeyTask class WrapKeyTask : public ExportKeyTask
{ {
@ -2273,30 +2264,11 @@ private:
nsRefPtr<KeyEncryptTask> mTask; nsRefPtr<KeyEncryptTask> mTask;
bool mResolved; bool mResolved;
static bool StringifyJWK(const JsonWebKey& aJwk, nsAString& aRetVal)
{
// XXX: This should move into DictionaryBase and Codegen.py,
// in the same way as ParseJSON is split out. (Bug 1038399)
// We use AutoSafeJSContext even though the exact compartment
// doesn't matter (since we're making an XPCOM string)
MOZ_ASSERT(NS_IsMainThread());
AutoSafeJSContext cx;
JS::Rooted<JS::Value> obj(cx);
bool ok = ToJSValue(cx, aJwk, &obj);
if (!ok) {
JS_ClearPendingException(cx);
return false;
}
return JS_Stringify(cx, &obj, JS::NullPtr(), JS::NullHandleValue,
JSONCreator, &aRetVal);
}
virtual nsresult AfterCrypto() MOZ_OVERRIDE { virtual nsresult AfterCrypto() MOZ_OVERRIDE {
// If wrapping JWK, stringify the JSON // If wrapping JWK, stringify the JSON
if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) { if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
nsAutoString json; nsAutoString json;
if (!StringifyJWK(mJwk, json)) { if (!mJwk.ToJSON(json)) {
return NS_ERROR_DOM_OPERATION_ERR; return NS_ERROR_DOM_OPERATION_ERR;
} }