AtObj AtlasObject::LoadFromJSON(JSContext* cx, const std::string& json) { // Convert UTF8 to UTF16 wxString jsonW(json.c_str(), wxConvUTF8); size_t json16len; wxCharBuffer json16 = wxMBConvUTF16().cWC2MB(jsonW.c_str(), jsonW.Length(), &json16len); jsval vp = JSVAL_NULL; JSONParser* parser = JS_BeginJSONParse(cx, &vp); if (!parser) { wxLogError(_T("ParseJSON failed to begin")); return AtObj(); } if (!JS_ConsumeJSONText(cx, parser, reinterpret_cast<const jschar*>(json16.data()), (uint32)(json16len/2))) { wxLogError(_T("ParseJSON failed to consume")); return AtObj(); } if (!JS_FinishJSONParse(cx, parser, JSVAL_NULL)) { wxLogError(_T("ParseJSON failed to finish")); return AtObj(); } AtObj obj; obj.p = ConvertNode(cx, vp); return obj; }
// Convert from a jsval to an AtNode static AtSmartPtr<AtNode> ConvertNode(JSContext* cx, jsval node) { AtSmartPtr<AtNode> obj (new AtNode()); // Non-objects get converted into strings if (!JSVAL_IS_OBJECT(node)) { JSString* str = JS_ValueToString(cx, node); if (!str) return obj; // error size_t valueLen; const jschar* valueChars = JS_GetStringCharsAndLength(cx, str, &valueLen); if (!valueChars) return obj; // error wxString valueWx(reinterpret_cast<const char*>(valueChars), wxMBConvUTF16(), valueLen*2); obj->value = valueWx.c_str(); // Annotate numbers/booleans specially, to allow round-tripping if (JSVAL_IS_NUMBER(node)) { obj->children.insert(AtNode::child_pairtype( "@number", AtSmartPtr<AtNode>(new AtNode()) )); } else if (JSVAL_IS_BOOLEAN(node)) { obj->children.insert(AtNode::child_pairtype( "@boolean", AtSmartPtr<AtNode>(new AtNode()) )); } return obj; } JSObject* it = JS_NewPropertyIterator(cx, JSVAL_TO_OBJECT(node)); if (!it) return obj; // error while (true) { jsid idp; jsval val; if (! JS_NextProperty(cx, it, &idp) || ! JS_IdToValue(cx, idp, &val)) return obj; // error if (val == JSVAL_VOID) break; // end of iteration if (! JSVAL_IS_STRING(val)) continue; // ignore integer properties JSString* name = JSVAL_TO_STRING(val); size_t len; const jschar* chars = JS_GetStringCharsAndLength(cx, name, &len); wxString nameWx(reinterpret_cast<const char*>(chars), wxMBConvUTF16(), len*2); std::string nameStr(nameWx.ToUTF8().data()); jsval vp; if (!JS_GetPropertyById(cx, JSVAL_TO_OBJECT(node), idp, &vp)) return obj; // error // Unwrap arrays into a special format like <$name><item>$i0</item><item>... // (This assumes arrays aren't nested) if (JSVAL_IS_OBJECT(vp) && JS_IsArrayObject(cx, JSVAL_TO_OBJECT(vp))) { AtSmartPtr<AtNode> child(new AtNode()); child->children.insert(AtNode::child_pairtype( "@array", AtSmartPtr<AtNode>(new AtNode()) )); jsuint arrayLength; if (!JS_GetArrayLength(cx, JSVAL_TO_OBJECT(vp), &arrayLength)) return obj; // error for (jsuint i = 0; i < arrayLength; ++i) { jsval val; if (!JS_GetElement(cx, JSVAL_TO_OBJECT(vp), i, &val)) return obj; // error child->children.insert(AtNode::child_pairtype( "item", ConvertNode(cx, val) )); } obj->children.insert(AtNode::child_pairtype( nameStr, child )); } else { obj->children.insert(AtNode::child_pairtype( nameStr, ConvertNode(cx, vp) )); } } return obj; }
MyTagLib::String OOPCharsetConv::utf16ToWide(const char *utf16, size_t numBytes) { wxWCharBuffer buf(wxMBConvUTF16().cMB2WC(utf16, numBytes, NULL)); return buf ? (const wchar_t *) buf : MyTagLib::EmptyString; }
char *OOPCharsetConv::wideToUtf16(const MyTagLib::String &wide) { return wxMBConvUTF16().cWC2MB(wide.c_str()).release(); }
void RoundTripUTF16() { DoRoundTripTest(wxMBConvUTF16()); }