зеркало из https://github.com/mozilla/gecko-dev.git
514 строки
14 KiB
C++
514 строки
14 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/*
|
|
|
|
Implementation for the RDF container utils.
|
|
|
|
*/
|
|
|
|
|
|
#include "nsCOMPtr.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsIRDFContainer.h"
|
|
#include "nsIRDFContainerUtils.h"
|
|
#include "nsIRDFService.h"
|
|
#include "nsRDFCID.h"
|
|
#include "nsString.h"
|
|
#include "plstr.h"
|
|
#include "rdf.h"
|
|
#include "rdfutil.h"
|
|
|
|
class RDFContainerUtilsImpl : public nsIRDFContainerUtils
|
|
{
|
|
public:
|
|
// nsISupports interface
|
|
NS_DECL_ISUPPORTS
|
|
|
|
// nsIRDFContainerUtils interface
|
|
NS_DECL_NSIRDFCONTAINERUTILS
|
|
|
|
private:
|
|
friend nsresult NS_NewRDFContainerUtils(nsIRDFContainerUtils** aResult);
|
|
|
|
RDFContainerUtilsImpl();
|
|
virtual ~RDFContainerUtilsImpl();
|
|
|
|
nsresult MakeContainer(nsIRDFDataSource* aDataSource,
|
|
nsIRDFResource* aResource,
|
|
nsIRDFResource* aType,
|
|
nsIRDFContainer** aResult);
|
|
|
|
bool IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType);
|
|
|
|
// pseudo constants
|
|
static int32_t gRefCnt;
|
|
static nsIRDFService* gRDFService;
|
|
static nsIRDFResource* kRDF_instanceOf;
|
|
static nsIRDFResource* kRDF_nextVal;
|
|
static nsIRDFResource* kRDF_Bag;
|
|
static nsIRDFResource* kRDF_Seq;
|
|
static nsIRDFResource* kRDF_Alt;
|
|
static nsIRDFLiteral* kOne;
|
|
static const char kRDFNameSpaceURI[];
|
|
};
|
|
|
|
int32_t RDFContainerUtilsImpl::gRefCnt = 0;
|
|
nsIRDFService* RDFContainerUtilsImpl::gRDFService;
|
|
nsIRDFResource* RDFContainerUtilsImpl::kRDF_instanceOf;
|
|
nsIRDFResource* RDFContainerUtilsImpl::kRDF_nextVal;
|
|
nsIRDFResource* RDFContainerUtilsImpl::kRDF_Bag;
|
|
nsIRDFResource* RDFContainerUtilsImpl::kRDF_Seq;
|
|
nsIRDFResource* RDFContainerUtilsImpl::kRDF_Alt;
|
|
nsIRDFLiteral* RDFContainerUtilsImpl::kOne;
|
|
const char RDFContainerUtilsImpl::kRDFNameSpaceURI[] = RDF_NAMESPACE_URI;
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// nsISupports interface
|
|
|
|
NS_IMPL_ISUPPORTS(RDFContainerUtilsImpl, nsIRDFContainerUtils)
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// nsIRDFContainerUtils interface
|
|
|
|
NS_IMETHODIMP
|
|
RDFContainerUtilsImpl::IsOrdinalProperty(nsIRDFResource *aProperty, bool *_retval)
|
|
{
|
|
NS_PRECONDITION(aProperty != nullptr, "null ptr");
|
|
if (! aProperty)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult rv;
|
|
|
|
const char *propertyStr;
|
|
rv = aProperty->GetValueConst( &propertyStr );
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (PL_strncmp(propertyStr, kRDFNameSpaceURI, sizeof(kRDFNameSpaceURI) - 1) != 0) {
|
|
*_retval = false;
|
|
return NS_OK;
|
|
}
|
|
|
|
const char* s = propertyStr;
|
|
s += sizeof(kRDFNameSpaceURI) - 1;
|
|
if (*s != '_') {
|
|
*_retval = false;
|
|
return NS_OK;
|
|
}
|
|
|
|
++s;
|
|
while (*s) {
|
|
if (*s < '0' || *s > '9') {
|
|
*_retval = false;
|
|
return NS_OK;
|
|
}
|
|
|
|
++s;
|
|
}
|
|
|
|
*_retval = true;
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFContainerUtilsImpl::IndexToOrdinalResource(int32_t aIndex, nsIRDFResource **aOrdinal)
|
|
{
|
|
NS_PRECONDITION(aIndex > 0, "illegal value");
|
|
if (aIndex <= 0)
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
|
|
nsAutoCString uri(kRDFNameSpaceURI);
|
|
uri.Append('_');
|
|
uri.AppendInt(aIndex);
|
|
|
|
nsresult rv = gRDFService->GetResource(uri, aOrdinal);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get ordinal resource");
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFContainerUtilsImpl::OrdinalResourceToIndex(nsIRDFResource *aOrdinal, int32_t *aIndex)
|
|
{
|
|
NS_PRECONDITION(aOrdinal != nullptr, "null ptr");
|
|
if (! aOrdinal)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
const char *ordinalStr;
|
|
if (NS_FAILED(aOrdinal->GetValueConst( &ordinalStr )))
|
|
return NS_ERROR_FAILURE;
|
|
|
|
const char* s = ordinalStr;
|
|
if (PL_strncmp(s, kRDFNameSpaceURI, sizeof(kRDFNameSpaceURI) - 1) != 0) {
|
|
NS_ERROR("not an ordinal");
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
|
|
s += sizeof(kRDFNameSpaceURI) - 1;
|
|
if (*s != '_') {
|
|
NS_ERROR("not an ordinal");
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
|
|
int32_t idx = 0;
|
|
|
|
++s;
|
|
while (*s) {
|
|
if (*s < '0' || *s > '9') {
|
|
NS_ERROR("not an ordinal");
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
|
|
idx *= 10;
|
|
idx += (*s - '0');
|
|
|
|
++s;
|
|
}
|
|
|
|
*aIndex = idx;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
RDFContainerUtilsImpl::IsContainer(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, bool *_retval)
|
|
{
|
|
NS_PRECONDITION(aDataSource != nullptr, "null ptr");
|
|
if (! aDataSource)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
NS_PRECONDITION(aResource != nullptr, "null ptr");
|
|
if (! aResource)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
NS_PRECONDITION(_retval != nullptr, "null ptr");
|
|
if (! _retval)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
if (IsA(aDataSource, aResource, kRDF_Seq) ||
|
|
IsA(aDataSource, aResource, kRDF_Bag) ||
|
|
IsA(aDataSource, aResource, kRDF_Alt)) {
|
|
*_retval = true;
|
|
}
|
|
else {
|
|
*_retval = false;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFContainerUtilsImpl::IsEmpty(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, bool* _retval)
|
|
{
|
|
if (! aDataSource)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult rv;
|
|
|
|
// By default, say that we're an empty container. Even if we're not
|
|
// really even a container.
|
|
*_retval = true;
|
|
|
|
nsCOMPtr<nsIRDFNode> nextValNode;
|
|
rv = aDataSource->GetTarget(aResource, kRDF_nextVal, true, getter_AddRefs(nextValNode));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (rv == NS_RDF_NO_VALUE)
|
|
return NS_OK;
|
|
|
|
nsCOMPtr<nsIRDFLiteral> nextValLiteral;
|
|
rv = nextValNode->QueryInterface(NS_GET_IID(nsIRDFLiteral), getter_AddRefs(nextValLiteral));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (nextValLiteral.get() != kOne)
|
|
*_retval = false;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFContainerUtilsImpl::IsBag(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, bool *_retval)
|
|
{
|
|
NS_PRECONDITION(aDataSource != nullptr, "null ptr");
|
|
if (! aDataSource)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
NS_PRECONDITION(aResource != nullptr, "null ptr");
|
|
if (! aResource)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
NS_PRECONDITION(_retval != nullptr, "null ptr");
|
|
if (! _retval)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
*_retval = IsA(aDataSource, aResource, kRDF_Bag);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFContainerUtilsImpl::IsSeq(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, bool *_retval)
|
|
{
|
|
NS_PRECONDITION(aDataSource != nullptr, "null ptr");
|
|
if (! aDataSource)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
NS_PRECONDITION(aResource != nullptr, "null ptr");
|
|
if (! aResource)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
NS_PRECONDITION(_retval != nullptr, "null ptr");
|
|
if (! _retval)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
*_retval = IsA(aDataSource, aResource, kRDF_Seq);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFContainerUtilsImpl::IsAlt(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, bool *_retval)
|
|
{
|
|
NS_PRECONDITION(aDataSource != nullptr, "null ptr");
|
|
if (! aDataSource)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
NS_PRECONDITION(aResource != nullptr, "null ptr");
|
|
if (! aResource)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
NS_PRECONDITION(_retval != nullptr, "null ptr");
|
|
if (! _retval)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
*_retval = IsA(aDataSource, aResource, kRDF_Alt);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFContainerUtilsImpl::MakeBag(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, nsIRDFContainer **_retval)
|
|
{
|
|
return MakeContainer(aDataSource, aResource, kRDF_Bag, _retval);
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFContainerUtilsImpl::MakeSeq(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, nsIRDFContainer **_retval)
|
|
{
|
|
return MakeContainer(aDataSource, aResource, kRDF_Seq, _retval);
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFContainerUtilsImpl::MakeAlt(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, nsIRDFContainer **_retval)
|
|
{
|
|
return MakeContainer(aDataSource, aResource, kRDF_Alt, _retval);
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
RDFContainerUtilsImpl::RDFContainerUtilsImpl()
|
|
{
|
|
if (gRefCnt++ == 0) {
|
|
nsresult rv;
|
|
|
|
NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
|
|
rv = CallGetService(kRDFServiceCID, &gRDFService);
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service");
|
|
if (NS_SUCCEEDED(rv)) {
|
|
gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "instanceOf"),
|
|
&kRDF_instanceOf);
|
|
gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "nextVal"),
|
|
&kRDF_nextVal);
|
|
gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Bag"),
|
|
&kRDF_Bag);
|
|
gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Seq"),
|
|
&kRDF_Seq);
|
|
gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Alt"),
|
|
&kRDF_Alt);
|
|
gRDFService->GetLiteral(u"1", &kOne);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
RDFContainerUtilsImpl::~RDFContainerUtilsImpl()
|
|
{
|
|
#ifdef DEBUG_REFS
|
|
--gInstanceCount;
|
|
fprintf(stdout, "%d - RDF: RDFContainerUtilsImpl\n", gInstanceCount);
|
|
#endif
|
|
|
|
if (--gRefCnt == 0) {
|
|
NS_IF_RELEASE(gRDFService);
|
|
NS_IF_RELEASE(kRDF_instanceOf);
|
|
NS_IF_RELEASE(kRDF_nextVal);
|
|
NS_IF_RELEASE(kRDF_Bag);
|
|
NS_IF_RELEASE(kRDF_Seq);
|
|
NS_IF_RELEASE(kRDF_Alt);
|
|
NS_IF_RELEASE(kOne);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
NS_NewRDFContainerUtils(nsIRDFContainerUtils** aResult)
|
|
{
|
|
NS_PRECONDITION(aResult != nullptr, "null ptr");
|
|
if (! aResult)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
RDFContainerUtilsImpl* result =
|
|
new RDFContainerUtilsImpl();
|
|
|
|
if (! result)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
NS_ADDREF(result);
|
|
*aResult = result;
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
nsresult
|
|
RDFContainerUtilsImpl::MakeContainer(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType, nsIRDFContainer** aResult)
|
|
{
|
|
NS_PRECONDITION(aDataSource != nullptr, "null ptr");
|
|
if (! aDataSource) return NS_ERROR_NULL_POINTER;
|
|
|
|
NS_PRECONDITION(aResource != nullptr, "null ptr");
|
|
if (! aResource) return NS_ERROR_NULL_POINTER;
|
|
|
|
NS_PRECONDITION(aType != nullptr, "null ptr");
|
|
if (! aType) return NS_ERROR_NULL_POINTER;
|
|
|
|
if (aResult) *aResult = nullptr;
|
|
|
|
nsresult rv;
|
|
|
|
// Check to see if somebody has already turned it into a container; if so
|
|
// don't try to do it again.
|
|
bool isContainer;
|
|
rv = IsContainer(aDataSource, aResource, &isContainer);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (!isContainer)
|
|
{
|
|
rv = aDataSource->Assert(aResource, kRDF_instanceOf, aType, true);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = aDataSource->Assert(aResource, kRDF_nextVal, kOne, true);
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
|
|
if (aResult) {
|
|
rv = NS_NewRDFContainer(aResult);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = (*aResult)->Init(aDataSource, aResource);
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
bool
|
|
RDFContainerUtilsImpl::IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType)
|
|
{
|
|
if (!aDataSource || !aResource || !aType) {
|
|
NS_WARNING("Unexpected null argument");
|
|
return false;
|
|
}
|
|
|
|
nsresult rv;
|
|
|
|
bool result;
|
|
rv = aDataSource->HasAssertion(aResource, kRDF_instanceOf, aType, true, &result);
|
|
if (NS_FAILED(rv))
|
|
return false;
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
RDFContainerUtilsImpl::IndexOf(nsIRDFDataSource* aDataSource, nsIRDFResource* aContainer, nsIRDFNode* aElement, int32_t* aIndex)
|
|
{
|
|
if (!aDataSource || !aContainer)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
// Assume we can't find it.
|
|
*aIndex = -1;
|
|
|
|
// If the resource is null, bail quietly
|
|
if (! aElement)
|
|
return NS_OK;
|
|
|
|
// We'll assume that fan-out is much higher than fan-in, so grovel
|
|
// through the inbound arcs, look for an ordinal resource, and
|
|
// decode it.
|
|
nsCOMPtr<nsISimpleEnumerator> arcsIn;
|
|
aDataSource->ArcLabelsIn(aElement, getter_AddRefs(arcsIn));
|
|
if (! arcsIn)
|
|
return NS_OK;
|
|
|
|
while (1) {
|
|
bool hasMoreArcs = false;
|
|
arcsIn->HasMoreElements(&hasMoreArcs);
|
|
if (! hasMoreArcs)
|
|
break;
|
|
|
|
nsCOMPtr<nsISupports> isupports;
|
|
arcsIn->GetNext(getter_AddRefs(isupports));
|
|
if (! isupports)
|
|
break;
|
|
|
|
nsCOMPtr<nsIRDFResource> property =
|
|
do_QueryInterface(isupports);
|
|
|
|
if (! property)
|
|
continue;
|
|
|
|
bool isOrdinal;
|
|
IsOrdinalProperty(property, &isOrdinal);
|
|
if (! isOrdinal)
|
|
continue;
|
|
|
|
nsCOMPtr<nsISimpleEnumerator> sources;
|
|
aDataSource->GetSources(property, aElement, true, getter_AddRefs(sources));
|
|
if (! sources)
|
|
continue;
|
|
|
|
while (1) {
|
|
bool hasMoreSources = false;
|
|
sources->HasMoreElements(&hasMoreSources);
|
|
if (! hasMoreSources)
|
|
break;
|
|
|
|
nsCOMPtr<nsISupports> isupports2;
|
|
sources->GetNext(getter_AddRefs(isupports2));
|
|
if (! isupports2)
|
|
break;
|
|
|
|
nsCOMPtr<nsIRDFResource> source =
|
|
do_QueryInterface(isupports2);
|
|
|
|
if (source == aContainer)
|
|
// Found it.
|
|
return OrdinalResourceToIndex(property, aIndex);
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|