1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/indexedDB/Key.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,345 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef mozilla_dom_indexeddb_key_h__ 1.11 +#define mozilla_dom_indexeddb_key_h__ 1.12 + 1.13 +#include "mozilla/dom/indexedDB/IndexedDatabase.h" 1.14 + 1.15 +#include "mozIStorageStatement.h" 1.16 + 1.17 +#include "js/Value.h" 1.18 + 1.19 +namespace IPC { 1.20 +template <typename T> struct ParamTraits; 1.21 +} // namespace IPC 1.22 + 1.23 +BEGIN_INDEXEDDB_NAMESPACE 1.24 + 1.25 +class Key 1.26 +{ 1.27 + friend struct IPC::ParamTraits<Key>; 1.28 + 1.29 +public: 1.30 + Key() 1.31 + { 1.32 + Unset(); 1.33 + } 1.34 + 1.35 + Key& operator=(const nsAString& aString) 1.36 + { 1.37 + SetFromString(aString); 1.38 + return *this; 1.39 + } 1.40 + 1.41 + Key& operator=(int64_t aInt) 1.42 + { 1.43 + SetFromInteger(aInt); 1.44 + return *this; 1.45 + } 1.46 + 1.47 + bool operator==(const Key& aOther) const 1.48 + { 1.49 + NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(), 1.50 + "Don't compare unset keys!"); 1.51 + 1.52 + return mBuffer.Equals(aOther.mBuffer); 1.53 + } 1.54 + 1.55 + bool operator!=(const Key& aOther) const 1.56 + { 1.57 + NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(), 1.58 + "Don't compare unset keys!"); 1.59 + 1.60 + return !mBuffer.Equals(aOther.mBuffer); 1.61 + } 1.62 + 1.63 + bool operator<(const Key& aOther) const 1.64 + { 1.65 + NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(), 1.66 + "Don't compare unset keys!"); 1.67 + 1.68 + return Compare(mBuffer, aOther.mBuffer) < 0; 1.69 + } 1.70 + 1.71 + bool operator>(const Key& aOther) const 1.72 + { 1.73 + NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(), 1.74 + "Don't compare unset keys!"); 1.75 + 1.76 + return Compare(mBuffer, aOther.mBuffer) > 0; 1.77 + } 1.78 + 1.79 + bool operator<=(const Key& aOther) const 1.80 + { 1.81 + NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(), 1.82 + "Don't compare unset keys!"); 1.83 + 1.84 + return Compare(mBuffer, aOther.mBuffer) <= 0; 1.85 + } 1.86 + 1.87 + bool operator>=(const Key& aOther) const 1.88 + { 1.89 + NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(), 1.90 + "Don't compare unset keys!"); 1.91 + 1.92 + return Compare(mBuffer, aOther.mBuffer) >= 0; 1.93 + } 1.94 + 1.95 + void 1.96 + Unset() 1.97 + { 1.98 + mBuffer.SetIsVoid(true); 1.99 + } 1.100 + 1.101 + bool IsUnset() const 1.102 + { 1.103 + return mBuffer.IsVoid(); 1.104 + } 1.105 + 1.106 + bool IsFloat() const 1.107 + { 1.108 + return !IsUnset() && mBuffer.First() == eFloat; 1.109 + } 1.110 + 1.111 + bool IsDate() const 1.112 + { 1.113 + return !IsUnset() && mBuffer.First() == eDate; 1.114 + } 1.115 + 1.116 + bool IsString() const 1.117 + { 1.118 + return !IsUnset() && mBuffer.First() == eString; 1.119 + } 1.120 + 1.121 + bool IsArray() const 1.122 + { 1.123 + return !IsUnset() && mBuffer.First() >= eArray; 1.124 + } 1.125 + 1.126 + double ToFloat() const 1.127 + { 1.128 + NS_ASSERTION(IsFloat(), "Why'd you call this?"); 1.129 + const unsigned char* pos = BufferStart(); 1.130 + double res = DecodeNumber(pos, BufferEnd()); 1.131 + NS_ASSERTION(pos >= BufferEnd(), "Should consume whole buffer"); 1.132 + return res; 1.133 + } 1.134 + 1.135 + double ToDateMsec() const 1.136 + { 1.137 + NS_ASSERTION(IsDate(), "Why'd you call this?"); 1.138 + const unsigned char* pos = BufferStart(); 1.139 + double res = DecodeNumber(pos, BufferEnd()); 1.140 + NS_ASSERTION(pos >= BufferEnd(), "Should consume whole buffer"); 1.141 + return res; 1.142 + } 1.143 + 1.144 + void ToString(nsString& aString) const 1.145 + { 1.146 + NS_ASSERTION(IsString(), "Why'd you call this?"); 1.147 + const unsigned char* pos = BufferStart(); 1.148 + DecodeString(pos, BufferEnd(), aString); 1.149 + NS_ASSERTION(pos >= BufferEnd(), "Should consume whole buffer"); 1.150 + } 1.151 + 1.152 + void SetFromString(const nsAString& aString) 1.153 + { 1.154 + mBuffer.Truncate(); 1.155 + EncodeString(aString, 0); 1.156 + TrimBuffer(); 1.157 + } 1.158 + 1.159 + void SetFromInteger(int64_t aInt) 1.160 + { 1.161 + mBuffer.Truncate(); 1.162 + EncodeNumber(double(aInt), eFloat); 1.163 + TrimBuffer(); 1.164 + } 1.165 + 1.166 + nsresult SetFromJSVal(JSContext* aCx, 1.167 + JS::Handle<JS::Value> aVal) 1.168 + { 1.169 + mBuffer.Truncate(); 1.170 + 1.171 + if (aVal.isNull() || aVal.isUndefined()) { 1.172 + Unset(); 1.173 + return NS_OK; 1.174 + } 1.175 + 1.176 + nsresult rv = EncodeJSVal(aCx, aVal, 0); 1.177 + if (NS_FAILED(rv)) { 1.178 + Unset(); 1.179 + return rv; 1.180 + } 1.181 + TrimBuffer(); 1.182 + 1.183 + return NS_OK; 1.184 + } 1.185 + 1.186 + nsresult ToJSVal(JSContext* aCx, 1.187 + JS::MutableHandle<JS::Value> aVal) const 1.188 + { 1.189 + if (IsUnset()) { 1.190 + aVal.setUndefined(); 1.191 + return NS_OK; 1.192 + } 1.193 + 1.194 + const unsigned char* pos = BufferStart(); 1.195 + nsresult rv = DecodeJSVal(pos, BufferEnd(), aCx, 0, aVal); 1.196 + NS_ENSURE_SUCCESS(rv, rv); 1.197 + 1.198 + NS_ASSERTION(pos >= BufferEnd(), 1.199 + "Didn't consume whole buffer"); 1.200 + 1.201 + return NS_OK; 1.202 + } 1.203 + 1.204 + nsresult ToJSVal(JSContext* aCx, 1.205 + JS::Heap<JS::Value>& aVal) const 1.206 + { 1.207 + JS::Rooted<JS::Value> value(aCx); 1.208 + nsresult rv = ToJSVal(aCx, &value); 1.209 + if (NS_SUCCEEDED(rv)) { 1.210 + aVal = value; 1.211 + } 1.212 + return rv; 1.213 + } 1.214 + 1.215 + nsresult AppendItem(JSContext* aCx, 1.216 + bool aFirstOfArray, 1.217 + JS::Handle<JS::Value> aVal) 1.218 + { 1.219 + nsresult rv = EncodeJSVal(aCx, aVal, aFirstOfArray ? eMaxType : 0); 1.220 + if (NS_FAILED(rv)) { 1.221 + Unset(); 1.222 + return rv; 1.223 + } 1.224 + 1.225 + return NS_OK; 1.226 + } 1.227 + 1.228 + void FinishArray() 1.229 + { 1.230 + TrimBuffer(); 1.231 + } 1.232 + 1.233 + const nsCString& GetBuffer() const 1.234 + { 1.235 + return mBuffer; 1.236 + } 1.237 + 1.238 + nsresult BindToStatement(mozIStorageStatement* aStatement, 1.239 + const nsACString& aParamName) const 1.240 + { 1.241 + nsresult rv = aStatement->BindBlobByName(aParamName, 1.242 + reinterpret_cast<const uint8_t*>(mBuffer.get()), mBuffer.Length()); 1.243 + 1.244 + return NS_SUCCEEDED(rv) ? NS_OK : NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.245 + } 1.246 + 1.247 + nsresult SetFromStatement(mozIStorageStatement* aStatement, 1.248 + uint32_t aIndex) 1.249 + { 1.250 + uint8_t* data; 1.251 + uint32_t dataLength = 0; 1.252 + 1.253 + nsresult rv = aStatement->GetBlob(aIndex, &dataLength, &data); 1.254 + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.255 + 1.256 + mBuffer.Adopt( 1.257 + reinterpret_cast<char*>(const_cast<uint8_t*>(data)), dataLength); 1.258 + 1.259 + return NS_OK; 1.260 + } 1.261 + 1.262 + static 1.263 + int16_t CompareKeys(Key& aFirst, Key& aSecond) 1.264 + { 1.265 + int32_t result = Compare(aFirst.mBuffer, aSecond.mBuffer); 1.266 + 1.267 + if (result < 0) { 1.268 + return -1; 1.269 + } 1.270 + 1.271 + if (result > 0) { 1.272 + return 1; 1.273 + } 1.274 + 1.275 + return 0; 1.276 + } 1.277 + 1.278 +private: 1.279 + const unsigned char* BufferStart() const 1.280 + { 1.281 + return reinterpret_cast<const unsigned char*>(mBuffer.BeginReading()); 1.282 + } 1.283 + 1.284 + const unsigned char* BufferEnd() const 1.285 + { 1.286 + return reinterpret_cast<const unsigned char*>(mBuffer.EndReading()); 1.287 + } 1.288 + 1.289 + enum { 1.290 + eTerminator = 0, 1.291 + eFloat = 1, 1.292 + eDate = 2, 1.293 + eString = 3, 1.294 + eArray = 4, 1.295 + eMaxType = eArray 1.296 + }; 1.297 + 1.298 + // Encoding helper. Trims trailing zeros off of mBuffer as a post-processing 1.299 + // step. 1.300 + void TrimBuffer() 1.301 + { 1.302 + const char* end = mBuffer.EndReading() - 1; 1.303 + while (!*end) { 1.304 + --end; 1.305 + } 1.306 + 1.307 + mBuffer.Truncate(end + 1 - mBuffer.BeginReading()); 1.308 + } 1.309 + 1.310 + // Encoding functions. These append the encoded value to the end of mBuffer 1.311 + inline nsresult EncodeJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal, 1.312 + uint8_t aTypeOffset) 1.313 + { 1.314 + return EncodeJSValInternal(aCx, aVal, aTypeOffset, 0); 1.315 + } 1.316 + void EncodeString(const nsAString& aString, uint8_t aTypeOffset); 1.317 + void EncodeNumber(double aFloat, uint8_t aType); 1.318 + 1.319 + // Decoding functions. aPos points into mBuffer and is adjusted to point 1.320 + // past the consumed value. 1.321 + static inline nsresult DecodeJSVal(const unsigned char*& aPos, 1.322 + const unsigned char* aEnd, JSContext* aCx, 1.323 + uint8_t aTypeOffset, JS::MutableHandle<JS::Value> aVal) 1.324 + { 1.325 + return DecodeJSValInternal(aPos, aEnd, aCx, aTypeOffset, aVal, 0); 1.326 + } 1.327 + 1.328 + static void DecodeString(const unsigned char*& aPos, 1.329 + const unsigned char* aEnd, 1.330 + nsString& aString); 1.331 + static double DecodeNumber(const unsigned char*& aPos, 1.332 + const unsigned char* aEnd); 1.333 + 1.334 + nsCString mBuffer; 1.335 + 1.336 +private: 1.337 + nsresult EncodeJSValInternal(JSContext* aCx, JS::Handle<JS::Value> aVal, 1.338 + uint8_t aTypeOffset, uint16_t aRecursionDepth); 1.339 + 1.340 + static nsresult DecodeJSValInternal(const unsigned char*& aPos, 1.341 + const unsigned char* aEnd, 1.342 + JSContext* aCx, uint8_t aTypeOffset, 1.343 + JS::MutableHandle<JS::Value> aVal, uint16_t aRecursionDepth); 1.344 +}; 1.345 + 1.346 +END_INDEXEDDB_NAMESPACE 1.347 + 1.348 +#endif /* mozilla_dom_indexeddb_key_h__ */