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