|
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 NS_IMPL_ISUPPORTS(RDFContainerImpl, nsIRDFContainer) |
|
92 |
|
93 |
|
94 |
|
95 //////////////////////////////////////////////////////////////////////// |
|
96 // nsIRDFContainer interface |
|
97 |
|
98 NS_IMETHODIMP |
|
99 RDFContainerImpl::GetDataSource(nsIRDFDataSource** _retval) |
|
100 { |
|
101 *_retval = mDataSource; |
|
102 NS_IF_ADDREF(*_retval); |
|
103 return NS_OK; |
|
104 } |
|
105 |
|
106 |
|
107 NS_IMETHODIMP |
|
108 RDFContainerImpl::GetResource(nsIRDFResource** _retval) |
|
109 { |
|
110 *_retval = mContainer; |
|
111 NS_IF_ADDREF(*_retval); |
|
112 return NS_OK; |
|
113 } |
|
114 |
|
115 |
|
116 NS_IMETHODIMP |
|
117 RDFContainerImpl::Init(nsIRDFDataSource *aDataSource, nsIRDFResource *aContainer) |
|
118 { |
|
119 NS_PRECONDITION(aDataSource != nullptr, "null ptr"); |
|
120 if (! aDataSource) |
|
121 return NS_ERROR_NULL_POINTER; |
|
122 |
|
123 NS_PRECONDITION(aContainer != nullptr, "null ptr"); |
|
124 if (! aContainer) |
|
125 return NS_ERROR_NULL_POINTER; |
|
126 |
|
127 nsresult rv; |
|
128 bool isContainer; |
|
129 rv = gRDFContainerUtils->IsContainer(aDataSource, aContainer, &isContainer); |
|
130 if (NS_FAILED(rv)) return rv; |
|
131 |
|
132 // ``throw'' if we can't create a container on the specified |
|
133 // datasource/resource combination. |
|
134 if (! isContainer) |
|
135 return NS_ERROR_FAILURE; |
|
136 |
|
137 NS_IF_RELEASE(mDataSource); |
|
138 mDataSource = aDataSource; |
|
139 NS_ADDREF(mDataSource); |
|
140 |
|
141 NS_IF_RELEASE(mContainer); |
|
142 mContainer = aContainer; |
|
143 NS_ADDREF(mContainer); |
|
144 |
|
145 return NS_OK; |
|
146 } |
|
147 |
|
148 |
|
149 NS_IMETHODIMP |
|
150 RDFContainerImpl::GetCount(int32_t *aCount) |
|
151 { |
|
152 if (!mDataSource || !mContainer) |
|
153 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 nsCOMPtr<nsIRDFNode> nextValNode; |
|
166 rv = mDataSource->GetTarget(mContainer, kRDF_nextVal, true, getter_AddRefs(nextValNode)); |
|
167 if (NS_FAILED(rv)) return rv; |
|
168 |
|
169 if (rv == NS_RDF_NO_VALUE) |
|
170 return NS_ERROR_UNEXPECTED; |
|
171 |
|
172 nsCOMPtr<nsIRDFLiteral> nextValLiteral; |
|
173 rv = nextValNode->QueryInterface(NS_GET_IID(nsIRDFLiteral), getter_AddRefs(nextValLiteral)); |
|
174 if (NS_FAILED(rv)) return rv; |
|
175 |
|
176 const char16_t *s; |
|
177 rv = nextValLiteral->GetValueConst( &s ); |
|
178 if (NS_FAILED(rv)) return rv; |
|
179 |
|
180 nsAutoString nextValStr(s); |
|
181 |
|
182 int32_t nextVal; |
|
183 nsresult err; |
|
184 nextVal = nextValStr.ToInteger(&err); |
|
185 if (NS_FAILED(err)) |
|
186 return NS_ERROR_UNEXPECTED; |
|
187 |
|
188 *aCount = nextVal - 1; |
|
189 return NS_OK; |
|
190 } |
|
191 |
|
192 |
|
193 NS_IMETHODIMP |
|
194 RDFContainerImpl::GetElements(nsISimpleEnumerator **_retval) |
|
195 { |
|
196 if (!mDataSource || !mContainer) |
|
197 return NS_ERROR_NOT_INITIALIZED; |
|
198 |
|
199 return NS_NewContainerEnumerator(mDataSource, mContainer, _retval); |
|
200 } |
|
201 |
|
202 |
|
203 NS_IMETHODIMP |
|
204 RDFContainerImpl::AppendElement(nsIRDFNode *aElement) |
|
205 { |
|
206 if (!mDataSource || !mContainer) |
|
207 return NS_ERROR_NOT_INITIALIZED; |
|
208 |
|
209 NS_PRECONDITION(aElement != nullptr, "null ptr"); |
|
210 if (! aElement) |
|
211 return NS_ERROR_NULL_POINTER; |
|
212 |
|
213 nsresult rv; |
|
214 |
|
215 nsCOMPtr<nsIRDFResource> nextVal; |
|
216 rv = GetNextValue(getter_AddRefs(nextVal)); |
|
217 if (NS_FAILED(rv)) return rv; |
|
218 |
|
219 rv = mDataSource->Assert(mContainer, nextVal, aElement, true); |
|
220 if (NS_FAILED(rv)) return rv; |
|
221 |
|
222 return NS_OK; |
|
223 } |
|
224 |
|
225 |
|
226 NS_IMETHODIMP |
|
227 RDFContainerImpl::RemoveElement(nsIRDFNode *aElement, bool aRenumber) |
|
228 { |
|
229 if (!mDataSource || !mContainer) |
|
230 return NS_ERROR_NOT_INITIALIZED; |
|
231 |
|
232 NS_PRECONDITION(aElement != nullptr, "null ptr"); |
|
233 if (! aElement) |
|
234 return NS_ERROR_NULL_POINTER; |
|
235 |
|
236 nsresult rv; |
|
237 |
|
238 int32_t idx; |
|
239 rv = IndexOf(aElement, &idx); |
|
240 if (NS_FAILED(rv)) return rv; |
|
241 |
|
242 if (idx < 0) |
|
243 return NS_OK; |
|
244 |
|
245 // Remove the element. |
|
246 nsCOMPtr<nsIRDFResource> ordinal; |
|
247 rv = gRDFContainerUtils->IndexToOrdinalResource(idx, |
|
248 getter_AddRefs(ordinal)); |
|
249 if (NS_FAILED(rv)) return rv; |
|
250 |
|
251 rv = mDataSource->Unassert(mContainer, ordinal, aElement); |
|
252 if (NS_FAILED(rv)) return rv; |
|
253 |
|
254 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 rv = Renumber(idx + 1, -1); |
|
259 if (NS_FAILED(rv)) return rv; |
|
260 } |
|
261 |
|
262 return NS_OK; |
|
263 } |
|
264 |
|
265 |
|
266 NS_IMETHODIMP |
|
267 RDFContainerImpl::InsertElementAt(nsIRDFNode *aElement, int32_t aIndex, bool aRenumber) |
|
268 { |
|
269 if (!mDataSource || !mContainer) |
|
270 return NS_ERROR_NOT_INITIALIZED; |
|
271 |
|
272 NS_PRECONDITION(aElement != nullptr, "null ptr"); |
|
273 if (! aElement) |
|
274 return NS_ERROR_NULL_POINTER; |
|
275 |
|
276 NS_PRECONDITION(aIndex >= 1, "illegal value"); |
|
277 if (aIndex < 1) |
|
278 return NS_ERROR_ILLEGAL_VALUE; |
|
279 |
|
280 nsresult rv; |
|
281 |
|
282 int32_t count; |
|
283 rv = GetCount(&count); |
|
284 if (NS_FAILED(rv)) return rv; |
|
285 |
|
286 NS_ASSERTION(aIndex <= count + 1, "illegal value"); |
|
287 if (aIndex > count + 1) |
|
288 return NS_ERROR_ILLEGAL_VALUE; |
|
289 |
|
290 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 rv = Renumber(aIndex, +1); |
|
295 if (NS_FAILED(rv)) return rv; |
|
296 } |
|
297 |
|
298 nsCOMPtr<nsIRDFResource> ordinal; |
|
299 rv = gRDFContainerUtils->IndexToOrdinalResource(aIndex, getter_AddRefs(ordinal)); |
|
300 if (NS_FAILED(rv)) return rv; |
|
301 |
|
302 rv = mDataSource->Assert(mContainer, ordinal, aElement, true); |
|
303 if (NS_FAILED(rv)) return rv; |
|
304 |
|
305 return NS_OK; |
|
306 } |
|
307 |
|
308 NS_IMETHODIMP |
|
309 RDFContainerImpl::RemoveElementAt(int32_t aIndex, bool aRenumber, nsIRDFNode** _retval) |
|
310 { |
|
311 if (!mDataSource || !mContainer) |
|
312 return NS_ERROR_NOT_INITIALIZED; |
|
313 |
|
314 *_retval = nullptr; |
|
315 |
|
316 if (aIndex< 1) |
|
317 return NS_ERROR_ILLEGAL_VALUE; |
|
318 |
|
319 nsresult rv; |
|
320 |
|
321 int32_t count; |
|
322 rv = GetCount(&count); |
|
323 if (NS_FAILED(rv)) return rv; |
|
324 |
|
325 if (aIndex > count) |
|
326 return NS_ERROR_ILLEGAL_VALUE; |
|
327 |
|
328 nsCOMPtr<nsIRDFResource> ordinal; |
|
329 rv = gRDFContainerUtils->IndexToOrdinalResource(aIndex, getter_AddRefs(ordinal)); |
|
330 if (NS_FAILED(rv)) return rv; |
|
331 |
|
332 nsCOMPtr<nsIRDFNode> old; |
|
333 rv = mDataSource->GetTarget(mContainer, ordinal, true, getter_AddRefs(old)); |
|
334 if (NS_FAILED(rv)) return rv; |
|
335 |
|
336 if (rv == NS_OK) { |
|
337 rv = mDataSource->Unassert(mContainer, ordinal, old); |
|
338 if (NS_FAILED(rv)) return rv; |
|
339 |
|
340 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 rv = Renumber(aIndex + 1, -1); |
|
345 if (NS_FAILED(rv)) return rv; |
|
346 } |
|
347 } |
|
348 |
|
349 old.swap(*_retval); |
|
350 |
|
351 return NS_OK; |
|
352 } |
|
353 |
|
354 NS_IMETHODIMP |
|
355 RDFContainerImpl::IndexOf(nsIRDFNode *aElement, int32_t *aIndex) |
|
356 { |
|
357 if (!mDataSource || !mContainer) |
|
358 return NS_ERROR_NOT_INITIALIZED; |
|
359 |
|
360 return gRDFContainerUtils->IndexOf(mDataSource, mContainer, |
|
361 aElement, aIndex); |
|
362 } |
|
363 |
|
364 |
|
365 //////////////////////////////////////////////////////////////////////// |
|
366 |
|
367 |
|
368 RDFContainerImpl::RDFContainerImpl() |
|
369 : mDataSource(nullptr), mContainer(nullptr) |
|
370 { |
|
371 } |
|
372 |
|
373 |
|
374 nsresult |
|
375 RDFContainerImpl::Init() |
|
376 { |
|
377 if (gRefCnt++ == 0) { |
|
378 nsresult rv; |
|
379 |
|
380 NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); |
|
381 rv = CallGetService(kRDFServiceCID, &gRDFService); |
|
382 if (NS_FAILED(rv)) { |
|
383 NS_ERROR("unable to get RDF service"); |
|
384 return rv; |
|
385 } |
|
386 |
|
387 rv = gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "nextVal"), |
|
388 &kRDF_nextVal); |
|
389 if (NS_FAILED(rv)) return rv; |
|
390 |
|
391 NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID); |
|
392 rv = CallGetService(kRDFContainerUtilsCID, &gRDFContainerUtils); |
|
393 if (NS_FAILED(rv)) { |
|
394 NS_ERROR("unable to get RDF container utils service"); |
|
395 return rv; |
|
396 } |
|
397 } |
|
398 |
|
399 return NS_OK; |
|
400 } |
|
401 |
|
402 |
|
403 RDFContainerImpl::~RDFContainerImpl() |
|
404 { |
|
405 #ifdef DEBUG_REFS |
|
406 --gInstanceCount; |
|
407 fprintf(stdout, "%d - RDF: RDFContainerImpl\n", gInstanceCount); |
|
408 #endif |
|
409 |
|
410 NS_IF_RELEASE(mContainer); |
|
411 NS_IF_RELEASE(mDataSource); |
|
412 |
|
413 if (--gRefCnt == 0) { |
|
414 NS_IF_RELEASE(gRDFContainerUtils); |
|
415 NS_IF_RELEASE(gRDFService); |
|
416 NS_IF_RELEASE(kRDF_nextVal); |
|
417 } |
|
418 } |
|
419 |
|
420 |
|
421 nsresult |
|
422 NS_NewRDFContainer(nsIRDFContainer** aResult) |
|
423 { |
|
424 RDFContainerImpl* result = new RDFContainerImpl(); |
|
425 if (! result) |
|
426 return NS_ERROR_OUT_OF_MEMORY; |
|
427 |
|
428 nsresult rv; |
|
429 rv = result->Init(); |
|
430 if (NS_FAILED(rv)) { |
|
431 delete result; |
|
432 return rv; |
|
433 } |
|
434 |
|
435 NS_ADDREF(result); |
|
436 *aResult = result; |
|
437 return NS_OK; |
|
438 } |
|
439 |
|
440 |
|
441 nsresult |
|
442 NS_NewRDFContainer(nsIRDFDataSource* aDataSource, |
|
443 nsIRDFResource* aResource, |
|
444 nsIRDFContainer** aResult) |
|
445 { |
|
446 nsresult rv; |
|
447 rv = NS_NewRDFContainer(aResult); |
|
448 if (NS_FAILED(rv)) return rv; |
|
449 |
|
450 rv = (*aResult)->Init(aDataSource, aResource); |
|
451 if (NS_FAILED(rv)) { |
|
452 NS_RELEASE(*aResult); |
|
453 } |
|
454 return rv; |
|
455 } |
|
456 |
|
457 |
|
458 nsresult |
|
459 RDFContainerImpl::Renumber(int32_t aStartIndex, int32_t aIncrement) |
|
460 { |
|
461 if (!mDataSource || !mContainer) |
|
462 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 if (! aIncrement) |
|
477 return NS_OK; |
|
478 |
|
479 int32_t count; |
|
480 rv = GetCount(&count); |
|
481 if (NS_FAILED(rv)) return rv; |
|
482 |
|
483 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 rv = SetNextValue(count + aIncrement + 1); |
|
489 if (NS_FAILED(rv)) return rv; |
|
490 } |
|
491 |
|
492 int32_t i; |
|
493 if (aIncrement < 0) { |
|
494 i = aStartIndex; |
|
495 } |
|
496 else { |
|
497 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 do_QueryInterface(mDataSource); |
|
504 if (propagatable) { |
|
505 propagatable->SetPropagateChanges(false); |
|
506 } |
|
507 |
|
508 bool err = false; |
|
509 while (!err && ((aIncrement < 0) ? (i <= count) : (i >= aStartIndex))) |
|
510 { |
|
511 nsCOMPtr<nsIRDFResource> oldOrdinal; |
|
512 rv = gRDFContainerUtils->IndexToOrdinalResource(i, getter_AddRefs(oldOrdinal)); |
|
513 if (NS_FAILED(rv)) |
|
514 { |
|
515 err = true; |
|
516 continue; |
|
517 } |
|
518 |
|
519 nsCOMPtr<nsIRDFResource> newOrdinal; |
|
520 rv = gRDFContainerUtils->IndexToOrdinalResource(i + aIncrement, getter_AddRefs(newOrdinal)); |
|
521 if (NS_FAILED(rv)) |
|
522 { |
|
523 err = true; |
|
524 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 nsCOMPtr<nsISimpleEnumerator> targets; |
|
534 rv = mDataSource->GetTargets(mContainer, oldOrdinal, true, getter_AddRefs(targets)); |
|
535 if (NS_FAILED(rv)) |
|
536 { |
|
537 err = true; |
|
538 continue; |
|
539 } |
|
540 |
|
541 while (1) { |
|
542 bool hasMore; |
|
543 rv = targets->HasMoreElements(&hasMore); |
|
544 if (NS_FAILED(rv)) |
|
545 { |
|
546 err = true; |
|
547 break; |
|
548 } |
|
549 |
|
550 if (! hasMore) |
|
551 break; |
|
552 |
|
553 nsCOMPtr<nsISupports> isupports; |
|
554 rv = targets->GetNext(getter_AddRefs(isupports)); |
|
555 if (NS_FAILED(rv)) |
|
556 { |
|
557 err = true; |
|
558 break; |
|
559 } |
|
560 |
|
561 nsCOMPtr<nsIRDFNode> element( do_QueryInterface(isupports) ); |
|
562 NS_ASSERTION(element != nullptr, "something funky in the enumerator"); |
|
563 if (! element) |
|
564 { |
|
565 err = true; |
|
566 rv = NS_ERROR_UNEXPECTED; |
|
567 break; |
|
568 } |
|
569 |
|
570 rv = mDataSource->Unassert(mContainer, oldOrdinal, element); |
|
571 if (NS_FAILED(rv)) |
|
572 { |
|
573 err = true; |
|
574 break; |
|
575 } |
|
576 |
|
577 rv = mDataSource->Assert(mContainer, newOrdinal, element, true); |
|
578 if (NS_FAILED(rv)) |
|
579 { |
|
580 err = true; |
|
581 break; |
|
582 } |
|
583 } |
|
584 |
|
585 i -= aIncrement; |
|
586 } |
|
587 |
|
588 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 rv = SetNextValue(count + aIncrement + 1); |
|
595 if (NS_FAILED(rv)) |
|
596 { |
|
597 err = true; |
|
598 } |
|
599 } |
|
600 |
|
601 // Note: MUST enable notifications before exiting this method |
|
602 if (propagatable) { |
|
603 propagatable->SetPropagateChanges(true); |
|
604 } |
|
605 |
|
606 if (err) return(rv); |
|
607 |
|
608 return NS_OK; |
|
609 } |
|
610 |
|
611 |
|
612 |
|
613 nsresult |
|
614 RDFContainerImpl::SetNextValue(int32_t aIndex) |
|
615 { |
|
616 if (!mDataSource || !mContainer) |
|
617 return NS_ERROR_NOT_INITIALIZED; |
|
618 |
|
619 nsresult rv; |
|
620 |
|
621 // Remove the current value of nextVal, if there is one. |
|
622 nsCOMPtr<nsIRDFNode> nextValNode; |
|
623 if (NS_SUCCEEDED(rv = mDataSource->GetTarget(mContainer, |
|
624 kRDF_nextVal, |
|
625 true, |
|
626 getter_AddRefs(nextValNode)))) { |
|
627 if (NS_FAILED(rv = mDataSource->Unassert(mContainer, kRDF_nextVal, nextValNode))) { |
|
628 NS_ERROR("unable to update nextVal"); |
|
629 return rv; |
|
630 } |
|
631 } |
|
632 |
|
633 nsAutoString s; |
|
634 s.AppendInt(aIndex, 10); |
|
635 |
|
636 nsCOMPtr<nsIRDFLiteral> nextVal; |
|
637 if (NS_FAILED(rv = gRDFService->GetLiteral(s.get(), getter_AddRefs(nextVal)))) { |
|
638 NS_ERROR("unable to get nextVal literal"); |
|
639 return rv; |
|
640 } |
|
641 |
|
642 rv = mDataSource->Assert(mContainer, kRDF_nextVal, nextVal, true); |
|
643 if (rv != NS_RDF_ASSERTION_ACCEPTED) { |
|
644 NS_ERROR("unable to update nextVal"); |
|
645 return NS_ERROR_FAILURE; |
|
646 } |
|
647 |
|
648 return NS_OK; |
|
649 } |
|
650 |
|
651 |
|
652 nsresult |
|
653 RDFContainerImpl::GetNextValue(nsIRDFResource** aResult) |
|
654 { |
|
655 if (!mDataSource || !mContainer) |
|
656 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 nsCOMPtr<nsIRDFNode> nextValNode; |
|
663 rv = mDataSource->GetTarget(mContainer, kRDF_nextVal, true, getter_AddRefs(nextValNode)); |
|
664 if (NS_FAILED(rv)) return rv; |
|
665 |
|
666 if (rv == NS_RDF_NO_VALUE) |
|
667 return NS_ERROR_UNEXPECTED; |
|
668 |
|
669 nsCOMPtr<nsIRDFLiteral> nextValLiteral; |
|
670 rv = nextValNode->QueryInterface(NS_GET_IID(nsIRDFLiteral), getter_AddRefs(nextValLiteral)); |
|
671 if (NS_FAILED(rv)) return rv; |
|
672 |
|
673 const char16_t* s; |
|
674 rv = nextValLiteral->GetValueConst(&s); |
|
675 if (NS_FAILED(rv)) return rv; |
|
676 |
|
677 int32_t nextVal = 0; |
|
678 { |
|
679 for (const char16_t* p = s; *p != 0; ++p) { |
|
680 NS_ASSERTION(*p >= '0' && *p <= '9', "not a digit"); |
|
681 if (*p < '0' || *p > '9') |
|
682 break; |
|
683 |
|
684 nextVal *= 10; |
|
685 nextVal += *p - '0'; |
|
686 } |
|
687 } |
|
688 |
|
689 static const char kRDFNameSpaceURI[] = RDF_NAMESPACE_URI; |
|
690 char buf[sizeof(kRDFNameSpaceURI) + 16]; |
|
691 nsFixedCString nextValStr(buf, sizeof(buf), 0); |
|
692 nextValStr = kRDFNameSpaceURI; |
|
693 nextValStr.Append("_"); |
|
694 nextValStr.AppendInt(nextVal, 10); |
|
695 |
|
696 rv = gRDFService->GetResource(nextValStr, aResult); |
|
697 if (NS_FAILED(rv)) return rv; |
|
698 |
|
699 // Now increment the RDF:nextVal property. |
|
700 rv = mDataSource->Unassert(mContainer, kRDF_nextVal, nextValLiteral); |
|
701 if (NS_FAILED(rv)) return rv; |
|
702 |
|
703 ++nextVal; |
|
704 nextValStr.Truncate(); |
|
705 nextValStr.AppendInt(nextVal, 10); |
|
706 |
|
707 rv = gRDFService->GetLiteral(NS_ConvertASCIItoUTF16(nextValStr).get(), getter_AddRefs(nextValLiteral)); |
|
708 if (NS_FAILED(rv)) return rv; |
|
709 |
|
710 rv = mDataSource->Assert(mContainer, kRDF_nextVal, nextValLiteral, true); |
|
711 if (NS_FAILED(rv)) return rv; |
|
712 |
|
713 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 nsCOMPtr<nsIRDFInMemoryDataSource> inMem = do_QueryInterface(mDataSource); |
|
718 if (inMem) |
|
719 { |
|
720 // ignore error; failure just means slower access |
|
721 (void)inMem->EnsureFastContainment(mContainer); |
|
722 } |
|
723 } |
|
724 |
|
725 return NS_OK; |
|
726 } |