rdf/base/src/nsRDFContainer.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 /*
michael@0 7
michael@0 8 Implementation for the RDF container.
michael@0 9
michael@0 10 Notes
michael@0 11 -----
michael@0 12
michael@0 13 1. RDF containers are one-indexed. This means that a lot of the loops
michael@0 14 that you'd normally think you'd write like this:
michael@0 15
michael@0 16 for (i = 0; i < count; ++i) {}
michael@0 17
michael@0 18 You've gotta write like this:
michael@0 19
michael@0 20 for (i = 1; i <= count; ++i) {}
michael@0 21
michael@0 22 "Sure, right, yeah, of course.", you say. Well maybe I'm just
michael@0 23 thick, but it's easy to slip up.
michael@0 24
michael@0 25 2. The RDF:nextVal property on the container is an
michael@0 26 implementation-level hack that is used to quickly compute the
michael@0 27 next value for appending to the container. It will no doubt
michael@0 28 become royally screwed up in the case of aggregation.
michael@0 29
michael@0 30 3. The RDF:nextVal property is also used to retrieve the count of
michael@0 31 elements in the container.
michael@0 32
michael@0 33 */
michael@0 34
michael@0 35
michael@0 36 #include "nsCOMPtr.h"
michael@0 37 #include "nsIRDFContainer.h"
michael@0 38 #include "nsIRDFContainerUtils.h"
michael@0 39 #include "nsIRDFInMemoryDataSource.h"
michael@0 40 #include "nsIRDFPropagatableDataSource.h"
michael@0 41 #include "nsIRDFService.h"
michael@0 42 #include "nsIServiceManager.h"
michael@0 43 #include "nsRDFCID.h"
michael@0 44 #include "nsString.h"
michael@0 45 #include "nsXPIDLString.h"
michael@0 46 #include "rdf.h"
michael@0 47
michael@0 48 #define RDF_SEQ_LIST_LIMIT 8
michael@0 49
michael@0 50 class RDFContainerImpl : public nsIRDFContainer
michael@0 51 {
michael@0 52 public:
michael@0 53
michael@0 54 // nsISupports interface
michael@0 55 NS_DECL_ISUPPORTS
michael@0 56
michael@0 57 // nsIRDFContainer interface
michael@0 58 NS_DECL_NSIRDFCONTAINER
michael@0 59
michael@0 60 private:
michael@0 61 friend nsresult NS_NewRDFContainer(nsIRDFContainer** aResult);
michael@0 62
michael@0 63 RDFContainerImpl();
michael@0 64 virtual ~RDFContainerImpl();
michael@0 65
michael@0 66 nsresult Init();
michael@0 67
michael@0 68 nsresult Renumber(int32_t aStartIndex, int32_t aIncrement);
michael@0 69 nsresult SetNextValue(int32_t aIndex);
michael@0 70 nsresult GetNextValue(nsIRDFResource** aResult);
michael@0 71
michael@0 72 nsIRDFDataSource* mDataSource;
michael@0 73 nsIRDFResource* mContainer;
michael@0 74
michael@0 75 // pseudo constants
michael@0 76 static int32_t gRefCnt;
michael@0 77 static nsIRDFService* gRDFService;
michael@0 78 static nsIRDFContainerUtils* gRDFContainerUtils;
michael@0 79 static nsIRDFResource* kRDF_nextVal;
michael@0 80 };
michael@0 81
michael@0 82
michael@0 83 int32_t RDFContainerImpl::gRefCnt = 0;
michael@0 84 nsIRDFService* RDFContainerImpl::gRDFService;
michael@0 85 nsIRDFContainerUtils* RDFContainerImpl::gRDFContainerUtils;
michael@0 86 nsIRDFResource* RDFContainerImpl::kRDF_nextVal;
michael@0 87
michael@0 88 ////////////////////////////////////////////////////////////////////////
michael@0 89 // nsISupports interface
michael@0 90
michael@0 91 NS_IMPL_ISUPPORTS(RDFContainerImpl, nsIRDFContainer)
michael@0 92
michael@0 93
michael@0 94
michael@0 95 ////////////////////////////////////////////////////////////////////////
michael@0 96 // nsIRDFContainer interface
michael@0 97
michael@0 98 NS_IMETHODIMP
michael@0 99 RDFContainerImpl::GetDataSource(nsIRDFDataSource** _retval)
michael@0 100 {
michael@0 101 *_retval = mDataSource;
michael@0 102 NS_IF_ADDREF(*_retval);
michael@0 103 return NS_OK;
michael@0 104 }
michael@0 105
michael@0 106
michael@0 107 NS_IMETHODIMP
michael@0 108 RDFContainerImpl::GetResource(nsIRDFResource** _retval)
michael@0 109 {
michael@0 110 *_retval = mContainer;
michael@0 111 NS_IF_ADDREF(*_retval);
michael@0 112 return NS_OK;
michael@0 113 }
michael@0 114
michael@0 115
michael@0 116 NS_IMETHODIMP
michael@0 117 RDFContainerImpl::Init(nsIRDFDataSource *aDataSource, nsIRDFResource *aContainer)
michael@0 118 {
michael@0 119 NS_PRECONDITION(aDataSource != nullptr, "null ptr");
michael@0 120 if (! aDataSource)
michael@0 121 return NS_ERROR_NULL_POINTER;
michael@0 122
michael@0 123 NS_PRECONDITION(aContainer != nullptr, "null ptr");
michael@0 124 if (! aContainer)
michael@0 125 return NS_ERROR_NULL_POINTER;
michael@0 126
michael@0 127 nsresult rv;
michael@0 128 bool isContainer;
michael@0 129 rv = gRDFContainerUtils->IsContainer(aDataSource, aContainer, &isContainer);
michael@0 130 if (NS_FAILED(rv)) return rv;
michael@0 131
michael@0 132 // ``throw'' if we can't create a container on the specified
michael@0 133 // datasource/resource combination.
michael@0 134 if (! isContainer)
michael@0 135 return NS_ERROR_FAILURE;
michael@0 136
michael@0 137 NS_IF_RELEASE(mDataSource);
michael@0 138 mDataSource = aDataSource;
michael@0 139 NS_ADDREF(mDataSource);
michael@0 140
michael@0 141 NS_IF_RELEASE(mContainer);
michael@0 142 mContainer = aContainer;
michael@0 143 NS_ADDREF(mContainer);
michael@0 144
michael@0 145 return NS_OK;
michael@0 146 }
michael@0 147
michael@0 148
michael@0 149 NS_IMETHODIMP
michael@0 150 RDFContainerImpl::GetCount(int32_t *aCount)
michael@0 151 {
michael@0 152 if (!mDataSource || !mContainer)
michael@0 153 return NS_ERROR_NOT_INITIALIZED;
michael@0 154
michael@0 155 nsresult rv;
michael@0 156
michael@0 157 // Get the next value, which hangs off of the bag via the
michael@0 158 // RDF:nextVal property. This is the _next value_ that will get
michael@0 159 // assigned in a one-indexed array. So, it's actually _one more_
michael@0 160 // than the actual count of elements in the container.
michael@0 161 //
michael@0 162 // XXX To handle aggregation, this should probably be a
michael@0 163 // GetTargets() that enumerates all of the values and picks the
michael@0 164 // largest one.
michael@0 165 nsCOMPtr<nsIRDFNode> nextValNode;
michael@0 166 rv = mDataSource->GetTarget(mContainer, kRDF_nextVal, true, getter_AddRefs(nextValNode));
michael@0 167 if (NS_FAILED(rv)) return rv;
michael@0 168
michael@0 169 if (rv == NS_RDF_NO_VALUE)
michael@0 170 return NS_ERROR_UNEXPECTED;
michael@0 171
michael@0 172 nsCOMPtr<nsIRDFLiteral> nextValLiteral;
michael@0 173 rv = nextValNode->QueryInterface(NS_GET_IID(nsIRDFLiteral), getter_AddRefs(nextValLiteral));
michael@0 174 if (NS_FAILED(rv)) return rv;
michael@0 175
michael@0 176 const char16_t *s;
michael@0 177 rv = nextValLiteral->GetValueConst( &s );
michael@0 178 if (NS_FAILED(rv)) return rv;
michael@0 179
michael@0 180 nsAutoString nextValStr(s);
michael@0 181
michael@0 182 int32_t nextVal;
michael@0 183 nsresult err;
michael@0 184 nextVal = nextValStr.ToInteger(&err);
michael@0 185 if (NS_FAILED(err))
michael@0 186 return NS_ERROR_UNEXPECTED;
michael@0 187
michael@0 188 *aCount = nextVal - 1;
michael@0 189 return NS_OK;
michael@0 190 }
michael@0 191
michael@0 192
michael@0 193 NS_IMETHODIMP
michael@0 194 RDFContainerImpl::GetElements(nsISimpleEnumerator **_retval)
michael@0 195 {
michael@0 196 if (!mDataSource || !mContainer)
michael@0 197 return NS_ERROR_NOT_INITIALIZED;
michael@0 198
michael@0 199 return NS_NewContainerEnumerator(mDataSource, mContainer, _retval);
michael@0 200 }
michael@0 201
michael@0 202
michael@0 203 NS_IMETHODIMP
michael@0 204 RDFContainerImpl::AppendElement(nsIRDFNode *aElement)
michael@0 205 {
michael@0 206 if (!mDataSource || !mContainer)
michael@0 207 return NS_ERROR_NOT_INITIALIZED;
michael@0 208
michael@0 209 NS_PRECONDITION(aElement != nullptr, "null ptr");
michael@0 210 if (! aElement)
michael@0 211 return NS_ERROR_NULL_POINTER;
michael@0 212
michael@0 213 nsresult rv;
michael@0 214
michael@0 215 nsCOMPtr<nsIRDFResource> nextVal;
michael@0 216 rv = GetNextValue(getter_AddRefs(nextVal));
michael@0 217 if (NS_FAILED(rv)) return rv;
michael@0 218
michael@0 219 rv = mDataSource->Assert(mContainer, nextVal, aElement, true);
michael@0 220 if (NS_FAILED(rv)) return rv;
michael@0 221
michael@0 222 return NS_OK;
michael@0 223 }
michael@0 224
michael@0 225
michael@0 226 NS_IMETHODIMP
michael@0 227 RDFContainerImpl::RemoveElement(nsIRDFNode *aElement, bool aRenumber)
michael@0 228 {
michael@0 229 if (!mDataSource || !mContainer)
michael@0 230 return NS_ERROR_NOT_INITIALIZED;
michael@0 231
michael@0 232 NS_PRECONDITION(aElement != nullptr, "null ptr");
michael@0 233 if (! aElement)
michael@0 234 return NS_ERROR_NULL_POINTER;
michael@0 235
michael@0 236 nsresult rv;
michael@0 237
michael@0 238 int32_t idx;
michael@0 239 rv = IndexOf(aElement, &idx);
michael@0 240 if (NS_FAILED(rv)) return rv;
michael@0 241
michael@0 242 if (idx < 0)
michael@0 243 return NS_OK;
michael@0 244
michael@0 245 // Remove the element.
michael@0 246 nsCOMPtr<nsIRDFResource> ordinal;
michael@0 247 rv = gRDFContainerUtils->IndexToOrdinalResource(idx,
michael@0 248 getter_AddRefs(ordinal));
michael@0 249 if (NS_FAILED(rv)) return rv;
michael@0 250
michael@0 251 rv = mDataSource->Unassert(mContainer, ordinal, aElement);
michael@0 252 if (NS_FAILED(rv)) return rv;
michael@0 253
michael@0 254 if (aRenumber) {
michael@0 255 // Now slide the rest of the collection backwards to fill in
michael@0 256 // the gap. This will have the side effect of completely
michael@0 257 // renumber the container from index to the end.
michael@0 258 rv = Renumber(idx + 1, -1);
michael@0 259 if (NS_FAILED(rv)) return rv;
michael@0 260 }
michael@0 261
michael@0 262 return NS_OK;
michael@0 263 }
michael@0 264
michael@0 265
michael@0 266 NS_IMETHODIMP
michael@0 267 RDFContainerImpl::InsertElementAt(nsIRDFNode *aElement, int32_t aIndex, bool aRenumber)
michael@0 268 {
michael@0 269 if (!mDataSource || !mContainer)
michael@0 270 return NS_ERROR_NOT_INITIALIZED;
michael@0 271
michael@0 272 NS_PRECONDITION(aElement != nullptr, "null ptr");
michael@0 273 if (! aElement)
michael@0 274 return NS_ERROR_NULL_POINTER;
michael@0 275
michael@0 276 NS_PRECONDITION(aIndex >= 1, "illegal value");
michael@0 277 if (aIndex < 1)
michael@0 278 return NS_ERROR_ILLEGAL_VALUE;
michael@0 279
michael@0 280 nsresult rv;
michael@0 281
michael@0 282 int32_t count;
michael@0 283 rv = GetCount(&count);
michael@0 284 if (NS_FAILED(rv)) return rv;
michael@0 285
michael@0 286 NS_ASSERTION(aIndex <= count + 1, "illegal value");
michael@0 287 if (aIndex > count + 1)
michael@0 288 return NS_ERROR_ILLEGAL_VALUE;
michael@0 289
michael@0 290 if (aRenumber) {
michael@0 291 // Make a hole for the element. This will have the side effect of
michael@0 292 // completely renumbering the container from 'aIndex' to 'count',
michael@0 293 // and will spew assertions.
michael@0 294 rv = Renumber(aIndex, +1);
michael@0 295 if (NS_FAILED(rv)) return rv;
michael@0 296 }
michael@0 297
michael@0 298 nsCOMPtr<nsIRDFResource> ordinal;
michael@0 299 rv = gRDFContainerUtils->IndexToOrdinalResource(aIndex, getter_AddRefs(ordinal));
michael@0 300 if (NS_FAILED(rv)) return rv;
michael@0 301
michael@0 302 rv = mDataSource->Assert(mContainer, ordinal, aElement, true);
michael@0 303 if (NS_FAILED(rv)) return rv;
michael@0 304
michael@0 305 return NS_OK;
michael@0 306 }
michael@0 307
michael@0 308 NS_IMETHODIMP
michael@0 309 RDFContainerImpl::RemoveElementAt(int32_t aIndex, bool aRenumber, nsIRDFNode** _retval)
michael@0 310 {
michael@0 311 if (!mDataSource || !mContainer)
michael@0 312 return NS_ERROR_NOT_INITIALIZED;
michael@0 313
michael@0 314 *_retval = nullptr;
michael@0 315
michael@0 316 if (aIndex< 1)
michael@0 317 return NS_ERROR_ILLEGAL_VALUE;
michael@0 318
michael@0 319 nsresult rv;
michael@0 320
michael@0 321 int32_t count;
michael@0 322 rv = GetCount(&count);
michael@0 323 if (NS_FAILED(rv)) return rv;
michael@0 324
michael@0 325 if (aIndex > count)
michael@0 326 return NS_ERROR_ILLEGAL_VALUE;
michael@0 327
michael@0 328 nsCOMPtr<nsIRDFResource> ordinal;
michael@0 329 rv = gRDFContainerUtils->IndexToOrdinalResource(aIndex, getter_AddRefs(ordinal));
michael@0 330 if (NS_FAILED(rv)) return rv;
michael@0 331
michael@0 332 nsCOMPtr<nsIRDFNode> old;
michael@0 333 rv = mDataSource->GetTarget(mContainer, ordinal, true, getter_AddRefs(old));
michael@0 334 if (NS_FAILED(rv)) return rv;
michael@0 335
michael@0 336 if (rv == NS_OK) {
michael@0 337 rv = mDataSource->Unassert(mContainer, ordinal, old);
michael@0 338 if (NS_FAILED(rv)) return rv;
michael@0 339
michael@0 340 if (aRenumber) {
michael@0 341 // Now slide the rest of the collection backwards to fill in
michael@0 342 // the gap. This will have the side effect of completely
michael@0 343 // renumber the container from index to the end.
michael@0 344 rv = Renumber(aIndex + 1, -1);
michael@0 345 if (NS_FAILED(rv)) return rv;
michael@0 346 }
michael@0 347 }
michael@0 348
michael@0 349 old.swap(*_retval);
michael@0 350
michael@0 351 return NS_OK;
michael@0 352 }
michael@0 353
michael@0 354 NS_IMETHODIMP
michael@0 355 RDFContainerImpl::IndexOf(nsIRDFNode *aElement, int32_t *aIndex)
michael@0 356 {
michael@0 357 if (!mDataSource || !mContainer)
michael@0 358 return NS_ERROR_NOT_INITIALIZED;
michael@0 359
michael@0 360 return gRDFContainerUtils->IndexOf(mDataSource, mContainer,
michael@0 361 aElement, aIndex);
michael@0 362 }
michael@0 363
michael@0 364
michael@0 365 ////////////////////////////////////////////////////////////////////////
michael@0 366
michael@0 367
michael@0 368 RDFContainerImpl::RDFContainerImpl()
michael@0 369 : mDataSource(nullptr), mContainer(nullptr)
michael@0 370 {
michael@0 371 }
michael@0 372
michael@0 373
michael@0 374 nsresult
michael@0 375 RDFContainerImpl::Init()
michael@0 376 {
michael@0 377 if (gRefCnt++ == 0) {
michael@0 378 nsresult rv;
michael@0 379
michael@0 380 NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
michael@0 381 rv = CallGetService(kRDFServiceCID, &gRDFService);
michael@0 382 if (NS_FAILED(rv)) {
michael@0 383 NS_ERROR("unable to get RDF service");
michael@0 384 return rv;
michael@0 385 }
michael@0 386
michael@0 387 rv = gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "nextVal"),
michael@0 388 &kRDF_nextVal);
michael@0 389 if (NS_FAILED(rv)) return rv;
michael@0 390
michael@0 391 NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID);
michael@0 392 rv = CallGetService(kRDFContainerUtilsCID, &gRDFContainerUtils);
michael@0 393 if (NS_FAILED(rv)) {
michael@0 394 NS_ERROR("unable to get RDF container utils service");
michael@0 395 return rv;
michael@0 396 }
michael@0 397 }
michael@0 398
michael@0 399 return NS_OK;
michael@0 400 }
michael@0 401
michael@0 402
michael@0 403 RDFContainerImpl::~RDFContainerImpl()
michael@0 404 {
michael@0 405 #ifdef DEBUG_REFS
michael@0 406 --gInstanceCount;
michael@0 407 fprintf(stdout, "%d - RDF: RDFContainerImpl\n", gInstanceCount);
michael@0 408 #endif
michael@0 409
michael@0 410 NS_IF_RELEASE(mContainer);
michael@0 411 NS_IF_RELEASE(mDataSource);
michael@0 412
michael@0 413 if (--gRefCnt == 0) {
michael@0 414 NS_IF_RELEASE(gRDFContainerUtils);
michael@0 415 NS_IF_RELEASE(gRDFService);
michael@0 416 NS_IF_RELEASE(kRDF_nextVal);
michael@0 417 }
michael@0 418 }
michael@0 419
michael@0 420
michael@0 421 nsresult
michael@0 422 NS_NewRDFContainer(nsIRDFContainer** aResult)
michael@0 423 {
michael@0 424 RDFContainerImpl* result = new RDFContainerImpl();
michael@0 425 if (! result)
michael@0 426 return NS_ERROR_OUT_OF_MEMORY;
michael@0 427
michael@0 428 nsresult rv;
michael@0 429 rv = result->Init();
michael@0 430 if (NS_FAILED(rv)) {
michael@0 431 delete result;
michael@0 432 return rv;
michael@0 433 }
michael@0 434
michael@0 435 NS_ADDREF(result);
michael@0 436 *aResult = result;
michael@0 437 return NS_OK;
michael@0 438 }
michael@0 439
michael@0 440
michael@0 441 nsresult
michael@0 442 NS_NewRDFContainer(nsIRDFDataSource* aDataSource,
michael@0 443 nsIRDFResource* aResource,
michael@0 444 nsIRDFContainer** aResult)
michael@0 445 {
michael@0 446 nsresult rv;
michael@0 447 rv = NS_NewRDFContainer(aResult);
michael@0 448 if (NS_FAILED(rv)) return rv;
michael@0 449
michael@0 450 rv = (*aResult)->Init(aDataSource, aResource);
michael@0 451 if (NS_FAILED(rv)) {
michael@0 452 NS_RELEASE(*aResult);
michael@0 453 }
michael@0 454 return rv;
michael@0 455 }
michael@0 456
michael@0 457
michael@0 458 nsresult
michael@0 459 RDFContainerImpl::Renumber(int32_t aStartIndex, int32_t aIncrement)
michael@0 460 {
michael@0 461 if (!mDataSource || !mContainer)
michael@0 462 return NS_ERROR_NOT_INITIALIZED;
michael@0 463
michael@0 464 // Renumber the elements in the container starting with
michael@0 465 // aStartIndex, updating each element's index by aIncrement. For
michael@0 466 // example,
michael@0 467 //
michael@0 468 // (1:a 2:b 3:c)
michael@0 469 // Renumber(2, +1);
michael@0 470 // (1:a 3:b 4:c)
michael@0 471 // Renumber(3, -1);
michael@0 472 // (1:a 2:b 3:c)
michael@0 473 //
michael@0 474 nsresult rv;
michael@0 475
michael@0 476 if (! aIncrement)
michael@0 477 return NS_OK;
michael@0 478
michael@0 479 int32_t count;
michael@0 480 rv = GetCount(&count);
michael@0 481 if (NS_FAILED(rv)) return rv;
michael@0 482
michael@0 483 if (aIncrement > 0) {
michael@0 484 // Update the container's nextVal to reflect the
michael@0 485 // renumbering. We do this now if aIncrement > 0 because we'll
michael@0 486 // want to be able to acknowledge that new elements are in the
michael@0 487 // container.
michael@0 488 rv = SetNextValue(count + aIncrement + 1);
michael@0 489 if (NS_FAILED(rv)) return rv;
michael@0 490 }
michael@0 491
michael@0 492 int32_t i;
michael@0 493 if (aIncrement < 0) {
michael@0 494 i = aStartIndex;
michael@0 495 }
michael@0 496 else {
michael@0 497 i = count; // we're one-indexed.
michael@0 498 }
michael@0 499
michael@0 500 // Note: once we disable notifications, don't exit this method until
michael@0 501 // enabling notifications
michael@0 502 nsCOMPtr<nsIRDFPropagatableDataSource> propagatable =
michael@0 503 do_QueryInterface(mDataSource);
michael@0 504 if (propagatable) {
michael@0 505 propagatable->SetPropagateChanges(false);
michael@0 506 }
michael@0 507
michael@0 508 bool err = false;
michael@0 509 while (!err && ((aIncrement < 0) ? (i <= count) : (i >= aStartIndex)))
michael@0 510 {
michael@0 511 nsCOMPtr<nsIRDFResource> oldOrdinal;
michael@0 512 rv = gRDFContainerUtils->IndexToOrdinalResource(i, getter_AddRefs(oldOrdinal));
michael@0 513 if (NS_FAILED(rv))
michael@0 514 {
michael@0 515 err = true;
michael@0 516 continue;
michael@0 517 }
michael@0 518
michael@0 519 nsCOMPtr<nsIRDFResource> newOrdinal;
michael@0 520 rv = gRDFContainerUtils->IndexToOrdinalResource(i + aIncrement, getter_AddRefs(newOrdinal));
michael@0 521 if (NS_FAILED(rv))
michael@0 522 {
michael@0 523 err = true;
michael@0 524 continue;
michael@0 525 }
michael@0 526
michael@0 527 // Because of aggregation, we need to be paranoid about the
michael@0 528 // possibility that >1 element may be present per ordinal. If
michael@0 529 // there _is_ in fact more than one element, they'll all get
michael@0 530 // assigned to the same new ordinal; i.e., we don't make any
michael@0 531 // attempt to "clean up" the duplicate numbering. (Doing so
michael@0 532 // would require two passes.)
michael@0 533 nsCOMPtr<nsISimpleEnumerator> targets;
michael@0 534 rv = mDataSource->GetTargets(mContainer, oldOrdinal, true, getter_AddRefs(targets));
michael@0 535 if (NS_FAILED(rv))
michael@0 536 {
michael@0 537 err = true;
michael@0 538 continue;
michael@0 539 }
michael@0 540
michael@0 541 while (1) {
michael@0 542 bool hasMore;
michael@0 543 rv = targets->HasMoreElements(&hasMore);
michael@0 544 if (NS_FAILED(rv))
michael@0 545 {
michael@0 546 err = true;
michael@0 547 break;
michael@0 548 }
michael@0 549
michael@0 550 if (! hasMore)
michael@0 551 break;
michael@0 552
michael@0 553 nsCOMPtr<nsISupports> isupports;
michael@0 554 rv = targets->GetNext(getter_AddRefs(isupports));
michael@0 555 if (NS_FAILED(rv))
michael@0 556 {
michael@0 557 err = true;
michael@0 558 break;
michael@0 559 }
michael@0 560
michael@0 561 nsCOMPtr<nsIRDFNode> element( do_QueryInterface(isupports) );
michael@0 562 NS_ASSERTION(element != nullptr, "something funky in the enumerator");
michael@0 563 if (! element)
michael@0 564 {
michael@0 565 err = true;
michael@0 566 rv = NS_ERROR_UNEXPECTED;
michael@0 567 break;
michael@0 568 }
michael@0 569
michael@0 570 rv = mDataSource->Unassert(mContainer, oldOrdinal, element);
michael@0 571 if (NS_FAILED(rv))
michael@0 572 {
michael@0 573 err = true;
michael@0 574 break;
michael@0 575 }
michael@0 576
michael@0 577 rv = mDataSource->Assert(mContainer, newOrdinal, element, true);
michael@0 578 if (NS_FAILED(rv))
michael@0 579 {
michael@0 580 err = true;
michael@0 581 break;
michael@0 582 }
michael@0 583 }
michael@0 584
michael@0 585 i -= aIncrement;
michael@0 586 }
michael@0 587
michael@0 588 if (!err && (aIncrement < 0))
michael@0 589 {
michael@0 590 // Update the container's nextVal to reflect the
michael@0 591 // renumbering. We do this now if aIncrement < 0 because, up
michael@0 592 // until this point, we'll want people to be able to find
michael@0 593 // things that are still "at the end".
michael@0 594 rv = SetNextValue(count + aIncrement + 1);
michael@0 595 if (NS_FAILED(rv))
michael@0 596 {
michael@0 597 err = true;
michael@0 598 }
michael@0 599 }
michael@0 600
michael@0 601 // Note: MUST enable notifications before exiting this method
michael@0 602 if (propagatable) {
michael@0 603 propagatable->SetPropagateChanges(true);
michael@0 604 }
michael@0 605
michael@0 606 if (err) return(rv);
michael@0 607
michael@0 608 return NS_OK;
michael@0 609 }
michael@0 610
michael@0 611
michael@0 612
michael@0 613 nsresult
michael@0 614 RDFContainerImpl::SetNextValue(int32_t aIndex)
michael@0 615 {
michael@0 616 if (!mDataSource || !mContainer)
michael@0 617 return NS_ERROR_NOT_INITIALIZED;
michael@0 618
michael@0 619 nsresult rv;
michael@0 620
michael@0 621 // Remove the current value of nextVal, if there is one.
michael@0 622 nsCOMPtr<nsIRDFNode> nextValNode;
michael@0 623 if (NS_SUCCEEDED(rv = mDataSource->GetTarget(mContainer,
michael@0 624 kRDF_nextVal,
michael@0 625 true,
michael@0 626 getter_AddRefs(nextValNode)))) {
michael@0 627 if (NS_FAILED(rv = mDataSource->Unassert(mContainer, kRDF_nextVal, nextValNode))) {
michael@0 628 NS_ERROR("unable to update nextVal");
michael@0 629 return rv;
michael@0 630 }
michael@0 631 }
michael@0 632
michael@0 633 nsAutoString s;
michael@0 634 s.AppendInt(aIndex, 10);
michael@0 635
michael@0 636 nsCOMPtr<nsIRDFLiteral> nextVal;
michael@0 637 if (NS_FAILED(rv = gRDFService->GetLiteral(s.get(), getter_AddRefs(nextVal)))) {
michael@0 638 NS_ERROR("unable to get nextVal literal");
michael@0 639 return rv;
michael@0 640 }
michael@0 641
michael@0 642 rv = mDataSource->Assert(mContainer, kRDF_nextVal, nextVal, true);
michael@0 643 if (rv != NS_RDF_ASSERTION_ACCEPTED) {
michael@0 644 NS_ERROR("unable to update nextVal");
michael@0 645 return NS_ERROR_FAILURE;
michael@0 646 }
michael@0 647
michael@0 648 return NS_OK;
michael@0 649 }
michael@0 650
michael@0 651
michael@0 652 nsresult
michael@0 653 RDFContainerImpl::GetNextValue(nsIRDFResource** aResult)
michael@0 654 {
michael@0 655 if (!mDataSource || !mContainer)
michael@0 656 return NS_ERROR_NOT_INITIALIZED;
michael@0 657
michael@0 658 nsresult rv;
michael@0 659
michael@0 660 // Get the next value, which hangs off of the bag via the
michael@0 661 // RDF:nextVal property.
michael@0 662 nsCOMPtr<nsIRDFNode> nextValNode;
michael@0 663 rv = mDataSource->GetTarget(mContainer, kRDF_nextVal, true, getter_AddRefs(nextValNode));
michael@0 664 if (NS_FAILED(rv)) return rv;
michael@0 665
michael@0 666 if (rv == NS_RDF_NO_VALUE)
michael@0 667 return NS_ERROR_UNEXPECTED;
michael@0 668
michael@0 669 nsCOMPtr<nsIRDFLiteral> nextValLiteral;
michael@0 670 rv = nextValNode->QueryInterface(NS_GET_IID(nsIRDFLiteral), getter_AddRefs(nextValLiteral));
michael@0 671 if (NS_FAILED(rv)) return rv;
michael@0 672
michael@0 673 const char16_t* s;
michael@0 674 rv = nextValLiteral->GetValueConst(&s);
michael@0 675 if (NS_FAILED(rv)) return rv;
michael@0 676
michael@0 677 int32_t nextVal = 0;
michael@0 678 {
michael@0 679 for (const char16_t* p = s; *p != 0; ++p) {
michael@0 680 NS_ASSERTION(*p >= '0' && *p <= '9', "not a digit");
michael@0 681 if (*p < '0' || *p > '9')
michael@0 682 break;
michael@0 683
michael@0 684 nextVal *= 10;
michael@0 685 nextVal += *p - '0';
michael@0 686 }
michael@0 687 }
michael@0 688
michael@0 689 static const char kRDFNameSpaceURI[] = RDF_NAMESPACE_URI;
michael@0 690 char buf[sizeof(kRDFNameSpaceURI) + 16];
michael@0 691 nsFixedCString nextValStr(buf, sizeof(buf), 0);
michael@0 692 nextValStr = kRDFNameSpaceURI;
michael@0 693 nextValStr.Append("_");
michael@0 694 nextValStr.AppendInt(nextVal, 10);
michael@0 695
michael@0 696 rv = gRDFService->GetResource(nextValStr, aResult);
michael@0 697 if (NS_FAILED(rv)) return rv;
michael@0 698
michael@0 699 // Now increment the RDF:nextVal property.
michael@0 700 rv = mDataSource->Unassert(mContainer, kRDF_nextVal, nextValLiteral);
michael@0 701 if (NS_FAILED(rv)) return rv;
michael@0 702
michael@0 703 ++nextVal;
michael@0 704 nextValStr.Truncate();
michael@0 705 nextValStr.AppendInt(nextVal, 10);
michael@0 706
michael@0 707 rv = gRDFService->GetLiteral(NS_ConvertASCIItoUTF16(nextValStr).get(), getter_AddRefs(nextValLiteral));
michael@0 708 if (NS_FAILED(rv)) return rv;
michael@0 709
michael@0 710 rv = mDataSource->Assert(mContainer, kRDF_nextVal, nextValLiteral, true);
michael@0 711 if (NS_FAILED(rv)) return rv;
michael@0 712
michael@0 713 if (RDF_SEQ_LIST_LIMIT == nextVal)
michael@0 714 {
michael@0 715 // focal point for RDF container mutation;
michael@0 716 // basically, provide a hint to allow for fast access
michael@0 717 nsCOMPtr<nsIRDFInMemoryDataSource> inMem = do_QueryInterface(mDataSource);
michael@0 718 if (inMem)
michael@0 719 {
michael@0 720 // ignore error; failure just means slower access
michael@0 721 (void)inMem->EnsureFastContainment(mContainer);
michael@0 722 }
michael@0 723 }
michael@0 724
michael@0 725 return NS_OK;
michael@0 726 }

mercurial