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
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/
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
15 * The Original Code is Mozilla Communicator client code.
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.
23 * Pierre Phaneuf <pp@ludusdesign.com>
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.
37 * ***** END LICENSE BLOCK ***** */
41 Implementation for the RDF container utils.
47 #include "nsIServiceManager.h"
48 #include "nsIRDFContainer.h"
49 #include "nsIRDFContainerUtils.h"
50 #include "nsIRDFService.h"
53 #include "nsXPIDLString.h"
59 static NS_DEFINE_CID(kRDFServiceCID
, NS_RDFSERVICE_CID
);
60 static const char kRDFNameSpaceURI
[] = RDF_NAMESPACE_URI
;
62 class RDFContainerUtilsImpl
: public nsIRDFContainerUtils
65 // nsISupports interface
68 // nsIRDFContainerUtils interface
69 NS_DECL_NSIRDFCONTAINERUTILS
72 friend nsresult
NS_NewRDFContainerUtils(nsIRDFContainerUtils
** aResult
);
74 RDFContainerUtilsImpl();
75 virtual ~RDFContainerUtilsImpl();
77 nsresult
MakeContainer(nsIRDFDataSource
* aDataSource
,
78 nsIRDFResource
* aResource
,
79 nsIRDFResource
* aType
,
80 nsIRDFContainer
** aResult
);
82 PRBool
IsA(nsIRDFDataSource
* aDataSource
, nsIRDFResource
* aResource
, nsIRDFResource
* aType
);
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
;
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
;
105 ////////////////////////////////////////////////////////////////////////
106 // nsISupports interface
108 NS_IMPL_THREADSAFE_ISUPPORTS1(RDFContainerUtilsImpl
, nsIRDFContainerUtils
)
110 ////////////////////////////////////////////////////////////////////////
111 // nsIRDFContainerUtils interface
114 RDFContainerUtilsImpl::IsOrdinalProperty(nsIRDFResource
*aProperty
, PRBool
*_retval
)
116 NS_PRECONDITION(aProperty
!= nsnull
, "null ptr");
118 return NS_ERROR_NULL_POINTER
;
122 const char *propertyStr
;
123 rv
= aProperty
->GetValueConst( &propertyStr
);
124 if (NS_FAILED(rv
)) return rv
;
126 if (PL_strncmp(propertyStr
, kRDFNameSpaceURI
, sizeof(kRDFNameSpaceURI
) - 1) != 0) {
131 const char* s
= propertyStr
;
132 s
+= sizeof(kRDFNameSpaceURI
) - 1;
140 if (*s
< '0' || *s
> '9') {
154 RDFContainerUtilsImpl::IndexToOrdinalResource(PRInt32 aIndex
, nsIRDFResource
**aOrdinal
)
156 NS_PRECONDITION(aIndex
> 0, "illegal value");
158 return NS_ERROR_ILLEGAL_VALUE
;
160 nsCAutoString
uri(kRDFNameSpaceURI
);
162 uri
.AppendInt(aIndex
);
164 nsresult rv
= gRDFService
->GetResource(uri
, aOrdinal
);
165 NS_ASSERTION(NS_SUCCEEDED(rv
), "unable to get ordinal resource");
166 if (NS_FAILED(rv
)) return rv
;
173 RDFContainerUtilsImpl::OrdinalResourceToIndex(nsIRDFResource
*aOrdinal
, PRInt32
*aIndex
)
175 NS_PRECONDITION(aOrdinal
!= nsnull
, "null ptr");
177 return NS_ERROR_NULL_POINTER
;
179 const char *ordinalStr
;
180 if (NS_FAILED(aOrdinal
->GetValueConst( &ordinalStr
)))
181 return NS_ERROR_FAILURE
;
183 const char* s
= ordinalStr
;
184 if (PL_strncmp(s
, kRDFNameSpaceURI
, sizeof(kRDFNameSpaceURI
) - 1) != 0) {
185 NS_ERROR("not an ordinal");
186 return NS_ERROR_UNEXPECTED
;
189 s
+= sizeof(kRDFNameSpaceURI
) - 1;
191 NS_ERROR("not an ordinal");
192 return NS_ERROR_UNEXPECTED
;
199 if (*s
< '0' || *s
> '9') {
200 NS_ERROR("not an ordinal");
201 return NS_ERROR_UNEXPECTED
;
215 RDFContainerUtilsImpl::IsContainer(nsIRDFDataSource
*aDataSource
, nsIRDFResource
*aResource
, PRBool
*_retval
)
217 NS_PRECONDITION(aDataSource
!= nsnull
, "null ptr");
219 return NS_ERROR_NULL_POINTER
;
221 NS_PRECONDITION(aResource
!= nsnull
, "null ptr");
223 return NS_ERROR_NULL_POINTER
;
225 NS_PRECONDITION(_retval
!= nsnull
, "null ptr");
227 return NS_ERROR_NULL_POINTER
;
229 if (IsA(aDataSource
, aResource
, kRDF_Seq
) ||
230 IsA(aDataSource
, aResource
, kRDF_Bag
) ||
231 IsA(aDataSource
, aResource
, kRDF_Alt
)) {
242 RDFContainerUtilsImpl::IsEmpty(nsIRDFDataSource
* aDataSource
, nsIRDFResource
* aResource
, PRBool
* _retval
)
245 return NS_ERROR_NULL_POINTER
;
249 // By default, say that we're an empty container. Even if we're not
250 // really even a container.
253 nsCOMPtr
<nsIRDFNode
> nextValNode
;
254 rv
= aDataSource
->GetTarget(aResource
, kRDF_nextVal
, PR_TRUE
, getter_AddRefs(nextValNode
));
255 if (NS_FAILED(rv
)) return rv
;
257 if (rv
== NS_RDF_NO_VALUE
)
260 nsCOMPtr
<nsIRDFLiteral
> nextValLiteral
;
261 rv
= nextValNode
->QueryInterface(NS_GET_IID(nsIRDFLiteral
), getter_AddRefs(nextValLiteral
));
262 if (NS_FAILED(rv
)) return rv
;
264 if (nextValLiteral
.get() != kOne
)
272 RDFContainerUtilsImpl::IsBag(nsIRDFDataSource
*aDataSource
, nsIRDFResource
*aResource
, PRBool
*_retval
)
274 NS_PRECONDITION(aDataSource
!= nsnull
, "null ptr");
276 return NS_ERROR_NULL_POINTER
;
278 NS_PRECONDITION(aResource
!= nsnull
, "null ptr");
280 return NS_ERROR_NULL_POINTER
;
282 NS_PRECONDITION(_retval
!= nsnull
, "null ptr");
284 return NS_ERROR_NULL_POINTER
;
286 *_retval
= IsA(aDataSource
, aResource
, kRDF_Bag
);
292 RDFContainerUtilsImpl::IsSeq(nsIRDFDataSource
*aDataSource
, nsIRDFResource
*aResource
, PRBool
*_retval
)
294 NS_PRECONDITION(aDataSource
!= nsnull
, "null ptr");
296 return NS_ERROR_NULL_POINTER
;
298 NS_PRECONDITION(aResource
!= nsnull
, "null ptr");
300 return NS_ERROR_NULL_POINTER
;
302 NS_PRECONDITION(_retval
!= nsnull
, "null ptr");
304 return NS_ERROR_NULL_POINTER
;
306 *_retval
= IsA(aDataSource
, aResource
, kRDF_Seq
);
312 RDFContainerUtilsImpl::IsAlt(nsIRDFDataSource
*aDataSource
, nsIRDFResource
*aResource
, PRBool
*_retval
)
314 NS_PRECONDITION(aDataSource
!= nsnull
, "null ptr");
316 return NS_ERROR_NULL_POINTER
;
318 NS_PRECONDITION(aResource
!= nsnull
, "null ptr");
320 return NS_ERROR_NULL_POINTER
;
322 NS_PRECONDITION(_retval
!= nsnull
, "null ptr");
324 return NS_ERROR_NULL_POINTER
;
326 *_retval
= IsA(aDataSource
, aResource
, kRDF_Alt
);
332 RDFContainerUtilsImpl::MakeBag(nsIRDFDataSource
*aDataSource
, nsIRDFResource
*aResource
, nsIRDFContainer
**_retval
)
334 return MakeContainer(aDataSource
, aResource
, kRDF_Bag
, _retval
);
339 RDFContainerUtilsImpl::MakeSeq(nsIRDFDataSource
*aDataSource
, nsIRDFResource
*aResource
, nsIRDFContainer
**_retval
)
341 return MakeContainer(aDataSource
, aResource
, kRDF_Seq
, _retval
);
346 RDFContainerUtilsImpl::MakeAlt(nsIRDFDataSource
*aDataSource
, nsIRDFResource
*aResource
, nsIRDFContainer
**_retval
)
348 return MakeContainer(aDataSource
, aResource
, kRDF_Alt
, _retval
);
353 ////////////////////////////////////////////////////////////////////////
356 RDFContainerUtilsImpl::RDFContainerUtilsImpl()
358 if (gRefCnt
++ == 0) {
361 rv
= CallGetService(kRDFServiceCID
, &gRDFService
);
363 NS_ASSERTION(NS_SUCCEEDED(rv
), "unable to get RDF service");
364 if (NS_SUCCEEDED(rv
)) {
365 gRDFService
->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI
"instanceOf"),
367 gRDFService
->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI
"nextVal"),
369 gRDFService
->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI
"Bag"),
371 gRDFService
->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI
"Seq"),
373 gRDFService
->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI
"Alt"),
375 gRDFService
->GetLiteral(NS_LITERAL_STRING("1").get(), &kOne
);
381 RDFContainerUtilsImpl::~RDFContainerUtilsImpl()
385 fprintf(stdout
, "%d - RDF: RDFContainerUtilsImpl\n", gInstanceCount
);
388 if (--gRefCnt
== 0) {
389 NS_IF_RELEASE(gRDFService
);
390 NS_IF_RELEASE(kRDF_instanceOf
);
391 NS_IF_RELEASE(kRDF_nextVal
);
392 NS_IF_RELEASE(kRDF_Bag
);
393 NS_IF_RELEASE(kRDF_Seq
);
394 NS_IF_RELEASE(kRDF_Alt
);
402 NS_NewRDFContainerUtils(nsIRDFContainerUtils
** aResult
)
404 NS_PRECONDITION(aResult
!= nsnull
, "null ptr");
406 return NS_ERROR_NULL_POINTER
;
408 RDFContainerUtilsImpl
* result
=
409 new RDFContainerUtilsImpl();
412 return NS_ERROR_OUT_OF_MEMORY
;
421 RDFContainerUtilsImpl::MakeContainer(nsIRDFDataSource
* aDataSource
, nsIRDFResource
* aResource
, nsIRDFResource
* aType
, nsIRDFContainer
** aResult
)
423 NS_PRECONDITION(aDataSource
!= nsnull
, "null ptr");
424 if (! aDataSource
) return NS_ERROR_NULL_POINTER
;
426 NS_PRECONDITION(aResource
!= nsnull
, "null ptr");
427 if (! aResource
) return NS_ERROR_NULL_POINTER
;
429 NS_PRECONDITION(aType
!= nsnull
, "null ptr");
430 if (! aType
) return NS_ERROR_NULL_POINTER
;
432 if (aResult
) *aResult
= nsnull
;
436 // Check to see if somebody has already turned it into a container; if so
437 // don't try to do it again.
439 rv
= IsContainer(aDataSource
, aResource
, &isContainer
);
440 if (NS_FAILED(rv
)) return rv
;
442 if (isContainer
== PR_FALSE
)
444 rv
= aDataSource
->Assert(aResource
, kRDF_instanceOf
, aType
, PR_TRUE
);
445 if (NS_FAILED(rv
)) return rv
;
447 rv
= aDataSource
->Assert(aResource
, kRDF_nextVal
, kOne
, PR_TRUE
);
448 if (NS_FAILED(rv
)) return rv
;
452 rv
= NS_NewRDFContainer(aResult
);
453 if (NS_FAILED(rv
)) return rv
;
455 rv
= (*aResult
)->Init(aDataSource
, aResource
);
456 if (NS_FAILED(rv
)) return rv
;
463 RDFContainerUtilsImpl::IsA(nsIRDFDataSource
* aDataSource
, nsIRDFResource
* aResource
, nsIRDFResource
* aType
)
465 if (!aDataSource
|| !aResource
|| !aType
)
466 return NS_ERROR_NULL_POINTER
;
471 rv
= aDataSource
->HasAssertion(aResource
, kRDF_instanceOf
, aType
, PR_TRUE
, &result
);
472 if (NS_FAILED(rv
)) return PR_FALSE
;
478 RDFContainerUtilsImpl::IndexOf(nsIRDFDataSource
* aDataSource
, nsIRDFResource
* aContainer
, nsIRDFNode
* aElement
, PRInt32
* aIndex
)
480 if (!aDataSource
|| !aContainer
)
481 return NS_ERROR_NULL_POINTER
;
483 // Assume we can't find it.
486 // If the resource is null, bail quietly
490 // We'll assume that fan-out is much higher than fan-in, so grovel
491 // through the inbound arcs, look for an ordinal resource, and
493 nsCOMPtr
<nsISimpleEnumerator
> arcsIn
;
494 aDataSource
->ArcLabelsIn(aElement
, getter_AddRefs(arcsIn
));
499 PRBool hasMoreArcs
= PR_FALSE
;
500 arcsIn
->HasMoreElements(&hasMoreArcs
);
504 nsCOMPtr
<nsISupports
> isupports
;
505 arcsIn
->GetNext(getter_AddRefs(isupports
));
509 nsCOMPtr
<nsIRDFResource
> property
=
510 do_QueryInterface(isupports
);
516 IsOrdinalProperty(property
, &isOrdinal
);
520 nsCOMPtr
<nsISimpleEnumerator
> sources
;
521 aDataSource
->GetSources(property
, aElement
, PR_TRUE
, getter_AddRefs(sources
));
526 PRBool hasMoreSources
= PR_FALSE
;
527 sources
->HasMoreElements(&hasMoreSources
);
528 if (! hasMoreSources
)
531 nsCOMPtr
<nsISupports
> isupports2
;
532 sources
->GetNext(getter_AddRefs(isupports2
));
536 nsCOMPtr
<nsIRDFResource
> source
=
537 do_QueryInterface(isupports2
);
539 if (source
== aContainer
)
541 return OrdinalResourceToIndex(property
, aIndex
);