Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "prprf.h"
8 #include "nsIDOMNodeList.h"
9 #include "nsUnicharUtils.h"
11 #include "nsArrayUtils.h"
12 #include "nsIVariant.h"
13 #include "nsAppDirectoryServiceDefs.h"
15 #include "nsIURI.h"
16 #include "nsIIOService.h"
17 #include "nsIFileChannel.h"
18 #include "nsIFile.h"
19 #include "nsGkAtoms.h"
20 #include "nsContentUtils.h"
22 #include "nsXULTemplateBuilder.h"
23 #include "nsXULTemplateResultStorage.h"
24 #include "nsXULContentUtils.h"
25 #include "nsXULSortService.h"
27 #include "mozIStorageService.h"
28 #include "nsIChannel.h"
29 #include "nsIDocument.h"
31 //----------------------------------------------------------------------
32 //
33 // nsXULTemplateResultSetStorage
34 //
36 NS_IMPL_ISUPPORTS(nsXULTemplateResultSetStorage, nsISimpleEnumerator)
39 nsXULTemplateResultSetStorage::nsXULTemplateResultSetStorage(mozIStorageStatement* aStatement)
40 : mStatement(aStatement)
41 {
42 uint32_t count;
43 nsresult rv = aStatement->GetColumnCount(&count);
44 if (NS_FAILED(rv)) {
45 mStatement = nullptr;
46 return;
47 }
48 for (uint32_t c = 0; c < count; c++) {
49 nsAutoCString name;
50 rv = aStatement->GetColumnName(c, name);
51 if (NS_SUCCEEDED(rv)) {
52 nsCOMPtr<nsIAtom> columnName = do_GetAtom(NS_LITERAL_CSTRING("?") + name);
53 mColumnNames.AppendObject(columnName);
54 }
55 }
56 }
58 NS_IMETHODIMP
59 nsXULTemplateResultSetStorage::HasMoreElements(bool *aResult)
60 {
61 if (!mStatement) {
62 *aResult = false;
63 return NS_OK;
64 }
66 nsresult rv = mStatement->ExecuteStep(aResult);
67 NS_ENSURE_SUCCESS(rv, rv);
68 // Because the nsXULTemplateResultSetStorage is owned by many nsXULTemplateResultStorage objects,
69 // it could live longer than it needed to get results.
70 // So we destroy the statement to free resources when all results are fetched
71 if (!*aResult) {
72 mStatement = nullptr;
73 }
74 return NS_OK;
75 }
77 NS_IMETHODIMP
78 nsXULTemplateResultSetStorage::GetNext(nsISupports **aResult)
79 {
80 nsXULTemplateResultStorage* result =
81 new nsXULTemplateResultStorage(this);
83 if (!result)
84 return NS_ERROR_OUT_OF_MEMORY;
86 *aResult = result;
87 NS_ADDREF(result);
88 return NS_OK;
89 }
92 int32_t
93 nsXULTemplateResultSetStorage::GetColumnIndex(nsIAtom* aColumnName)
94 {
95 int32_t count = mColumnNames.Count();
96 for (int32_t c = 0; c < count; c++) {
97 if (mColumnNames[c] == aColumnName)
98 return c;
99 }
101 return -1;
102 }
104 void
105 nsXULTemplateResultSetStorage::FillColumnValues(nsCOMArray<nsIVariant>& aArray)
106 {
107 if (!mStatement)
108 return;
110 int32_t count = mColumnNames.Count();
112 for (int32_t c = 0; c < count; c++) {
113 nsCOMPtr<nsIWritableVariant> value = do_CreateInstance("@mozilla.org/variant;1");
115 int32_t type;
116 mStatement->GetTypeOfIndex(c, &type);
118 if (type == mStatement->VALUE_TYPE_INTEGER) {
119 int64_t val = mStatement->AsInt64(c);
120 value->SetAsInt64(val);
121 }
122 else if (type == mStatement->VALUE_TYPE_FLOAT) {
123 double val = mStatement->AsDouble(c);
124 value->SetAsDouble(val);
125 }
126 else {
127 nsAutoString val;
128 nsresult rv = mStatement->GetString(c, val);
129 if (NS_FAILED(rv))
130 value->SetAsAString(EmptyString());
131 else
132 value->SetAsAString(val);
133 }
134 aArray.AppendObject(value);
135 }
136 }
140 //----------------------------------------------------------------------
141 //
142 // nsXULTemplateQueryProcessorStorage
143 //
145 NS_IMPL_ISUPPORTS(nsXULTemplateQueryProcessorStorage,
146 nsIXULTemplateQueryProcessor)
149 nsXULTemplateQueryProcessorStorage::nsXULTemplateQueryProcessorStorage()
150 : mGenerationStarted(false)
151 {
152 }
154 NS_IMETHODIMP
155 nsXULTemplateQueryProcessorStorage::GetDatasource(nsIArray* aDataSources,
156 nsIDOMNode* aRootNode,
157 bool aIsTrusted,
158 nsIXULTemplateBuilder* aBuilder,
159 bool* aShouldDelayBuilding,
160 nsISupports** aReturn)
161 {
162 *aReturn = nullptr;
163 *aShouldDelayBuilding = false;
165 if (!aIsTrusted) {
166 return NS_OK;
167 }
169 uint32_t length;
170 nsresult rv = aDataSources->GetLength(&length);
171 NS_ENSURE_SUCCESS(rv, rv);
173 if (length == 0) {
174 return NS_OK;
175 }
177 // We get only the first uri. This query processor supports
178 // only one database at a time.
179 nsCOMPtr<nsIURI> uri;
180 uri = do_QueryElementAt(aDataSources, 0);
182 if (!uri) {
183 // No uri in the list of datasources
184 return NS_OK;
185 }
187 nsCOMPtr<mozIStorageService> storage =
188 do_GetService("@mozilla.org/storage/service;1", &rv);
189 NS_ENSURE_SUCCESS(rv, rv);
191 nsCOMPtr<nsIFile> databaseFile;
192 nsAutoCString scheme;
193 rv = uri->GetScheme(scheme);
194 NS_ENSURE_SUCCESS(rv, rv);
196 if (scheme.EqualsLiteral("profile")) {
198 nsAutoCString path;
199 rv = uri->GetPath(path);
200 NS_ENSURE_SUCCESS(rv, rv);
202 if (path.IsEmpty()) {
203 return NS_ERROR_FAILURE;
204 }
206 rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
207 getter_AddRefs(databaseFile));
208 NS_ENSURE_SUCCESS(rv, rv);
210 rv = databaseFile->AppendNative(path);
211 NS_ENSURE_SUCCESS(rv, rv);
212 }
213 else {
214 nsCOMPtr<nsIChannel> channel;
215 nsCOMPtr<nsIIOService> ioservice =
216 do_GetService("@mozilla.org/network/io-service;1", &rv);
217 NS_ENSURE_SUCCESS(rv, rv);
219 rv = ioservice->NewChannelFromURI(uri, getter_AddRefs(channel));
220 NS_ENSURE_SUCCESS(rv, rv);
222 nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(channel, &rv);
223 if (NS_FAILED(rv)) { // if it fails, not a file url
224 nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_BAD_URI);
225 return rv;
226 }
228 nsCOMPtr<nsIFile> file;
229 rv = fileChannel->GetFile(getter_AddRefs(databaseFile));
230 NS_ENSURE_SUCCESS(rv, rv);
231 }
233 // ok now we have an URI of a sqlite file
234 nsCOMPtr<mozIStorageConnection> connection;
235 rv = storage->OpenDatabase(databaseFile, getter_AddRefs(connection));
236 if (NS_FAILED(rv)) {
237 nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_CANNOT_OPEN_DATABASE);
238 return rv;
239 }
241 NS_ADDREF(*aReturn = connection);
242 return NS_OK;
243 }
247 NS_IMETHODIMP
248 nsXULTemplateQueryProcessorStorage::InitializeForBuilding(nsISupports* aDatasource,
249 nsIXULTemplateBuilder* aBuilder,
250 nsIDOMNode* aRootNode)
251 {
252 NS_ENSURE_STATE(!mGenerationStarted);
254 mStorageConnection = do_QueryInterface(aDatasource);
255 if (!mStorageConnection)
256 return NS_ERROR_INVALID_ARG;
258 bool ready;
259 mStorageConnection->GetConnectionReady(&ready);
260 if (!ready)
261 return NS_ERROR_UNEXPECTED;
263 return NS_OK;
264 }
266 NS_IMETHODIMP
267 nsXULTemplateQueryProcessorStorage::Done()
268 {
269 mGenerationStarted = false;
270 return NS_OK;
271 }
273 NS_IMETHODIMP
274 nsXULTemplateQueryProcessorStorage::CompileQuery(nsIXULTemplateBuilder* aBuilder,
275 nsIDOMNode* aQueryNode,
276 nsIAtom* aRefVariable,
277 nsIAtom* aMemberVariable,
278 nsISupports** aReturn)
279 {
280 nsCOMPtr<nsIDOMNodeList> childNodes;
281 aQueryNode->GetChildNodes(getter_AddRefs(childNodes));
283 uint32_t length;
284 childNodes->GetLength(&length);
286 nsCOMPtr<mozIStorageStatement> statement;
287 nsCOMPtr<nsIContent> queryContent = do_QueryInterface(aQueryNode);
288 nsAutoString sqlQuery;
290 // Let's get all text nodes (which should be the query)
291 if (!nsContentUtils::GetNodeTextContent(queryContent, false, sqlQuery)) {
292 return NS_ERROR_OUT_OF_MEMORY;
293 }
295 nsresult rv = mStorageConnection->CreateStatement(NS_ConvertUTF16toUTF8(sqlQuery),
296 getter_AddRefs(statement));
297 if (NS_FAILED(rv)) {
298 nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_BAD_QUERY);
299 return rv;
300 }
302 uint32_t parameterCount = 0;
303 for (nsIContent* child = queryContent->GetFirstChild();
304 child;
305 child = child->GetNextSibling()) {
307 if (child->NodeInfo()->Equals(nsGkAtoms::param, kNameSpaceID_XUL)) {
308 nsAutoString value;
309 if (!nsContentUtils::GetNodeTextContent(child, false, value)) {
310 return NS_ERROR_OUT_OF_MEMORY;
311 }
313 uint32_t index = parameterCount;
314 nsAutoString name, indexValue;
316 if (child->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name)) {
317 rv = statement->GetParameterIndex(NS_ConvertUTF16toUTF8(name),
318 &index);
319 if (NS_FAILED(rv)) {
320 nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_UNKNOWN_QUERY_PARAMETER);
321 return rv;
322 }
323 parameterCount++;
324 }
325 else if (child->GetAttr(kNameSpaceID_None, nsGkAtoms::index, indexValue)) {
326 PR_sscanf(NS_ConvertUTF16toUTF8(indexValue).get(),"%d",&index);
327 if (index > 0)
328 index--;
329 }
330 else {
331 parameterCount++;
332 }
334 static nsIContent::AttrValuesArray sTypeValues[] =
335 { &nsGkAtoms::int32, &nsGkAtoms::integer, &nsGkAtoms::int64,
336 &nsGkAtoms::null, &nsGkAtoms::double_, &nsGkAtoms::string, nullptr };
338 int32_t typeError = 1;
339 int32_t typeValue = child->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type,
340 sTypeValues, eCaseMatters);
341 rv = NS_ERROR_ILLEGAL_VALUE;
342 int32_t valInt32 = 0;
343 int64_t valInt64 = 0;
344 double valFloat = 0;
346 switch (typeValue) {
347 case 0:
348 case 1:
349 typeError = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(),"%d",&valInt32);
350 if (typeError > 0)
351 rv = statement->BindInt32ByIndex(index, valInt32);
352 break;
353 case 2:
354 typeError = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(),"%lld",&valInt64);
355 if (typeError > 0)
356 rv = statement->BindInt64ByIndex(index, valInt64);
357 break;
358 case 3:
359 rv = statement->BindNullByIndex(index);
360 break;
361 case 4:
362 typeError = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(),"%lf",&valFloat);
363 if (typeError > 0)
364 rv = statement->BindDoubleByIndex(index, valFloat);
365 break;
366 case 5:
367 case nsIContent::ATTR_MISSING:
368 rv = statement->BindStringByIndex(index, value);
369 break;
370 default:
371 typeError = 0;
372 }
374 if (typeError <= 0) {
375 nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_WRONG_TYPE_QUERY_PARAMETER);
376 return rv;
377 }
379 if (NS_FAILED(rv)) {
380 nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_QUERY_PARAMETER_NOT_BOUND);
381 return rv;
382 }
383 }
384 }
386 *aReturn = statement;
387 NS_IF_ADDREF(*aReturn);
389 return NS_OK;
390 }
392 NS_IMETHODIMP
393 nsXULTemplateQueryProcessorStorage::GenerateResults(nsISupports* aDatasource,
394 nsIXULTemplateResult* aRef,
395 nsISupports* aQuery,
396 nsISimpleEnumerator** aResults)
397 {
398 mGenerationStarted = true;
400 nsCOMPtr<mozIStorageStatement> statement = do_QueryInterface(aQuery);
401 if (!statement)
402 return NS_ERROR_FAILURE;
404 nsXULTemplateResultSetStorage* results =
405 new nsXULTemplateResultSetStorage(statement);
407 if (!results)
408 return NS_ERROR_OUT_OF_MEMORY;
410 *aResults = results;
411 NS_ADDREF(*aResults);
413 return NS_OK;
414 }
416 NS_IMETHODIMP
417 nsXULTemplateQueryProcessorStorage::AddBinding(nsIDOMNode* aRuleNode,
418 nsIAtom* aVar,
419 nsIAtom* aRef,
420 const nsAString& aExpr)
421 {
422 return NS_OK;
423 }
425 NS_IMETHODIMP
426 nsXULTemplateQueryProcessorStorage::TranslateRef(nsISupports* aDatasource,
427 const nsAString& aRefString,
428 nsIXULTemplateResult** aRef)
429 {
430 nsXULTemplateResultStorage* result =
431 new nsXULTemplateResultStorage(nullptr);
432 if (!result)
433 return NS_ERROR_OUT_OF_MEMORY;
435 *aRef = result;
436 NS_ADDREF(*aRef);
437 return NS_OK;
438 }
441 NS_IMETHODIMP
442 nsXULTemplateQueryProcessorStorage::CompareResults(nsIXULTemplateResult* aLeft,
443 nsIXULTemplateResult* aRight,
444 nsIAtom* aVar,
445 uint32_t aSortHints,
446 int32_t* aResult)
447 {
448 *aResult = 0;
449 if (!aVar)
450 return NS_OK;
452 // We're going to see if values are integers or float, to perform
453 // a suitable comparison
454 nsCOMPtr<nsISupports> leftValue, rightValue;
455 if (aLeft)
456 aLeft->GetBindingObjectFor(aVar, getter_AddRefs(leftValue));
457 if (aRight)
458 aRight->GetBindingObjectFor(aVar, getter_AddRefs(rightValue));
460 if (leftValue && rightValue) {
461 nsCOMPtr<nsIVariant> vLeftValue = do_QueryInterface(leftValue);
462 nsCOMPtr<nsIVariant> vRightValue = do_QueryInterface(rightValue);
464 if (vLeftValue && vRightValue) {
465 nsresult rv1, rv2;
466 uint16_t vtypeL, vtypeR;
467 vLeftValue->GetDataType(&vtypeL);
468 vRightValue->GetDataType(&vtypeR);
470 if (vtypeL == vtypeR) {
471 if (vtypeL == nsIDataType::VTYPE_INT64) {
472 int64_t leftValue, rightValue;
473 rv1 = vLeftValue->GetAsInt64(&leftValue);
474 rv2 = vRightValue->GetAsInt64(&rightValue);
475 if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) {
476 if (leftValue > rightValue)
477 *aResult = 1;
478 else if (leftValue < rightValue)
479 *aResult = -1;
480 return NS_OK;
481 }
482 }
483 else if (vtypeL == nsIDataType::VTYPE_DOUBLE) {
484 double leftValue, rightValue;
485 rv1 = vLeftValue->GetAsDouble(&leftValue);
486 rv2 = vRightValue->GetAsDouble(&rightValue);
487 if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) {
488 if (leftValue > rightValue)
489 *aResult = 1;
490 else if (leftValue < rightValue)
491 *aResult = -1;
492 return NS_OK;
493 }
494 }
495 }
496 }
497 }
499 // Values are not integers or floats, so we just compare them as simple strings
500 nsAutoString leftVal;
501 if (aLeft)
502 aLeft->GetBindingFor(aVar, leftVal);
504 nsAutoString rightVal;
505 if (aRight)
506 aRight->GetBindingFor(aVar, rightVal);
508 *aResult = XULSortServiceImpl::CompareValues(leftVal, rightVal, aSortHints);
509 return NS_OK;
510 }