michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsMemory.h" michael@0: #include "nsString.h" michael@0: michael@0: #include "mozStorageStatementRow.h" michael@0: #include "mozStorageStatement.h" michael@0: michael@0: #include "jsapi.h" michael@0: michael@0: namespace mozilla { michael@0: namespace storage { michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: //// StatementRow michael@0: michael@0: StatementRow::StatementRow(Statement *aStatement) michael@0: : mStatement(aStatement) michael@0: { michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS( michael@0: StatementRow, michael@0: mozIStorageStatementRow, michael@0: nsIXPCScriptable michael@0: ) michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: //// nsIXPCScriptable michael@0: michael@0: #define XPC_MAP_CLASSNAME StatementRow michael@0: #define XPC_MAP_QUOTED_CLASSNAME "StatementRow" michael@0: #define XPC_MAP_WANT_GETPROPERTY michael@0: #define XPC_MAP_WANT_NEWRESOLVE michael@0: #define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE michael@0: #include "xpc_map_end.h" michael@0: michael@0: NS_IMETHODIMP michael@0: StatementRow::GetProperty(nsIXPConnectWrappedNative *aWrapper, michael@0: JSContext *aCtx, michael@0: JSObject *aScopeObj, michael@0: jsid aId, michael@0: jsval *_vp, michael@0: bool *_retval) michael@0: { michael@0: NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED); michael@0: michael@0: JS::RootedObject scope(aCtx, aScopeObj); michael@0: if (JSID_IS_STRING(aId)) { michael@0: ::JSAutoByteString idBytes(aCtx, JSID_TO_STRING(aId)); michael@0: NS_ENSURE_TRUE(!!idBytes, NS_ERROR_OUT_OF_MEMORY); michael@0: nsDependentCString jsid(idBytes.ptr()); michael@0: michael@0: uint32_t idx; michael@0: nsresult rv = mStatement->GetColumnIndex(jsid, &idx); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: int32_t type; michael@0: rv = mStatement->GetTypeOfIndex(idx, &type); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: if (type == mozIStorageValueArray::VALUE_TYPE_INTEGER || michael@0: type == mozIStorageValueArray::VALUE_TYPE_FLOAT) { michael@0: double dval; michael@0: rv = mStatement->GetDouble(idx, &dval); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: *_vp = ::JS_NumberValue(dval); michael@0: } michael@0: else if (type == mozIStorageValueArray::VALUE_TYPE_TEXT) { michael@0: uint32_t bytes; michael@0: const jschar *sval = reinterpret_cast( michael@0: static_cast(mStatement)-> michael@0: AsSharedWString(idx, &bytes) michael@0: ); michael@0: JSString *str = ::JS_NewUCStringCopyN(aCtx, sval, bytes / 2); michael@0: if (!str) { michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: *_vp = STRING_TO_JSVAL(str); michael@0: } michael@0: else if (type == mozIStorageValueArray::VALUE_TYPE_BLOB) { michael@0: uint32_t length; michael@0: const uint8_t *blob = static_cast(mStatement)-> michael@0: AsSharedBlob(idx, &length); michael@0: JSObject *obj = ::JS_NewArrayObject(aCtx, length); michael@0: if (!obj) { michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: *_vp = OBJECT_TO_JSVAL(obj); michael@0: michael@0: // Copy the blob over to the JS array. michael@0: for (uint32_t i = 0; i < length; i++) { michael@0: if (!::JS_SetElement(aCtx, scope, i, blob[i])) { michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: } michael@0: } michael@0: else if (type == mozIStorageValueArray::VALUE_TYPE_NULL) { michael@0: *_vp = JSVAL_NULL; michael@0: } michael@0: else { michael@0: NS_ERROR("unknown column type returned, what's going on?"); michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: StatementRow::NewResolve(nsIXPConnectWrappedNative *aWrapper, michael@0: JSContext *aCtx, michael@0: JSObject *aScopeObj, michael@0: jsid aId, michael@0: JSObject **_objp, michael@0: bool *_retval) michael@0: { michael@0: JS::Rooted scopeObj(aCtx, aScopeObj); michael@0: michael@0: NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED); michael@0: // We do not throw at any point after this because we want to allow the michael@0: // prototype chain to be checked for the property. michael@0: michael@0: if (JSID_IS_STRING(aId)) { michael@0: ::JSAutoByteString idBytes(aCtx, JSID_TO_STRING(aId)); michael@0: NS_ENSURE_TRUE(!!idBytes, NS_ERROR_OUT_OF_MEMORY); michael@0: nsDependentCString name(idBytes.ptr()); michael@0: michael@0: uint32_t idx; michael@0: nsresult rv = mStatement->GetColumnIndex(name, &idx); michael@0: if (NS_FAILED(rv)) { michael@0: // It's highly likely that the name doesn't exist, so let the JS engine michael@0: // check the prototype chain and throw if that doesn't have the property michael@0: // either. michael@0: *_objp = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: *_retval = ::JS_DefinePropertyById(aCtx, scopeObj, aId, JSVAL_VOID, michael@0: nullptr, nullptr, 0); michael@0: *_objp = scopeObj; michael@0: return NS_OK; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: } // namespace storage michael@0: } // namescape mozilla