1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/rdf/base/src/nsRDFContainer.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,726 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + 1.11 + Implementation for the RDF container. 1.12 + 1.13 + Notes 1.14 + ----- 1.15 + 1.16 + 1. RDF containers are one-indexed. This means that a lot of the loops 1.17 + that you'd normally think you'd write like this: 1.18 + 1.19 + for (i = 0; i < count; ++i) {} 1.20 + 1.21 + You've gotta write like this: 1.22 + 1.23 + for (i = 1; i <= count; ++i) {} 1.24 + 1.25 + "Sure, right, yeah, of course.", you say. Well maybe I'm just 1.26 + thick, but it's easy to slip up. 1.27 + 1.28 + 2. The RDF:nextVal property on the container is an 1.29 + implementation-level hack that is used to quickly compute the 1.30 + next value for appending to the container. It will no doubt 1.31 + become royally screwed up in the case of aggregation. 1.32 + 1.33 + 3. The RDF:nextVal property is also used to retrieve the count of 1.34 + elements in the container. 1.35 + 1.36 + */ 1.37 + 1.38 + 1.39 +#include "nsCOMPtr.h" 1.40 +#include "nsIRDFContainer.h" 1.41 +#include "nsIRDFContainerUtils.h" 1.42 +#include "nsIRDFInMemoryDataSource.h" 1.43 +#include "nsIRDFPropagatableDataSource.h" 1.44 +#include "nsIRDFService.h" 1.45 +#include "nsIServiceManager.h" 1.46 +#include "nsRDFCID.h" 1.47 +#include "nsString.h" 1.48 +#include "nsXPIDLString.h" 1.49 +#include "rdf.h" 1.50 + 1.51 +#define RDF_SEQ_LIST_LIMIT 8 1.52 + 1.53 +class RDFContainerImpl : public nsIRDFContainer 1.54 +{ 1.55 +public: 1.56 + 1.57 + // nsISupports interface 1.58 + NS_DECL_ISUPPORTS 1.59 + 1.60 + // nsIRDFContainer interface 1.61 + NS_DECL_NSIRDFCONTAINER 1.62 + 1.63 +private: 1.64 + friend nsresult NS_NewRDFContainer(nsIRDFContainer** aResult); 1.65 + 1.66 + RDFContainerImpl(); 1.67 + virtual ~RDFContainerImpl(); 1.68 + 1.69 + nsresult Init(); 1.70 + 1.71 + nsresult Renumber(int32_t aStartIndex, int32_t aIncrement); 1.72 + nsresult SetNextValue(int32_t aIndex); 1.73 + nsresult GetNextValue(nsIRDFResource** aResult); 1.74 + 1.75 + nsIRDFDataSource* mDataSource; 1.76 + nsIRDFResource* mContainer; 1.77 + 1.78 + // pseudo constants 1.79 + static int32_t gRefCnt; 1.80 + static nsIRDFService* gRDFService; 1.81 + static nsIRDFContainerUtils* gRDFContainerUtils; 1.82 + static nsIRDFResource* kRDF_nextVal; 1.83 +}; 1.84 + 1.85 + 1.86 +int32_t RDFContainerImpl::gRefCnt = 0; 1.87 +nsIRDFService* RDFContainerImpl::gRDFService; 1.88 +nsIRDFContainerUtils* RDFContainerImpl::gRDFContainerUtils; 1.89 +nsIRDFResource* RDFContainerImpl::kRDF_nextVal; 1.90 + 1.91 +//////////////////////////////////////////////////////////////////////// 1.92 +// nsISupports interface 1.93 + 1.94 +NS_IMPL_ISUPPORTS(RDFContainerImpl, nsIRDFContainer) 1.95 + 1.96 + 1.97 + 1.98 +//////////////////////////////////////////////////////////////////////// 1.99 +// nsIRDFContainer interface 1.100 + 1.101 +NS_IMETHODIMP 1.102 +RDFContainerImpl::GetDataSource(nsIRDFDataSource** _retval) 1.103 +{ 1.104 + *_retval = mDataSource; 1.105 + NS_IF_ADDREF(*_retval); 1.106 + return NS_OK; 1.107 +} 1.108 + 1.109 + 1.110 +NS_IMETHODIMP 1.111 +RDFContainerImpl::GetResource(nsIRDFResource** _retval) 1.112 +{ 1.113 + *_retval = mContainer; 1.114 + NS_IF_ADDREF(*_retval); 1.115 + return NS_OK; 1.116 +} 1.117 + 1.118 + 1.119 +NS_IMETHODIMP 1.120 +RDFContainerImpl::Init(nsIRDFDataSource *aDataSource, nsIRDFResource *aContainer) 1.121 +{ 1.122 + NS_PRECONDITION(aDataSource != nullptr, "null ptr"); 1.123 + if (! aDataSource) 1.124 + return NS_ERROR_NULL_POINTER; 1.125 + 1.126 + NS_PRECONDITION(aContainer != nullptr, "null ptr"); 1.127 + if (! aContainer) 1.128 + return NS_ERROR_NULL_POINTER; 1.129 + 1.130 + nsresult rv; 1.131 + bool isContainer; 1.132 + rv = gRDFContainerUtils->IsContainer(aDataSource, aContainer, &isContainer); 1.133 + if (NS_FAILED(rv)) return rv; 1.134 + 1.135 + // ``throw'' if we can't create a container on the specified 1.136 + // datasource/resource combination. 1.137 + if (! isContainer) 1.138 + return NS_ERROR_FAILURE; 1.139 + 1.140 + NS_IF_RELEASE(mDataSource); 1.141 + mDataSource = aDataSource; 1.142 + NS_ADDREF(mDataSource); 1.143 + 1.144 + NS_IF_RELEASE(mContainer); 1.145 + mContainer = aContainer; 1.146 + NS_ADDREF(mContainer); 1.147 + 1.148 + return NS_OK; 1.149 +} 1.150 + 1.151 + 1.152 +NS_IMETHODIMP 1.153 +RDFContainerImpl::GetCount(int32_t *aCount) 1.154 +{ 1.155 + if (!mDataSource || !mContainer) 1.156 + return NS_ERROR_NOT_INITIALIZED; 1.157 + 1.158 + nsresult rv; 1.159 + 1.160 + // Get the next value, which hangs off of the bag via the 1.161 + // RDF:nextVal property. This is the _next value_ that will get 1.162 + // assigned in a one-indexed array. So, it's actually _one more_ 1.163 + // than the actual count of elements in the container. 1.164 + // 1.165 + // XXX To handle aggregation, this should probably be a 1.166 + // GetTargets() that enumerates all of the values and picks the 1.167 + // largest one. 1.168 + nsCOMPtr<nsIRDFNode> nextValNode; 1.169 + rv = mDataSource->GetTarget(mContainer, kRDF_nextVal, true, getter_AddRefs(nextValNode)); 1.170 + if (NS_FAILED(rv)) return rv; 1.171 + 1.172 + if (rv == NS_RDF_NO_VALUE) 1.173 + return NS_ERROR_UNEXPECTED; 1.174 + 1.175 + nsCOMPtr<nsIRDFLiteral> nextValLiteral; 1.176 + rv = nextValNode->QueryInterface(NS_GET_IID(nsIRDFLiteral), getter_AddRefs(nextValLiteral)); 1.177 + if (NS_FAILED(rv)) return rv; 1.178 + 1.179 + const char16_t *s; 1.180 + rv = nextValLiteral->GetValueConst( &s ); 1.181 + if (NS_FAILED(rv)) return rv; 1.182 + 1.183 + nsAutoString nextValStr(s); 1.184 + 1.185 + int32_t nextVal; 1.186 + nsresult err; 1.187 + nextVal = nextValStr.ToInteger(&err); 1.188 + if (NS_FAILED(err)) 1.189 + return NS_ERROR_UNEXPECTED; 1.190 + 1.191 + *aCount = nextVal - 1; 1.192 + return NS_OK; 1.193 +} 1.194 + 1.195 + 1.196 +NS_IMETHODIMP 1.197 +RDFContainerImpl::GetElements(nsISimpleEnumerator **_retval) 1.198 +{ 1.199 + if (!mDataSource || !mContainer) 1.200 + return NS_ERROR_NOT_INITIALIZED; 1.201 + 1.202 + return NS_NewContainerEnumerator(mDataSource, mContainer, _retval); 1.203 +} 1.204 + 1.205 + 1.206 +NS_IMETHODIMP 1.207 +RDFContainerImpl::AppendElement(nsIRDFNode *aElement) 1.208 +{ 1.209 + if (!mDataSource || !mContainer) 1.210 + return NS_ERROR_NOT_INITIALIZED; 1.211 + 1.212 + NS_PRECONDITION(aElement != nullptr, "null ptr"); 1.213 + if (! aElement) 1.214 + return NS_ERROR_NULL_POINTER; 1.215 + 1.216 + nsresult rv; 1.217 + 1.218 + nsCOMPtr<nsIRDFResource> nextVal; 1.219 + rv = GetNextValue(getter_AddRefs(nextVal)); 1.220 + if (NS_FAILED(rv)) return rv; 1.221 + 1.222 + rv = mDataSource->Assert(mContainer, nextVal, aElement, true); 1.223 + if (NS_FAILED(rv)) return rv; 1.224 + 1.225 + return NS_OK; 1.226 +} 1.227 + 1.228 + 1.229 +NS_IMETHODIMP 1.230 +RDFContainerImpl::RemoveElement(nsIRDFNode *aElement, bool aRenumber) 1.231 +{ 1.232 + if (!mDataSource || !mContainer) 1.233 + return NS_ERROR_NOT_INITIALIZED; 1.234 + 1.235 + NS_PRECONDITION(aElement != nullptr, "null ptr"); 1.236 + if (! aElement) 1.237 + return NS_ERROR_NULL_POINTER; 1.238 + 1.239 + nsresult rv; 1.240 + 1.241 + int32_t idx; 1.242 + rv = IndexOf(aElement, &idx); 1.243 + if (NS_FAILED(rv)) return rv; 1.244 + 1.245 + if (idx < 0) 1.246 + return NS_OK; 1.247 + 1.248 + // Remove the element. 1.249 + nsCOMPtr<nsIRDFResource> ordinal; 1.250 + rv = gRDFContainerUtils->IndexToOrdinalResource(idx, 1.251 + getter_AddRefs(ordinal)); 1.252 + if (NS_FAILED(rv)) return rv; 1.253 + 1.254 + rv = mDataSource->Unassert(mContainer, ordinal, aElement); 1.255 + if (NS_FAILED(rv)) return rv; 1.256 + 1.257 + if (aRenumber) { 1.258 + // Now slide the rest of the collection backwards to fill in 1.259 + // the gap. This will have the side effect of completely 1.260 + // renumber the container from index to the end. 1.261 + rv = Renumber(idx + 1, -1); 1.262 + if (NS_FAILED(rv)) return rv; 1.263 + } 1.264 + 1.265 + return NS_OK; 1.266 +} 1.267 + 1.268 + 1.269 +NS_IMETHODIMP 1.270 +RDFContainerImpl::InsertElementAt(nsIRDFNode *aElement, int32_t aIndex, bool aRenumber) 1.271 +{ 1.272 + if (!mDataSource || !mContainer) 1.273 + return NS_ERROR_NOT_INITIALIZED; 1.274 + 1.275 + NS_PRECONDITION(aElement != nullptr, "null ptr"); 1.276 + if (! aElement) 1.277 + return NS_ERROR_NULL_POINTER; 1.278 + 1.279 + NS_PRECONDITION(aIndex >= 1, "illegal value"); 1.280 + if (aIndex < 1) 1.281 + return NS_ERROR_ILLEGAL_VALUE; 1.282 + 1.283 + nsresult rv; 1.284 + 1.285 + int32_t count; 1.286 + rv = GetCount(&count); 1.287 + if (NS_FAILED(rv)) return rv; 1.288 + 1.289 + NS_ASSERTION(aIndex <= count + 1, "illegal value"); 1.290 + if (aIndex > count + 1) 1.291 + return NS_ERROR_ILLEGAL_VALUE; 1.292 + 1.293 + if (aRenumber) { 1.294 + // Make a hole for the element. This will have the side effect of 1.295 + // completely renumbering the container from 'aIndex' to 'count', 1.296 + // and will spew assertions. 1.297 + rv = Renumber(aIndex, +1); 1.298 + if (NS_FAILED(rv)) return rv; 1.299 + } 1.300 + 1.301 + nsCOMPtr<nsIRDFResource> ordinal; 1.302 + rv = gRDFContainerUtils->IndexToOrdinalResource(aIndex, getter_AddRefs(ordinal)); 1.303 + if (NS_FAILED(rv)) return rv; 1.304 + 1.305 + rv = mDataSource->Assert(mContainer, ordinal, aElement, true); 1.306 + if (NS_FAILED(rv)) return rv; 1.307 + 1.308 + return NS_OK; 1.309 +} 1.310 + 1.311 +NS_IMETHODIMP 1.312 +RDFContainerImpl::RemoveElementAt(int32_t aIndex, bool aRenumber, nsIRDFNode** _retval) 1.313 +{ 1.314 + if (!mDataSource || !mContainer) 1.315 + return NS_ERROR_NOT_INITIALIZED; 1.316 + 1.317 + *_retval = nullptr; 1.318 + 1.319 + if (aIndex< 1) 1.320 + return NS_ERROR_ILLEGAL_VALUE; 1.321 + 1.322 + nsresult rv; 1.323 + 1.324 + int32_t count; 1.325 + rv = GetCount(&count); 1.326 + if (NS_FAILED(rv)) return rv; 1.327 + 1.328 + if (aIndex > count) 1.329 + return NS_ERROR_ILLEGAL_VALUE; 1.330 + 1.331 + nsCOMPtr<nsIRDFResource> ordinal; 1.332 + rv = gRDFContainerUtils->IndexToOrdinalResource(aIndex, getter_AddRefs(ordinal)); 1.333 + if (NS_FAILED(rv)) return rv; 1.334 + 1.335 + nsCOMPtr<nsIRDFNode> old; 1.336 + rv = mDataSource->GetTarget(mContainer, ordinal, true, getter_AddRefs(old)); 1.337 + if (NS_FAILED(rv)) return rv; 1.338 + 1.339 + if (rv == NS_OK) { 1.340 + rv = mDataSource->Unassert(mContainer, ordinal, old); 1.341 + if (NS_FAILED(rv)) return rv; 1.342 + 1.343 + if (aRenumber) { 1.344 + // Now slide the rest of the collection backwards to fill in 1.345 + // the gap. This will have the side effect of completely 1.346 + // renumber the container from index to the end. 1.347 + rv = Renumber(aIndex + 1, -1); 1.348 + if (NS_FAILED(rv)) return rv; 1.349 + } 1.350 + } 1.351 + 1.352 + old.swap(*_retval); 1.353 + 1.354 + return NS_OK; 1.355 +} 1.356 + 1.357 +NS_IMETHODIMP 1.358 +RDFContainerImpl::IndexOf(nsIRDFNode *aElement, int32_t *aIndex) 1.359 +{ 1.360 + if (!mDataSource || !mContainer) 1.361 + return NS_ERROR_NOT_INITIALIZED; 1.362 + 1.363 + return gRDFContainerUtils->IndexOf(mDataSource, mContainer, 1.364 + aElement, aIndex); 1.365 +} 1.366 + 1.367 + 1.368 +//////////////////////////////////////////////////////////////////////// 1.369 + 1.370 + 1.371 +RDFContainerImpl::RDFContainerImpl() 1.372 + : mDataSource(nullptr), mContainer(nullptr) 1.373 +{ 1.374 +} 1.375 + 1.376 + 1.377 +nsresult 1.378 +RDFContainerImpl::Init() 1.379 +{ 1.380 + if (gRefCnt++ == 0) { 1.381 + nsresult rv; 1.382 + 1.383 + NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); 1.384 + rv = CallGetService(kRDFServiceCID, &gRDFService); 1.385 + if (NS_FAILED(rv)) { 1.386 + NS_ERROR("unable to get RDF service"); 1.387 + return rv; 1.388 + } 1.389 + 1.390 + rv = gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "nextVal"), 1.391 + &kRDF_nextVal); 1.392 + if (NS_FAILED(rv)) return rv; 1.393 + 1.394 + NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID); 1.395 + rv = CallGetService(kRDFContainerUtilsCID, &gRDFContainerUtils); 1.396 + if (NS_FAILED(rv)) { 1.397 + NS_ERROR("unable to get RDF container utils service"); 1.398 + return rv; 1.399 + } 1.400 + } 1.401 + 1.402 + return NS_OK; 1.403 +} 1.404 + 1.405 + 1.406 +RDFContainerImpl::~RDFContainerImpl() 1.407 +{ 1.408 +#ifdef DEBUG_REFS 1.409 + --gInstanceCount; 1.410 + fprintf(stdout, "%d - RDF: RDFContainerImpl\n", gInstanceCount); 1.411 +#endif 1.412 + 1.413 + NS_IF_RELEASE(mContainer); 1.414 + NS_IF_RELEASE(mDataSource); 1.415 + 1.416 + if (--gRefCnt == 0) { 1.417 + NS_IF_RELEASE(gRDFContainerUtils); 1.418 + NS_IF_RELEASE(gRDFService); 1.419 + NS_IF_RELEASE(kRDF_nextVal); 1.420 + } 1.421 +} 1.422 + 1.423 + 1.424 +nsresult 1.425 +NS_NewRDFContainer(nsIRDFContainer** aResult) 1.426 +{ 1.427 + RDFContainerImpl* result = new RDFContainerImpl(); 1.428 + if (! result) 1.429 + return NS_ERROR_OUT_OF_MEMORY; 1.430 + 1.431 + nsresult rv; 1.432 + rv = result->Init(); 1.433 + if (NS_FAILED(rv)) { 1.434 + delete result; 1.435 + return rv; 1.436 + } 1.437 + 1.438 + NS_ADDREF(result); 1.439 + *aResult = result; 1.440 + return NS_OK; 1.441 +} 1.442 + 1.443 + 1.444 +nsresult 1.445 +NS_NewRDFContainer(nsIRDFDataSource* aDataSource, 1.446 + nsIRDFResource* aResource, 1.447 + nsIRDFContainer** aResult) 1.448 +{ 1.449 + nsresult rv; 1.450 + rv = NS_NewRDFContainer(aResult); 1.451 + if (NS_FAILED(rv)) return rv; 1.452 + 1.453 + rv = (*aResult)->Init(aDataSource, aResource); 1.454 + if (NS_FAILED(rv)) { 1.455 + NS_RELEASE(*aResult); 1.456 + } 1.457 + return rv; 1.458 +} 1.459 + 1.460 + 1.461 +nsresult 1.462 +RDFContainerImpl::Renumber(int32_t aStartIndex, int32_t aIncrement) 1.463 +{ 1.464 + if (!mDataSource || !mContainer) 1.465 + return NS_ERROR_NOT_INITIALIZED; 1.466 + 1.467 + // Renumber the elements in the container starting with 1.468 + // aStartIndex, updating each element's index by aIncrement. For 1.469 + // example, 1.470 + // 1.471 + // (1:a 2:b 3:c) 1.472 + // Renumber(2, +1); 1.473 + // (1:a 3:b 4:c) 1.474 + // Renumber(3, -1); 1.475 + // (1:a 2:b 3:c) 1.476 + // 1.477 + nsresult rv; 1.478 + 1.479 + if (! aIncrement) 1.480 + return NS_OK; 1.481 + 1.482 + int32_t count; 1.483 + rv = GetCount(&count); 1.484 + if (NS_FAILED(rv)) return rv; 1.485 + 1.486 + if (aIncrement > 0) { 1.487 + // Update the container's nextVal to reflect the 1.488 + // renumbering. We do this now if aIncrement > 0 because we'll 1.489 + // want to be able to acknowledge that new elements are in the 1.490 + // container. 1.491 + rv = SetNextValue(count + aIncrement + 1); 1.492 + if (NS_FAILED(rv)) return rv; 1.493 + } 1.494 + 1.495 + int32_t i; 1.496 + if (aIncrement < 0) { 1.497 + i = aStartIndex; 1.498 + } 1.499 + else { 1.500 + i = count; // we're one-indexed. 1.501 + } 1.502 + 1.503 + // Note: once we disable notifications, don't exit this method until 1.504 + // enabling notifications 1.505 + nsCOMPtr<nsIRDFPropagatableDataSource> propagatable = 1.506 + do_QueryInterface(mDataSource); 1.507 + if (propagatable) { 1.508 + propagatable->SetPropagateChanges(false); 1.509 + } 1.510 + 1.511 + bool err = false; 1.512 + while (!err && ((aIncrement < 0) ? (i <= count) : (i >= aStartIndex))) 1.513 + { 1.514 + nsCOMPtr<nsIRDFResource> oldOrdinal; 1.515 + rv = gRDFContainerUtils->IndexToOrdinalResource(i, getter_AddRefs(oldOrdinal)); 1.516 + if (NS_FAILED(rv)) 1.517 + { 1.518 + err = true; 1.519 + continue; 1.520 + } 1.521 + 1.522 + nsCOMPtr<nsIRDFResource> newOrdinal; 1.523 + rv = gRDFContainerUtils->IndexToOrdinalResource(i + aIncrement, getter_AddRefs(newOrdinal)); 1.524 + if (NS_FAILED(rv)) 1.525 + { 1.526 + err = true; 1.527 + continue; 1.528 + } 1.529 + 1.530 + // Because of aggregation, we need to be paranoid about the 1.531 + // possibility that >1 element may be present per ordinal. If 1.532 + // there _is_ in fact more than one element, they'll all get 1.533 + // assigned to the same new ordinal; i.e., we don't make any 1.534 + // attempt to "clean up" the duplicate numbering. (Doing so 1.535 + // would require two passes.) 1.536 + nsCOMPtr<nsISimpleEnumerator> targets; 1.537 + rv = mDataSource->GetTargets(mContainer, oldOrdinal, true, getter_AddRefs(targets)); 1.538 + if (NS_FAILED(rv)) 1.539 + { 1.540 + err = true; 1.541 + continue; 1.542 + } 1.543 + 1.544 + while (1) { 1.545 + bool hasMore; 1.546 + rv = targets->HasMoreElements(&hasMore); 1.547 + if (NS_FAILED(rv)) 1.548 + { 1.549 + err = true; 1.550 + break; 1.551 + } 1.552 + 1.553 + if (! hasMore) 1.554 + break; 1.555 + 1.556 + nsCOMPtr<nsISupports> isupports; 1.557 + rv = targets->GetNext(getter_AddRefs(isupports)); 1.558 + if (NS_FAILED(rv)) 1.559 + { 1.560 + err = true; 1.561 + break; 1.562 + } 1.563 + 1.564 + nsCOMPtr<nsIRDFNode> element( do_QueryInterface(isupports) ); 1.565 + NS_ASSERTION(element != nullptr, "something funky in the enumerator"); 1.566 + if (! element) 1.567 + { 1.568 + err = true; 1.569 + rv = NS_ERROR_UNEXPECTED; 1.570 + break; 1.571 + } 1.572 + 1.573 + rv = mDataSource->Unassert(mContainer, oldOrdinal, element); 1.574 + if (NS_FAILED(rv)) 1.575 + { 1.576 + err = true; 1.577 + break; 1.578 + } 1.579 + 1.580 + rv = mDataSource->Assert(mContainer, newOrdinal, element, true); 1.581 + if (NS_FAILED(rv)) 1.582 + { 1.583 + err = true; 1.584 + break; 1.585 + } 1.586 + } 1.587 + 1.588 + i -= aIncrement; 1.589 + } 1.590 + 1.591 + if (!err && (aIncrement < 0)) 1.592 + { 1.593 + // Update the container's nextVal to reflect the 1.594 + // renumbering. We do this now if aIncrement < 0 because, up 1.595 + // until this point, we'll want people to be able to find 1.596 + // things that are still "at the end". 1.597 + rv = SetNextValue(count + aIncrement + 1); 1.598 + if (NS_FAILED(rv)) 1.599 + { 1.600 + err = true; 1.601 + } 1.602 + } 1.603 + 1.604 + // Note: MUST enable notifications before exiting this method 1.605 + if (propagatable) { 1.606 + propagatable->SetPropagateChanges(true); 1.607 + } 1.608 + 1.609 + if (err) return(rv); 1.610 + 1.611 + return NS_OK; 1.612 +} 1.613 + 1.614 + 1.615 + 1.616 +nsresult 1.617 +RDFContainerImpl::SetNextValue(int32_t aIndex) 1.618 +{ 1.619 + if (!mDataSource || !mContainer) 1.620 + return NS_ERROR_NOT_INITIALIZED; 1.621 + 1.622 + nsresult rv; 1.623 + 1.624 + // Remove the current value of nextVal, if there is one. 1.625 + nsCOMPtr<nsIRDFNode> nextValNode; 1.626 + if (NS_SUCCEEDED(rv = mDataSource->GetTarget(mContainer, 1.627 + kRDF_nextVal, 1.628 + true, 1.629 + getter_AddRefs(nextValNode)))) { 1.630 + if (NS_FAILED(rv = mDataSource->Unassert(mContainer, kRDF_nextVal, nextValNode))) { 1.631 + NS_ERROR("unable to update nextVal"); 1.632 + return rv; 1.633 + } 1.634 + } 1.635 + 1.636 + nsAutoString s; 1.637 + s.AppendInt(aIndex, 10); 1.638 + 1.639 + nsCOMPtr<nsIRDFLiteral> nextVal; 1.640 + if (NS_FAILED(rv = gRDFService->GetLiteral(s.get(), getter_AddRefs(nextVal)))) { 1.641 + NS_ERROR("unable to get nextVal literal"); 1.642 + return rv; 1.643 + } 1.644 + 1.645 + rv = mDataSource->Assert(mContainer, kRDF_nextVal, nextVal, true); 1.646 + if (rv != NS_RDF_ASSERTION_ACCEPTED) { 1.647 + NS_ERROR("unable to update nextVal"); 1.648 + return NS_ERROR_FAILURE; 1.649 + } 1.650 + 1.651 + return NS_OK; 1.652 +} 1.653 + 1.654 + 1.655 +nsresult 1.656 +RDFContainerImpl::GetNextValue(nsIRDFResource** aResult) 1.657 +{ 1.658 + if (!mDataSource || !mContainer) 1.659 + return NS_ERROR_NOT_INITIALIZED; 1.660 + 1.661 + nsresult rv; 1.662 + 1.663 + // Get the next value, which hangs off of the bag via the 1.664 + // RDF:nextVal property. 1.665 + nsCOMPtr<nsIRDFNode> nextValNode; 1.666 + rv = mDataSource->GetTarget(mContainer, kRDF_nextVal, true, getter_AddRefs(nextValNode)); 1.667 + if (NS_FAILED(rv)) return rv; 1.668 + 1.669 + if (rv == NS_RDF_NO_VALUE) 1.670 + return NS_ERROR_UNEXPECTED; 1.671 + 1.672 + nsCOMPtr<nsIRDFLiteral> nextValLiteral; 1.673 + rv = nextValNode->QueryInterface(NS_GET_IID(nsIRDFLiteral), getter_AddRefs(nextValLiteral)); 1.674 + if (NS_FAILED(rv)) return rv; 1.675 + 1.676 + const char16_t* s; 1.677 + rv = nextValLiteral->GetValueConst(&s); 1.678 + if (NS_FAILED(rv)) return rv; 1.679 + 1.680 + int32_t nextVal = 0; 1.681 + { 1.682 + for (const char16_t* p = s; *p != 0; ++p) { 1.683 + NS_ASSERTION(*p >= '0' && *p <= '9', "not a digit"); 1.684 + if (*p < '0' || *p > '9') 1.685 + break; 1.686 + 1.687 + nextVal *= 10; 1.688 + nextVal += *p - '0'; 1.689 + } 1.690 + } 1.691 + 1.692 + static const char kRDFNameSpaceURI[] = RDF_NAMESPACE_URI; 1.693 + char buf[sizeof(kRDFNameSpaceURI) + 16]; 1.694 + nsFixedCString nextValStr(buf, sizeof(buf), 0); 1.695 + nextValStr = kRDFNameSpaceURI; 1.696 + nextValStr.Append("_"); 1.697 + nextValStr.AppendInt(nextVal, 10); 1.698 + 1.699 + rv = gRDFService->GetResource(nextValStr, aResult); 1.700 + if (NS_FAILED(rv)) return rv; 1.701 + 1.702 + // Now increment the RDF:nextVal property. 1.703 + rv = mDataSource->Unassert(mContainer, kRDF_nextVal, nextValLiteral); 1.704 + if (NS_FAILED(rv)) return rv; 1.705 + 1.706 + ++nextVal; 1.707 + nextValStr.Truncate(); 1.708 + nextValStr.AppendInt(nextVal, 10); 1.709 + 1.710 + rv = gRDFService->GetLiteral(NS_ConvertASCIItoUTF16(nextValStr).get(), getter_AddRefs(nextValLiteral)); 1.711 + if (NS_FAILED(rv)) return rv; 1.712 + 1.713 + rv = mDataSource->Assert(mContainer, kRDF_nextVal, nextValLiteral, true); 1.714 + if (NS_FAILED(rv)) return rv; 1.715 + 1.716 + if (RDF_SEQ_LIST_LIMIT == nextVal) 1.717 + { 1.718 + // focal point for RDF container mutation; 1.719 + // basically, provide a hint to allow for fast access 1.720 + nsCOMPtr<nsIRDFInMemoryDataSource> inMem = do_QueryInterface(mDataSource); 1.721 + if (inMem) 1.722 + { 1.723 + // ignore error; failure just means slower access 1.724 + (void)inMem->EnsureFastContainment(mContainer); 1.725 + } 1.726 + } 1.727 + 1.728 + return NS_OK; 1.729 +}