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 19709 : {
51 : public:
52 16035 : Key()
53 16035 : {
54 16035 : Unset();
55 16035 : }
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 0 : bool operator==(const Key& aOther) const
70 : {
71 0 : NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(),
72 : "Don't compare unset keys!");
73 :
74 0 : return mBuffer.Equals(aOther.mBuffer);
75 : }
76 :
77 : bool operator!=(const Key& aOther) const
78 : {
79 : NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(),
80 : "Don't compare unset keys!");
81 :
82 : 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 : bool operator>(const Key& aOther) const
94 : {
95 : NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(),
96 : "Don't compare unset keys!");
97 :
98 : return Compare(mBuffer, aOther.mBuffer) > 0;
99 : }
100 :
101 : bool operator<=(const Key& aOther) const
102 : {
103 : NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(),
104 : "Don't compare unset keys!");
105 :
106 : return Compare(mBuffer, aOther.mBuffer) <= 0;
107 : }
108 :
109 : bool operator>=(const Key& aOther) const
110 : {
111 : NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(),
112 : "Don't compare unset keys!");
113 :
114 : return Compare(mBuffer, aOther.mBuffer) >= 0;
115 : }
116 :
117 : void
118 21096 : Unset()
119 : {
120 21096 : mBuffer.SetIsVoid(true);
121 21096 : }
122 :
123 0 : bool IsUnset() const
124 : {
125 0 : return mBuffer.IsVoid();
126 : }
127 :
128 211 : bool IsFloat() const
129 : {
130 211 : return !mBuffer.IsVoid() && mBuffer.First() == eFloat;
131 : }
132 :
133 133 : double ToFloat() const
134 : {
135 133 : NS_ASSERTION(IsFloat(), "Why'd you call this?");
136 133 : const unsigned char* pos = BufferStart();
137 133 : double res = DecodeNumber(pos, BufferEnd());
138 133 : NS_ASSERTION(pos >= BufferEnd(), "Should consume whole buffer");
139 133 : return res;
140 : }
141 :
142 0 : void SetFromString(const nsAString& aString)
143 : {
144 0 : mBuffer.Truncate();
145 0 : EncodeString(aString, 0);
146 0 : TrimBuffer();
147 0 : }
148 :
149 1307 : void SetFromInteger(PRInt64 aInt)
150 : {
151 1307 : mBuffer.Truncate();
152 1307 : EncodeNumber(double(aInt), eFloat);
153 1307 : TrimBuffer();
154 1307 : }
155 :
156 0 : nsresult SetFromJSVal(JSContext* aCx,
157 : const jsval aVal)
158 : {
159 0 : mBuffer.Truncate();
160 :
161 0 : if (JSVAL_IS_NULL(aVal) || JSVAL_IS_VOID(aVal)) {
162 0 : Unset();
163 0 : return NS_OK;
164 : }
165 :
166 0 : nsresult rv = EncodeJSVal(aCx, aVal, 0);
167 0 : if (NS_FAILED(rv)) {
168 0 : Unset();
169 0 : return rv;
170 : }
171 0 : TrimBuffer();
172 :
173 0 : return NS_OK;
174 : }
175 :
176 0 : nsresult ToJSVal(JSContext* aCx,
177 : jsval* aVal) const
178 : {
179 0 : if (IsUnset()) {
180 0 : *aVal = JSVAL_VOID;
181 0 : return NS_OK;
182 : }
183 :
184 0 : const unsigned char* pos = BufferStart();
185 0 : nsresult rv = DecodeJSVal(pos, BufferEnd(), aCx, 0, aVal);
186 0 : NS_ENSURE_SUCCESS(rv, rv);
187 :
188 0 : NS_ASSERTION(pos >= BufferEnd(),
189 : "Didn't consume whole buffer");
190 :
191 0 : return NS_OK;
192 : }
193 :
194 0 : nsresult AppendArrayItem(JSContext* aCx,
195 : bool aFirst,
196 : const jsval aVal)
197 : {
198 0 : if (aFirst) {
199 0 : Unset();
200 : }
201 :
202 0 : nsresult rv = EncodeJSVal(aCx, aVal, aFirst ? eMaxType : 0);
203 0 : if (NS_FAILED(rv)) {
204 0 : Unset();
205 0 : return rv;
206 : }
207 :
208 0 : return NS_OK;
209 : }
210 :
211 0 : void FinishArray()
212 : {
213 0 : TrimBuffer();
214 0 : }
215 :
216 0 : const nsCString& GetBuffer() const
217 : {
218 0 : return mBuffer;
219 : }
220 :
221 0 : nsresult BindToStatement(mozIStorageStatement* aStatement,
222 : const nsACString& aParamName) const
223 : {
224 : nsresult rv = aStatement->BindBlobByName(aParamName,
225 0 : reinterpret_cast<const PRUint8*>(mBuffer.get()), mBuffer.Length());
226 :
227 0 : return NS_SUCCEEDED(rv) ? NS_OK : NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
228 : }
229 :
230 0 : nsresult SetFromStatement(mozIStorageStatement* aStatement,
231 : PRUint32 aIndex)
232 : {
233 : PRUint8* data;
234 0 : PRUint32 dataLength = 0;
235 :
236 0 : nsresult rv = aStatement->GetBlob(aIndex, &dataLength, &data);
237 0 : NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
238 :
239 : mBuffer.Adopt(
240 0 : reinterpret_cast<char*>(const_cast<PRUint8*>(data)), dataLength);
241 :
242 0 : return NS_OK;
243 : }
244 :
245 : static
246 2824 : PRInt16 CompareKeys(Key& aFirst, Key& aSecond)
247 : {
248 2824 : PRInt32 result = Compare(aFirst.mBuffer, aSecond.mBuffer);
249 :
250 2824 : if (result < 0) {
251 1223 : return -1;
252 : }
253 :
254 1601 : if (result > 0) {
255 1223 : return 1;
256 : }
257 :
258 378 : return 0;
259 : }
260 :
261 : private:
262 0 : const unsigned char* BufferStart() const
263 : {
264 0 : return reinterpret_cast<const unsigned char*>(mBuffer.BeginReading());
265 : }
266 :
267 0 : const unsigned char* BufferEnd() const
268 : {
269 0 : 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 0 : void TrimBuffer()
284 : {
285 0 : const char* end = mBuffer.EndReading() - 1;
286 0 : while (!*end) {
287 0 : --end;
288 : }
289 :
290 0 : mBuffer.Truncate(end + 1 - mBuffer.BeginReading());
291 0 : }
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__ */
|