rdf/base/src/nsRDFContentSink.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 /*
michael@0 7
michael@0 8 An implementation for an NGLayout-style content sink that knows how
michael@0 9 to build an RDF content model from XML-serialized RDF.
michael@0 10
michael@0 11 For more information on the RDF/XML syntax,
michael@0 12 see http://www.w3.org/TR/REC-rdf-syntax/
michael@0 13
michael@0 14 This code is based on the final W3C Recommendation,
michael@0 15 http://www.w3.org/TR/1999/REC-rdf-syntax-19990222.
michael@0 16
michael@0 17 Open Issues ------------------
michael@0 18
michael@0 19 1) factoring code with nsXMLContentSink - There's some amount of
michael@0 20 common code between this and the HTML content sink. This will
michael@0 21 increase as we support more and more HTML elements. How can code
michael@0 22 from XML/HTML be factored?
michael@0 23
michael@0 24 2) We don't support the `parseType' attribute on the Description
michael@0 25 tag; therefore, it is impossible to "inline" raw XML in this
michael@0 26 implemenation.
michael@0 27
michael@0 28 3) We don't build the reifications at parse time due to the
michael@0 29 footprint overhead it would incur for large RDF documents. (It
michael@0 30 may be possible to attach a "reification" wrapper datasource that
michael@0 31 would present this information at query-time.) Because of this,
michael@0 32 the `bagID' attribute is not processed correctly.
michael@0 33
michael@0 34 4) No attempt is made to `resolve URIs' to a canonical form (the
michael@0 35 specification hints that an implementation should do this). This
michael@0 36 is omitted for the obvious reason that we can ill afford to
michael@0 37 resolve each URI reference.
michael@0 38
michael@0 39 */
michael@0 40
michael@0 41 #include "nsCOMPtr.h"
michael@0 42 #include "nsInterfaceHashtable.h"
michael@0 43 #include "nsIContentSink.h"
michael@0 44 #include "nsIRDFContainer.h"
michael@0 45 #include "nsIRDFContainerUtils.h"
michael@0 46 #include "nsIRDFContentSink.h"
michael@0 47 #include "nsIRDFNode.h"
michael@0 48 #include "nsIRDFService.h"
michael@0 49 #include "nsIRDFXMLSink.h"
michael@0 50 #include "nsIServiceManager.h"
michael@0 51 #include "nsIURL.h"
michael@0 52 #include "nsIXMLContentSink.h"
michael@0 53 #include "nsRDFCID.h"
michael@0 54 #include "nsTArray.h"
michael@0 55 #include "nsXPIDLString.h"
michael@0 56 #include "prlog.h"
michael@0 57 #include "rdf.h"
michael@0 58 #include "rdfutil.h"
michael@0 59 #include "nsReadableUtils.h"
michael@0 60 #include "nsIExpatSink.h"
michael@0 61 #include "nsCRT.h"
michael@0 62 #include "nsIAtom.h"
michael@0 63 #include "nsStaticAtom.h"
michael@0 64 #include "nsIScriptError.h"
michael@0 65 #include "nsIDTD.h"
michael@0 66
michael@0 67 using namespace mozilla;
michael@0 68
michael@0 69 ///////////////////////////////////////////////////////////////////////
michael@0 70
michael@0 71 enum RDFContentSinkState {
michael@0 72 eRDFContentSinkState_InProlog,
michael@0 73 eRDFContentSinkState_InDocumentElement,
michael@0 74 eRDFContentSinkState_InDescriptionElement,
michael@0 75 eRDFContentSinkState_InContainerElement,
michael@0 76 eRDFContentSinkState_InPropertyElement,
michael@0 77 eRDFContentSinkState_InMemberElement,
michael@0 78 eRDFContentSinkState_InEpilog
michael@0 79 };
michael@0 80
michael@0 81 enum RDFContentSinkParseMode {
michael@0 82 eRDFContentSinkParseMode_Resource,
michael@0 83 eRDFContentSinkParseMode_Literal,
michael@0 84 eRDFContentSinkParseMode_Int,
michael@0 85 eRDFContentSinkParseMode_Date
michael@0 86 };
michael@0 87
michael@0 88 typedef
michael@0 89 NS_STDCALL_FUNCPROTO(nsresult,
michael@0 90 nsContainerTestFn,
michael@0 91 nsIRDFContainerUtils, IsAlt,
michael@0 92 (nsIRDFDataSource*, nsIRDFResource*, bool*));
michael@0 93
michael@0 94 typedef
michael@0 95 NS_STDCALL_FUNCPROTO(nsresult,
michael@0 96 nsMakeContainerFn,
michael@0 97 nsIRDFContainerUtils, MakeAlt,
michael@0 98 (nsIRDFDataSource*, nsIRDFResource*, nsIRDFContainer**));
michael@0 99
michael@0 100 class RDFContentSinkImpl : public nsIRDFContentSink,
michael@0 101 public nsIExpatSink
michael@0 102 {
michael@0 103 public:
michael@0 104 RDFContentSinkImpl();
michael@0 105 virtual ~RDFContentSinkImpl();
michael@0 106
michael@0 107 // nsISupports
michael@0 108 NS_DECL_ISUPPORTS
michael@0 109 NS_DECL_NSIEXPATSINK
michael@0 110
michael@0 111 // nsIContentSink
michael@0 112 NS_IMETHOD WillParse(void);
michael@0 113 NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode);
michael@0 114 NS_IMETHOD DidBuildModel(bool aTerminated);
michael@0 115 NS_IMETHOD WillInterrupt(void);
michael@0 116 NS_IMETHOD WillResume(void);
michael@0 117 NS_IMETHOD SetParser(nsParserBase* aParser);
michael@0 118 virtual void FlushPendingNotifications(mozFlushType aType) { }
michael@0 119 NS_IMETHOD SetDocumentCharset(nsACString& aCharset) { return NS_OK; }
michael@0 120 virtual nsISupports *GetTarget() { return nullptr; }
michael@0 121
michael@0 122 // nsIRDFContentSink
michael@0 123 NS_IMETHOD Init(nsIURI* aURL);
michael@0 124 NS_IMETHOD SetDataSource(nsIRDFDataSource* aDataSource);
michael@0 125 NS_IMETHOD GetDataSource(nsIRDFDataSource*& aDataSource);
michael@0 126
michael@0 127 // pseudo constants
michael@0 128 static int32_t gRefCnt;
michael@0 129 static nsIRDFService* gRDFService;
michael@0 130 static nsIRDFContainerUtils* gRDFContainerUtils;
michael@0 131 static nsIRDFResource* kRDF_type;
michael@0 132 static nsIRDFResource* kRDF_instanceOf; // XXX should be RDF:type
michael@0 133 static nsIRDFResource* kRDF_Alt;
michael@0 134 static nsIRDFResource* kRDF_Bag;
michael@0 135 static nsIRDFResource* kRDF_Seq;
michael@0 136 static nsIRDFResource* kRDF_nextVal;
michael@0 137
michael@0 138 #define RDF_ATOM(name_, value_) static nsIAtom* name_;
michael@0 139 #include "nsRDFContentSinkAtomList.h"
michael@0 140 #undef RDF_ATOM
michael@0 141
michael@0 142 typedef struct ContainerInfo {
michael@0 143 nsIRDFResource** mType;
michael@0 144 nsContainerTestFn mTestFn;
michael@0 145 nsMakeContainerFn mMakeFn;
michael@0 146 } ContainerInfo;
michael@0 147
michael@0 148 protected:
michael@0 149 // Text management
michael@0 150 void ParseText(nsIRDFNode **aResult);
michael@0 151
michael@0 152 nsresult FlushText();
michael@0 153 nsresult AddText(const char16_t* aText, int32_t aLength);
michael@0 154
michael@0 155 // RDF-specific parsing
michael@0 156 nsresult OpenRDF(const char16_t* aName);
michael@0 157 nsresult OpenObject(const char16_t* aName ,const char16_t** aAttributes);
michael@0 158 nsresult OpenProperty(const char16_t* aName, const char16_t** aAttributes);
michael@0 159 nsresult OpenMember(const char16_t* aName, const char16_t** aAttributes);
michael@0 160 nsresult OpenValue(const char16_t* aName, const char16_t** aAttributes);
michael@0 161
michael@0 162 nsresult GetIdAboutAttribute(const char16_t** aAttributes, nsIRDFResource** aResource, bool* aIsAnonymous = nullptr);
michael@0 163 nsresult GetResourceAttribute(const char16_t** aAttributes, nsIRDFResource** aResource);
michael@0 164 nsresult AddProperties(const char16_t** aAttributes, nsIRDFResource* aSubject, int32_t* aCount = nullptr);
michael@0 165 void SetParseMode(const char16_t **aAttributes);
michael@0 166
michael@0 167 char16_t* mText;
michael@0 168 int32_t mTextLength;
michael@0 169 int32_t mTextSize;
michael@0 170
michael@0 171 /**
michael@0 172 * From the set of given attributes, this method extracts the
michael@0 173 * namespace definitions and feeds them to the datasource.
michael@0 174 * These can then be suggested to the serializer to be used again.
michael@0 175 * Hopefully, this will keep namespace definitions intact in a
michael@0 176 * parse - serialize cycle.
michael@0 177 */
michael@0 178 void RegisterNamespaces(const char16_t **aAttributes);
michael@0 179
michael@0 180 /**
michael@0 181 * Extracts the localname from aExpatName, the name that the Expat parser
michael@0 182 * passes us.
michael@0 183 * aLocalName will contain the localname in aExpatName.
michael@0 184 * The return value is a dependent string containing just the namespace.
michael@0 185 */
michael@0 186 const nsDependentSubstring SplitExpatName(const char16_t *aExpatName,
michael@0 187 nsIAtom **aLocalName);
michael@0 188
michael@0 189 enum eContainerType { eBag, eSeq, eAlt };
michael@0 190 nsresult InitContainer(nsIRDFResource* aContainerType, nsIRDFResource* aContainer);
michael@0 191 nsresult ReinitContainer(nsIRDFResource* aContainerType, nsIRDFResource* aContainer);
michael@0 192
michael@0 193 // The datasource in which we're assigning assertions
michael@0 194 nsCOMPtr<nsIRDFDataSource> mDataSource;
michael@0 195
michael@0 196 // A hash of all the node IDs referred to
michael@0 197 nsInterfaceHashtable<nsStringHashKey, nsIRDFResource> mNodeIDMap;
michael@0 198
michael@0 199 // The current state of the content sink
michael@0 200 RDFContentSinkState mState;
michael@0 201 RDFContentSinkParseMode mParseMode;
michael@0 202
michael@0 203 // content stack management
michael@0 204 int32_t
michael@0 205 PushContext(nsIRDFResource *aContext,
michael@0 206 RDFContentSinkState aState,
michael@0 207 RDFContentSinkParseMode aParseMode);
michael@0 208
michael@0 209 nsresult
michael@0 210 PopContext(nsIRDFResource *&aContext,
michael@0 211 RDFContentSinkState &aState,
michael@0 212 RDFContentSinkParseMode &aParseMode);
michael@0 213
michael@0 214 nsIRDFResource* GetContextElement(int32_t ancestor = 0);
michael@0 215
michael@0 216
michael@0 217 struct RDFContextStackElement {
michael@0 218 nsCOMPtr<nsIRDFResource> mResource;
michael@0 219 RDFContentSinkState mState;
michael@0 220 RDFContentSinkParseMode mParseMode;
michael@0 221 };
michael@0 222
michael@0 223 nsAutoTArray<RDFContextStackElement, 8>* mContextStack;
michael@0 224
michael@0 225 nsIURI* mDocumentURL;
michael@0 226
michael@0 227 private:
michael@0 228 #ifdef PR_LOGGING
michael@0 229 static PRLogModuleInfo* gLog;
michael@0 230 #endif
michael@0 231 };
michael@0 232
michael@0 233 int32_t RDFContentSinkImpl::gRefCnt = 0;
michael@0 234 nsIRDFService* RDFContentSinkImpl::gRDFService;
michael@0 235 nsIRDFContainerUtils* RDFContentSinkImpl::gRDFContainerUtils;
michael@0 236 nsIRDFResource* RDFContentSinkImpl::kRDF_type;
michael@0 237 nsIRDFResource* RDFContentSinkImpl::kRDF_instanceOf;
michael@0 238 nsIRDFResource* RDFContentSinkImpl::kRDF_Alt;
michael@0 239 nsIRDFResource* RDFContentSinkImpl::kRDF_Bag;
michael@0 240 nsIRDFResource* RDFContentSinkImpl::kRDF_Seq;
michael@0 241 nsIRDFResource* RDFContentSinkImpl::kRDF_nextVal;
michael@0 242
michael@0 243 #ifdef PR_LOGGING
michael@0 244 PRLogModuleInfo* RDFContentSinkImpl::gLog;
michael@0 245 #endif
michael@0 246
michael@0 247 ////////////////////////////////////////////////////////////////////////
michael@0 248
michael@0 249 #define RDF_ATOM(name_, value_) nsIAtom* RDFContentSinkImpl::name_;
michael@0 250 #include "nsRDFContentSinkAtomList.h"
michael@0 251 #undef RDF_ATOM
michael@0 252
michael@0 253 #define RDF_ATOM(name_, value_) NS_STATIC_ATOM_BUFFER(name_##_buffer, value_)
michael@0 254 #include "nsRDFContentSinkAtomList.h"
michael@0 255 #undef RDF_ATOM
michael@0 256
michael@0 257 static const nsStaticAtom rdf_atoms[] = {
michael@0 258 #define RDF_ATOM(name_, value_) NS_STATIC_ATOM(name_##_buffer, &RDFContentSinkImpl::name_),
michael@0 259 #include "nsRDFContentSinkAtomList.h"
michael@0 260 #undef RDF_ATOM
michael@0 261 };
michael@0 262
michael@0 263 RDFContentSinkImpl::RDFContentSinkImpl()
michael@0 264 : mText(nullptr),
michael@0 265 mTextLength(0),
michael@0 266 mTextSize(0),
michael@0 267 mState(eRDFContentSinkState_InProlog),
michael@0 268 mParseMode(eRDFContentSinkParseMode_Literal),
michael@0 269 mContextStack(nullptr),
michael@0 270 mDocumentURL(nullptr)
michael@0 271 {
michael@0 272 if (gRefCnt++ == 0) {
michael@0 273 NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
michael@0 274 nsresult rv = CallGetService(kRDFServiceCID, &gRDFService);
michael@0 275
michael@0 276 NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service");
michael@0 277 if (NS_SUCCEEDED(rv)) {
michael@0 278 rv = gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "type"),
michael@0 279 &kRDF_type);
michael@0 280 rv = gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "instanceOf"),
michael@0 281 &kRDF_instanceOf);
michael@0 282 rv = gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Alt"),
michael@0 283 &kRDF_Alt);
michael@0 284 rv = gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Bag"),
michael@0 285 &kRDF_Bag);
michael@0 286 rv = gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Seq"),
michael@0 287 &kRDF_Seq);
michael@0 288 rv = gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "nextVal"),
michael@0 289 &kRDF_nextVal);
michael@0 290 }
michael@0 291
michael@0 292 NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID);
michael@0 293 rv = CallGetService(kRDFContainerUtilsCID, &gRDFContainerUtils);
michael@0 294
michael@0 295 NS_RegisterStaticAtoms(rdf_atoms);
michael@0 296 }
michael@0 297
michael@0 298 #ifdef PR_LOGGING
michael@0 299 if (! gLog)
michael@0 300 gLog = PR_NewLogModule("nsRDFContentSink");
michael@0 301 #endif
michael@0 302 }
michael@0 303
michael@0 304
michael@0 305 RDFContentSinkImpl::~RDFContentSinkImpl()
michael@0 306 {
michael@0 307 #ifdef DEBUG_REFS
michael@0 308 --gInstanceCount;
michael@0 309 fprintf(stdout, "%d - RDF: RDFContentSinkImpl\n", gInstanceCount);
michael@0 310 #endif
michael@0 311
michael@0 312 NS_IF_RELEASE(mDocumentURL);
michael@0 313
michael@0 314 if (mContextStack) {
michael@0 315 PR_LOG(gLog, PR_LOG_WARNING,
michael@0 316 ("rdfxml: warning! unclosed tag"));
michael@0 317
michael@0 318 // XXX we should never need to do this, but, we'll write the
michael@0 319 // code all the same. If someone left the content stack dirty,
michael@0 320 // pop all the elements off the stack and release them.
michael@0 321 int32_t i = mContextStack->Length();
michael@0 322 while (0 < i--) {
michael@0 323 nsIRDFResource* resource = nullptr;
michael@0 324 RDFContentSinkState state;
michael@0 325 RDFContentSinkParseMode parseMode;
michael@0 326 PopContext(resource, state, parseMode);
michael@0 327
michael@0 328 #ifdef PR_LOGGING
michael@0 329 // print some fairly useless debugging info
michael@0 330 // XXX we should save line numbers on the context stack: this'd
michael@0 331 // be about 1000x more helpful.
michael@0 332 if (resource) {
michael@0 333 nsXPIDLCString uri;
michael@0 334 resource->GetValue(getter_Copies(uri));
michael@0 335 PR_LOG(gLog, PR_LOG_NOTICE,
michael@0 336 ("rdfxml: uri=%s", (const char*) uri));
michael@0 337 }
michael@0 338 #endif
michael@0 339
michael@0 340 NS_IF_RELEASE(resource);
michael@0 341 }
michael@0 342
michael@0 343 delete mContextStack;
michael@0 344 }
michael@0 345 moz_free(mText);
michael@0 346
michael@0 347
michael@0 348 if (--gRefCnt == 0) {
michael@0 349 NS_IF_RELEASE(gRDFService);
michael@0 350 NS_IF_RELEASE(gRDFContainerUtils);
michael@0 351 NS_IF_RELEASE(kRDF_type);
michael@0 352 NS_IF_RELEASE(kRDF_instanceOf);
michael@0 353 NS_IF_RELEASE(kRDF_Alt);
michael@0 354 NS_IF_RELEASE(kRDF_Bag);
michael@0 355 NS_IF_RELEASE(kRDF_Seq);
michael@0 356 NS_IF_RELEASE(kRDF_nextVal);
michael@0 357 }
michael@0 358 }
michael@0 359
michael@0 360 ////////////////////////////////////////////////////////////////////////
michael@0 361 // nsISupports interface
michael@0 362
michael@0 363 NS_IMPL_ADDREF(RDFContentSinkImpl)
michael@0 364 NS_IMPL_RELEASE(RDFContentSinkImpl)
michael@0 365
michael@0 366 NS_IMETHODIMP
michael@0 367 RDFContentSinkImpl::QueryInterface(REFNSIID iid, void** result)
michael@0 368 {
michael@0 369 NS_PRECONDITION(result, "null ptr");
michael@0 370 if (! result)
michael@0 371 return NS_ERROR_NULL_POINTER;
michael@0 372
michael@0 373 NS_DEFINE_IID(kIContentSinkIID, NS_ICONTENT_SINK_IID);
michael@0 374 NS_DEFINE_IID(kIExpatSinkIID, NS_IEXPATSINK_IID);
michael@0 375 NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
michael@0 376 NS_DEFINE_IID(kIXMLContentSinkIID, NS_IXMLCONTENT_SINK_IID);
michael@0 377 NS_DEFINE_IID(kIRDFContentSinkIID, NS_IRDFCONTENTSINK_IID);
michael@0 378
michael@0 379 *result = nullptr;
michael@0 380 if (iid.Equals(kIRDFContentSinkIID) ||
michael@0 381 iid.Equals(kIXMLContentSinkIID) ||
michael@0 382 iid.Equals(kIContentSinkIID) ||
michael@0 383 iid.Equals(kISupportsIID)) {
michael@0 384 *result = static_cast<nsIXMLContentSink*>(this);
michael@0 385 AddRef();
michael@0 386 return NS_OK;
michael@0 387 }
michael@0 388 else if (iid.Equals(kIExpatSinkIID)) {
michael@0 389 *result = static_cast<nsIExpatSink*>(this);
michael@0 390 AddRef();
michael@0 391 return NS_OK;
michael@0 392 }
michael@0 393 return NS_NOINTERFACE;
michael@0 394 }
michael@0 395
michael@0 396 NS_IMETHODIMP
michael@0 397 RDFContentSinkImpl::HandleStartElement(const char16_t *aName,
michael@0 398 const char16_t **aAtts,
michael@0 399 uint32_t aAttsCount,
michael@0 400 int32_t aIndex,
michael@0 401 uint32_t aLineNumber)
michael@0 402 {
michael@0 403 FlushText();
michael@0 404
michael@0 405 nsresult rv = NS_ERROR_UNEXPECTED; // XXX
michael@0 406
michael@0 407 RegisterNamespaces(aAtts);
michael@0 408
michael@0 409 switch (mState) {
michael@0 410 case eRDFContentSinkState_InProlog:
michael@0 411 rv = OpenRDF(aName);
michael@0 412 break;
michael@0 413
michael@0 414 case eRDFContentSinkState_InDocumentElement:
michael@0 415 rv = OpenObject(aName,aAtts);
michael@0 416 break;
michael@0 417
michael@0 418 case eRDFContentSinkState_InDescriptionElement:
michael@0 419 rv = OpenProperty(aName,aAtts);
michael@0 420 break;
michael@0 421
michael@0 422 case eRDFContentSinkState_InContainerElement:
michael@0 423 rv = OpenMember(aName,aAtts);
michael@0 424 break;
michael@0 425
michael@0 426 case eRDFContentSinkState_InPropertyElement:
michael@0 427 case eRDFContentSinkState_InMemberElement:
michael@0 428 rv = OpenValue(aName,aAtts);
michael@0 429 break;
michael@0 430
michael@0 431 case eRDFContentSinkState_InEpilog:
michael@0 432 PR_LOG(gLog, PR_LOG_WARNING,
michael@0 433 ("rdfxml: unexpected content in epilog at line %d",
michael@0 434 aLineNumber));
michael@0 435 break;
michael@0 436 }
michael@0 437
michael@0 438 return rv;
michael@0 439 }
michael@0 440
michael@0 441 NS_IMETHODIMP
michael@0 442 RDFContentSinkImpl::HandleEndElement(const char16_t *aName)
michael@0 443 {
michael@0 444 FlushText();
michael@0 445
michael@0 446 nsIRDFResource* resource;
michael@0 447 if (NS_FAILED(PopContext(resource, mState, mParseMode))) {
michael@0 448 // XXX parser didn't catch unmatched tags?
michael@0 449 #ifdef PR_LOGGING
michael@0 450 if (PR_LOG_TEST(gLog, PR_LOG_WARNING)) {
michael@0 451 nsAutoString tagStr(aName);
michael@0 452 char* tagCStr = ToNewCString(tagStr);
michael@0 453
michael@0 454 PR_LogPrint
michael@0 455 ("rdfxml: extra close tag '%s' at line %d",
michael@0 456 tagCStr, 0/*XXX fix me */);
michael@0 457
michael@0 458 NS_Free(tagCStr);
michael@0 459 }
michael@0 460 #endif
michael@0 461
michael@0 462 return NS_ERROR_UNEXPECTED; // XXX
michael@0 463 }
michael@0 464
michael@0 465 // If we've just popped a member or property element, _now_ is the
michael@0 466 // time to add that element to the graph.
michael@0 467 switch (mState) {
michael@0 468 case eRDFContentSinkState_InMemberElement:
michael@0 469 {
michael@0 470 nsCOMPtr<nsIRDFContainer> container;
michael@0 471 NS_NewRDFContainer(getter_AddRefs(container));
michael@0 472 container->Init(mDataSource, GetContextElement(1));
michael@0 473 container->AppendElement(resource);
michael@0 474 }
michael@0 475 break;
michael@0 476
michael@0 477 case eRDFContentSinkState_InPropertyElement:
michael@0 478 {
michael@0 479 mDataSource->Assert(GetContextElement(1), GetContextElement(0), resource, true);
michael@0 480 } break;
michael@0 481 default:
michael@0 482 break;
michael@0 483 }
michael@0 484
michael@0 485 if (mContextStack->IsEmpty())
michael@0 486 mState = eRDFContentSinkState_InEpilog;
michael@0 487
michael@0 488 NS_IF_RELEASE(resource);
michael@0 489 return NS_OK;
michael@0 490 }
michael@0 491
michael@0 492 NS_IMETHODIMP
michael@0 493 RDFContentSinkImpl::HandleComment(const char16_t *aName)
michael@0 494 {
michael@0 495 return NS_OK;
michael@0 496 }
michael@0 497
michael@0 498 NS_IMETHODIMP
michael@0 499 RDFContentSinkImpl::HandleCDataSection(const char16_t *aData,
michael@0 500 uint32_t aLength)
michael@0 501 {
michael@0 502 return aData ? AddText(aData, aLength) : NS_OK;
michael@0 503 }
michael@0 504
michael@0 505 NS_IMETHODIMP
michael@0 506 RDFContentSinkImpl::HandleDoctypeDecl(const nsAString & aSubset,
michael@0 507 const nsAString & aName,
michael@0 508 const nsAString & aSystemId,
michael@0 509 const nsAString & aPublicId,
michael@0 510 nsISupports* aCatalogData)
michael@0 511 {
michael@0 512 return NS_OK;
michael@0 513 }
michael@0 514
michael@0 515 NS_IMETHODIMP
michael@0 516 RDFContentSinkImpl::HandleCharacterData(const char16_t *aData,
michael@0 517 uint32_t aLength)
michael@0 518 {
michael@0 519 return aData ? AddText(aData, aLength) : NS_OK;
michael@0 520 }
michael@0 521
michael@0 522 NS_IMETHODIMP
michael@0 523 RDFContentSinkImpl::HandleProcessingInstruction(const char16_t *aTarget,
michael@0 524 const char16_t *aData)
michael@0 525 {
michael@0 526 return NS_OK;
michael@0 527 }
michael@0 528
michael@0 529 NS_IMETHODIMP
michael@0 530 RDFContentSinkImpl::HandleXMLDeclaration(const char16_t *aVersion,
michael@0 531 const char16_t *aEncoding,
michael@0 532 int32_t aStandalone)
michael@0 533 {
michael@0 534 return NS_OK;
michael@0 535 }
michael@0 536
michael@0 537 NS_IMETHODIMP
michael@0 538 RDFContentSinkImpl::ReportError(const char16_t* aErrorText,
michael@0 539 const char16_t* aSourceText,
michael@0 540 nsIScriptError *aError,
michael@0 541 bool *_retval)
michael@0 542 {
michael@0 543 NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!");
michael@0 544
michael@0 545 // The expat driver should report the error.
michael@0 546 *_retval = true;
michael@0 547 return NS_OK;
michael@0 548 }
michael@0 549
michael@0 550 ////////////////////////////////////////////////////////////////////////
michael@0 551 // nsIContentSink interface
michael@0 552
michael@0 553 NS_IMETHODIMP
michael@0 554 RDFContentSinkImpl::WillParse(void)
michael@0 555 {
michael@0 556 return NS_OK;
michael@0 557 }
michael@0 558
michael@0 559
michael@0 560 NS_IMETHODIMP
michael@0 561 RDFContentSinkImpl::WillBuildModel(nsDTDMode)
michael@0 562 {
michael@0 563 if (mDataSource) {
michael@0 564 nsCOMPtr<nsIRDFXMLSink> sink = do_QueryInterface(mDataSource);
michael@0 565 if (sink)
michael@0 566 return sink->BeginLoad();
michael@0 567 }
michael@0 568 return NS_OK;
michael@0 569 }
michael@0 570
michael@0 571 NS_IMETHODIMP
michael@0 572 RDFContentSinkImpl::DidBuildModel(bool aTerminated)
michael@0 573 {
michael@0 574 if (mDataSource) {
michael@0 575 nsCOMPtr<nsIRDFXMLSink> sink = do_QueryInterface(mDataSource);
michael@0 576 if (sink)
michael@0 577 return sink->EndLoad();
michael@0 578 }
michael@0 579 return NS_OK;
michael@0 580 }
michael@0 581
michael@0 582 NS_IMETHODIMP
michael@0 583 RDFContentSinkImpl::WillInterrupt(void)
michael@0 584 {
michael@0 585 if (mDataSource) {
michael@0 586 nsCOMPtr<nsIRDFXMLSink> sink = do_QueryInterface(mDataSource);
michael@0 587 if (sink)
michael@0 588 return sink->Interrupt();
michael@0 589 }
michael@0 590 return NS_OK;
michael@0 591 }
michael@0 592
michael@0 593 NS_IMETHODIMP
michael@0 594 RDFContentSinkImpl::WillResume(void)
michael@0 595 {
michael@0 596 if (mDataSource) {
michael@0 597 nsCOMPtr<nsIRDFXMLSink> sink = do_QueryInterface(mDataSource);
michael@0 598 if (sink)
michael@0 599 return sink->Resume();
michael@0 600 }
michael@0 601 return NS_OK;
michael@0 602 }
michael@0 603
michael@0 604 NS_IMETHODIMP
michael@0 605 RDFContentSinkImpl::SetParser(nsParserBase* aParser)
michael@0 606 {
michael@0 607 return NS_OK;
michael@0 608 }
michael@0 609
michael@0 610 ////////////////////////////////////////////////////////////////////////
michael@0 611 // nsIRDFContentSink interface
michael@0 612
michael@0 613 NS_IMETHODIMP
michael@0 614 RDFContentSinkImpl::Init(nsIURI* aURL)
michael@0 615 {
michael@0 616 NS_PRECONDITION(aURL != nullptr, "null ptr");
michael@0 617 if (! aURL)
michael@0 618 return NS_ERROR_NULL_POINTER;
michael@0 619
michael@0 620 mDocumentURL = aURL;
michael@0 621 NS_ADDREF(aURL);
michael@0 622
michael@0 623 mState = eRDFContentSinkState_InProlog;
michael@0 624 return NS_OK;
michael@0 625 }
michael@0 626
michael@0 627 NS_IMETHODIMP
michael@0 628 RDFContentSinkImpl::SetDataSource(nsIRDFDataSource* aDataSource)
michael@0 629 {
michael@0 630 NS_PRECONDITION(aDataSource != nullptr, "SetDataSource null ptr");
michael@0 631 mDataSource = aDataSource;
michael@0 632 NS_ASSERTION(mDataSource != nullptr,"Couldn't QI RDF DataSource");
michael@0 633 return NS_OK;
michael@0 634 }
michael@0 635
michael@0 636
michael@0 637 NS_IMETHODIMP
michael@0 638 RDFContentSinkImpl::GetDataSource(nsIRDFDataSource*& aDataSource)
michael@0 639 {
michael@0 640 aDataSource = mDataSource;
michael@0 641 NS_IF_ADDREF(aDataSource);
michael@0 642 return NS_OK;
michael@0 643 }
michael@0 644
michael@0 645 ////////////////////////////////////////////////////////////////////////
michael@0 646 // Text buffering
michael@0 647
michael@0 648 static bool
michael@0 649 rdf_IsDataInBuffer(char16_t* buffer, int32_t length)
michael@0 650 {
michael@0 651 for (int32_t i = 0; i < length; ++i) {
michael@0 652 if (buffer[i] == ' ' ||
michael@0 653 buffer[i] == '\t' ||
michael@0 654 buffer[i] == '\n' ||
michael@0 655 buffer[i] == '\r')
michael@0 656 continue;
michael@0 657
michael@0 658 return true;
michael@0 659 }
michael@0 660 return false;
michael@0 661 }
michael@0 662
michael@0 663 void
michael@0 664 RDFContentSinkImpl::ParseText(nsIRDFNode **aResult)
michael@0 665 {
michael@0 666 // XXXwaterson wasteful, but we'd need to make a copy anyway to be
michael@0 667 // able to call nsIRDFService::Get[Resource|Literal|...]().
michael@0 668 nsAutoString value;
michael@0 669 value.Append(mText, mTextLength);
michael@0 670 value.Trim(" \t\n\r");
michael@0 671
michael@0 672 switch (mParseMode) {
michael@0 673 case eRDFContentSinkParseMode_Literal:
michael@0 674 {
michael@0 675 nsIRDFLiteral *result;
michael@0 676 gRDFService->GetLiteral(value.get(), &result);
michael@0 677 *aResult = result;
michael@0 678 }
michael@0 679 break;
michael@0 680
michael@0 681 case eRDFContentSinkParseMode_Resource:
michael@0 682 {
michael@0 683 nsIRDFResource *result;
michael@0 684 gRDFService->GetUnicodeResource(value, &result);
michael@0 685 *aResult = result;
michael@0 686 }
michael@0 687 break;
michael@0 688
michael@0 689 case eRDFContentSinkParseMode_Int:
michael@0 690 {
michael@0 691 nsresult err;
michael@0 692 int32_t i = value.ToInteger(&err);
michael@0 693 nsIRDFInt *result;
michael@0 694 gRDFService->GetIntLiteral(i, &result);
michael@0 695 *aResult = result;
michael@0 696 }
michael@0 697 break;
michael@0 698
michael@0 699 case eRDFContentSinkParseMode_Date:
michael@0 700 {
michael@0 701 PRTime t = rdf_ParseDate(nsDependentCString(NS_LossyConvertUTF16toASCII(value).get(), value.Length()));
michael@0 702 nsIRDFDate *result;
michael@0 703 gRDFService->GetDateLiteral(t, &result);
michael@0 704 *aResult = result;
michael@0 705 }
michael@0 706 break;
michael@0 707
michael@0 708 default:
michael@0 709 NS_NOTREACHED("unknown parse type");
michael@0 710 break;
michael@0 711 }
michael@0 712 }
michael@0 713
michael@0 714 nsresult
michael@0 715 RDFContentSinkImpl::FlushText()
michael@0 716 {
michael@0 717 nsresult rv = NS_OK;
michael@0 718 if (0 != mTextLength) {
michael@0 719 if (rdf_IsDataInBuffer(mText, mTextLength)) {
michael@0 720 // XXX if there's anything but whitespace, then we'll
michael@0 721 // create a text node.
michael@0 722
michael@0 723 switch (mState) {
michael@0 724 case eRDFContentSinkState_InMemberElement: {
michael@0 725 nsCOMPtr<nsIRDFNode> node;
michael@0 726 ParseText(getter_AddRefs(node));
michael@0 727
michael@0 728 nsCOMPtr<nsIRDFContainer> container;
michael@0 729 NS_NewRDFContainer(getter_AddRefs(container));
michael@0 730 container->Init(mDataSource, GetContextElement(1));
michael@0 731
michael@0 732 container->AppendElement(node);
michael@0 733 } break;
michael@0 734
michael@0 735 case eRDFContentSinkState_InPropertyElement: {
michael@0 736 nsCOMPtr<nsIRDFNode> node;
michael@0 737 ParseText(getter_AddRefs(node));
michael@0 738
michael@0 739 mDataSource->Assert(GetContextElement(1), GetContextElement(0), node, true);
michael@0 740 } break;
michael@0 741
michael@0 742 default:
michael@0 743 // just ignore it
michael@0 744 break;
michael@0 745 }
michael@0 746 }
michael@0 747 mTextLength = 0;
michael@0 748 }
michael@0 749 return rv;
michael@0 750 }
michael@0 751
michael@0 752
michael@0 753 nsresult
michael@0 754 RDFContentSinkImpl::AddText(const char16_t* aText, int32_t aLength)
michael@0 755 {
michael@0 756 // Create buffer when we first need it
michael@0 757 if (0 == mTextSize) {
michael@0 758 mText = (char16_t *) moz_malloc(sizeof(char16_t) * 4096);
michael@0 759 if (!mText) {
michael@0 760 return NS_ERROR_OUT_OF_MEMORY;
michael@0 761 }
michael@0 762 mTextSize = 4096;
michael@0 763 }
michael@0 764
michael@0 765 // Copy data from string into our buffer; grow the buffer as needed.
michael@0 766 // It never shrinks, but since the content sink doesn't stick around,
michael@0 767 // this shouldn't be a bloat issue.
michael@0 768 int32_t amount = mTextSize - mTextLength;
michael@0 769 if (amount < aLength) {
michael@0 770 // Grow the buffer by at least a factor of two to prevent thrashing.
michael@0 771 // Since PR_REALLOC will leave mText intact if the call fails,
michael@0 772 // don't clobber mText or mTextSize until the new mem is allocated.
michael@0 773 int32_t newSize = (2 * mTextSize > (mTextSize + aLength)) ?
michael@0 774 (2 * mTextSize) : (mTextSize + aLength);
michael@0 775 char16_t* newText =
michael@0 776 (char16_t *) moz_realloc(mText, sizeof(char16_t) * newSize);
michael@0 777 if (!newText)
michael@0 778 return NS_ERROR_OUT_OF_MEMORY;
michael@0 779 mTextSize = newSize;
michael@0 780 mText = newText;
michael@0 781 }
michael@0 782 memcpy(&mText[mTextLength], aText, sizeof(char16_t) * aLength);
michael@0 783 mTextLength += aLength;
michael@0 784
michael@0 785 return NS_OK;
michael@0 786 }
michael@0 787
michael@0 788 bool
michael@0 789 rdf_RequiresAbsoluteURI(const nsString& uri)
michael@0 790 {
michael@0 791 // cheap shot at figuring out if this requires an absolute url translation
michael@0 792 return !(StringBeginsWith(uri, NS_LITERAL_STRING("urn:")) ||
michael@0 793 StringBeginsWith(uri, NS_LITERAL_STRING("chrome:")));
michael@0 794 }
michael@0 795
michael@0 796 nsresult
michael@0 797 RDFContentSinkImpl::GetIdAboutAttribute(const char16_t** aAttributes,
michael@0 798 nsIRDFResource** aResource,
michael@0 799 bool* aIsAnonymous)
michael@0 800 {
michael@0 801 // This corresponds to the dirty work of production [6.5]
michael@0 802 nsresult rv = NS_OK;
michael@0 803
michael@0 804 nsAutoString nodeID;
michael@0 805
michael@0 806 nsCOMPtr<nsIAtom> localName;
michael@0 807 for (; *aAttributes; aAttributes += 2) {
michael@0 808 const nsDependentSubstring& nameSpaceURI =
michael@0 809 SplitExpatName(aAttributes[0], getter_AddRefs(localName));
michael@0 810
michael@0 811 // We'll accept either `ID' or `rdf:ID' (ibid with `about' or
michael@0 812 // `rdf:about') in the spirit of being liberal towards the
michael@0 813 // input that we receive.
michael@0 814 if (!nameSpaceURI.IsEmpty() &&
michael@0 815 !nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI)) {
michael@0 816 continue;
michael@0 817 }
michael@0 818
michael@0 819 // XXX you can't specify both, but we'll just pick up the
michael@0 820 // first thing that was specified and ignore the other.
michael@0 821
michael@0 822 if (localName == kAboutAtom) {
michael@0 823 if (aIsAnonymous)
michael@0 824 *aIsAnonymous = false;
michael@0 825
michael@0 826 nsAutoString relURI(aAttributes[1]);
michael@0 827 if (rdf_RequiresAbsoluteURI(relURI)) {
michael@0 828 nsAutoCString uri;
michael@0 829 rv = mDocumentURL->Resolve(NS_ConvertUTF16toUTF8(aAttributes[1]), uri);
michael@0 830 if (NS_FAILED(rv)) return rv;
michael@0 831
michael@0 832 return gRDFService->GetResource(uri,
michael@0 833 aResource);
michael@0 834 }
michael@0 835 return gRDFService->GetResource(NS_ConvertUTF16toUTF8(aAttributes[1]),
michael@0 836 aResource);
michael@0 837 }
michael@0 838 else if (localName == kIdAtom) {
michael@0 839 if (aIsAnonymous)
michael@0 840 *aIsAnonymous = false;
michael@0 841 // In the spirit of leniency, we do not bother trying to
michael@0 842 // enforce that this be a valid "XML Name" (see
michael@0 843 // http://www.w3.org/TR/REC-xml#NT-Nmtoken), as per
michael@0 844 // 6.21. If we wanted to, this would be where to do it.
michael@0 845
michael@0 846 // Construct an in-line resource whose URI is the
michael@0 847 // document's URI plus the XML name specified in the ID
michael@0 848 // attribute.
michael@0 849 nsAutoCString name;
michael@0 850 nsAutoCString ref('#');
michael@0 851 AppendUTF16toUTF8(aAttributes[1], ref);
michael@0 852
michael@0 853 rv = mDocumentURL->Resolve(ref, name);
michael@0 854 if (NS_FAILED(rv)) return rv;
michael@0 855
michael@0 856 return gRDFService->GetResource(name, aResource);
michael@0 857 }
michael@0 858 else if (localName == kNodeIdAtom) {
michael@0 859 nodeID.Assign(aAttributes[1]);
michael@0 860 }
michael@0 861 else if (localName == kAboutEachAtom) {
michael@0 862 // XXX we don't deal with aboutEach...
michael@0 863 //PR_LOG(gLog, PR_LOG_WARNING,
michael@0 864 // ("rdfxml: ignoring aboutEach at line %d",
michael@0 865 // aNode.GetSourceLineNumber()));
michael@0 866 }
michael@0 867 }
michael@0 868
michael@0 869 // Otherwise, we couldn't find anything, so just gensym one...
michael@0 870 if (aIsAnonymous)
michael@0 871 *aIsAnonymous = true;
michael@0 872
michael@0 873 // If nodeID is present, check if we already know about it. If we've seen
michael@0 874 // the nodeID before, use the same resource, otherwise generate a new one.
michael@0 875 if (!nodeID.IsEmpty()) {
michael@0 876 mNodeIDMap.Get(nodeID,aResource);
michael@0 877
michael@0 878 if (!*aResource) {
michael@0 879 rv = gRDFService->GetAnonymousResource(aResource);
michael@0 880 mNodeIDMap.Put(nodeID,*aResource);
michael@0 881 }
michael@0 882 }
michael@0 883 else {
michael@0 884 rv = gRDFService->GetAnonymousResource(aResource);
michael@0 885 }
michael@0 886
michael@0 887 return rv;
michael@0 888 }
michael@0 889
michael@0 890 nsresult
michael@0 891 RDFContentSinkImpl::GetResourceAttribute(const char16_t** aAttributes,
michael@0 892 nsIRDFResource** aResource)
michael@0 893 {
michael@0 894 nsCOMPtr<nsIAtom> localName;
michael@0 895
michael@0 896 nsAutoString nodeID;
michael@0 897
michael@0 898 for (; *aAttributes; aAttributes += 2) {
michael@0 899 const nsDependentSubstring& nameSpaceURI =
michael@0 900 SplitExpatName(aAttributes[0], getter_AddRefs(localName));
michael@0 901
michael@0 902 // We'll accept `resource' or `rdf:resource', under the spirit
michael@0 903 // that we should be liberal towards the input that we
michael@0 904 // receive.
michael@0 905 if (!nameSpaceURI.IsEmpty() &&
michael@0 906 !nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI)) {
michael@0 907 continue;
michael@0 908 }
michael@0 909
michael@0 910 // XXX you can't specify both, but we'll just pick up the
michael@0 911 // first thing that was specified and ignore the other.
michael@0 912
michael@0 913 if (localName == kResourceAtom) {
michael@0 914 // XXX Take the URI and make it fully qualified by
michael@0 915 // sticking it into the document's URL. This may not be
michael@0 916 // appropriate...
michael@0 917 nsAutoString relURI(aAttributes[1]);
michael@0 918 if (rdf_RequiresAbsoluteURI(relURI)) {
michael@0 919 nsresult rv;
michael@0 920 nsAutoCString uri;
michael@0 921
michael@0 922 rv = mDocumentURL->Resolve(NS_ConvertUTF16toUTF8(aAttributes[1]), uri);
michael@0 923 if (NS_FAILED(rv)) return rv;
michael@0 924
michael@0 925 return gRDFService->GetResource(uri, aResource);
michael@0 926 }
michael@0 927 return gRDFService->GetResource(NS_ConvertUTF16toUTF8(aAttributes[1]),
michael@0 928 aResource);
michael@0 929 }
michael@0 930 else if (localName == kNodeIdAtom) {
michael@0 931 nodeID.Assign(aAttributes[1]);
michael@0 932 }
michael@0 933 }
michael@0 934
michael@0 935 // If nodeID is present, check if we already know about it. If we've seen
michael@0 936 // the nodeID before, use the same resource, otherwise generate a new one.
michael@0 937 if (!nodeID.IsEmpty()) {
michael@0 938 mNodeIDMap.Get(nodeID,aResource);
michael@0 939
michael@0 940 if (!*aResource) {
michael@0 941 nsresult rv;
michael@0 942 rv = gRDFService->GetAnonymousResource(aResource);
michael@0 943 if (NS_FAILED(rv)) {
michael@0 944 return rv;
michael@0 945 }
michael@0 946 mNodeIDMap.Put(nodeID,*aResource);
michael@0 947 }
michael@0 948 return NS_OK;
michael@0 949 }
michael@0 950
michael@0 951 return NS_ERROR_FAILURE;
michael@0 952 }
michael@0 953
michael@0 954 nsresult
michael@0 955 RDFContentSinkImpl::AddProperties(const char16_t** aAttributes,
michael@0 956 nsIRDFResource* aSubject,
michael@0 957 int32_t* aCount)
michael@0 958 {
michael@0 959 if (aCount)
michael@0 960 *aCount = 0;
michael@0 961
michael@0 962 nsCOMPtr<nsIAtom> localName;
michael@0 963 for (; *aAttributes; aAttributes += 2) {
michael@0 964 const nsDependentSubstring& nameSpaceURI =
michael@0 965 SplitExpatName(aAttributes[0], getter_AddRefs(localName));
michael@0 966
michael@0 967 // skip 'xmlns' directives, these are "meta" information
michael@0 968 if (nameSpaceURI.EqualsLiteral("http://www.w3.org/2000/xmlns/")) {
michael@0 969 continue;
michael@0 970 }
michael@0 971
michael@0 972 // skip `about', `ID', `resource', and 'nodeID' attributes (either with or
michael@0 973 // without the `rdf:' prefix); these are all "special" and
michael@0 974 // should've been dealt with by the caller.
michael@0 975 if (localName == kAboutAtom || localName == kIdAtom ||
michael@0 976 localName == kResourceAtom || localName == kNodeIdAtom) {
michael@0 977 if (nameSpaceURI.IsEmpty() ||
michael@0 978 nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI))
michael@0 979 continue;
michael@0 980 }
michael@0 981
michael@0 982 // Skip `parseType', `RDF:parseType', and `NC:parseType'. This
michael@0 983 // is meta-information that will be handled in SetParseMode.
michael@0 984 if (localName == kParseTypeAtom) {
michael@0 985 if (nameSpaceURI.IsEmpty() ||
michael@0 986 nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI) ||
michael@0 987 nameSpaceURI.EqualsLiteral(NC_NAMESPACE_URI)) {
michael@0 988 continue;
michael@0 989 }
michael@0 990 }
michael@0 991
michael@0 992 NS_ConvertUTF16toUTF8 propertyStr(nameSpaceURI);
michael@0 993 propertyStr.Append(nsAtomCString(localName));
michael@0 994
michael@0 995 // Add the assertion to RDF
michael@0 996 nsCOMPtr<nsIRDFResource> property;
michael@0 997 gRDFService->GetResource(propertyStr, getter_AddRefs(property));
michael@0 998
michael@0 999 nsCOMPtr<nsIRDFLiteral> target;
michael@0 1000 gRDFService->GetLiteral(aAttributes[1],
michael@0 1001 getter_AddRefs(target));
michael@0 1002
michael@0 1003 mDataSource->Assert(aSubject, property, target, true);
michael@0 1004 }
michael@0 1005 return NS_OK;
michael@0 1006 }
michael@0 1007
michael@0 1008 void
michael@0 1009 RDFContentSinkImpl::SetParseMode(const char16_t **aAttributes)
michael@0 1010 {
michael@0 1011 nsCOMPtr<nsIAtom> localName;
michael@0 1012 for (; *aAttributes; aAttributes += 2) {
michael@0 1013 const nsDependentSubstring& nameSpaceURI =
michael@0 1014 SplitExpatName(aAttributes[0], getter_AddRefs(localName));
michael@0 1015
michael@0 1016 if (localName == kParseTypeAtom) {
michael@0 1017 nsDependentString v(aAttributes[1]);
michael@0 1018
michael@0 1019 if (nameSpaceURI.IsEmpty() ||
michael@0 1020 nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI)) {
michael@0 1021 if (v.EqualsLiteral("Resource"))
michael@0 1022 mParseMode = eRDFContentSinkParseMode_Resource;
michael@0 1023
michael@0 1024 break;
michael@0 1025 }
michael@0 1026 else if (nameSpaceURI.EqualsLiteral(NC_NAMESPACE_URI)) {
michael@0 1027 if (v.EqualsLiteral("Date"))
michael@0 1028 mParseMode = eRDFContentSinkParseMode_Date;
michael@0 1029 else if (v.EqualsLiteral("Integer"))
michael@0 1030 mParseMode = eRDFContentSinkParseMode_Int;
michael@0 1031
michael@0 1032 break;
michael@0 1033 }
michael@0 1034 }
michael@0 1035 }
michael@0 1036 }
michael@0 1037
michael@0 1038 ////////////////////////////////////////////////////////////////////////
michael@0 1039 // RDF-specific routines used to build the model
michael@0 1040
michael@0 1041 nsresult
michael@0 1042 RDFContentSinkImpl::OpenRDF(const char16_t* aName)
michael@0 1043 {
michael@0 1044 // ensure that we're actually reading RDF by making sure that the
michael@0 1045 // opening tag is <rdf:RDF>, where "rdf:" corresponds to whatever
michael@0 1046 // they've declared the standard RDF namespace to be.
michael@0 1047 nsCOMPtr<nsIAtom> localName;
michael@0 1048 const nsDependentSubstring& nameSpaceURI =
michael@0 1049 SplitExpatName(aName, getter_AddRefs(localName));
michael@0 1050
michael@0 1051 if (!nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI) || localName != kRDFAtom) {
michael@0 1052 // PR_LOG(gLog, PR_LOG_ALWAYS,
michael@0 1053 // ("rdfxml: expected RDF:RDF at line %d",
michael@0 1054 // aNode.GetSourceLineNumber()));
michael@0 1055
michael@0 1056 return NS_ERROR_UNEXPECTED;
michael@0 1057 }
michael@0 1058
michael@0 1059 PushContext(nullptr, mState, mParseMode);
michael@0 1060 mState = eRDFContentSinkState_InDocumentElement;
michael@0 1061 return NS_OK;
michael@0 1062 }
michael@0 1063
michael@0 1064 nsresult
michael@0 1065 RDFContentSinkImpl::OpenObject(const char16_t* aName,
michael@0 1066 const char16_t** aAttributes)
michael@0 1067 {
michael@0 1068 // an "object" non-terminal is either a "description", a "typed
michael@0 1069 // node", or a "container", so this change the content sink's
michael@0 1070 // state appropriately.
michael@0 1071 nsCOMPtr<nsIAtom> localName;
michael@0 1072 const nsDependentSubstring& nameSpaceURI =
michael@0 1073 SplitExpatName(aName, getter_AddRefs(localName));
michael@0 1074
michael@0 1075 // Figure out the URI of this object, and create an RDF node for it.
michael@0 1076 nsCOMPtr<nsIRDFResource> source;
michael@0 1077 GetIdAboutAttribute(aAttributes, getter_AddRefs(source));
michael@0 1078
michael@0 1079 // If there is no `ID' or `about', then there's not much we can do.
michael@0 1080 if (! source)
michael@0 1081 return NS_ERROR_FAILURE;
michael@0 1082
michael@0 1083 // Push the element onto the context stack
michael@0 1084 PushContext(source, mState, mParseMode);
michael@0 1085
michael@0 1086 // Now figure out what kind of state transition we need to
michael@0 1087 // make. We'll either be going into a mode where we parse a
michael@0 1088 // description or a container.
michael@0 1089 bool isaTypedNode = true;
michael@0 1090
michael@0 1091 if (nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI)) {
michael@0 1092 isaTypedNode = false;
michael@0 1093
michael@0 1094 if (localName == kDescriptionAtom) {
michael@0 1095 // it's a description
michael@0 1096 mState = eRDFContentSinkState_InDescriptionElement;
michael@0 1097 }
michael@0 1098 else if (localName == kBagAtom) {
michael@0 1099 // it's a bag container
michael@0 1100 InitContainer(kRDF_Bag, source);
michael@0 1101 mState = eRDFContentSinkState_InContainerElement;
michael@0 1102 }
michael@0 1103 else if (localName == kSeqAtom) {
michael@0 1104 // it's a seq container
michael@0 1105 InitContainer(kRDF_Seq, source);
michael@0 1106 mState = eRDFContentSinkState_InContainerElement;
michael@0 1107 }
michael@0 1108 else if (localName == kAltAtom) {
michael@0 1109 // it's an alt container
michael@0 1110 InitContainer(kRDF_Alt, source);
michael@0 1111 mState = eRDFContentSinkState_InContainerElement;
michael@0 1112 }
michael@0 1113 else {
michael@0 1114 // heh, that's not *in* the RDF namespace: just treat it
michael@0 1115 // like a typed node
michael@0 1116 isaTypedNode = true;
michael@0 1117 }
michael@0 1118 }
michael@0 1119
michael@0 1120 if (isaTypedNode) {
michael@0 1121 NS_ConvertUTF16toUTF8 typeStr(nameSpaceURI);
michael@0 1122 typeStr.Append(nsAtomCString(localName));
michael@0 1123
michael@0 1124 nsCOMPtr<nsIRDFResource> type;
michael@0 1125 nsresult rv = gRDFService->GetResource(typeStr, getter_AddRefs(type));
michael@0 1126 if (NS_FAILED(rv)) return rv;
michael@0 1127
michael@0 1128 rv = mDataSource->Assert(source, kRDF_type, type, true);
michael@0 1129 if (NS_FAILED(rv)) return rv;
michael@0 1130
michael@0 1131 mState = eRDFContentSinkState_InDescriptionElement;
michael@0 1132 }
michael@0 1133
michael@0 1134 AddProperties(aAttributes, source);
michael@0 1135 return NS_OK;
michael@0 1136 }
michael@0 1137
michael@0 1138 nsresult
michael@0 1139 RDFContentSinkImpl::OpenProperty(const char16_t* aName, const char16_t** aAttributes)
michael@0 1140 {
michael@0 1141 nsresult rv;
michael@0 1142
michael@0 1143 // an "object" non-terminal is either a "description", a "typed
michael@0 1144 // node", or a "container", so this change the content sink's
michael@0 1145 // state appropriately.
michael@0 1146 nsCOMPtr<nsIAtom> localName;
michael@0 1147 const nsDependentSubstring& nameSpaceURI =
michael@0 1148 SplitExpatName(aName, getter_AddRefs(localName));
michael@0 1149
michael@0 1150 NS_ConvertUTF16toUTF8 propertyStr(nameSpaceURI);
michael@0 1151 propertyStr.Append(nsAtomCString(localName));
michael@0 1152
michael@0 1153 nsCOMPtr<nsIRDFResource> property;
michael@0 1154 rv = gRDFService->GetResource(propertyStr, getter_AddRefs(property));
michael@0 1155 if (NS_FAILED(rv)) return rv;
michael@0 1156
michael@0 1157 // See if they've specified a 'resource' attribute, in which case
michael@0 1158 // they mean *that* to be the object of this property.
michael@0 1159 nsCOMPtr<nsIRDFResource> target;
michael@0 1160 GetResourceAttribute(aAttributes, getter_AddRefs(target));
michael@0 1161
michael@0 1162 bool isAnonymous = false;
michael@0 1163
michael@0 1164 if (! target) {
michael@0 1165 // See if an 'ID' attribute has been specified, in which case
michael@0 1166 // this corresponds to the fourth form of [6.12].
michael@0 1167
michael@0 1168 // XXX strictly speaking, we should reject the RDF/XML as
michael@0 1169 // invalid if they've specified both an 'ID' and a 'resource'
michael@0 1170 // attribute. Bah.
michael@0 1171
michael@0 1172 // XXX strictly speaking, 'about=' isn't allowed here, but
michael@0 1173 // what the hell.
michael@0 1174 GetIdAboutAttribute(aAttributes, getter_AddRefs(target), &isAnonymous);
michael@0 1175 }
michael@0 1176
michael@0 1177 if (target) {
michael@0 1178 // They specified an inline resource for the value of this
michael@0 1179 // property. Create an RDF resource for the inline resource
michael@0 1180 // URI, add the properties to it, and attach the inline
michael@0 1181 // resource to its parent.
michael@0 1182 int32_t count;
michael@0 1183 rv = AddProperties(aAttributes, target, &count);
michael@0 1184 NS_ASSERTION(NS_SUCCEEDED(rv), "problem adding properties");
michael@0 1185 if (NS_FAILED(rv)) return rv;
michael@0 1186
michael@0 1187 if (count || !isAnonymous) {
michael@0 1188 // If the resource was "anonymous" (i.e., they hadn't
michael@0 1189 // explicitly set an ID or resource attribute), then we'll
michael@0 1190 // only assert this property from the context element *if*
michael@0 1191 // there were properties specified on the anonymous
michael@0 1192 // resource.
michael@0 1193 rv = mDataSource->Assert(GetContextElement(0), property, target, true);
michael@0 1194 if (NS_FAILED(rv)) return rv;
michael@0 1195 }
michael@0 1196
michael@0 1197 // XXX Technically, we should _not_ fall through here and push
michael@0 1198 // the element onto the stack: this is supposed to be a closed
michael@0 1199 // node. But right now I'm lazy and the code will just Do The
michael@0 1200 // Right Thing so long as the RDF is well-formed.
michael@0 1201 }
michael@0 1202
michael@0 1203 // Push the element onto the context stack and change state.
michael@0 1204 PushContext(property, mState, mParseMode);
michael@0 1205 mState = eRDFContentSinkState_InPropertyElement;
michael@0 1206 SetParseMode(aAttributes);
michael@0 1207
michael@0 1208 return NS_OK;
michael@0 1209 }
michael@0 1210
michael@0 1211 nsresult
michael@0 1212 RDFContentSinkImpl::OpenMember(const char16_t* aName,
michael@0 1213 const char16_t** aAttributes)
michael@0 1214 {
michael@0 1215 // ensure that we're actually reading a member element by making
michael@0 1216 // sure that the opening tag is <rdf:li>, where "rdf:" corresponds
michael@0 1217 // to whatever they've declared the standard RDF namespace to be.
michael@0 1218 nsresult rv;
michael@0 1219
michael@0 1220 nsCOMPtr<nsIAtom> localName;
michael@0 1221 const nsDependentSubstring& nameSpaceURI =
michael@0 1222 SplitExpatName(aName, getter_AddRefs(localName));
michael@0 1223
michael@0 1224 if (!nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI) ||
michael@0 1225 localName != kLiAtom) {
michael@0 1226 PR_LOG(gLog, PR_LOG_ALWAYS,
michael@0 1227 ("rdfxml: expected RDF:li at line %d",
michael@0 1228 -1)); // XXX pass in line number
michael@0 1229
michael@0 1230 return NS_ERROR_UNEXPECTED;
michael@0 1231 }
michael@0 1232
michael@0 1233 // The parent element is the container.
michael@0 1234 nsIRDFResource* container = GetContextElement(0);
michael@0 1235 if (! container)
michael@0 1236 return NS_ERROR_NULL_POINTER;
michael@0 1237
michael@0 1238 nsIRDFResource* resource;
michael@0 1239 if (NS_SUCCEEDED(rv = GetResourceAttribute(aAttributes, &resource))) {
michael@0 1240 // Okay, this node has an RDF:resource="..." attribute. That
michael@0 1241 // means that it's a "referenced item," as covered in [6.29].
michael@0 1242 nsCOMPtr<nsIRDFContainer> c;
michael@0 1243 NS_NewRDFContainer(getter_AddRefs(c));
michael@0 1244 c->Init(mDataSource, container);
michael@0 1245 c->AppendElement(resource);
michael@0 1246
michael@0 1247 // XXX Technically, we should _not_ fall through here and push
michael@0 1248 // the element onto the stack: this is supposed to be a closed
michael@0 1249 // node. But right now I'm lazy and the code will just Do The
michael@0 1250 // Right Thing so long as the RDF is well-formed.
michael@0 1251 NS_RELEASE(resource);
michael@0 1252 }
michael@0 1253
michael@0 1254 // Change state. Pushing a null context element is a bit weird,
michael@0 1255 // but the idea is that there really is _no_ context "property".
michael@0 1256 // The contained element will use nsIRDFContainer::AppendElement() to add
michael@0 1257 // the element to the container, which requires only the container
michael@0 1258 // and the element to be added.
michael@0 1259 PushContext(nullptr, mState, mParseMode);
michael@0 1260 mState = eRDFContentSinkState_InMemberElement;
michael@0 1261 SetParseMode(aAttributes);
michael@0 1262
michael@0 1263 return NS_OK;
michael@0 1264 }
michael@0 1265
michael@0 1266
michael@0 1267 nsresult
michael@0 1268 RDFContentSinkImpl::OpenValue(const char16_t* aName, const char16_t** aAttributes)
michael@0 1269 {
michael@0 1270 // a "value" can either be an object or a string: we'll only get
michael@0 1271 // *here* if it's an object, as raw text is added as a leaf.
michael@0 1272 return OpenObject(aName,aAttributes);
michael@0 1273 }
michael@0 1274
michael@0 1275 ////////////////////////////////////////////////////////////////////////
michael@0 1276 // namespace resolution
michael@0 1277 void
michael@0 1278 RDFContentSinkImpl::RegisterNamespaces(const char16_t **aAttributes)
michael@0 1279 {
michael@0 1280 nsCOMPtr<nsIRDFXMLSink> sink = do_QueryInterface(mDataSource);
michael@0 1281 if (!sink) {
michael@0 1282 return;
michael@0 1283 }
michael@0 1284 NS_NAMED_LITERAL_STRING(xmlns, "http://www.w3.org/2000/xmlns/");
michael@0 1285 for (; *aAttributes; aAttributes += 2) {
michael@0 1286 // check the namespace
michael@0 1287 const char16_t* attr = aAttributes[0];
michael@0 1288 const char16_t* xmlnsP = xmlns.BeginReading();
michael@0 1289 while (*attr == *xmlnsP) {
michael@0 1290 ++attr;
michael@0 1291 ++xmlnsP;
michael@0 1292 }
michael@0 1293 if (*attr != 0xFFFF ||
michael@0 1294 xmlnsP != xmlns.EndReading()) {
michael@0 1295 continue;
michael@0 1296 }
michael@0 1297 // get the localname (or "xmlns" for the default namespace)
michael@0 1298 const char16_t* endLocal = ++attr;
michael@0 1299 while (*endLocal && *endLocal != 0xFFFF) {
michael@0 1300 ++endLocal;
michael@0 1301 }
michael@0 1302 nsDependentSubstring lname(attr, endLocal);
michael@0 1303 nsCOMPtr<nsIAtom> preferred = do_GetAtom(lname);
michael@0 1304 if (preferred == kXMLNSAtom) {
michael@0 1305 preferred = nullptr;
michael@0 1306 }
michael@0 1307 sink->AddNameSpace(preferred, nsDependentString(aAttributes[1]));
michael@0 1308 }
michael@0 1309 }
michael@0 1310
michael@0 1311 ////////////////////////////////////////////////////////////////////////
michael@0 1312 // Qualified name resolution
michael@0 1313
michael@0 1314 const nsDependentSubstring
michael@0 1315 RDFContentSinkImpl::SplitExpatName(const char16_t *aExpatName,
michael@0 1316 nsIAtom **aLocalName)
michael@0 1317 {
michael@0 1318 /**
michael@0 1319 * Expat can send the following:
michael@0 1320 * localName
michael@0 1321 * namespaceURI<separator>localName
michael@0 1322 * namespaceURI<separator>localName<separator>prefix
michael@0 1323 *
michael@0 1324 * and we use 0xFFFF for the <separator>.
michael@0 1325 *
michael@0 1326 */
michael@0 1327
michael@0 1328 const char16_t *uriEnd = aExpatName;
michael@0 1329 const char16_t *nameStart = aExpatName;
michael@0 1330 const char16_t *pos;
michael@0 1331 for (pos = aExpatName; *pos; ++pos) {
michael@0 1332 if (*pos == 0xFFFF) {
michael@0 1333 if (uriEnd != aExpatName) {
michael@0 1334 break;
michael@0 1335 }
michael@0 1336
michael@0 1337 uriEnd = pos;
michael@0 1338 nameStart = pos + 1;
michael@0 1339 }
michael@0 1340 }
michael@0 1341
michael@0 1342 const nsDependentSubstring& nameSpaceURI = Substring(aExpatName, uriEnd);
michael@0 1343 *aLocalName = NS_NewAtom(Substring(nameStart, pos)).take();
michael@0 1344 return nameSpaceURI;
michael@0 1345 }
michael@0 1346
michael@0 1347 nsresult
michael@0 1348 RDFContentSinkImpl::InitContainer(nsIRDFResource* aContainerType, nsIRDFResource* aContainer)
michael@0 1349 {
michael@0 1350 // Do the right kind of initialization based on the container
michael@0 1351 // 'type' resource, and the state of the container (i.e., 'make' a
michael@0 1352 // new container vs. 'reinitialize' the container).
michael@0 1353 nsresult rv;
michael@0 1354
michael@0 1355 static const ContainerInfo gContainerInfo[] = {
michael@0 1356 { &RDFContentSinkImpl::kRDF_Alt, &nsIRDFContainerUtils::IsAlt, &nsIRDFContainerUtils::MakeAlt },
michael@0 1357 { &RDFContentSinkImpl::kRDF_Bag, &nsIRDFContainerUtils::IsBag, &nsIRDFContainerUtils::MakeBag },
michael@0 1358 { &RDFContentSinkImpl::kRDF_Seq, &nsIRDFContainerUtils::IsSeq, &nsIRDFContainerUtils::MakeSeq },
michael@0 1359 { 0, 0, 0 },
michael@0 1360 };
michael@0 1361
michael@0 1362 for (const ContainerInfo* info = gContainerInfo; info->mType != 0; ++info) {
michael@0 1363 if (*info->mType != aContainerType)
michael@0 1364 continue;
michael@0 1365
michael@0 1366 bool isContainer;
michael@0 1367 rv = (gRDFContainerUtils->*(info->mTestFn))(mDataSource, aContainer, &isContainer);
michael@0 1368 if (isContainer) {
michael@0 1369 rv = ReinitContainer(aContainerType, aContainer);
michael@0 1370 }
michael@0 1371 else {
michael@0 1372 rv = (gRDFContainerUtils->*(info->mMakeFn))(mDataSource, aContainer, nullptr);
michael@0 1373 }
michael@0 1374 return rv;
michael@0 1375 }
michael@0 1376
michael@0 1377 NS_NOTREACHED("not an RDF container type");
michael@0 1378 return NS_ERROR_FAILURE;
michael@0 1379 }
michael@0 1380
michael@0 1381
michael@0 1382
michael@0 1383 nsresult
michael@0 1384 RDFContentSinkImpl::ReinitContainer(nsIRDFResource* aContainerType, nsIRDFResource* aContainer)
michael@0 1385 {
michael@0 1386 // Mega-kludge to deal with the fact that Make[Seq|Alt|Bag] is
michael@0 1387 // idempotent, and as such, containers will have state (e.g.,
michael@0 1388 // RDF:nextVal) maintained in the graph across loads. This
michael@0 1389 // re-initializes each container's RDF:nextVal to '1', and 'marks'
michael@0 1390 // the container as such.
michael@0 1391 nsresult rv;
michael@0 1392
michael@0 1393 nsCOMPtr<nsIRDFLiteral> one;
michael@0 1394 rv = gRDFService->GetLiteral(MOZ_UTF16("1"), getter_AddRefs(one));
michael@0 1395 if (NS_FAILED(rv)) return rv;
michael@0 1396
michael@0 1397 // Re-initialize the 'nextval' property
michael@0 1398 nsCOMPtr<nsIRDFNode> nextval;
michael@0 1399 rv = mDataSource->GetTarget(aContainer, kRDF_nextVal, true, getter_AddRefs(nextval));
michael@0 1400 if (NS_FAILED(rv)) return rv;
michael@0 1401
michael@0 1402 rv = mDataSource->Change(aContainer, kRDF_nextVal, nextval, one);
michael@0 1403 if (NS_FAILED(rv)) return rv;
michael@0 1404
michael@0 1405 // Re-mark as a container. XXX should be kRDF_type
michael@0 1406 rv = mDataSource->Assert(aContainer, kRDF_instanceOf, aContainerType, true);
michael@0 1407 NS_ASSERTION(NS_SUCCEEDED(rv), "unable to mark container as such");
michael@0 1408 if (NS_FAILED(rv)) return rv;
michael@0 1409
michael@0 1410 return NS_OK;
michael@0 1411 }
michael@0 1412
michael@0 1413 ////////////////////////////////////////////////////////////////////////
michael@0 1414 // Content stack management
michael@0 1415
michael@0 1416 nsIRDFResource*
michael@0 1417 RDFContentSinkImpl::GetContextElement(int32_t ancestor /* = 0 */)
michael@0 1418 {
michael@0 1419 if ((nullptr == mContextStack) ||
michael@0 1420 (uint32_t(ancestor) >= mContextStack->Length())) {
michael@0 1421 return nullptr;
michael@0 1422 }
michael@0 1423
michael@0 1424 return mContextStack->ElementAt(
michael@0 1425 mContextStack->Length()-ancestor-1).mResource;
michael@0 1426 }
michael@0 1427
michael@0 1428 int32_t
michael@0 1429 RDFContentSinkImpl::PushContext(nsIRDFResource *aResource,
michael@0 1430 RDFContentSinkState aState,
michael@0 1431 RDFContentSinkParseMode aParseMode)
michael@0 1432 {
michael@0 1433 if (! mContextStack) {
michael@0 1434 mContextStack = new nsAutoTArray<RDFContextStackElement, 8>();
michael@0 1435 if (! mContextStack)
michael@0 1436 return 0;
michael@0 1437 }
michael@0 1438
michael@0 1439 RDFContextStackElement* e = mContextStack->AppendElement();
michael@0 1440 if (! e)
michael@0 1441 return mContextStack->Length();
michael@0 1442
michael@0 1443 e->mResource = aResource;
michael@0 1444 e->mState = aState;
michael@0 1445 e->mParseMode = aParseMode;
michael@0 1446
michael@0 1447 return mContextStack->Length();
michael@0 1448 }
michael@0 1449
michael@0 1450 nsresult
michael@0 1451 RDFContentSinkImpl::PopContext(nsIRDFResource *&aResource,
michael@0 1452 RDFContentSinkState &aState,
michael@0 1453 RDFContentSinkParseMode &aParseMode)
michael@0 1454 {
michael@0 1455 if ((nullptr == mContextStack) ||
michael@0 1456 (mContextStack->IsEmpty())) {
michael@0 1457 return NS_ERROR_NULL_POINTER;
michael@0 1458 }
michael@0 1459
michael@0 1460 uint32_t i = mContextStack->Length() - 1;
michael@0 1461 RDFContextStackElement &e = mContextStack->ElementAt(i);
michael@0 1462
michael@0 1463 aResource = e.mResource;
michael@0 1464 NS_IF_ADDREF(aResource);
michael@0 1465 aState = e.mState;
michael@0 1466 aParseMode = e.mParseMode;
michael@0 1467
michael@0 1468 mContextStack->RemoveElementAt(i);
michael@0 1469 return NS_OK;
michael@0 1470 }
michael@0 1471
michael@0 1472
michael@0 1473 ////////////////////////////////////////////////////////////////////////
michael@0 1474
michael@0 1475 nsresult
michael@0 1476 NS_NewRDFContentSink(nsIRDFContentSink** aResult)
michael@0 1477 {
michael@0 1478 NS_PRECONDITION(aResult != nullptr, "null ptr");
michael@0 1479 if (! aResult)
michael@0 1480 return NS_ERROR_NULL_POINTER;
michael@0 1481
michael@0 1482 RDFContentSinkImpl* sink = new RDFContentSinkImpl();
michael@0 1483 if (! sink)
michael@0 1484 return NS_ERROR_OUT_OF_MEMORY;
michael@0 1485
michael@0 1486 NS_ADDREF(sink);
michael@0 1487 *aResult = sink;
michael@0 1488 return NS_OK;
michael@0 1489 }

mercurial