rdf/base/src/nsRDFContentSink.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial