1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Pierre Phaneuf <pp@ludusdesign.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : /*
40 :
41 : Implementation for the RDF container utils.
42 :
43 : */
44 :
45 :
46 : #include "nsCOMPtr.h"
47 : #include "nsIServiceManager.h"
48 : #include "nsIRDFContainer.h"
49 : #include "nsIRDFContainerUtils.h"
50 : #include "nsIRDFService.h"
51 : #include "nsRDFCID.h"
52 : #include "nsString.h"
53 : #include "nsXPIDLString.h"
54 : #include "plstr.h"
55 : #include "prprf.h"
56 : #include "rdf.h"
57 : #include "rdfutil.h"
58 :
59 : static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
60 : static const char kRDFNameSpaceURI[] = RDF_NAMESPACE_URI;
61 :
62 : class RDFContainerUtilsImpl : public nsIRDFContainerUtils
63 : {
64 : public:
65 : // nsISupports interface
66 : NS_DECL_ISUPPORTS
67 :
68 : // nsIRDFContainerUtils interface
69 : NS_DECL_NSIRDFCONTAINERUTILS
70 :
71 : private:
72 : friend nsresult NS_NewRDFContainerUtils(nsIRDFContainerUtils** aResult);
73 :
74 : RDFContainerUtilsImpl();
75 : virtual ~RDFContainerUtilsImpl();
76 :
77 : nsresult MakeContainer(nsIRDFDataSource* aDataSource,
78 : nsIRDFResource* aResource,
79 : nsIRDFResource* aType,
80 : nsIRDFContainer** aResult);
81 :
82 : bool IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType);
83 :
84 : // pseudo constants
85 : static PRInt32 gRefCnt;
86 : static nsIRDFService* gRDFService;
87 : static nsIRDFResource* kRDF_instanceOf;
88 : static nsIRDFResource* kRDF_nextVal;
89 : static nsIRDFResource* kRDF_Bag;
90 : static nsIRDFResource* kRDF_Seq;
91 : static nsIRDFResource* kRDF_Alt;
92 : static nsIRDFLiteral* kOne;
93 : };
94 :
95 :
96 : PRInt32 RDFContainerUtilsImpl::gRefCnt = 0;
97 : nsIRDFService* RDFContainerUtilsImpl::gRDFService;
98 : nsIRDFResource* RDFContainerUtilsImpl::kRDF_instanceOf;
99 : nsIRDFResource* RDFContainerUtilsImpl::kRDF_nextVal;
100 : nsIRDFResource* RDFContainerUtilsImpl::kRDF_Bag;
101 : nsIRDFResource* RDFContainerUtilsImpl::kRDF_Seq;
102 : nsIRDFResource* RDFContainerUtilsImpl::kRDF_Alt;
103 : nsIRDFLiteral* RDFContainerUtilsImpl::kOne;
104 :
105 : ////////////////////////////////////////////////////////////////////////
106 : // nsISupports interface
107 :
108 20274 : NS_IMPL_THREADSAFE_ISUPPORTS1(RDFContainerUtilsImpl, nsIRDFContainerUtils)
109 :
110 : ////////////////////////////////////////////////////////////////////////
111 : // nsIRDFContainerUtils interface
112 :
113 : NS_IMETHODIMP
114 1419 : RDFContainerUtilsImpl::IsOrdinalProperty(nsIRDFResource *aProperty, bool *_retval)
115 : {
116 1419 : NS_PRECONDITION(aProperty != nsnull, "null ptr");
117 1419 : if (! aProperty)
118 0 : return NS_ERROR_NULL_POINTER;
119 :
120 : nsresult rv;
121 :
122 : const char *propertyStr;
123 1419 : rv = aProperty->GetValueConst( &propertyStr );
124 1419 : if (NS_FAILED(rv)) return rv;
125 :
126 1419 : if (PL_strncmp(propertyStr, kRDFNameSpaceURI, sizeof(kRDFNameSpaceURI) - 1) != 0) {
127 1228 : *_retval = false;
128 1228 : return NS_OK;
129 : }
130 :
131 191 : const char* s = propertyStr;
132 191 : s += sizeof(kRDFNameSpaceURI) - 1;
133 191 : if (*s != '_') {
134 0 : *_retval = false;
135 0 : return NS_OK;
136 : }
137 :
138 191 : ++s;
139 573 : while (*s) {
140 191 : if (*s < '0' || *s > '9') {
141 0 : *_retval = false;
142 0 : return NS_OK;
143 : }
144 :
145 191 : ++s;
146 : }
147 :
148 191 : *_retval = true;
149 191 : return NS_OK;
150 : }
151 :
152 :
153 : NS_IMETHODIMP
154 459 : RDFContainerUtilsImpl::IndexToOrdinalResource(PRInt32 aIndex, nsIRDFResource **aOrdinal)
155 : {
156 459 : NS_PRECONDITION(aIndex > 0, "illegal value");
157 459 : if (aIndex <= 0)
158 0 : return NS_ERROR_ILLEGAL_VALUE;
159 :
160 918 : nsCAutoString uri(kRDFNameSpaceURI);
161 459 : uri.Append('_');
162 459 : uri.AppendInt(aIndex);
163 :
164 459 : nsresult rv = gRDFService->GetResource(uri, aOrdinal);
165 459 : NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get ordinal resource");
166 459 : if (NS_FAILED(rv)) return rv;
167 :
168 459 : return NS_OK;
169 : }
170 :
171 :
172 : NS_IMETHODIMP
173 5 : RDFContainerUtilsImpl::OrdinalResourceToIndex(nsIRDFResource *aOrdinal, PRInt32 *aIndex)
174 : {
175 5 : NS_PRECONDITION(aOrdinal != nsnull, "null ptr");
176 5 : if (! aOrdinal)
177 0 : return NS_ERROR_NULL_POINTER;
178 :
179 : const char *ordinalStr;
180 5 : if (NS_FAILED(aOrdinal->GetValueConst( &ordinalStr )))
181 0 : return NS_ERROR_FAILURE;
182 :
183 5 : const char* s = ordinalStr;
184 5 : if (PL_strncmp(s, kRDFNameSpaceURI, sizeof(kRDFNameSpaceURI) - 1) != 0) {
185 0 : NS_ERROR("not an ordinal");
186 0 : return NS_ERROR_UNEXPECTED;
187 : }
188 :
189 5 : s += sizeof(kRDFNameSpaceURI) - 1;
190 5 : if (*s != '_') {
191 0 : NS_ERROR("not an ordinal");
192 0 : return NS_ERROR_UNEXPECTED;
193 : }
194 :
195 5 : PRInt32 idx = 0;
196 :
197 5 : ++s;
198 15 : while (*s) {
199 5 : if (*s < '0' || *s > '9') {
200 0 : NS_ERROR("not an ordinal");
201 0 : return NS_ERROR_UNEXPECTED;
202 : }
203 :
204 5 : idx *= 10;
205 5 : idx += (*s - '0');
206 :
207 5 : ++s;
208 : }
209 :
210 5 : *aIndex = idx;
211 5 : return NS_OK;
212 : }
213 :
214 : NS_IMETHODIMP
215 4024 : RDFContainerUtilsImpl::IsContainer(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, bool *_retval)
216 : {
217 4024 : NS_PRECONDITION(aDataSource != nsnull, "null ptr");
218 4024 : if (! aDataSource)
219 0 : return NS_ERROR_NULL_POINTER;
220 :
221 4024 : NS_PRECONDITION(aResource != nsnull, "null ptr");
222 4024 : if (! aResource)
223 0 : return NS_ERROR_NULL_POINTER;
224 :
225 4024 : NS_PRECONDITION(_retval != nsnull, "null ptr");
226 4024 : if (! _retval)
227 0 : return NS_ERROR_NULL_POINTER;
228 :
229 6948 : if (IsA(aDataSource, aResource, kRDF_Seq) ||
230 1462 : IsA(aDataSource, aResource, kRDF_Bag) ||
231 1462 : IsA(aDataSource, aResource, kRDF_Alt)) {
232 2562 : *_retval = true;
233 : }
234 : else {
235 1462 : *_retval = false;
236 : }
237 4024 : return NS_OK;
238 : }
239 :
240 :
241 : NS_IMETHODIMP
242 0 : RDFContainerUtilsImpl::IsEmpty(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, bool* _retval)
243 : {
244 0 : if (! aDataSource)
245 0 : return NS_ERROR_NULL_POINTER;
246 :
247 : nsresult rv;
248 :
249 : // By default, say that we're an empty container. Even if we're not
250 : // really even a container.
251 0 : *_retval = true;
252 :
253 0 : nsCOMPtr<nsIRDFNode> nextValNode;
254 0 : rv = aDataSource->GetTarget(aResource, kRDF_nextVal, true, getter_AddRefs(nextValNode));
255 0 : if (NS_FAILED(rv)) return rv;
256 :
257 0 : if (rv == NS_RDF_NO_VALUE)
258 0 : return NS_OK;
259 :
260 0 : nsCOMPtr<nsIRDFLiteral> nextValLiteral;
261 0 : rv = nextValNode->QueryInterface(NS_GET_IID(nsIRDFLiteral), getter_AddRefs(nextValLiteral));
262 0 : if (NS_FAILED(rv)) return rv;
263 :
264 0 : if (nextValLiteral.get() != kOne)
265 0 : *_retval = false;
266 :
267 0 : return NS_OK;
268 : }
269 :
270 :
271 : NS_IMETHODIMP
272 42 : RDFContainerUtilsImpl::IsBag(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, bool *_retval)
273 : {
274 42 : NS_PRECONDITION(aDataSource != nsnull, "null ptr");
275 42 : if (! aDataSource)
276 0 : return NS_ERROR_NULL_POINTER;
277 :
278 42 : NS_PRECONDITION(aResource != nsnull, "null ptr");
279 42 : if (! aResource)
280 0 : return NS_ERROR_NULL_POINTER;
281 :
282 42 : NS_PRECONDITION(_retval != nsnull, "null ptr");
283 42 : if (! _retval)
284 0 : return NS_ERROR_NULL_POINTER;
285 :
286 42 : *_retval = IsA(aDataSource, aResource, kRDF_Bag);
287 42 : return NS_OK;
288 : }
289 :
290 :
291 : NS_IMETHODIMP
292 1512 : RDFContainerUtilsImpl::IsSeq(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, bool *_retval)
293 : {
294 1512 : NS_PRECONDITION(aDataSource != nsnull, "null ptr");
295 1512 : if (! aDataSource)
296 0 : return NS_ERROR_NULL_POINTER;
297 :
298 1512 : NS_PRECONDITION(aResource != nsnull, "null ptr");
299 1512 : if (! aResource)
300 0 : return NS_ERROR_NULL_POINTER;
301 :
302 1512 : NS_PRECONDITION(_retval != nsnull, "null ptr");
303 1512 : if (! _retval)
304 0 : return NS_ERROR_NULL_POINTER;
305 :
306 1512 : *_retval = IsA(aDataSource, aResource, kRDF_Seq);
307 1512 : return NS_OK;
308 : }
309 :
310 :
311 : NS_IMETHODIMP
312 42 : RDFContainerUtilsImpl::IsAlt(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, bool *_retval)
313 : {
314 42 : NS_PRECONDITION(aDataSource != nsnull, "null ptr");
315 42 : if (! aDataSource)
316 0 : return NS_ERROR_NULL_POINTER;
317 :
318 42 : NS_PRECONDITION(aResource != nsnull, "null ptr");
319 42 : if (! aResource)
320 0 : return NS_ERROR_NULL_POINTER;
321 :
322 42 : NS_PRECONDITION(_retval != nsnull, "null ptr");
323 42 : if (! _retval)
324 0 : return NS_ERROR_NULL_POINTER;
325 :
326 42 : *_retval = IsA(aDataSource, aResource, kRDF_Alt);
327 42 : return NS_OK;
328 : }
329 :
330 :
331 : NS_IMETHODIMP
332 0 : RDFContainerUtilsImpl::MakeBag(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, nsIRDFContainer **_retval)
333 : {
334 0 : return MakeContainer(aDataSource, aResource, kRDF_Bag, _retval);
335 : }
336 :
337 :
338 : NS_IMETHODIMP
339 1473 : RDFContainerUtilsImpl::MakeSeq(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, nsIRDFContainer **_retval)
340 : {
341 1473 : return MakeContainer(aDataSource, aResource, kRDF_Seq, _retval);
342 : }
343 :
344 :
345 : NS_IMETHODIMP
346 0 : RDFContainerUtilsImpl::MakeAlt(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, nsIRDFContainer **_retval)
347 : {
348 0 : return MakeContainer(aDataSource, aResource, kRDF_Alt, _retval);
349 : }
350 :
351 :
352 :
353 : ////////////////////////////////////////////////////////////////////////
354 :
355 :
356 172 : RDFContainerUtilsImpl::RDFContainerUtilsImpl()
357 : {
358 172 : if (gRefCnt++ == 0) {
359 : nsresult rv;
360 :
361 172 : rv = CallGetService(kRDFServiceCID, &gRDFService);
362 :
363 172 : NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service");
364 172 : if (NS_SUCCEEDED(rv)) {
365 172 : gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "instanceOf"),
366 172 : &kRDF_instanceOf);
367 172 : gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "nextVal"),
368 172 : &kRDF_nextVal);
369 172 : gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Bag"),
370 172 : &kRDF_Bag);
371 172 : gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Seq"),
372 172 : &kRDF_Seq);
373 172 : gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Alt"),
374 172 : &kRDF_Alt);
375 172 : gRDFService->GetLiteral(NS_LITERAL_STRING("1").get(), &kOne);
376 : }
377 : }
378 172 : }
379 :
380 :
381 344 : RDFContainerUtilsImpl::~RDFContainerUtilsImpl()
382 : {
383 : #ifdef DEBUG_REFS
384 : --gInstanceCount;
385 : fprintf(stdout, "%d - RDF: RDFContainerUtilsImpl\n", gInstanceCount);
386 : #endif
387 :
388 172 : if (--gRefCnt == 0) {
389 172 : NS_IF_RELEASE(gRDFService);
390 172 : NS_IF_RELEASE(kRDF_instanceOf);
391 172 : NS_IF_RELEASE(kRDF_nextVal);
392 172 : NS_IF_RELEASE(kRDF_Bag);
393 172 : NS_IF_RELEASE(kRDF_Seq);
394 172 : NS_IF_RELEASE(kRDF_Alt);
395 172 : NS_IF_RELEASE(kOne);
396 : }
397 688 : }
398 :
399 :
400 :
401 : nsresult
402 172 : NS_NewRDFContainerUtils(nsIRDFContainerUtils** aResult)
403 : {
404 172 : NS_PRECONDITION(aResult != nsnull, "null ptr");
405 172 : if (! aResult)
406 0 : return NS_ERROR_NULL_POINTER;
407 :
408 : RDFContainerUtilsImpl* result =
409 172 : new RDFContainerUtilsImpl();
410 :
411 172 : if (! result)
412 0 : return NS_ERROR_OUT_OF_MEMORY;
413 :
414 172 : NS_ADDREF(result);
415 172 : *aResult = result;
416 172 : return NS_OK;
417 : }
418 :
419 :
420 : nsresult
421 1473 : RDFContainerUtilsImpl::MakeContainer(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType, nsIRDFContainer** aResult)
422 : {
423 1473 : NS_PRECONDITION(aDataSource != nsnull, "null ptr");
424 1473 : if (! aDataSource) return NS_ERROR_NULL_POINTER;
425 :
426 1473 : NS_PRECONDITION(aResource != nsnull, "null ptr");
427 1473 : if (! aResource) return NS_ERROR_NULL_POINTER;
428 :
429 1473 : NS_PRECONDITION(aType != nsnull, "null ptr");
430 1473 : if (! aType) return NS_ERROR_NULL_POINTER;
431 :
432 1473 : if (aResult) *aResult = nsnull;
433 :
434 : nsresult rv;
435 :
436 : // Check to see if somebody has already turned it into a container; if so
437 : // don't try to do it again.
438 : bool isContainer;
439 1473 : rv = IsContainer(aDataSource, aResource, &isContainer);
440 1473 : if (NS_FAILED(rv)) return rv;
441 :
442 1473 : if (!isContainer)
443 : {
444 1459 : rv = aDataSource->Assert(aResource, kRDF_instanceOf, aType, true);
445 1459 : if (NS_FAILED(rv)) return rv;
446 :
447 1459 : rv = aDataSource->Assert(aResource, kRDF_nextVal, kOne, true);
448 1459 : if (NS_FAILED(rv)) return rv;
449 : }
450 :
451 1473 : if (aResult) {
452 17 : rv = NS_NewRDFContainer(aResult);
453 17 : if (NS_FAILED(rv)) return rv;
454 :
455 17 : rv = (*aResult)->Init(aDataSource, aResource);
456 17 : if (NS_FAILED(rv)) return rv;
457 : }
458 :
459 1473 : return NS_OK;
460 : }
461 :
462 : bool
463 8544 : RDFContainerUtilsImpl::IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType)
464 : {
465 8544 : if (!aDataSource || !aResource || !aType) {
466 0 : NS_WARNING("Unexpected null argument");
467 0 : return false;
468 : }
469 :
470 : nsresult rv;
471 :
472 : bool result;
473 8544 : rv = aDataSource->HasAssertion(aResource, kRDF_instanceOf, aType, true, &result);
474 8544 : if (NS_FAILED(rv))
475 0 : return false;
476 :
477 8544 : return result;
478 : }
479 :
480 : NS_IMETHODIMP
481 19 : RDFContainerUtilsImpl::IndexOf(nsIRDFDataSource* aDataSource, nsIRDFResource* aContainer, nsIRDFNode* aElement, PRInt32* aIndex)
482 : {
483 19 : if (!aDataSource || !aContainer)
484 0 : return NS_ERROR_NULL_POINTER;
485 :
486 : // Assume we can't find it.
487 19 : *aIndex = -1;
488 :
489 : // If the resource is null, bail quietly
490 19 : if (! aElement)
491 0 : return NS_OK;
492 :
493 : // We'll assume that fan-out is much higher than fan-in, so grovel
494 : // through the inbound arcs, look for an ordinal resource, and
495 : // decode it.
496 38 : nsCOMPtr<nsISimpleEnumerator> arcsIn;
497 19 : aDataSource->ArcLabelsIn(aElement, getter_AddRefs(arcsIn));
498 19 : if (! arcsIn)
499 0 : return NS_OK;
500 :
501 0 : while (1) {
502 19 : bool hasMoreArcs = false;
503 19 : arcsIn->HasMoreElements(&hasMoreArcs);
504 19 : if (! hasMoreArcs)
505 14 : break;
506 :
507 10 : nsCOMPtr<nsISupports> isupports;
508 5 : arcsIn->GetNext(getter_AddRefs(isupports));
509 5 : if (! isupports)
510 : break;
511 :
512 : nsCOMPtr<nsIRDFResource> property =
513 10 : do_QueryInterface(isupports);
514 :
515 5 : if (! property)
516 0 : continue;
517 :
518 : bool isOrdinal;
519 5 : IsOrdinalProperty(property, &isOrdinal);
520 5 : if (! isOrdinal)
521 0 : continue;
522 :
523 10 : nsCOMPtr<nsISimpleEnumerator> sources;
524 5 : aDataSource->GetSources(property, aElement, true, getter_AddRefs(sources));
525 5 : if (! sources)
526 0 : continue;
527 :
528 0 : while (1) {
529 5 : bool hasMoreSources = false;
530 5 : sources->HasMoreElements(&hasMoreSources);
531 5 : if (! hasMoreSources)
532 0 : break;
533 :
534 10 : nsCOMPtr<nsISupports> isupports2;
535 5 : sources->GetNext(getter_AddRefs(isupports2));
536 5 : if (! isupports2)
537 : break;
538 :
539 : nsCOMPtr<nsIRDFResource> source =
540 10 : do_QueryInterface(isupports2);
541 :
542 5 : if (source == aContainer)
543 : // Found it.
544 5 : return OrdinalResourceToIndex(property, aIndex);
545 : }
546 : }
547 :
548 14 : return NS_OK;
549 : }
|