content/xul/templates/src/nsXULTemplateQueryProcessorStorage.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial