1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/rdf/base/src/nsRDFContainerUtils.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,515 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + 1.11 + Implementation for the RDF container utils. 1.12 + 1.13 + */ 1.14 + 1.15 + 1.16 +#include "nsCOMPtr.h" 1.17 +#include "nsIServiceManager.h" 1.18 +#include "nsIRDFContainer.h" 1.19 +#include "nsIRDFContainerUtils.h" 1.20 +#include "nsIRDFService.h" 1.21 +#include "nsRDFCID.h" 1.22 +#include "nsString.h" 1.23 +#include "nsXPIDLString.h" 1.24 +#include "plstr.h" 1.25 +#include "prprf.h" 1.26 +#include "rdf.h" 1.27 +#include "rdfutil.h" 1.28 + 1.29 +class RDFContainerUtilsImpl : public nsIRDFContainerUtils 1.30 +{ 1.31 +public: 1.32 + // nsISupports interface 1.33 + NS_DECL_ISUPPORTS 1.34 + 1.35 + // nsIRDFContainerUtils interface 1.36 + NS_DECL_NSIRDFCONTAINERUTILS 1.37 + 1.38 +private: 1.39 + friend nsresult NS_NewRDFContainerUtils(nsIRDFContainerUtils** aResult); 1.40 + 1.41 + RDFContainerUtilsImpl(); 1.42 + virtual ~RDFContainerUtilsImpl(); 1.43 + 1.44 + nsresult MakeContainer(nsIRDFDataSource* aDataSource, 1.45 + nsIRDFResource* aResource, 1.46 + nsIRDFResource* aType, 1.47 + nsIRDFContainer** aResult); 1.48 + 1.49 + bool IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType); 1.50 + 1.51 + // pseudo constants 1.52 + static int32_t gRefCnt; 1.53 + static nsIRDFService* gRDFService; 1.54 + static nsIRDFResource* kRDF_instanceOf; 1.55 + static nsIRDFResource* kRDF_nextVal; 1.56 + static nsIRDFResource* kRDF_Bag; 1.57 + static nsIRDFResource* kRDF_Seq; 1.58 + static nsIRDFResource* kRDF_Alt; 1.59 + static nsIRDFLiteral* kOne; 1.60 + static const char kRDFNameSpaceURI[]; 1.61 +}; 1.62 + 1.63 +int32_t RDFContainerUtilsImpl::gRefCnt = 0; 1.64 +nsIRDFService* RDFContainerUtilsImpl::gRDFService; 1.65 +nsIRDFResource* RDFContainerUtilsImpl::kRDF_instanceOf; 1.66 +nsIRDFResource* RDFContainerUtilsImpl::kRDF_nextVal; 1.67 +nsIRDFResource* RDFContainerUtilsImpl::kRDF_Bag; 1.68 +nsIRDFResource* RDFContainerUtilsImpl::kRDF_Seq; 1.69 +nsIRDFResource* RDFContainerUtilsImpl::kRDF_Alt; 1.70 +nsIRDFLiteral* RDFContainerUtilsImpl::kOne; 1.71 +const char RDFContainerUtilsImpl::kRDFNameSpaceURI[] = RDF_NAMESPACE_URI; 1.72 + 1.73 +//////////////////////////////////////////////////////////////////////// 1.74 +// nsISupports interface 1.75 + 1.76 +NS_IMPL_ISUPPORTS(RDFContainerUtilsImpl, nsIRDFContainerUtils) 1.77 + 1.78 +//////////////////////////////////////////////////////////////////////// 1.79 +// nsIRDFContainerUtils interface 1.80 + 1.81 +NS_IMETHODIMP 1.82 +RDFContainerUtilsImpl::IsOrdinalProperty(nsIRDFResource *aProperty, bool *_retval) 1.83 +{ 1.84 + NS_PRECONDITION(aProperty != nullptr, "null ptr"); 1.85 + if (! aProperty) 1.86 + return NS_ERROR_NULL_POINTER; 1.87 + 1.88 + nsresult rv; 1.89 + 1.90 + const char *propertyStr; 1.91 + rv = aProperty->GetValueConst( &propertyStr ); 1.92 + if (NS_FAILED(rv)) return rv; 1.93 + 1.94 + if (PL_strncmp(propertyStr, kRDFNameSpaceURI, sizeof(kRDFNameSpaceURI) - 1) != 0) { 1.95 + *_retval = false; 1.96 + return NS_OK; 1.97 + } 1.98 + 1.99 + const char* s = propertyStr; 1.100 + s += sizeof(kRDFNameSpaceURI) - 1; 1.101 + if (*s != '_') { 1.102 + *_retval = false; 1.103 + return NS_OK; 1.104 + } 1.105 + 1.106 + ++s; 1.107 + while (*s) { 1.108 + if (*s < '0' || *s > '9') { 1.109 + *_retval = false; 1.110 + return NS_OK; 1.111 + } 1.112 + 1.113 + ++s; 1.114 + } 1.115 + 1.116 + *_retval = true; 1.117 + return NS_OK; 1.118 +} 1.119 + 1.120 + 1.121 +NS_IMETHODIMP 1.122 +RDFContainerUtilsImpl::IndexToOrdinalResource(int32_t aIndex, nsIRDFResource **aOrdinal) 1.123 +{ 1.124 + NS_PRECONDITION(aIndex > 0, "illegal value"); 1.125 + if (aIndex <= 0) 1.126 + return NS_ERROR_ILLEGAL_VALUE; 1.127 + 1.128 + nsAutoCString uri(kRDFNameSpaceURI); 1.129 + uri.Append('_'); 1.130 + uri.AppendInt(aIndex); 1.131 + 1.132 + nsresult rv = gRDFService->GetResource(uri, aOrdinal); 1.133 + NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get ordinal resource"); 1.134 + if (NS_FAILED(rv)) return rv; 1.135 + 1.136 + return NS_OK; 1.137 +} 1.138 + 1.139 + 1.140 +NS_IMETHODIMP 1.141 +RDFContainerUtilsImpl::OrdinalResourceToIndex(nsIRDFResource *aOrdinal, int32_t *aIndex) 1.142 +{ 1.143 + NS_PRECONDITION(aOrdinal != nullptr, "null ptr"); 1.144 + if (! aOrdinal) 1.145 + return NS_ERROR_NULL_POINTER; 1.146 + 1.147 + const char *ordinalStr; 1.148 + if (NS_FAILED(aOrdinal->GetValueConst( &ordinalStr ))) 1.149 + return NS_ERROR_FAILURE; 1.150 + 1.151 + const char* s = ordinalStr; 1.152 + if (PL_strncmp(s, kRDFNameSpaceURI, sizeof(kRDFNameSpaceURI) - 1) != 0) { 1.153 + NS_ERROR("not an ordinal"); 1.154 + return NS_ERROR_UNEXPECTED; 1.155 + } 1.156 + 1.157 + s += sizeof(kRDFNameSpaceURI) - 1; 1.158 + if (*s != '_') { 1.159 + NS_ERROR("not an ordinal"); 1.160 + return NS_ERROR_UNEXPECTED; 1.161 + } 1.162 + 1.163 + int32_t idx = 0; 1.164 + 1.165 + ++s; 1.166 + while (*s) { 1.167 + if (*s < '0' || *s > '9') { 1.168 + NS_ERROR("not an ordinal"); 1.169 + return NS_ERROR_UNEXPECTED; 1.170 + } 1.171 + 1.172 + idx *= 10; 1.173 + idx += (*s - '0'); 1.174 + 1.175 + ++s; 1.176 + } 1.177 + 1.178 + *aIndex = idx; 1.179 + return NS_OK; 1.180 +} 1.181 + 1.182 +NS_IMETHODIMP 1.183 +RDFContainerUtilsImpl::IsContainer(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, bool *_retval) 1.184 +{ 1.185 + NS_PRECONDITION(aDataSource != nullptr, "null ptr"); 1.186 + if (! aDataSource) 1.187 + return NS_ERROR_NULL_POINTER; 1.188 + 1.189 + NS_PRECONDITION(aResource != nullptr, "null ptr"); 1.190 + if (! aResource) 1.191 + return NS_ERROR_NULL_POINTER; 1.192 + 1.193 + NS_PRECONDITION(_retval != nullptr, "null ptr"); 1.194 + if (! _retval) 1.195 + return NS_ERROR_NULL_POINTER; 1.196 + 1.197 + if (IsA(aDataSource, aResource, kRDF_Seq) || 1.198 + IsA(aDataSource, aResource, kRDF_Bag) || 1.199 + IsA(aDataSource, aResource, kRDF_Alt)) { 1.200 + *_retval = true; 1.201 + } 1.202 + else { 1.203 + *_retval = false; 1.204 + } 1.205 + return NS_OK; 1.206 +} 1.207 + 1.208 + 1.209 +NS_IMETHODIMP 1.210 +RDFContainerUtilsImpl::IsEmpty(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, bool* _retval) 1.211 +{ 1.212 + if (! aDataSource) 1.213 + return NS_ERROR_NULL_POINTER; 1.214 + 1.215 + nsresult rv; 1.216 + 1.217 + // By default, say that we're an empty container. Even if we're not 1.218 + // really even a container. 1.219 + *_retval = true; 1.220 + 1.221 + nsCOMPtr<nsIRDFNode> nextValNode; 1.222 + rv = aDataSource->GetTarget(aResource, kRDF_nextVal, true, getter_AddRefs(nextValNode)); 1.223 + if (NS_FAILED(rv)) return rv; 1.224 + 1.225 + if (rv == NS_RDF_NO_VALUE) 1.226 + return NS_OK; 1.227 + 1.228 + nsCOMPtr<nsIRDFLiteral> nextValLiteral; 1.229 + rv = nextValNode->QueryInterface(NS_GET_IID(nsIRDFLiteral), getter_AddRefs(nextValLiteral)); 1.230 + if (NS_FAILED(rv)) return rv; 1.231 + 1.232 + if (nextValLiteral.get() != kOne) 1.233 + *_retval = false; 1.234 + 1.235 + return NS_OK; 1.236 +} 1.237 + 1.238 + 1.239 +NS_IMETHODIMP 1.240 +RDFContainerUtilsImpl::IsBag(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, bool *_retval) 1.241 +{ 1.242 + NS_PRECONDITION(aDataSource != nullptr, "null ptr"); 1.243 + if (! aDataSource) 1.244 + return NS_ERROR_NULL_POINTER; 1.245 + 1.246 + NS_PRECONDITION(aResource != nullptr, "null ptr"); 1.247 + if (! aResource) 1.248 + return NS_ERROR_NULL_POINTER; 1.249 + 1.250 + NS_PRECONDITION(_retval != nullptr, "null ptr"); 1.251 + if (! _retval) 1.252 + return NS_ERROR_NULL_POINTER; 1.253 + 1.254 + *_retval = IsA(aDataSource, aResource, kRDF_Bag); 1.255 + return NS_OK; 1.256 +} 1.257 + 1.258 + 1.259 +NS_IMETHODIMP 1.260 +RDFContainerUtilsImpl::IsSeq(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, bool *_retval) 1.261 +{ 1.262 + NS_PRECONDITION(aDataSource != nullptr, "null ptr"); 1.263 + if (! aDataSource) 1.264 + return NS_ERROR_NULL_POINTER; 1.265 + 1.266 + NS_PRECONDITION(aResource != nullptr, "null ptr"); 1.267 + if (! aResource) 1.268 + return NS_ERROR_NULL_POINTER; 1.269 + 1.270 + NS_PRECONDITION(_retval != nullptr, "null ptr"); 1.271 + if (! _retval) 1.272 + return NS_ERROR_NULL_POINTER; 1.273 + 1.274 + *_retval = IsA(aDataSource, aResource, kRDF_Seq); 1.275 + return NS_OK; 1.276 +} 1.277 + 1.278 + 1.279 +NS_IMETHODIMP 1.280 +RDFContainerUtilsImpl::IsAlt(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, bool *_retval) 1.281 +{ 1.282 + NS_PRECONDITION(aDataSource != nullptr, "null ptr"); 1.283 + if (! aDataSource) 1.284 + return NS_ERROR_NULL_POINTER; 1.285 + 1.286 + NS_PRECONDITION(aResource != nullptr, "null ptr"); 1.287 + if (! aResource) 1.288 + return NS_ERROR_NULL_POINTER; 1.289 + 1.290 + NS_PRECONDITION(_retval != nullptr, "null ptr"); 1.291 + if (! _retval) 1.292 + return NS_ERROR_NULL_POINTER; 1.293 + 1.294 + *_retval = IsA(aDataSource, aResource, kRDF_Alt); 1.295 + return NS_OK; 1.296 +} 1.297 + 1.298 + 1.299 +NS_IMETHODIMP 1.300 +RDFContainerUtilsImpl::MakeBag(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, nsIRDFContainer **_retval) 1.301 +{ 1.302 + return MakeContainer(aDataSource, aResource, kRDF_Bag, _retval); 1.303 +} 1.304 + 1.305 + 1.306 +NS_IMETHODIMP 1.307 +RDFContainerUtilsImpl::MakeSeq(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, nsIRDFContainer **_retval) 1.308 +{ 1.309 + return MakeContainer(aDataSource, aResource, kRDF_Seq, _retval); 1.310 +} 1.311 + 1.312 + 1.313 +NS_IMETHODIMP 1.314 +RDFContainerUtilsImpl::MakeAlt(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, nsIRDFContainer **_retval) 1.315 +{ 1.316 + return MakeContainer(aDataSource, aResource, kRDF_Alt, _retval); 1.317 +} 1.318 + 1.319 + 1.320 + 1.321 +//////////////////////////////////////////////////////////////////////// 1.322 + 1.323 + 1.324 +RDFContainerUtilsImpl::RDFContainerUtilsImpl() 1.325 +{ 1.326 + if (gRefCnt++ == 0) { 1.327 + nsresult rv; 1.328 + 1.329 + NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); 1.330 + rv = CallGetService(kRDFServiceCID, &gRDFService); 1.331 + 1.332 + NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service"); 1.333 + if (NS_SUCCEEDED(rv)) { 1.334 + gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "instanceOf"), 1.335 + &kRDF_instanceOf); 1.336 + gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "nextVal"), 1.337 + &kRDF_nextVal); 1.338 + gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Bag"), 1.339 + &kRDF_Bag); 1.340 + gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Seq"), 1.341 + &kRDF_Seq); 1.342 + gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Alt"), 1.343 + &kRDF_Alt); 1.344 + gRDFService->GetLiteral(MOZ_UTF16("1"), &kOne); 1.345 + } 1.346 + } 1.347 +} 1.348 + 1.349 + 1.350 +RDFContainerUtilsImpl::~RDFContainerUtilsImpl() 1.351 +{ 1.352 +#ifdef DEBUG_REFS 1.353 + --gInstanceCount; 1.354 + fprintf(stdout, "%d - RDF: RDFContainerUtilsImpl\n", gInstanceCount); 1.355 +#endif 1.356 + 1.357 + if (--gRefCnt == 0) { 1.358 + NS_IF_RELEASE(gRDFService); 1.359 + NS_IF_RELEASE(kRDF_instanceOf); 1.360 + NS_IF_RELEASE(kRDF_nextVal); 1.361 + NS_IF_RELEASE(kRDF_Bag); 1.362 + NS_IF_RELEASE(kRDF_Seq); 1.363 + NS_IF_RELEASE(kRDF_Alt); 1.364 + NS_IF_RELEASE(kOne); 1.365 + } 1.366 +} 1.367 + 1.368 + 1.369 + 1.370 +nsresult 1.371 +NS_NewRDFContainerUtils(nsIRDFContainerUtils** aResult) 1.372 +{ 1.373 + NS_PRECONDITION(aResult != nullptr, "null ptr"); 1.374 + if (! aResult) 1.375 + return NS_ERROR_NULL_POINTER; 1.376 + 1.377 + RDFContainerUtilsImpl* result = 1.378 + new RDFContainerUtilsImpl(); 1.379 + 1.380 + if (! result) 1.381 + return NS_ERROR_OUT_OF_MEMORY; 1.382 + 1.383 + NS_ADDREF(result); 1.384 + *aResult = result; 1.385 + return NS_OK; 1.386 +} 1.387 + 1.388 + 1.389 +nsresult 1.390 +RDFContainerUtilsImpl::MakeContainer(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType, nsIRDFContainer** aResult) 1.391 +{ 1.392 + NS_PRECONDITION(aDataSource != nullptr, "null ptr"); 1.393 + if (! aDataSource) return NS_ERROR_NULL_POINTER; 1.394 + 1.395 + NS_PRECONDITION(aResource != nullptr, "null ptr"); 1.396 + if (! aResource) return NS_ERROR_NULL_POINTER; 1.397 + 1.398 + NS_PRECONDITION(aType != nullptr, "null ptr"); 1.399 + if (! aType) return NS_ERROR_NULL_POINTER; 1.400 + 1.401 + if (aResult) *aResult = nullptr; 1.402 + 1.403 + nsresult rv; 1.404 + 1.405 + // Check to see if somebody has already turned it into a container; if so 1.406 + // don't try to do it again. 1.407 + bool isContainer; 1.408 + rv = IsContainer(aDataSource, aResource, &isContainer); 1.409 + if (NS_FAILED(rv)) return rv; 1.410 + 1.411 + if (!isContainer) 1.412 + { 1.413 + rv = aDataSource->Assert(aResource, kRDF_instanceOf, aType, true); 1.414 + if (NS_FAILED(rv)) return rv; 1.415 + 1.416 + rv = aDataSource->Assert(aResource, kRDF_nextVal, kOne, true); 1.417 + if (NS_FAILED(rv)) return rv; 1.418 + } 1.419 + 1.420 + if (aResult) { 1.421 + rv = NS_NewRDFContainer(aResult); 1.422 + if (NS_FAILED(rv)) return rv; 1.423 + 1.424 + rv = (*aResult)->Init(aDataSource, aResource); 1.425 + if (NS_FAILED(rv)) return rv; 1.426 + } 1.427 + 1.428 + return NS_OK; 1.429 +} 1.430 + 1.431 +bool 1.432 +RDFContainerUtilsImpl::IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType) 1.433 +{ 1.434 + if (!aDataSource || !aResource || !aType) { 1.435 + NS_WARNING("Unexpected null argument"); 1.436 + return false; 1.437 + } 1.438 + 1.439 + nsresult rv; 1.440 + 1.441 + bool result; 1.442 + rv = aDataSource->HasAssertion(aResource, kRDF_instanceOf, aType, true, &result); 1.443 + if (NS_FAILED(rv)) 1.444 + return false; 1.445 + 1.446 + return result; 1.447 +} 1.448 + 1.449 +NS_IMETHODIMP 1.450 +RDFContainerUtilsImpl::IndexOf(nsIRDFDataSource* aDataSource, nsIRDFResource* aContainer, nsIRDFNode* aElement, int32_t* aIndex) 1.451 +{ 1.452 + if (!aDataSource || !aContainer) 1.453 + return NS_ERROR_NULL_POINTER; 1.454 + 1.455 + // Assume we can't find it. 1.456 + *aIndex = -1; 1.457 + 1.458 + // If the resource is null, bail quietly 1.459 + if (! aElement) 1.460 + return NS_OK; 1.461 + 1.462 + // We'll assume that fan-out is much higher than fan-in, so grovel 1.463 + // through the inbound arcs, look for an ordinal resource, and 1.464 + // decode it. 1.465 + nsCOMPtr<nsISimpleEnumerator> arcsIn; 1.466 + aDataSource->ArcLabelsIn(aElement, getter_AddRefs(arcsIn)); 1.467 + if (! arcsIn) 1.468 + return NS_OK; 1.469 + 1.470 + while (1) { 1.471 + bool hasMoreArcs = false; 1.472 + arcsIn->HasMoreElements(&hasMoreArcs); 1.473 + if (! hasMoreArcs) 1.474 + break; 1.475 + 1.476 + nsCOMPtr<nsISupports> isupports; 1.477 + arcsIn->GetNext(getter_AddRefs(isupports)); 1.478 + if (! isupports) 1.479 + break; 1.480 + 1.481 + nsCOMPtr<nsIRDFResource> property = 1.482 + do_QueryInterface(isupports); 1.483 + 1.484 + if (! property) 1.485 + continue; 1.486 + 1.487 + bool isOrdinal; 1.488 + IsOrdinalProperty(property, &isOrdinal); 1.489 + if (! isOrdinal) 1.490 + continue; 1.491 + 1.492 + nsCOMPtr<nsISimpleEnumerator> sources; 1.493 + aDataSource->GetSources(property, aElement, true, getter_AddRefs(sources)); 1.494 + if (! sources) 1.495 + continue; 1.496 + 1.497 + while (1) { 1.498 + bool hasMoreSources = false; 1.499 + sources->HasMoreElements(&hasMoreSources); 1.500 + if (! hasMoreSources) 1.501 + break; 1.502 + 1.503 + nsCOMPtr<nsISupports> isupports2; 1.504 + sources->GetNext(getter_AddRefs(isupports2)); 1.505 + if (! isupports2) 1.506 + break; 1.507 + 1.508 + nsCOMPtr<nsIRDFResource> source = 1.509 + do_QueryInterface(isupports2); 1.510 + 1.511 + if (source == aContainer) 1.512 + // Found it. 1.513 + return OrdinalResourceToIndex(property, aIndex); 1.514 + } 1.515 + } 1.516 + 1.517 + return NS_OK; 1.518 +}