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 utils.
9 :
10 : */
11 :
12 :
13 : #include "nsCOMPtr.h"
14 : #include "nsIServiceManager.h"
15 : #include "nsIRDFContainer.h"
16 : #include "nsIRDFContainerUtils.h"
17 : #include "nsIRDFService.h"
18 : #include "nsRDFCID.h"
19 : #include "nsString.h"
20 : #include "nsXPIDLString.h"
21 : #include "plstr.h"
22 : #include "rdf.h"
23 : #include "rdfutil.h"
24 :
25 : class RDFContainerUtilsImpl : public nsIRDFContainerUtils
26 : {
27 : public:
28 : // nsISupports interface
29 : NS_DECL_ISUPPORTS
30 :
31 : // nsIRDFContainerUtils interface
32 : NS_DECL_NSIRDFCONTAINERUTILS
33 :
34 : private:
35 : friend nsresult NS_NewRDFContainerUtils(nsIRDFContainerUtils** aResult);
36 :
37 : RDFContainerUtilsImpl();
38 : virtual ~RDFContainerUtilsImpl();
39 :
40 : nsresult MakeContainer(nsIRDFDataSource* aDataSource,
41 : nsIRDFResource* aResource,
42 : nsIRDFResource* aType,
43 : nsIRDFContainer** aResult);
44 :
45 : bool IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType);
46 :
47 : // pseudo constants
48 : static int32_t gRefCnt;
49 : static nsIRDFService* gRDFService;
50 : static nsIRDFResource* kRDF_instanceOf;
51 : static nsIRDFResource* kRDF_nextVal;
52 : static nsIRDFResource* kRDF_Bag;
53 : static nsIRDFResource* kRDF_Seq;
54 : static nsIRDFResource* kRDF_Alt;
55 : static nsIRDFLiteral* kOne;
56 : static const char kRDFNameSpaceURI[];
57 : };
58 :
59 : int32_t RDFContainerUtilsImpl::gRefCnt = 0;
60 : nsIRDFService* RDFContainerUtilsImpl::gRDFService;
61 : nsIRDFResource* RDFContainerUtilsImpl::kRDF_instanceOf;
62 : nsIRDFResource* RDFContainerUtilsImpl::kRDF_nextVal;
63 : nsIRDFResource* RDFContainerUtilsImpl::kRDF_Bag;
64 : nsIRDFResource* RDFContainerUtilsImpl::kRDF_Seq;
65 : nsIRDFResource* RDFContainerUtilsImpl::kRDF_Alt;
66 : nsIRDFLiteral* RDFContainerUtilsImpl::kOne;
67 : const char RDFContainerUtilsImpl::kRDFNameSpaceURI[] = RDF_NAMESPACE_URI;
68 :
69 : ////////////////////////////////////////////////////////////////////////
70 : // nsISupports interface
71 :
72 33 : NS_IMPL_ISUPPORTS(RDFContainerUtilsImpl, nsIRDFContainerUtils)
73 :
74 : ////////////////////////////////////////////////////////////////////////
75 : // nsIRDFContainerUtils interface
76 :
77 : NS_IMETHODIMP
78 0 : RDFContainerUtilsImpl::IsOrdinalProperty(nsIRDFResource *aProperty, bool *_retval)
79 : {
80 0 : NS_PRECONDITION(aProperty != nullptr, "null ptr");
81 0 : if (! aProperty)
82 0 : return NS_ERROR_NULL_POINTER;
83 :
84 : nsresult rv;
85 :
86 : const char *propertyStr;
87 0 : rv = aProperty->GetValueConst( &propertyStr );
88 0 : if (NS_FAILED(rv)) return rv;
89 :
90 0 : if (PL_strncmp(propertyStr, kRDFNameSpaceURI, sizeof(kRDFNameSpaceURI) - 1) != 0) {
91 0 : *_retval = false;
92 0 : return NS_OK;
93 : }
94 :
95 0 : const char* s = propertyStr;
96 0 : s += sizeof(kRDFNameSpaceURI) - 1;
97 0 : if (*s != '_') {
98 0 : *_retval = false;
99 0 : return NS_OK;
100 : }
101 :
102 0 : ++s;
103 0 : while (*s) {
104 0 : if (*s < '0' || *s > '9') {
105 0 : *_retval = false;
106 0 : return NS_OK;
107 : }
108 :
109 0 : ++s;
110 : }
111 :
112 0 : *_retval = true;
113 0 : return NS_OK;
114 : }
115 :
116 :
117 : NS_IMETHODIMP
118 0 : RDFContainerUtilsImpl::IndexToOrdinalResource(int32_t aIndex, nsIRDFResource **aOrdinal)
119 : {
120 0 : NS_PRECONDITION(aIndex > 0, "illegal value");
121 0 : if (aIndex <= 0)
122 0 : return NS_ERROR_ILLEGAL_VALUE;
123 :
124 0 : nsAutoCString uri(kRDFNameSpaceURI);
125 0 : uri.Append('_');
126 0 : uri.AppendInt(aIndex);
127 :
128 0 : nsresult rv = gRDFService->GetResource(uri, aOrdinal);
129 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get ordinal resource");
130 0 : if (NS_FAILED(rv)) return rv;
131 :
132 0 : return NS_OK;
133 : }
134 :
135 :
136 : NS_IMETHODIMP
137 0 : RDFContainerUtilsImpl::OrdinalResourceToIndex(nsIRDFResource *aOrdinal, int32_t *aIndex)
138 : {
139 0 : NS_PRECONDITION(aOrdinal != nullptr, "null ptr");
140 0 : if (! aOrdinal)
141 0 : return NS_ERROR_NULL_POINTER;
142 :
143 : const char *ordinalStr;
144 0 : if (NS_FAILED(aOrdinal->GetValueConst( &ordinalStr )))
145 0 : return NS_ERROR_FAILURE;
146 :
147 0 : const char* s = ordinalStr;
148 0 : if (PL_strncmp(s, kRDFNameSpaceURI, sizeof(kRDFNameSpaceURI) - 1) != 0) {
149 0 : NS_ERROR("not an ordinal");
150 0 : return NS_ERROR_UNEXPECTED;
151 : }
152 :
153 0 : s += sizeof(kRDFNameSpaceURI) - 1;
154 0 : if (*s != '_') {
155 0 : NS_ERROR("not an ordinal");
156 0 : return NS_ERROR_UNEXPECTED;
157 : }
158 :
159 0 : int32_t idx = 0;
160 :
161 0 : ++s;
162 0 : while (*s) {
163 0 : if (*s < '0' || *s > '9') {
164 0 : NS_ERROR("not an ordinal");
165 0 : return NS_ERROR_UNEXPECTED;
166 : }
167 :
168 0 : idx *= 10;
169 0 : idx += (*s - '0');
170 :
171 0 : ++s;
172 : }
173 :
174 0 : *aIndex = idx;
175 0 : return NS_OK;
176 : }
177 :
178 : NS_IMETHODIMP
179 6 : RDFContainerUtilsImpl::IsContainer(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, bool *_retval)
180 : {
181 6 : NS_PRECONDITION(aDataSource != nullptr, "null ptr");
182 6 : if (! aDataSource)
183 0 : return NS_ERROR_NULL_POINTER;
184 :
185 6 : NS_PRECONDITION(aResource != nullptr, "null ptr");
186 6 : if (! aResource)
187 0 : return NS_ERROR_NULL_POINTER;
188 :
189 6 : NS_PRECONDITION(_retval != nullptr, "null ptr");
190 6 : if (! _retval)
191 0 : return NS_ERROR_NULL_POINTER;
192 :
193 15 : if (IsA(aDataSource, aResource, kRDF_Seq) ||
194 9 : IsA(aDataSource, aResource, kRDF_Bag) ||
195 3 : IsA(aDataSource, aResource, kRDF_Alt)) {
196 3 : *_retval = true;
197 : }
198 : else {
199 3 : *_retval = false;
200 : }
201 6 : return NS_OK;
202 : }
203 :
204 :
205 : NS_IMETHODIMP
206 0 : RDFContainerUtilsImpl::IsEmpty(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, bool* _retval)
207 : {
208 0 : if (! aDataSource)
209 0 : return NS_ERROR_NULL_POINTER;
210 :
211 : nsresult rv;
212 :
213 : // By default, say that we're an empty container. Even if we're not
214 : // really even a container.
215 0 : *_retval = true;
216 :
217 0 : nsCOMPtr<nsIRDFNode> nextValNode;
218 0 : rv = aDataSource->GetTarget(aResource, kRDF_nextVal, true, getter_AddRefs(nextValNode));
219 0 : if (NS_FAILED(rv)) return rv;
220 :
221 0 : if (rv == NS_RDF_NO_VALUE)
222 0 : return NS_OK;
223 :
224 0 : nsCOMPtr<nsIRDFLiteral> nextValLiteral;
225 0 : rv = nextValNode->QueryInterface(NS_GET_IID(nsIRDFLiteral), getter_AddRefs(nextValLiteral));
226 0 : if (NS_FAILED(rv)) return rv;
227 :
228 0 : if (nextValLiteral.get() != kOne)
229 0 : *_retval = false;
230 :
231 0 : return NS_OK;
232 : }
233 :
234 :
235 : NS_IMETHODIMP
236 0 : RDFContainerUtilsImpl::IsBag(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, bool *_retval)
237 : {
238 0 : NS_PRECONDITION(aDataSource != nullptr, "null ptr");
239 0 : if (! aDataSource)
240 0 : return NS_ERROR_NULL_POINTER;
241 :
242 0 : NS_PRECONDITION(aResource != nullptr, "null ptr");
243 0 : if (! aResource)
244 0 : return NS_ERROR_NULL_POINTER;
245 :
246 0 : NS_PRECONDITION(_retval != nullptr, "null ptr");
247 0 : if (! _retval)
248 0 : return NS_ERROR_NULL_POINTER;
249 :
250 0 : *_retval = IsA(aDataSource, aResource, kRDF_Bag);
251 0 : return NS_OK;
252 : }
253 :
254 :
255 : NS_IMETHODIMP
256 0 : RDFContainerUtilsImpl::IsSeq(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, bool *_retval)
257 : {
258 0 : NS_PRECONDITION(aDataSource != nullptr, "null ptr");
259 0 : if (! aDataSource)
260 0 : return NS_ERROR_NULL_POINTER;
261 :
262 0 : NS_PRECONDITION(aResource != nullptr, "null ptr");
263 0 : if (! aResource)
264 0 : return NS_ERROR_NULL_POINTER;
265 :
266 0 : NS_PRECONDITION(_retval != nullptr, "null ptr");
267 0 : if (! _retval)
268 0 : return NS_ERROR_NULL_POINTER;
269 :
270 0 : *_retval = IsA(aDataSource, aResource, kRDF_Seq);
271 0 : return NS_OK;
272 : }
273 :
274 :
275 : NS_IMETHODIMP
276 0 : RDFContainerUtilsImpl::IsAlt(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, bool *_retval)
277 : {
278 0 : NS_PRECONDITION(aDataSource != nullptr, "null ptr");
279 0 : if (! aDataSource)
280 0 : return NS_ERROR_NULL_POINTER;
281 :
282 0 : NS_PRECONDITION(aResource != nullptr, "null ptr");
283 0 : if (! aResource)
284 0 : return NS_ERROR_NULL_POINTER;
285 :
286 0 : NS_PRECONDITION(_retval != nullptr, "null ptr");
287 0 : if (! _retval)
288 0 : return NS_ERROR_NULL_POINTER;
289 :
290 0 : *_retval = IsA(aDataSource, aResource, kRDF_Alt);
291 0 : return NS_OK;
292 : }
293 :
294 :
295 : NS_IMETHODIMP
296 0 : RDFContainerUtilsImpl::MakeBag(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, nsIRDFContainer **_retval)
297 : {
298 0 : return MakeContainer(aDataSource, aResource, kRDF_Bag, _retval);
299 : }
300 :
301 :
302 : NS_IMETHODIMP
303 3 : RDFContainerUtilsImpl::MakeSeq(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, nsIRDFContainer **_retval)
304 : {
305 3 : return MakeContainer(aDataSource, aResource, kRDF_Seq, _retval);
306 : }
307 :
308 :
309 : NS_IMETHODIMP
310 0 : RDFContainerUtilsImpl::MakeAlt(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, nsIRDFContainer **_retval)
311 : {
312 0 : return MakeContainer(aDataSource, aResource, kRDF_Alt, _retval);
313 : }
314 :
315 :
316 :
317 : ////////////////////////////////////////////////////////////////////////
318 :
319 :
320 3 : RDFContainerUtilsImpl::RDFContainerUtilsImpl()
321 : {
322 3 : if (gRefCnt++ == 0) {
323 : nsresult rv;
324 :
325 3 : NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
326 3 : rv = CallGetService(kRDFServiceCID, &gRDFService);
327 :
328 3 : NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service");
329 3 : if (NS_SUCCEEDED(rv)) {
330 9 : gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "instanceOf"),
331 9 : &kRDF_instanceOf);
332 9 : gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "nextVal"),
333 9 : &kRDF_nextVal);
334 9 : gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Bag"),
335 9 : &kRDF_Bag);
336 9 : gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Seq"),
337 9 : &kRDF_Seq);
338 9 : gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Alt"),
339 9 : &kRDF_Alt);
340 3 : gRDFService->GetLiteral(u"1", &kOne);
341 : }
342 : }
343 3 : }
344 :
345 :
346 0 : RDFContainerUtilsImpl::~RDFContainerUtilsImpl()
347 : {
348 : #ifdef DEBUG_REFS
349 : --gInstanceCount;
350 : fprintf(stdout, "%d - RDF: RDFContainerUtilsImpl\n", gInstanceCount);
351 : #endif
352 :
353 0 : if (--gRefCnt == 0) {
354 0 : NS_IF_RELEASE(gRDFService);
355 0 : NS_IF_RELEASE(kRDF_instanceOf);
356 0 : NS_IF_RELEASE(kRDF_nextVal);
357 0 : NS_IF_RELEASE(kRDF_Bag);
358 0 : NS_IF_RELEASE(kRDF_Seq);
359 0 : NS_IF_RELEASE(kRDF_Alt);
360 0 : NS_IF_RELEASE(kOne);
361 : }
362 0 : }
363 :
364 :
365 :
366 : nsresult
367 3 : NS_NewRDFContainerUtils(nsIRDFContainerUtils** aResult)
368 : {
369 3 : NS_PRECONDITION(aResult != nullptr, "null ptr");
370 3 : if (! aResult)
371 0 : return NS_ERROR_NULL_POINTER;
372 :
373 : RDFContainerUtilsImpl* result =
374 3 : new RDFContainerUtilsImpl();
375 :
376 3 : if (! result)
377 0 : return NS_ERROR_OUT_OF_MEMORY;
378 :
379 3 : NS_ADDREF(result);
380 3 : *aResult = result;
381 3 : return NS_OK;
382 : }
383 :
384 :
385 : nsresult
386 3 : RDFContainerUtilsImpl::MakeContainer(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType, nsIRDFContainer** aResult)
387 : {
388 3 : NS_PRECONDITION(aDataSource != nullptr, "null ptr");
389 3 : if (! aDataSource) return NS_ERROR_NULL_POINTER;
390 :
391 3 : NS_PRECONDITION(aResource != nullptr, "null ptr");
392 3 : if (! aResource) return NS_ERROR_NULL_POINTER;
393 :
394 3 : NS_PRECONDITION(aType != nullptr, "null ptr");
395 3 : if (! aType) return NS_ERROR_NULL_POINTER;
396 :
397 3 : if (aResult) *aResult = nullptr;
398 :
399 : nsresult rv;
400 :
401 : // Check to see if somebody has already turned it into a container; if so
402 : // don't try to do it again.
403 : bool isContainer;
404 3 : rv = IsContainer(aDataSource, aResource, &isContainer);
405 3 : if (NS_FAILED(rv)) return rv;
406 :
407 3 : if (!isContainer)
408 : {
409 3 : rv = aDataSource->Assert(aResource, kRDF_instanceOf, aType, true);
410 3 : if (NS_FAILED(rv)) return rv;
411 :
412 3 : rv = aDataSource->Assert(aResource, kRDF_nextVal, kOne, true);
413 3 : if (NS_FAILED(rv)) return rv;
414 : }
415 :
416 3 : if (aResult) {
417 3 : rv = NS_NewRDFContainer(aResult);
418 3 : if (NS_FAILED(rv)) return rv;
419 :
420 3 : rv = (*aResult)->Init(aDataSource, aResource);
421 3 : if (NS_FAILED(rv)) return rv;
422 : }
423 :
424 3 : return NS_OK;
425 : }
426 :
427 : bool
428 12 : RDFContainerUtilsImpl::IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType)
429 : {
430 12 : if (!aDataSource || !aResource || !aType) {
431 0 : NS_WARNING("Unexpected null argument");
432 0 : return false;
433 : }
434 :
435 : nsresult rv;
436 :
437 : bool result;
438 12 : rv = aDataSource->HasAssertion(aResource, kRDF_instanceOf, aType, true, &result);
439 12 : if (NS_FAILED(rv))
440 0 : return false;
441 :
442 12 : return result;
443 : }
444 :
445 : NS_IMETHODIMP
446 0 : RDFContainerUtilsImpl::IndexOf(nsIRDFDataSource* aDataSource, nsIRDFResource* aContainer, nsIRDFNode* aElement, int32_t* aIndex)
447 : {
448 0 : if (!aDataSource || !aContainer)
449 0 : return NS_ERROR_NULL_POINTER;
450 :
451 : // Assume we can't find it.
452 0 : *aIndex = -1;
453 :
454 : // If the resource is null, bail quietly
455 0 : if (! aElement)
456 0 : return NS_OK;
457 :
458 : // We'll assume that fan-out is much higher than fan-in, so grovel
459 : // through the inbound arcs, look for an ordinal resource, and
460 : // decode it.
461 0 : nsCOMPtr<nsISimpleEnumerator> arcsIn;
462 0 : aDataSource->ArcLabelsIn(aElement, getter_AddRefs(arcsIn));
463 0 : if (! arcsIn)
464 0 : return NS_OK;
465 :
466 : while (1) {
467 0 : bool hasMoreArcs = false;
468 0 : arcsIn->HasMoreElements(&hasMoreArcs);
469 0 : if (! hasMoreArcs)
470 0 : break;
471 :
472 0 : nsCOMPtr<nsISupports> isupports;
473 0 : arcsIn->GetNext(getter_AddRefs(isupports));
474 0 : if (! isupports)
475 0 : break;
476 :
477 : nsCOMPtr<nsIRDFResource> property =
478 0 : do_QueryInterface(isupports);
479 :
480 0 : if (! property)
481 0 : continue;
482 :
483 : bool isOrdinal;
484 0 : IsOrdinalProperty(property, &isOrdinal);
485 0 : if (! isOrdinal)
486 0 : continue;
487 :
488 0 : nsCOMPtr<nsISimpleEnumerator> sources;
489 0 : aDataSource->GetSources(property, aElement, true, getter_AddRefs(sources));
490 0 : if (! sources)
491 0 : continue;
492 :
493 : while (1) {
494 0 : bool hasMoreSources = false;
495 0 : sources->HasMoreElements(&hasMoreSources);
496 0 : if (! hasMoreSources)
497 0 : break;
498 :
499 0 : nsCOMPtr<nsISupports> isupports2;
500 0 : sources->GetNext(getter_AddRefs(isupports2));
501 0 : if (! isupports2)
502 0 : break;
503 :
504 : nsCOMPtr<nsIRDFResource> source =
505 0 : do_QueryInterface(isupports2);
506 :
507 0 : if (source == aContainer)
508 : // Found it.
509 0 : return OrdinalResourceToIndex(property, aIndex);
510 0 : }
511 0 : }
512 :
513 0 : return NS_OK;
514 : }
|