LCOV - code coverage report
Current view: top level - rdf/base - nsRDFContentSink.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 3 549 0.5 %
Date: 2017-07-14 16:53:18 Functions: 1 52 1.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13