1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=2 et sw=2 tw=80: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Indexed Database.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * The Mozilla Foundation.
20 : * Portions created by the Initial Developer are Copyright (C) 2010
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Ben Turner <bent.mozilla@gmail.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #ifndef mozilla_dom_indexeddb_key_h__
41 : #define mozilla_dom_indexeddb_key_h__
42 :
43 : #include "mozilla/dom/indexedDB/IndexedDatabase.h"
44 :
45 : #include "mozIStorageStatement.h"
46 :
47 : BEGIN_INDEXEDDB_NAMESPACE
48 :
49 : class Key
50 5901 : {
51 : public:
52 0 : Key()
53 0 : {
54 0 : Unset();
55 0 : }
56 :
57 : Key& operator=(const nsAString& aString)
58 : {
59 : SetFromString(aString);
60 : return *this;
61 : }
62 :
63 : Key& operator=(PRInt64 aInt)
64 : {
65 : SetFromInteger(aInt);
66 : return *this;
67 : }
68 :
69 77 : bool operator==(const Key& aOther) const
70 : {
71 77 : NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(),
72 : "Don't compare unset keys!");
73 :
74 77 : return mBuffer.Equals(aOther.mBuffer);
75 : }
76 :
77 14 : bool operator!=(const Key& aOther) const
78 : {
79 14 : NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(),
80 : "Don't compare unset keys!");
81 :
82 14 : return !mBuffer.Equals(aOther.mBuffer);
83 : }
84 :
85 : bool operator<(const Key& aOther) const
86 : {
87 : NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(),
88 : "Don't compare unset keys!");
89 :
90 : return Compare(mBuffer, aOther.mBuffer) < 0;
91 : }
92 :
93 54 : bool operator>(const Key& aOther) const
94 : {
95 54 : NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(),
96 : "Don't compare unset keys!");
97 :
98 54 : return Compare(mBuffer, aOther.mBuffer) > 0;
99 : }
100 :
101 7 : bool operator<=(const Key& aOther) const
102 : {
103 7 : NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(),
104 : "Don't compare unset keys!");
105 :
106 7 : return Compare(mBuffer, aOther.mBuffer) <= 0;
107 : }
108 :
109 0 : bool operator>=(const Key& aOther) const
110 : {
111 0 : NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(),
112 : "Don't compare unset keys!");
113 :
114 0 : return Compare(mBuffer, aOther.mBuffer) >= 0;
115 : }
116 :
117 : void
118 0 : Unset()
119 : {
120 0 : mBuffer.SetIsVoid(true);
121 0 : }
122 :
123 27082 : bool IsUnset() const
124 : {
125 27082 : return mBuffer.IsVoid();
126 : }
127 :
128 : bool IsFloat() const
129 : {
130 : return !mBuffer.IsVoid() && mBuffer.First() == eFloat;
131 : }
132 :
133 : double ToFloat() const
134 : {
135 : NS_ASSERTION(IsFloat(), "Why'd you call this?");
136 : const unsigned char* pos = BufferStart();
137 : double res = DecodeNumber(pos, BufferEnd());
138 : NS_ASSERTION(pos >= BufferEnd(), "Should consume whole buffer");
139 : return res;
140 : }
141 :
142 : void SetFromString(const nsAString& aString)
143 : {
144 : mBuffer.Truncate();
145 : EncodeString(aString, 0);
146 : TrimBuffer();
147 : }
148 :
149 : void SetFromInteger(PRInt64 aInt)
150 : {
151 : mBuffer.Truncate();
152 : EncodeNumber(double(aInt), eFloat);
153 : TrimBuffer();
154 : }
155 :
156 10267 : nsresult SetFromJSVal(JSContext* aCx,
157 : const jsval aVal)
158 : {
159 10267 : mBuffer.Truncate();
160 :
161 10267 : if (JSVAL_IS_NULL(aVal) || JSVAL_IS_VOID(aVal)) {
162 3136 : Unset();
163 3136 : return NS_OK;
164 : }
165 :
166 7131 : nsresult rv = EncodeJSVal(aCx, aVal, 0);
167 7131 : if (NS_FAILED(rv)) {
168 109 : Unset();
169 109 : return rv;
170 : }
171 7022 : TrimBuffer();
172 :
173 7022 : return NS_OK;
174 : }
175 :
176 2679 : nsresult ToJSVal(JSContext* aCx,
177 : jsval* aVal) const
178 : {
179 2679 : if (IsUnset()) {
180 2 : *aVal = JSVAL_VOID;
181 2 : return NS_OK;
182 : }
183 :
184 2677 : const unsigned char* pos = BufferStart();
185 2677 : nsresult rv = DecodeJSVal(pos, BufferEnd(), aCx, 0, aVal);
186 2677 : NS_ENSURE_SUCCESS(rv, rv);
187 :
188 2677 : NS_ASSERTION(pos >= BufferEnd(),
189 : "Didn't consume whole buffer");
190 :
191 2677 : return NS_OK;
192 : }
193 :
194 : nsresult AppendArrayItem(JSContext* aCx,
195 : bool aFirst,
196 : const jsval aVal)
197 : {
198 : if (aFirst) {
199 : Unset();
200 : }
201 :
202 : nsresult rv = EncodeJSVal(aCx, aVal, aFirst ? eMaxType : 0);
203 : if (NS_FAILED(rv)) {
204 : Unset();
205 : return rv;
206 : }
207 :
208 : return NS_OK;
209 : }
210 :
211 : void FinishArray()
212 : {
213 : TrimBuffer();
214 : }
215 :
216 : const nsCString& GetBuffer() const
217 : {
218 : return mBuffer;
219 : }
220 :
221 5379 : nsresult BindToStatement(mozIStorageStatement* aStatement,
222 : const nsACString& aParamName) const
223 : {
224 : nsresult rv = aStatement->BindBlobByName(aParamName,
225 5379 : reinterpret_cast<const PRUint8*>(mBuffer.get()), mBuffer.Length());
226 :
227 5379 : return NS_SUCCEEDED(rv) ? NS_OK : NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
228 : }
229 :
230 2436 : nsresult SetFromStatement(mozIStorageStatement* aStatement,
231 : PRUint32 aIndex)
232 : {
233 : PRUint8* data;
234 2436 : PRUint32 dataLength = 0;
235 :
236 2436 : nsresult rv = aStatement->GetBlob(aIndex, &dataLength, &data);
237 2436 : NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
238 :
239 : mBuffer.Adopt(
240 2436 : reinterpret_cast<char*>(const_cast<PRUint8*>(data)), dataLength);
241 :
242 2436 : return NS_OK;
243 : }
244 :
245 : static
246 : PRInt16 CompareKeys(Key& aFirst, Key& aSecond)
247 : {
248 : PRInt32 result = Compare(aFirst.mBuffer, aSecond.mBuffer);
249 :
250 : if (result < 0) {
251 : return -1;
252 : }
253 :
254 : if (result > 0) {
255 : return 1;
256 : }
257 :
258 : return 0;
259 : }
260 :
261 : private:
262 2810 : const unsigned char* BufferStart() const
263 : {
264 2810 : return reinterpret_cast<const unsigned char*>(mBuffer.BeginReading());
265 : }
266 :
267 5620 : const unsigned char* BufferEnd() const
268 : {
269 5620 : return reinterpret_cast<const unsigned char*>(mBuffer.EndReading());
270 : }
271 :
272 : enum {
273 : eTerminator = 0,
274 : eFloat = 1,
275 : eDate = 2,
276 : eString = 3,
277 : eArray = 4,
278 : eMaxType = eArray
279 : };
280 :
281 : // Encoding helper. Trims trailing zeros off of mBuffer as a post-processing
282 : // step.
283 8329 : void TrimBuffer()
284 : {
285 8329 : const char* end = mBuffer.EndReading() - 1;
286 45051 : while (!*end) {
287 28393 : --end;
288 : }
289 :
290 8329 : mBuffer.Truncate(end + 1 - mBuffer.BeginReading());
291 8329 : }
292 :
293 : // Encoding functions. These append the encoded value to the end of mBuffer
294 : nsresult EncodeJSVal(JSContext* aCx, const jsval aVal, PRUint8 aTypeOffset);
295 : void EncodeString(const nsAString& aString, PRUint8 aTypeOffset);
296 : void EncodeNumber(double aFloat, PRUint8 aType);
297 :
298 : // Decoding functions. aPos points into mBuffer and is adjusted to point
299 : // past the consumed value.
300 : static nsresult DecodeJSVal(const unsigned char*& aPos,
301 : const unsigned char* aEnd, JSContext* aCx,
302 : PRUint8 aTypeOffset, jsval* aVal);
303 : static void DecodeString(const unsigned char*& aPos,
304 : const unsigned char* aEnd,
305 : nsString& aString);
306 : static double DecodeNumber(const unsigned char*& aPos,
307 : const unsigned char* aEnd);
308 :
309 : nsCString mBuffer;
310 : };
311 :
312 : END_INDEXEDDB_NAMESPACE
313 :
314 : #endif /* mozilla_dom_indexeddb_key_h__ */
|