rdf/base/src/nsRDFContentSink.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/rdf/base/src/nsRDFContentSink.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1489 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/*
    1.10 +
    1.11 +  An implementation for an NGLayout-style content sink that knows how
    1.12 +  to build an RDF content model from XML-serialized RDF.
    1.13 +
    1.14 +  For more information on the RDF/XML syntax,
    1.15 +  see http://www.w3.org/TR/REC-rdf-syntax/
    1.16 +
    1.17 +  This code is based on the final W3C Recommendation,
    1.18 +  http://www.w3.org/TR/1999/REC-rdf-syntax-19990222.
    1.19 +
    1.20 +  Open Issues ------------------
    1.21 +
    1.22 +  1) factoring code with nsXMLContentSink - There's some amount of
    1.23 +     common code between this and the HTML content sink. This will
    1.24 +     increase as we support more and more HTML elements. How can code
    1.25 +     from XML/HTML be factored?
    1.26 +
    1.27 +  2) We don't support the `parseType' attribute on the Description
    1.28 +     tag; therefore, it is impossible to "inline" raw XML in this
    1.29 +     implemenation.
    1.30 +
    1.31 +  3) We don't build the reifications at parse time due to the
    1.32 +     footprint overhead it would incur for large RDF documents. (It
    1.33 +     may be possible to attach a "reification" wrapper datasource that
    1.34 +     would present this information at query-time.) Because of this,
    1.35 +     the `bagID' attribute is not processed correctly.
    1.36 +
    1.37 +  4) No attempt is made to `resolve URIs' to a canonical form (the
    1.38 +     specification hints that an implementation should do this). This
    1.39 +     is omitted for the obvious reason that we can ill afford to
    1.40 +     resolve each URI reference.
    1.41 +
    1.42 +*/
    1.43 +
    1.44 +#include "nsCOMPtr.h"
    1.45 +#include "nsInterfaceHashtable.h"
    1.46 +#include "nsIContentSink.h"
    1.47 +#include "nsIRDFContainer.h"
    1.48 +#include "nsIRDFContainerUtils.h"
    1.49 +#include "nsIRDFContentSink.h"
    1.50 +#include "nsIRDFNode.h"
    1.51 +#include "nsIRDFService.h"
    1.52 +#include "nsIRDFXMLSink.h"
    1.53 +#include "nsIServiceManager.h"
    1.54 +#include "nsIURL.h"
    1.55 +#include "nsIXMLContentSink.h"
    1.56 +#include "nsRDFCID.h"
    1.57 +#include "nsTArray.h"
    1.58 +#include "nsXPIDLString.h"
    1.59 +#include "prlog.h"
    1.60 +#include "rdf.h"
    1.61 +#include "rdfutil.h"
    1.62 +#include "nsReadableUtils.h"
    1.63 +#include "nsIExpatSink.h"
    1.64 +#include "nsCRT.h"
    1.65 +#include "nsIAtom.h"
    1.66 +#include "nsStaticAtom.h"
    1.67 +#include "nsIScriptError.h"
    1.68 +#include "nsIDTD.h"
    1.69 +
    1.70 +using namespace mozilla;
    1.71 +
    1.72 +///////////////////////////////////////////////////////////////////////
    1.73 +
    1.74 +enum RDFContentSinkState {
    1.75 +    eRDFContentSinkState_InProlog,
    1.76 +    eRDFContentSinkState_InDocumentElement,
    1.77 +    eRDFContentSinkState_InDescriptionElement,
    1.78 +    eRDFContentSinkState_InContainerElement,
    1.79 +    eRDFContentSinkState_InPropertyElement,
    1.80 +    eRDFContentSinkState_InMemberElement,
    1.81 +    eRDFContentSinkState_InEpilog
    1.82 +};
    1.83 +
    1.84 +enum RDFContentSinkParseMode {
    1.85 +    eRDFContentSinkParseMode_Resource,
    1.86 +    eRDFContentSinkParseMode_Literal,
    1.87 +    eRDFContentSinkParseMode_Int,
    1.88 +    eRDFContentSinkParseMode_Date
    1.89 +};
    1.90 +
    1.91 +typedef
    1.92 +NS_STDCALL_FUNCPROTO(nsresult,
    1.93 +                     nsContainerTestFn,
    1.94 +                     nsIRDFContainerUtils, IsAlt,
    1.95 +                     (nsIRDFDataSource*, nsIRDFResource*, bool*));
    1.96 +
    1.97 +typedef
    1.98 +NS_STDCALL_FUNCPROTO(nsresult,
    1.99 +                     nsMakeContainerFn,
   1.100 +                     nsIRDFContainerUtils, MakeAlt,
   1.101 +                     (nsIRDFDataSource*, nsIRDFResource*, nsIRDFContainer**));
   1.102 +
   1.103 +class RDFContentSinkImpl : public nsIRDFContentSink,
   1.104 +                           public nsIExpatSink
   1.105 +{
   1.106 +public:
   1.107 +    RDFContentSinkImpl();
   1.108 +    virtual ~RDFContentSinkImpl();
   1.109 +
   1.110 +    // nsISupports
   1.111 +    NS_DECL_ISUPPORTS
   1.112 +    NS_DECL_NSIEXPATSINK
   1.113 +
   1.114 +    // nsIContentSink
   1.115 +    NS_IMETHOD WillParse(void);
   1.116 +    NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode);
   1.117 +    NS_IMETHOD DidBuildModel(bool aTerminated);
   1.118 +    NS_IMETHOD WillInterrupt(void);
   1.119 +    NS_IMETHOD WillResume(void);
   1.120 +    NS_IMETHOD SetParser(nsParserBase* aParser);
   1.121 +    virtual void FlushPendingNotifications(mozFlushType aType) { }
   1.122 +    NS_IMETHOD SetDocumentCharset(nsACString& aCharset) { return NS_OK; }
   1.123 +    virtual nsISupports *GetTarget() { return nullptr; }
   1.124 +
   1.125 +    // nsIRDFContentSink
   1.126 +    NS_IMETHOD Init(nsIURI* aURL);
   1.127 +    NS_IMETHOD SetDataSource(nsIRDFDataSource* aDataSource);
   1.128 +    NS_IMETHOD GetDataSource(nsIRDFDataSource*& aDataSource);
   1.129 +
   1.130 +    // pseudo constants
   1.131 +    static int32_t gRefCnt;
   1.132 +    static nsIRDFService* gRDFService;
   1.133 +    static nsIRDFContainerUtils* gRDFContainerUtils;
   1.134 +    static nsIRDFResource* kRDF_type;
   1.135 +    static nsIRDFResource* kRDF_instanceOf; // XXX should be RDF:type
   1.136 +    static nsIRDFResource* kRDF_Alt;
   1.137 +    static nsIRDFResource* kRDF_Bag;
   1.138 +    static nsIRDFResource* kRDF_Seq;
   1.139 +    static nsIRDFResource* kRDF_nextVal;
   1.140 +
   1.141 +#define RDF_ATOM(name_, value_) static nsIAtom* name_;
   1.142 +#include "nsRDFContentSinkAtomList.h"
   1.143 +#undef RDF_ATOM
   1.144 +
   1.145 +    typedef struct ContainerInfo {
   1.146 +        nsIRDFResource**  mType;
   1.147 +        nsContainerTestFn mTestFn;
   1.148 +        nsMakeContainerFn mMakeFn;
   1.149 +    } ContainerInfo;
   1.150 +
   1.151 +protected:
   1.152 +    // Text management
   1.153 +    void ParseText(nsIRDFNode **aResult);
   1.154 +
   1.155 +    nsresult FlushText();
   1.156 +    nsresult AddText(const char16_t* aText, int32_t aLength);
   1.157 +
   1.158 +    // RDF-specific parsing
   1.159 +    nsresult OpenRDF(const char16_t* aName);
   1.160 +    nsresult OpenObject(const char16_t* aName ,const char16_t** aAttributes);
   1.161 +    nsresult OpenProperty(const char16_t* aName, const char16_t** aAttributes);
   1.162 +    nsresult OpenMember(const char16_t* aName, const char16_t** aAttributes);
   1.163 +    nsresult OpenValue(const char16_t* aName, const char16_t** aAttributes);
   1.164 +    
   1.165 +    nsresult GetIdAboutAttribute(const char16_t** aAttributes, nsIRDFResource** aResource, bool* aIsAnonymous = nullptr);
   1.166 +    nsresult GetResourceAttribute(const char16_t** aAttributes, nsIRDFResource** aResource);
   1.167 +    nsresult AddProperties(const char16_t** aAttributes, nsIRDFResource* aSubject, int32_t* aCount = nullptr);
   1.168 +    void SetParseMode(const char16_t **aAttributes);
   1.169 +
   1.170 +    char16_t* mText;
   1.171 +    int32_t mTextLength;
   1.172 +    int32_t mTextSize;
   1.173 +
   1.174 +    /**
   1.175 +     * From the set of given attributes, this method extracts the 
   1.176 +     * namespace definitions and feeds them to the datasource.
   1.177 +     * These can then be suggested to the serializer to be used again.
   1.178 +     * Hopefully, this will keep namespace definitions intact in a 
   1.179 +     * parse - serialize cycle.
   1.180 +     */
   1.181 +    void RegisterNamespaces(const char16_t **aAttributes);
   1.182 +
   1.183 +    /**
   1.184 +     * Extracts the localname from aExpatName, the name that the Expat parser
   1.185 +     * passes us.
   1.186 +     * aLocalName will contain the localname in aExpatName.
   1.187 +     * The return value is a dependent string containing just the namespace.
   1.188 +     */
   1.189 +    const nsDependentSubstring SplitExpatName(const char16_t *aExpatName,
   1.190 +                                              nsIAtom **aLocalName);
   1.191 +
   1.192 +    enum eContainerType { eBag, eSeq, eAlt };
   1.193 +    nsresult InitContainer(nsIRDFResource* aContainerType, nsIRDFResource* aContainer);
   1.194 +    nsresult ReinitContainer(nsIRDFResource* aContainerType, nsIRDFResource* aContainer);
   1.195 +
   1.196 +    // The datasource in which we're assigning assertions
   1.197 +    nsCOMPtr<nsIRDFDataSource> mDataSource;
   1.198 +
   1.199 +    // A hash of all the node IDs referred to
   1.200 +    nsInterfaceHashtable<nsStringHashKey, nsIRDFResource> mNodeIDMap;
   1.201 +
   1.202 +    // The current state of the content sink
   1.203 +    RDFContentSinkState mState;
   1.204 +    RDFContentSinkParseMode mParseMode;
   1.205 +
   1.206 +    // content stack management
   1.207 +    int32_t         
   1.208 +    PushContext(nsIRDFResource *aContext,
   1.209 +                RDFContentSinkState aState,
   1.210 +                RDFContentSinkParseMode aParseMode);
   1.211 +
   1.212 +    nsresult
   1.213 +    PopContext(nsIRDFResource         *&aContext,
   1.214 +               RDFContentSinkState     &aState,
   1.215 +               RDFContentSinkParseMode &aParseMode);
   1.216 +
   1.217 +    nsIRDFResource* GetContextElement(int32_t ancestor = 0);
   1.218 +
   1.219 +
   1.220 +    struct RDFContextStackElement {
   1.221 +        nsCOMPtr<nsIRDFResource> mResource;
   1.222 +        RDFContentSinkState      mState;
   1.223 +        RDFContentSinkParseMode  mParseMode;
   1.224 +    };
   1.225 +
   1.226 +    nsAutoTArray<RDFContextStackElement, 8>* mContextStack;
   1.227 +
   1.228 +    nsIURI*      mDocumentURL;
   1.229 +
   1.230 +private:
   1.231 +#ifdef PR_LOGGING
   1.232 +    static PRLogModuleInfo* gLog;
   1.233 +#endif
   1.234 +};
   1.235 +
   1.236 +int32_t         RDFContentSinkImpl::gRefCnt = 0;
   1.237 +nsIRDFService*  RDFContentSinkImpl::gRDFService;
   1.238 +nsIRDFContainerUtils* RDFContentSinkImpl::gRDFContainerUtils;
   1.239 +nsIRDFResource* RDFContentSinkImpl::kRDF_type;
   1.240 +nsIRDFResource* RDFContentSinkImpl::kRDF_instanceOf;
   1.241 +nsIRDFResource* RDFContentSinkImpl::kRDF_Alt;
   1.242 +nsIRDFResource* RDFContentSinkImpl::kRDF_Bag;
   1.243 +nsIRDFResource* RDFContentSinkImpl::kRDF_Seq;
   1.244 +nsIRDFResource* RDFContentSinkImpl::kRDF_nextVal;
   1.245 +
   1.246 +#ifdef PR_LOGGING
   1.247 +PRLogModuleInfo* RDFContentSinkImpl::gLog;
   1.248 +#endif
   1.249 +
   1.250 +////////////////////////////////////////////////////////////////////////
   1.251 +
   1.252 +#define RDF_ATOM(name_, value_) nsIAtom* RDFContentSinkImpl::name_;
   1.253 +#include "nsRDFContentSinkAtomList.h"
   1.254 +#undef RDF_ATOM
   1.255 +
   1.256 +#define RDF_ATOM(name_, value_) NS_STATIC_ATOM_BUFFER(name_##_buffer, value_)
   1.257 +#include "nsRDFContentSinkAtomList.h"
   1.258 +#undef RDF_ATOM
   1.259 +
   1.260 +static const nsStaticAtom rdf_atoms[] = {
   1.261 +#define RDF_ATOM(name_, value_) NS_STATIC_ATOM(name_##_buffer, &RDFContentSinkImpl::name_),
   1.262 +#include "nsRDFContentSinkAtomList.h"
   1.263 +#undef RDF_ATOM
   1.264 +};
   1.265 +
   1.266 +RDFContentSinkImpl::RDFContentSinkImpl()
   1.267 +    : mText(nullptr),
   1.268 +      mTextLength(0),
   1.269 +      mTextSize(0),
   1.270 +      mState(eRDFContentSinkState_InProlog),
   1.271 +      mParseMode(eRDFContentSinkParseMode_Literal),
   1.272 +      mContextStack(nullptr),
   1.273 +      mDocumentURL(nullptr)
   1.274 +{
   1.275 +    if (gRefCnt++ == 0) {
   1.276 +        NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
   1.277 +        nsresult rv = CallGetService(kRDFServiceCID, &gRDFService);
   1.278 +
   1.279 +        NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service");
   1.280 +        if (NS_SUCCEEDED(rv)) {
   1.281 +            rv = gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "type"),
   1.282 +                                          &kRDF_type);
   1.283 +            rv = gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "instanceOf"),
   1.284 +                                          &kRDF_instanceOf);
   1.285 +            rv = gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Alt"),
   1.286 +                                          &kRDF_Alt);
   1.287 +            rv = gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Bag"),
   1.288 +                                          &kRDF_Bag);
   1.289 +            rv = gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Seq"),
   1.290 +                                          &kRDF_Seq);
   1.291 +            rv = gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "nextVal"),
   1.292 +                                          &kRDF_nextVal);
   1.293 +        }
   1.294 +
   1.295 +        NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID);
   1.296 +        rv = CallGetService(kRDFContainerUtilsCID, &gRDFContainerUtils);
   1.297 +
   1.298 +        NS_RegisterStaticAtoms(rdf_atoms);
   1.299 +    }
   1.300 +
   1.301 +#ifdef PR_LOGGING
   1.302 +    if (! gLog)
   1.303 +        gLog = PR_NewLogModule("nsRDFContentSink");
   1.304 +#endif
   1.305 +}
   1.306 +
   1.307 +
   1.308 +RDFContentSinkImpl::~RDFContentSinkImpl()
   1.309 +{
   1.310 +#ifdef DEBUG_REFS
   1.311 +    --gInstanceCount;
   1.312 +    fprintf(stdout, "%d - RDF: RDFContentSinkImpl\n", gInstanceCount);
   1.313 +#endif
   1.314 +
   1.315 +    NS_IF_RELEASE(mDocumentURL);
   1.316 +
   1.317 +    if (mContextStack) {
   1.318 +        PR_LOG(gLog, PR_LOG_WARNING,
   1.319 +               ("rdfxml: warning! unclosed tag"));
   1.320 +
   1.321 +        // XXX we should never need to do this, but, we'll write the
   1.322 +        // code all the same. If someone left the content stack dirty,
   1.323 +        // pop all the elements off the stack and release them.
   1.324 +        int32_t i = mContextStack->Length();
   1.325 +        while (0 < i--) {
   1.326 +            nsIRDFResource* resource = nullptr;
   1.327 +            RDFContentSinkState state;
   1.328 +            RDFContentSinkParseMode parseMode;
   1.329 +            PopContext(resource, state, parseMode);
   1.330 +
   1.331 +#ifdef PR_LOGGING
   1.332 +            // print some fairly useless debugging info
   1.333 +            // XXX we should save line numbers on the context stack: this'd
   1.334 +            // be about 1000x more helpful.
   1.335 +            if (resource) {
   1.336 +                nsXPIDLCString uri;
   1.337 +                resource->GetValue(getter_Copies(uri));
   1.338 +                PR_LOG(gLog, PR_LOG_NOTICE,
   1.339 +                       ("rdfxml:   uri=%s", (const char*) uri));
   1.340 +            }
   1.341 +#endif
   1.342 +
   1.343 +            NS_IF_RELEASE(resource);
   1.344 +        }
   1.345 +
   1.346 +        delete mContextStack;
   1.347 +    }
   1.348 +    moz_free(mText);
   1.349 +
   1.350 +
   1.351 +    if (--gRefCnt == 0) {
   1.352 +        NS_IF_RELEASE(gRDFService);
   1.353 +        NS_IF_RELEASE(gRDFContainerUtils);
   1.354 +        NS_IF_RELEASE(kRDF_type);
   1.355 +        NS_IF_RELEASE(kRDF_instanceOf);
   1.356 +        NS_IF_RELEASE(kRDF_Alt);
   1.357 +        NS_IF_RELEASE(kRDF_Bag);
   1.358 +        NS_IF_RELEASE(kRDF_Seq);
   1.359 +        NS_IF_RELEASE(kRDF_nextVal);
   1.360 +    }
   1.361 +}
   1.362 +
   1.363 +////////////////////////////////////////////////////////////////////////
   1.364 +// nsISupports interface
   1.365 +
   1.366 +NS_IMPL_ADDREF(RDFContentSinkImpl)
   1.367 +NS_IMPL_RELEASE(RDFContentSinkImpl)
   1.368 +
   1.369 +NS_IMETHODIMP
   1.370 +RDFContentSinkImpl::QueryInterface(REFNSIID iid, void** result)
   1.371 +{
   1.372 +    NS_PRECONDITION(result, "null ptr");
   1.373 +    if (! result)
   1.374 +        return NS_ERROR_NULL_POINTER;
   1.375 +
   1.376 +    NS_DEFINE_IID(kIContentSinkIID,    NS_ICONTENT_SINK_IID);
   1.377 +    NS_DEFINE_IID(kIExpatSinkIID,      NS_IEXPATSINK_IID);
   1.378 +    NS_DEFINE_IID(kISupportsIID,       NS_ISUPPORTS_IID);
   1.379 +    NS_DEFINE_IID(kIXMLContentSinkIID, NS_IXMLCONTENT_SINK_IID);
   1.380 +    NS_DEFINE_IID(kIRDFContentSinkIID, NS_IRDFCONTENTSINK_IID);
   1.381 +
   1.382 +    *result = nullptr;
   1.383 +    if (iid.Equals(kIRDFContentSinkIID) ||
   1.384 +        iid.Equals(kIXMLContentSinkIID) ||
   1.385 +        iid.Equals(kIContentSinkIID) ||
   1.386 +        iid.Equals(kISupportsIID)) {
   1.387 +        *result = static_cast<nsIXMLContentSink*>(this);
   1.388 +        AddRef();
   1.389 +        return NS_OK;
   1.390 +    }
   1.391 +    else if (iid.Equals(kIExpatSinkIID)) {
   1.392 +      *result = static_cast<nsIExpatSink*>(this);
   1.393 +       AddRef();
   1.394 +       return NS_OK;
   1.395 +    }
   1.396 +    return NS_NOINTERFACE;
   1.397 +}
   1.398 +
   1.399 +NS_IMETHODIMP 
   1.400 +RDFContentSinkImpl::HandleStartElement(const char16_t *aName, 
   1.401 +                                       const char16_t **aAtts, 
   1.402 +                                       uint32_t aAttsCount, 
   1.403 +                                       int32_t aIndex, 
   1.404 +                                       uint32_t aLineNumber)
   1.405 +{
   1.406 +  FlushText();
   1.407 +
   1.408 +  nsresult rv = NS_ERROR_UNEXPECTED; // XXX
   1.409 +
   1.410 +  RegisterNamespaces(aAtts);
   1.411 +
   1.412 +  switch (mState) {
   1.413 +  case eRDFContentSinkState_InProlog:
   1.414 +      rv = OpenRDF(aName);
   1.415 +      break;
   1.416 +
   1.417 +  case eRDFContentSinkState_InDocumentElement:
   1.418 +      rv = OpenObject(aName,aAtts);
   1.419 +      break;
   1.420 +
   1.421 +  case eRDFContentSinkState_InDescriptionElement:
   1.422 +      rv = OpenProperty(aName,aAtts);
   1.423 +      break;
   1.424 +
   1.425 +  case eRDFContentSinkState_InContainerElement:
   1.426 +      rv = OpenMember(aName,aAtts);
   1.427 +      break;
   1.428 +
   1.429 +  case eRDFContentSinkState_InPropertyElement:
   1.430 +  case eRDFContentSinkState_InMemberElement:
   1.431 +      rv = OpenValue(aName,aAtts);
   1.432 +      break;
   1.433 +
   1.434 +  case eRDFContentSinkState_InEpilog:
   1.435 +      PR_LOG(gLog, PR_LOG_WARNING,
   1.436 +             ("rdfxml: unexpected content in epilog at line %d",
   1.437 +              aLineNumber));
   1.438 +      break;
   1.439 +  }
   1.440 +
   1.441 +  return rv;
   1.442 +}
   1.443 +
   1.444 +NS_IMETHODIMP 
   1.445 +RDFContentSinkImpl::HandleEndElement(const char16_t *aName)
   1.446 +{
   1.447 +  FlushText();
   1.448 +
   1.449 +  nsIRDFResource* resource;
   1.450 +  if (NS_FAILED(PopContext(resource, mState, mParseMode))) {
   1.451 +      // XXX parser didn't catch unmatched tags?
   1.452 +#ifdef PR_LOGGING
   1.453 +      if (PR_LOG_TEST(gLog, PR_LOG_WARNING)) {
   1.454 +          nsAutoString tagStr(aName);
   1.455 +          char* tagCStr = ToNewCString(tagStr);
   1.456 +
   1.457 +          PR_LogPrint
   1.458 +                 ("rdfxml: extra close tag '%s' at line %d",
   1.459 +                  tagCStr, 0/*XXX fix me */);
   1.460 +
   1.461 +          NS_Free(tagCStr);
   1.462 +      }
   1.463 +#endif
   1.464 +
   1.465 +      return NS_ERROR_UNEXPECTED; // XXX
   1.466 +  }
   1.467 +
   1.468 +  // If we've just popped a member or property element, _now_ is the
   1.469 +  // time to add that element to the graph.
   1.470 +  switch (mState) {
   1.471 +    case eRDFContentSinkState_InMemberElement: 
   1.472 +      {
   1.473 +        nsCOMPtr<nsIRDFContainer> container;
   1.474 +        NS_NewRDFContainer(getter_AddRefs(container));
   1.475 +        container->Init(mDataSource, GetContextElement(1));
   1.476 +        container->AppendElement(resource);
   1.477 +      } 
   1.478 +      break;
   1.479 +
   1.480 +    case eRDFContentSinkState_InPropertyElement: 
   1.481 +      {
   1.482 +        mDataSource->Assert(GetContextElement(1), GetContextElement(0), resource, true);                                          
   1.483 +      } break;
   1.484 +    default:
   1.485 +      break;
   1.486 +  }
   1.487 +  
   1.488 +  if (mContextStack->IsEmpty())
   1.489 +      mState = eRDFContentSinkState_InEpilog;
   1.490 +
   1.491 +  NS_IF_RELEASE(resource);
   1.492 +  return NS_OK;
   1.493 +}
   1.494 + 
   1.495 +NS_IMETHODIMP 
   1.496 +RDFContentSinkImpl::HandleComment(const char16_t *aName)
   1.497 +{
   1.498 +    return NS_OK;
   1.499 +}
   1.500 +
   1.501 +NS_IMETHODIMP 
   1.502 +RDFContentSinkImpl::HandleCDataSection(const char16_t *aData, 
   1.503 +                                       uint32_t aLength)
   1.504 +{
   1.505 +  return aData ?  AddText(aData, aLength) : NS_OK;
   1.506 +}
   1.507 +
   1.508 +NS_IMETHODIMP 
   1.509 +RDFContentSinkImpl::HandleDoctypeDecl(const nsAString & aSubset, 
   1.510 +                                      const nsAString & aName, 
   1.511 +                                      const nsAString & aSystemId, 
   1.512 +                                      const nsAString & aPublicId,
   1.513 +                                      nsISupports* aCatalogData)
   1.514 +{
   1.515 +    return NS_OK;
   1.516 +}
   1.517 +
   1.518 +NS_IMETHODIMP 
   1.519 +RDFContentSinkImpl::HandleCharacterData(const char16_t *aData, 
   1.520 +                                        uint32_t aLength)
   1.521 +{
   1.522 +  return aData ?  AddText(aData, aLength) : NS_OK;
   1.523 +}
   1.524 +
   1.525 +NS_IMETHODIMP 
   1.526 +RDFContentSinkImpl::HandleProcessingInstruction(const char16_t *aTarget, 
   1.527 +                                                const char16_t *aData)
   1.528 +{
   1.529 +    return NS_OK;
   1.530 +}
   1.531 +
   1.532 +NS_IMETHODIMP 
   1.533 +RDFContentSinkImpl::HandleXMLDeclaration(const char16_t *aVersion,
   1.534 +                                         const char16_t *aEncoding,
   1.535 +                                         int32_t aStandalone)
   1.536 +{
   1.537 +    return NS_OK;
   1.538 +}
   1.539 +
   1.540 +NS_IMETHODIMP
   1.541 +RDFContentSinkImpl::ReportError(const char16_t* aErrorText, 
   1.542 +                                const char16_t* aSourceText,
   1.543 +                                nsIScriptError *aError,
   1.544 +                                bool *_retval)
   1.545 +{
   1.546 +  NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!");
   1.547 +
   1.548 +  // The expat driver should report the error.
   1.549 +  *_retval = true;
   1.550 +  return NS_OK;
   1.551 +}
   1.552 +
   1.553 +////////////////////////////////////////////////////////////////////////
   1.554 +// nsIContentSink interface
   1.555 +
   1.556 +NS_IMETHODIMP 
   1.557 +RDFContentSinkImpl::WillParse(void)
   1.558 +{
   1.559 +    return NS_OK;
   1.560 +}
   1.561 +
   1.562 +
   1.563 +NS_IMETHODIMP 
   1.564 +RDFContentSinkImpl::WillBuildModel(nsDTDMode)
   1.565 +{
   1.566 +    if (mDataSource) {
   1.567 +        nsCOMPtr<nsIRDFXMLSink> sink = do_QueryInterface(mDataSource);
   1.568 +        if (sink) 
   1.569 +            return sink->BeginLoad();
   1.570 +    }
   1.571 +    return NS_OK;
   1.572 +}
   1.573 +
   1.574 +NS_IMETHODIMP 
   1.575 +RDFContentSinkImpl::DidBuildModel(bool aTerminated)
   1.576 +{
   1.577 +    if (mDataSource) {
   1.578 +        nsCOMPtr<nsIRDFXMLSink> sink = do_QueryInterface(mDataSource);
   1.579 +        if (sink)
   1.580 +            return sink->EndLoad();
   1.581 +    }
   1.582 +    return NS_OK;
   1.583 +}
   1.584 +
   1.585 +NS_IMETHODIMP 
   1.586 +RDFContentSinkImpl::WillInterrupt(void)
   1.587 +{
   1.588 +    if (mDataSource) {
   1.589 +        nsCOMPtr<nsIRDFXMLSink> sink = do_QueryInterface(mDataSource);
   1.590 +        if (sink)
   1.591 +            return sink->Interrupt();
   1.592 +    }
   1.593 +    return NS_OK;
   1.594 +}
   1.595 +
   1.596 +NS_IMETHODIMP 
   1.597 +RDFContentSinkImpl::WillResume(void)
   1.598 +{
   1.599 +    if (mDataSource) {
   1.600 +        nsCOMPtr<nsIRDFXMLSink> sink = do_QueryInterface(mDataSource);
   1.601 +        if (sink)
   1.602 +            return sink->Resume();
   1.603 +    }
   1.604 +    return NS_OK;
   1.605 +}
   1.606 +
   1.607 +NS_IMETHODIMP 
   1.608 +RDFContentSinkImpl::SetParser(nsParserBase* aParser)
   1.609 +{
   1.610 +    return NS_OK;
   1.611 +}
   1.612 +
   1.613 +////////////////////////////////////////////////////////////////////////
   1.614 +// nsIRDFContentSink interface
   1.615 +
   1.616 +NS_IMETHODIMP
   1.617 +RDFContentSinkImpl::Init(nsIURI* aURL)
   1.618 +{
   1.619 +    NS_PRECONDITION(aURL != nullptr, "null ptr");
   1.620 +    if (! aURL)
   1.621 +        return NS_ERROR_NULL_POINTER;
   1.622 +
   1.623 +    mDocumentURL = aURL;
   1.624 +    NS_ADDREF(aURL);
   1.625 +
   1.626 +    mState = eRDFContentSinkState_InProlog;
   1.627 +    return NS_OK;
   1.628 +}
   1.629 +
   1.630 +NS_IMETHODIMP
   1.631 +RDFContentSinkImpl::SetDataSource(nsIRDFDataSource* aDataSource)
   1.632 +{
   1.633 +    NS_PRECONDITION(aDataSource != nullptr, "SetDataSource null ptr");
   1.634 +    mDataSource = aDataSource;
   1.635 +    NS_ASSERTION(mDataSource != nullptr,"Couldn't QI RDF DataSource");
   1.636 +    return NS_OK;
   1.637 +}
   1.638 +
   1.639 +
   1.640 +NS_IMETHODIMP
   1.641 +RDFContentSinkImpl::GetDataSource(nsIRDFDataSource*& aDataSource)
   1.642 +{
   1.643 +    aDataSource = mDataSource;
   1.644 +    NS_IF_ADDREF(aDataSource);
   1.645 +    return NS_OK;
   1.646 +}
   1.647 +
   1.648 +////////////////////////////////////////////////////////////////////////
   1.649 +// Text buffering
   1.650 +
   1.651 +static bool
   1.652 +rdf_IsDataInBuffer(char16_t* buffer, int32_t length)
   1.653 +{
   1.654 +    for (int32_t i = 0; i < length; ++i) {
   1.655 +        if (buffer[i] == ' ' ||
   1.656 +            buffer[i] == '\t' ||
   1.657 +            buffer[i] == '\n' ||
   1.658 +            buffer[i] == '\r')
   1.659 +            continue;
   1.660 +
   1.661 +        return true;
   1.662 +    }
   1.663 +    return false;
   1.664 +}
   1.665 +
   1.666 +void
   1.667 +RDFContentSinkImpl::ParseText(nsIRDFNode **aResult)
   1.668 +{
   1.669 +    // XXXwaterson wasteful, but we'd need to make a copy anyway to be
   1.670 +    // able to call nsIRDFService::Get[Resource|Literal|...]().
   1.671 +    nsAutoString value;
   1.672 +    value.Append(mText, mTextLength);
   1.673 +    value.Trim(" \t\n\r");
   1.674 +
   1.675 +    switch (mParseMode) {
   1.676 +    case eRDFContentSinkParseMode_Literal:
   1.677 +        {
   1.678 +            nsIRDFLiteral *result;
   1.679 +            gRDFService->GetLiteral(value.get(), &result);
   1.680 +            *aResult = result;
   1.681 +        }
   1.682 +        break;
   1.683 +
   1.684 +    case eRDFContentSinkParseMode_Resource:
   1.685 +        {
   1.686 +            nsIRDFResource *result;
   1.687 +            gRDFService->GetUnicodeResource(value, &result);
   1.688 +            *aResult = result;
   1.689 +        }
   1.690 +        break;
   1.691 +
   1.692 +    case eRDFContentSinkParseMode_Int:
   1.693 +        {
   1.694 +            nsresult err;
   1.695 +            int32_t i = value.ToInteger(&err);
   1.696 +            nsIRDFInt *result;
   1.697 +            gRDFService->GetIntLiteral(i, &result);
   1.698 +            *aResult = result;
   1.699 +        }
   1.700 +        break;
   1.701 +
   1.702 +    case eRDFContentSinkParseMode_Date:
   1.703 +        {
   1.704 +            PRTime t = rdf_ParseDate(nsDependentCString(NS_LossyConvertUTF16toASCII(value).get(), value.Length()));
   1.705 +            nsIRDFDate *result;
   1.706 +            gRDFService->GetDateLiteral(t, &result);
   1.707 +            *aResult = result;
   1.708 +        }
   1.709 +        break;
   1.710 +
   1.711 +    default:
   1.712 +        NS_NOTREACHED("unknown parse type");
   1.713 +        break;
   1.714 +    }
   1.715 +}
   1.716 +
   1.717 +nsresult
   1.718 +RDFContentSinkImpl::FlushText()
   1.719 +{
   1.720 +    nsresult rv = NS_OK;
   1.721 +    if (0 != mTextLength) {
   1.722 +        if (rdf_IsDataInBuffer(mText, mTextLength)) {
   1.723 +            // XXX if there's anything but whitespace, then we'll
   1.724 +            // create a text node.
   1.725 +
   1.726 +            switch (mState) {
   1.727 +            case eRDFContentSinkState_InMemberElement: {
   1.728 +                nsCOMPtr<nsIRDFNode> node;
   1.729 +                ParseText(getter_AddRefs(node));
   1.730 +
   1.731 +                nsCOMPtr<nsIRDFContainer> container;
   1.732 +                NS_NewRDFContainer(getter_AddRefs(container));
   1.733 +                container->Init(mDataSource, GetContextElement(1));
   1.734 +
   1.735 +                container->AppendElement(node);
   1.736 +            } break;
   1.737 +
   1.738 +            case eRDFContentSinkState_InPropertyElement: {
   1.739 +                nsCOMPtr<nsIRDFNode> node;
   1.740 +                ParseText(getter_AddRefs(node));
   1.741 +
   1.742 +                mDataSource->Assert(GetContextElement(1), GetContextElement(0), node, true);
   1.743 +            } break;
   1.744 +
   1.745 +            default:
   1.746 +                // just ignore it
   1.747 +                break;
   1.748 +            }
   1.749 +        }
   1.750 +        mTextLength = 0;
   1.751 +    }
   1.752 +    return rv;
   1.753 +}
   1.754 +
   1.755 +
   1.756 +nsresult
   1.757 +RDFContentSinkImpl::AddText(const char16_t* aText, int32_t aLength)
   1.758 +{
   1.759 +    // Create buffer when we first need it
   1.760 +    if (0 == mTextSize) {
   1.761 +        mText = (char16_t *) moz_malloc(sizeof(char16_t) * 4096);
   1.762 +        if (!mText) {
   1.763 +            return NS_ERROR_OUT_OF_MEMORY;
   1.764 +        }
   1.765 +        mTextSize = 4096;
   1.766 +    }
   1.767 +
   1.768 +    // Copy data from string into our buffer; grow the buffer as needed.
   1.769 +    // It never shrinks, but since the content sink doesn't stick around,
   1.770 +    // this shouldn't be a bloat issue.
   1.771 +    int32_t amount = mTextSize - mTextLength;
   1.772 +    if (amount < aLength) {
   1.773 +        // Grow the buffer by at least a factor of two to prevent thrashing.
   1.774 +        // Since PR_REALLOC will leave mText intact if the call fails,
   1.775 +        // don't clobber mText or mTextSize until the new mem is allocated.
   1.776 +        int32_t newSize = (2 * mTextSize > (mTextSize + aLength)) ?
   1.777 +                          (2 * mTextSize) : (mTextSize + aLength);
   1.778 +        char16_t* newText = 
   1.779 +            (char16_t *) moz_realloc(mText, sizeof(char16_t) * newSize);
   1.780 +        if (!newText)
   1.781 +            return NS_ERROR_OUT_OF_MEMORY;
   1.782 +        mTextSize = newSize;
   1.783 +        mText = newText;
   1.784 +    }
   1.785 +    memcpy(&mText[mTextLength], aText, sizeof(char16_t) * aLength);
   1.786 +    mTextLength += aLength;
   1.787 +
   1.788 +    return NS_OK;
   1.789 +}
   1.790 +
   1.791 +bool
   1.792 +rdf_RequiresAbsoluteURI(const nsString& uri)
   1.793 +{
   1.794 +    // cheap shot at figuring out if this requires an absolute url translation
   1.795 +    return !(StringBeginsWith(uri, NS_LITERAL_STRING("urn:")) ||
   1.796 +             StringBeginsWith(uri, NS_LITERAL_STRING("chrome:")));
   1.797 +}
   1.798 +
   1.799 +nsresult
   1.800 +RDFContentSinkImpl::GetIdAboutAttribute(const char16_t** aAttributes,
   1.801 +                                        nsIRDFResource** aResource,
   1.802 +                                        bool* aIsAnonymous)
   1.803 +{
   1.804 +    // This corresponds to the dirty work of production [6.5]
   1.805 +    nsresult rv = NS_OK;
   1.806 +
   1.807 +    nsAutoString nodeID;
   1.808 +
   1.809 +    nsCOMPtr<nsIAtom> localName;
   1.810 +    for (; *aAttributes; aAttributes += 2) {
   1.811 +        const nsDependentSubstring& nameSpaceURI =
   1.812 +            SplitExpatName(aAttributes[0], getter_AddRefs(localName));
   1.813 +
   1.814 +        // We'll accept either `ID' or `rdf:ID' (ibid with `about' or
   1.815 +        // `rdf:about') in the spirit of being liberal towards the
   1.816 +        // input that we receive.
   1.817 +        if (!nameSpaceURI.IsEmpty() &&
   1.818 +            !nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI)) {
   1.819 +          continue;
   1.820 +        }
   1.821 +
   1.822 +        // XXX you can't specify both, but we'll just pick up the
   1.823 +        // first thing that was specified and ignore the other.
   1.824 +      
   1.825 +        if (localName == kAboutAtom) {
   1.826 +            if (aIsAnonymous)
   1.827 +                *aIsAnonymous = false;
   1.828 +
   1.829 +            nsAutoString relURI(aAttributes[1]);
   1.830 +            if (rdf_RequiresAbsoluteURI(relURI)) {
   1.831 +                nsAutoCString uri;
   1.832 +                rv = mDocumentURL->Resolve(NS_ConvertUTF16toUTF8(aAttributes[1]), uri);
   1.833 +                if (NS_FAILED(rv)) return rv;
   1.834 +                
   1.835 +                return gRDFService->GetResource(uri, 
   1.836 +                                                aResource);
   1.837 +            } 
   1.838 +            return gRDFService->GetResource(NS_ConvertUTF16toUTF8(aAttributes[1]), 
   1.839 +                                            aResource);
   1.840 +        }
   1.841 +        else if (localName == kIdAtom) {
   1.842 +            if (aIsAnonymous)
   1.843 +                *aIsAnonymous = false;
   1.844 +            // In the spirit of leniency, we do not bother trying to
   1.845 +            // enforce that this be a valid "XML Name" (see
   1.846 +            // http://www.w3.org/TR/REC-xml#NT-Nmtoken), as per
   1.847 +            // 6.21. If we wanted to, this would be where to do it.
   1.848 +
   1.849 +            // Construct an in-line resource whose URI is the
   1.850 +            // document's URI plus the XML name specified in the ID
   1.851 +            // attribute.
   1.852 +            nsAutoCString name;
   1.853 +            nsAutoCString ref('#');
   1.854 +            AppendUTF16toUTF8(aAttributes[1], ref);
   1.855 +
   1.856 +            rv = mDocumentURL->Resolve(ref, name);
   1.857 +            if (NS_FAILED(rv)) return rv;
   1.858 +
   1.859 +            return gRDFService->GetResource(name, aResource);
   1.860 +        }
   1.861 +        else if (localName == kNodeIdAtom) {
   1.862 +            nodeID.Assign(aAttributes[1]);
   1.863 +        }
   1.864 +        else if (localName == kAboutEachAtom) {
   1.865 +            // XXX we don't deal with aboutEach...
   1.866 +            //PR_LOG(gLog, PR_LOG_WARNING,
   1.867 +            //       ("rdfxml: ignoring aboutEach at line %d",
   1.868 +            //        aNode.GetSourceLineNumber()));
   1.869 +        }
   1.870 +    }
   1.871 +
   1.872 +    // Otherwise, we couldn't find anything, so just gensym one...
   1.873 +    if (aIsAnonymous)
   1.874 +        *aIsAnonymous = true;
   1.875 +
   1.876 +    // If nodeID is present, check if we already know about it. If we've seen
   1.877 +    // the nodeID before, use the same resource, otherwise generate a new one.
   1.878 +    if (!nodeID.IsEmpty()) {
   1.879 +        mNodeIDMap.Get(nodeID,aResource);
   1.880 +
   1.881 +        if (!*aResource) {
   1.882 +            rv = gRDFService->GetAnonymousResource(aResource);
   1.883 +            mNodeIDMap.Put(nodeID,*aResource);
   1.884 +        }
   1.885 +    }
   1.886 +    else {
   1.887 +        rv = gRDFService->GetAnonymousResource(aResource);
   1.888 +    }
   1.889 +
   1.890 +    return rv;
   1.891 +}
   1.892 +
   1.893 +nsresult
   1.894 +RDFContentSinkImpl::GetResourceAttribute(const char16_t** aAttributes,
   1.895 +                                         nsIRDFResource** aResource)
   1.896 +{
   1.897 +  nsCOMPtr<nsIAtom> localName;
   1.898 +
   1.899 +  nsAutoString nodeID;
   1.900 +
   1.901 +  for (; *aAttributes; aAttributes += 2) {
   1.902 +      const nsDependentSubstring& nameSpaceURI =
   1.903 +          SplitExpatName(aAttributes[0], getter_AddRefs(localName));
   1.904 +
   1.905 +      // We'll accept `resource' or `rdf:resource', under the spirit
   1.906 +      // that we should be liberal towards the input that we
   1.907 +      // receive.
   1.908 +      if (!nameSpaceURI.IsEmpty() &&
   1.909 +          !nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI)) {
   1.910 +          continue;
   1.911 +      }
   1.912 +
   1.913 +      // XXX you can't specify both, but we'll just pick up the
   1.914 +      // first thing that was specified and ignore the other.
   1.915 +
   1.916 +      if (localName == kResourceAtom) {
   1.917 +          // XXX Take the URI and make it fully qualified by
   1.918 +          // sticking it into the document's URL. This may not be
   1.919 +          // appropriate...
   1.920 +          nsAutoString relURI(aAttributes[1]);
   1.921 +          if (rdf_RequiresAbsoluteURI(relURI)) {
   1.922 +              nsresult rv;
   1.923 +              nsAutoCString uri;
   1.924 +
   1.925 +              rv = mDocumentURL->Resolve(NS_ConvertUTF16toUTF8(aAttributes[1]), uri);
   1.926 +              if (NS_FAILED(rv)) return rv;
   1.927 +
   1.928 +              return gRDFService->GetResource(uri, aResource);
   1.929 +          } 
   1.930 +          return gRDFService->GetResource(NS_ConvertUTF16toUTF8(aAttributes[1]), 
   1.931 +                                          aResource);
   1.932 +      }
   1.933 +      else if (localName == kNodeIdAtom) {
   1.934 +          nodeID.Assign(aAttributes[1]);
   1.935 +      }
   1.936 +  }
   1.937 +    
   1.938 +  // If nodeID is present, check if we already know about it. If we've seen
   1.939 +  // the nodeID before, use the same resource, otherwise generate a new one.
   1.940 +  if (!nodeID.IsEmpty()) {
   1.941 +      mNodeIDMap.Get(nodeID,aResource);
   1.942 +
   1.943 +      if (!*aResource) {
   1.944 +          nsresult rv;
   1.945 +          rv = gRDFService->GetAnonymousResource(aResource);
   1.946 +          if (NS_FAILED(rv)) {
   1.947 +              return rv;
   1.948 +          }
   1.949 +          mNodeIDMap.Put(nodeID,*aResource);
   1.950 +      }
   1.951 +      return NS_OK;
   1.952 +  }
   1.953 +
   1.954 +  return NS_ERROR_FAILURE;
   1.955 +}
   1.956 +
   1.957 +nsresult
   1.958 +RDFContentSinkImpl::AddProperties(const char16_t** aAttributes,
   1.959 +                                  nsIRDFResource* aSubject,
   1.960 +                                  int32_t* aCount)
   1.961 +{
   1.962 +  if (aCount)
   1.963 +      *aCount = 0;
   1.964 +
   1.965 +  nsCOMPtr<nsIAtom> localName;
   1.966 +  for (; *aAttributes; aAttributes += 2) {
   1.967 +      const nsDependentSubstring& nameSpaceURI =
   1.968 +          SplitExpatName(aAttributes[0], getter_AddRefs(localName));
   1.969 +
   1.970 +      // skip 'xmlns' directives, these are "meta" information
   1.971 +      if (nameSpaceURI.EqualsLiteral("http://www.w3.org/2000/xmlns/")) {
   1.972 +        continue;
   1.973 +      }
   1.974 +
   1.975 +      // skip `about', `ID', `resource', and 'nodeID' attributes (either with or
   1.976 +      // without the `rdf:' prefix); these are all "special" and
   1.977 +      // should've been dealt with by the caller.
   1.978 +      if (localName == kAboutAtom || localName == kIdAtom ||
   1.979 +          localName == kResourceAtom || localName == kNodeIdAtom) {
   1.980 +          if (nameSpaceURI.IsEmpty() ||
   1.981 +              nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI))
   1.982 +              continue;
   1.983 +      }
   1.984 +
   1.985 +      // Skip `parseType', `RDF:parseType', and `NC:parseType'. This
   1.986 +      // is meta-information that will be handled in SetParseMode.
   1.987 +      if (localName == kParseTypeAtom) {
   1.988 +          if (nameSpaceURI.IsEmpty() ||
   1.989 +              nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI) ||
   1.990 +              nameSpaceURI.EqualsLiteral(NC_NAMESPACE_URI)) {
   1.991 +              continue;
   1.992 +          }
   1.993 +      }
   1.994 +
   1.995 +      NS_ConvertUTF16toUTF8 propertyStr(nameSpaceURI);    
   1.996 +      propertyStr.Append(nsAtomCString(localName));
   1.997 +
   1.998 +      // Add the assertion to RDF
   1.999 +      nsCOMPtr<nsIRDFResource> property;
  1.1000 +      gRDFService->GetResource(propertyStr, getter_AddRefs(property));
  1.1001 +
  1.1002 +      nsCOMPtr<nsIRDFLiteral> target;
  1.1003 +      gRDFService->GetLiteral(aAttributes[1], 
  1.1004 +                              getter_AddRefs(target));
  1.1005 +
  1.1006 +      mDataSource->Assert(aSubject, property, target, true);
  1.1007 +  }
  1.1008 +  return NS_OK;
  1.1009 +}
  1.1010 +
  1.1011 +void
  1.1012 +RDFContentSinkImpl::SetParseMode(const char16_t **aAttributes)
  1.1013 +{
  1.1014 +    nsCOMPtr<nsIAtom> localName;
  1.1015 +    for (; *aAttributes; aAttributes += 2) {
  1.1016 +        const nsDependentSubstring& nameSpaceURI =
  1.1017 +            SplitExpatName(aAttributes[0], getter_AddRefs(localName));
  1.1018 +
  1.1019 +        if (localName == kParseTypeAtom) {
  1.1020 +            nsDependentString v(aAttributes[1]);
  1.1021 +
  1.1022 +            if (nameSpaceURI.IsEmpty() ||
  1.1023 +                nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI)) {
  1.1024 +                if (v.EqualsLiteral("Resource"))
  1.1025 +                    mParseMode = eRDFContentSinkParseMode_Resource;
  1.1026 +
  1.1027 +                break;
  1.1028 +            }
  1.1029 +            else if (nameSpaceURI.EqualsLiteral(NC_NAMESPACE_URI)) {
  1.1030 +                if (v.EqualsLiteral("Date"))
  1.1031 +                    mParseMode = eRDFContentSinkParseMode_Date;
  1.1032 +                else if (v.EqualsLiteral("Integer"))
  1.1033 +                    mParseMode = eRDFContentSinkParseMode_Int;
  1.1034 +
  1.1035 +                break;
  1.1036 +            }
  1.1037 +        }
  1.1038 +    }
  1.1039 +}
  1.1040 +
  1.1041 +////////////////////////////////////////////////////////////////////////
  1.1042 +// RDF-specific routines used to build the model
  1.1043 +
  1.1044 +nsresult
  1.1045 +RDFContentSinkImpl::OpenRDF(const char16_t* aName)
  1.1046 +{
  1.1047 +    // ensure that we're actually reading RDF by making sure that the
  1.1048 +    // opening tag is <rdf:RDF>, where "rdf:" corresponds to whatever
  1.1049 +    // they've declared the standard RDF namespace to be.
  1.1050 +    nsCOMPtr<nsIAtom> localName;
  1.1051 +    const nsDependentSubstring& nameSpaceURI =
  1.1052 +        SplitExpatName(aName, getter_AddRefs(localName));
  1.1053 +
  1.1054 +    if (!nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI) || localName != kRDFAtom) {
  1.1055 +       // PR_LOG(gLog, PR_LOG_ALWAYS,
  1.1056 +       //        ("rdfxml: expected RDF:RDF at line %d",
  1.1057 +       //         aNode.GetSourceLineNumber()));
  1.1058 +
  1.1059 +        return NS_ERROR_UNEXPECTED;
  1.1060 +    }
  1.1061 +
  1.1062 +    PushContext(nullptr, mState, mParseMode);
  1.1063 +    mState = eRDFContentSinkState_InDocumentElement;
  1.1064 +    return NS_OK;
  1.1065 +}
  1.1066 +
  1.1067 +nsresult
  1.1068 +RDFContentSinkImpl::OpenObject(const char16_t* aName, 
  1.1069 +                               const char16_t** aAttributes)
  1.1070 +{
  1.1071 +    // an "object" non-terminal is either a "description", a "typed
  1.1072 +    // node", or a "container", so this change the content sink's
  1.1073 +    // state appropriately.
  1.1074 +    nsCOMPtr<nsIAtom> localName;
  1.1075 +    const nsDependentSubstring& nameSpaceURI =
  1.1076 +        SplitExpatName(aName, getter_AddRefs(localName));
  1.1077 +
  1.1078 +    // Figure out the URI of this object, and create an RDF node for it.
  1.1079 +    nsCOMPtr<nsIRDFResource> source;
  1.1080 +    GetIdAboutAttribute(aAttributes, getter_AddRefs(source));
  1.1081 +
  1.1082 +    // If there is no `ID' or `about', then there's not much we can do.
  1.1083 +    if (! source)
  1.1084 +        return NS_ERROR_FAILURE;
  1.1085 +
  1.1086 +    // Push the element onto the context stack
  1.1087 +    PushContext(source, mState, mParseMode);
  1.1088 +
  1.1089 +    // Now figure out what kind of state transition we need to
  1.1090 +    // make. We'll either be going into a mode where we parse a
  1.1091 +    // description or a container.
  1.1092 +    bool isaTypedNode = true;
  1.1093 +
  1.1094 +    if (nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI)) {
  1.1095 +        isaTypedNode = false;
  1.1096 +
  1.1097 +        if (localName == kDescriptionAtom) {
  1.1098 +            // it's a description
  1.1099 +            mState = eRDFContentSinkState_InDescriptionElement;
  1.1100 +        }
  1.1101 +        else if (localName == kBagAtom) {
  1.1102 +            // it's a bag container
  1.1103 +            InitContainer(kRDF_Bag, source);
  1.1104 +            mState = eRDFContentSinkState_InContainerElement;
  1.1105 +        }
  1.1106 +        else if (localName == kSeqAtom) {
  1.1107 +            // it's a seq container
  1.1108 +            InitContainer(kRDF_Seq, source);
  1.1109 +            mState = eRDFContentSinkState_InContainerElement;
  1.1110 +        }
  1.1111 +        else if (localName == kAltAtom) {
  1.1112 +            // it's an alt container
  1.1113 +            InitContainer(kRDF_Alt, source);
  1.1114 +            mState = eRDFContentSinkState_InContainerElement;
  1.1115 +        }
  1.1116 +        else {
  1.1117 +            // heh, that's not *in* the RDF namespace: just treat it
  1.1118 +            // like a typed node
  1.1119 +            isaTypedNode = true;
  1.1120 +        }
  1.1121 +    }
  1.1122 +
  1.1123 +    if (isaTypedNode) {
  1.1124 +        NS_ConvertUTF16toUTF8 typeStr(nameSpaceURI);
  1.1125 +        typeStr.Append(nsAtomCString(localName));
  1.1126 +
  1.1127 +        nsCOMPtr<nsIRDFResource> type;
  1.1128 +        nsresult rv = gRDFService->GetResource(typeStr, getter_AddRefs(type));
  1.1129 +        if (NS_FAILED(rv)) return rv;
  1.1130 +
  1.1131 +        rv = mDataSource->Assert(source, kRDF_type, type, true);
  1.1132 +        if (NS_FAILED(rv)) return rv;
  1.1133 +
  1.1134 +        mState = eRDFContentSinkState_InDescriptionElement;
  1.1135 +    }
  1.1136 +
  1.1137 +    AddProperties(aAttributes, source);
  1.1138 +    return NS_OK;
  1.1139 +}
  1.1140 +
  1.1141 +nsresult
  1.1142 +RDFContentSinkImpl::OpenProperty(const char16_t* aName, const char16_t** aAttributes)
  1.1143 +{
  1.1144 +    nsresult rv;
  1.1145 +
  1.1146 +    // an "object" non-terminal is either a "description", a "typed
  1.1147 +    // node", or a "container", so this change the content sink's
  1.1148 +    // state appropriately.
  1.1149 +    nsCOMPtr<nsIAtom> localName;
  1.1150 +    const nsDependentSubstring& nameSpaceURI =
  1.1151 +        SplitExpatName(aName, getter_AddRefs(localName));
  1.1152 +
  1.1153 +    NS_ConvertUTF16toUTF8 propertyStr(nameSpaceURI);
  1.1154 +    propertyStr.Append(nsAtomCString(localName));
  1.1155 +
  1.1156 +    nsCOMPtr<nsIRDFResource> property;
  1.1157 +    rv = gRDFService->GetResource(propertyStr, getter_AddRefs(property));
  1.1158 +    if (NS_FAILED(rv)) return rv;
  1.1159 +
  1.1160 +    // See if they've specified a 'resource' attribute, in which case
  1.1161 +    // they mean *that* to be the object of this property.
  1.1162 +    nsCOMPtr<nsIRDFResource> target;
  1.1163 +    GetResourceAttribute(aAttributes, getter_AddRefs(target));
  1.1164 +
  1.1165 +    bool isAnonymous = false;
  1.1166 +
  1.1167 +    if (! target) {
  1.1168 +        // See if an 'ID' attribute has been specified, in which case
  1.1169 +        // this corresponds to the fourth form of [6.12].
  1.1170 +
  1.1171 +        // XXX strictly speaking, we should reject the RDF/XML as
  1.1172 +        // invalid if they've specified both an 'ID' and a 'resource'
  1.1173 +        // attribute. Bah.
  1.1174 +
  1.1175 +        // XXX strictly speaking, 'about=' isn't allowed here, but
  1.1176 +        // what the hell.
  1.1177 +        GetIdAboutAttribute(aAttributes, getter_AddRefs(target), &isAnonymous);
  1.1178 +    }
  1.1179 +
  1.1180 +    if (target) {
  1.1181 +        // They specified an inline resource for the value of this
  1.1182 +        // property. Create an RDF resource for the inline resource
  1.1183 +        // URI, add the properties to it, and attach the inline
  1.1184 +        // resource to its parent.
  1.1185 +        int32_t count;
  1.1186 +        rv = AddProperties(aAttributes, target, &count);
  1.1187 +        NS_ASSERTION(NS_SUCCEEDED(rv), "problem adding properties");
  1.1188 +        if (NS_FAILED(rv)) return rv;
  1.1189 +
  1.1190 +        if (count || !isAnonymous) {
  1.1191 +            // If the resource was "anonymous" (i.e., they hadn't
  1.1192 +            // explicitly set an ID or resource attribute), then we'll
  1.1193 +            // only assert this property from the context element *if*
  1.1194 +            // there were properties specified on the anonymous
  1.1195 +            // resource.
  1.1196 +            rv = mDataSource->Assert(GetContextElement(0), property, target, true);
  1.1197 +            if (NS_FAILED(rv)) return rv;
  1.1198 +        }
  1.1199 +
  1.1200 +        // XXX Technically, we should _not_ fall through here and push
  1.1201 +        // the element onto the stack: this is supposed to be a closed
  1.1202 +        // node. But right now I'm lazy and the code will just Do The
  1.1203 +        // Right Thing so long as the RDF is well-formed.
  1.1204 +    }
  1.1205 +
  1.1206 +    // Push the element onto the context stack and change state.
  1.1207 +    PushContext(property, mState, mParseMode);
  1.1208 +    mState = eRDFContentSinkState_InPropertyElement;
  1.1209 +    SetParseMode(aAttributes);
  1.1210 +
  1.1211 +    return NS_OK;
  1.1212 +}
  1.1213 +
  1.1214 +nsresult
  1.1215 +RDFContentSinkImpl::OpenMember(const char16_t* aName, 
  1.1216 +                               const char16_t** aAttributes)
  1.1217 +{
  1.1218 +    // ensure that we're actually reading a member element by making
  1.1219 +    // sure that the opening tag is <rdf:li>, where "rdf:" corresponds
  1.1220 +    // to whatever they've declared the standard RDF namespace to be.
  1.1221 +    nsresult rv;
  1.1222 +
  1.1223 +    nsCOMPtr<nsIAtom> localName;
  1.1224 +    const nsDependentSubstring& nameSpaceURI =
  1.1225 +        SplitExpatName(aName, getter_AddRefs(localName));
  1.1226 +
  1.1227 +    if (!nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI) ||
  1.1228 +        localName != kLiAtom) {
  1.1229 +        PR_LOG(gLog, PR_LOG_ALWAYS,
  1.1230 +               ("rdfxml: expected RDF:li at line %d",
  1.1231 +                -1)); // XXX pass in line number
  1.1232 +
  1.1233 +        return NS_ERROR_UNEXPECTED;
  1.1234 +    }
  1.1235 +
  1.1236 +    // The parent element is the container.
  1.1237 +    nsIRDFResource* container = GetContextElement(0);
  1.1238 +    if (! container)
  1.1239 +        return NS_ERROR_NULL_POINTER;
  1.1240 +
  1.1241 +    nsIRDFResource* resource;
  1.1242 +    if (NS_SUCCEEDED(rv = GetResourceAttribute(aAttributes, &resource))) {
  1.1243 +        // Okay, this node has an RDF:resource="..." attribute. That
  1.1244 +        // means that it's a "referenced item," as covered in [6.29].
  1.1245 +        nsCOMPtr<nsIRDFContainer> c;
  1.1246 +        NS_NewRDFContainer(getter_AddRefs(c));
  1.1247 +        c->Init(mDataSource, container);
  1.1248 +        c->AppendElement(resource);
  1.1249 +
  1.1250 +        // XXX Technically, we should _not_ fall through here and push
  1.1251 +        // the element onto the stack: this is supposed to be a closed
  1.1252 +        // node. But right now I'm lazy and the code will just Do The
  1.1253 +        // Right Thing so long as the RDF is well-formed.
  1.1254 +        NS_RELEASE(resource);
  1.1255 +    }
  1.1256 +
  1.1257 +    // Change state. Pushing a null context element is a bit weird,
  1.1258 +    // but the idea is that there really is _no_ context "property".
  1.1259 +    // The contained element will use nsIRDFContainer::AppendElement() to add
  1.1260 +    // the element to the container, which requires only the container
  1.1261 +    // and the element to be added.
  1.1262 +    PushContext(nullptr, mState, mParseMode);
  1.1263 +    mState = eRDFContentSinkState_InMemberElement;
  1.1264 +    SetParseMode(aAttributes);
  1.1265 +
  1.1266 +    return NS_OK;
  1.1267 +}
  1.1268 +
  1.1269 +
  1.1270 +nsresult
  1.1271 +RDFContentSinkImpl::OpenValue(const char16_t* aName, const char16_t** aAttributes)
  1.1272 +{
  1.1273 +    // a "value" can either be an object or a string: we'll only get
  1.1274 +    // *here* if it's an object, as raw text is added as a leaf.
  1.1275 +    return OpenObject(aName,aAttributes);
  1.1276 +}
  1.1277 +
  1.1278 +////////////////////////////////////////////////////////////////////////
  1.1279 +// namespace resolution
  1.1280 +void
  1.1281 +RDFContentSinkImpl::RegisterNamespaces(const char16_t **aAttributes)
  1.1282 +{
  1.1283 +    nsCOMPtr<nsIRDFXMLSink> sink = do_QueryInterface(mDataSource);
  1.1284 +    if (!sink) {
  1.1285 +        return;
  1.1286 +    }
  1.1287 +    NS_NAMED_LITERAL_STRING(xmlns, "http://www.w3.org/2000/xmlns/");
  1.1288 +    for (; *aAttributes; aAttributes += 2) {
  1.1289 +        // check the namespace
  1.1290 +        const char16_t* attr = aAttributes[0];
  1.1291 +        const char16_t* xmlnsP = xmlns.BeginReading();
  1.1292 +        while (*attr ==  *xmlnsP) {
  1.1293 +            ++attr;
  1.1294 +            ++xmlnsP;
  1.1295 +        }
  1.1296 +        if (*attr != 0xFFFF ||
  1.1297 +            xmlnsP != xmlns.EndReading()) {
  1.1298 +            continue;
  1.1299 +        }
  1.1300 +        // get the localname (or "xmlns" for the default namespace)
  1.1301 +        const char16_t* endLocal = ++attr;
  1.1302 +        while (*endLocal && *endLocal != 0xFFFF) {
  1.1303 +            ++endLocal;
  1.1304 +        }
  1.1305 +        nsDependentSubstring lname(attr, endLocal);
  1.1306 +        nsCOMPtr<nsIAtom> preferred = do_GetAtom(lname);
  1.1307 +        if (preferred == kXMLNSAtom) {
  1.1308 +            preferred = nullptr;
  1.1309 +        }
  1.1310 +        sink->AddNameSpace(preferred, nsDependentString(aAttributes[1]));
  1.1311 +    }
  1.1312 +}
  1.1313 +
  1.1314 +////////////////////////////////////////////////////////////////////////
  1.1315 +// Qualified name resolution
  1.1316 +
  1.1317 +const nsDependentSubstring
  1.1318 +RDFContentSinkImpl::SplitExpatName(const char16_t *aExpatName,
  1.1319 +                                   nsIAtom **aLocalName)
  1.1320 +{
  1.1321 +    /**
  1.1322 +     *  Expat can send the following:
  1.1323 +     *    localName
  1.1324 +     *    namespaceURI<separator>localName
  1.1325 +     *    namespaceURI<separator>localName<separator>prefix
  1.1326 +     *
  1.1327 +     *  and we use 0xFFFF for the <separator>.
  1.1328 +     *
  1.1329 +     */
  1.1330 +
  1.1331 +    const char16_t *uriEnd = aExpatName;
  1.1332 +    const char16_t *nameStart = aExpatName;
  1.1333 +    const char16_t *pos;
  1.1334 +    for (pos = aExpatName; *pos; ++pos) {
  1.1335 +        if (*pos == 0xFFFF) {
  1.1336 +            if (uriEnd != aExpatName) {
  1.1337 +                break;
  1.1338 +            }
  1.1339 +
  1.1340 +            uriEnd = pos;
  1.1341 +            nameStart = pos + 1;
  1.1342 +        }
  1.1343 +    }
  1.1344 +
  1.1345 +    const nsDependentSubstring& nameSpaceURI = Substring(aExpatName, uriEnd);
  1.1346 +    *aLocalName = NS_NewAtom(Substring(nameStart, pos)).take();
  1.1347 +    return nameSpaceURI;
  1.1348 +}
  1.1349 +
  1.1350 +nsresult
  1.1351 +RDFContentSinkImpl::InitContainer(nsIRDFResource* aContainerType, nsIRDFResource* aContainer)
  1.1352 +{
  1.1353 +    // Do the right kind of initialization based on the container
  1.1354 +    // 'type' resource, and the state of the container (i.e., 'make' a
  1.1355 +    // new container vs. 'reinitialize' the container).
  1.1356 +    nsresult rv;
  1.1357 +
  1.1358 +    static const ContainerInfo gContainerInfo[] = {
  1.1359 +        { &RDFContentSinkImpl::kRDF_Alt, &nsIRDFContainerUtils::IsAlt, &nsIRDFContainerUtils::MakeAlt },
  1.1360 +        { &RDFContentSinkImpl::kRDF_Bag, &nsIRDFContainerUtils::IsBag, &nsIRDFContainerUtils::MakeBag },
  1.1361 +        { &RDFContentSinkImpl::kRDF_Seq, &nsIRDFContainerUtils::IsSeq, &nsIRDFContainerUtils::MakeSeq },
  1.1362 +        { 0, 0, 0 },
  1.1363 +    };
  1.1364 +
  1.1365 +    for (const ContainerInfo* info = gContainerInfo; info->mType != 0; ++info) {
  1.1366 +        if (*info->mType != aContainerType)
  1.1367 +            continue;
  1.1368 +
  1.1369 +        bool isContainer;
  1.1370 +        rv = (gRDFContainerUtils->*(info->mTestFn))(mDataSource, aContainer, &isContainer);
  1.1371 +        if (isContainer) {
  1.1372 +            rv = ReinitContainer(aContainerType, aContainer);
  1.1373 +        }
  1.1374 +        else {
  1.1375 +            rv = (gRDFContainerUtils->*(info->mMakeFn))(mDataSource, aContainer, nullptr);
  1.1376 +        }
  1.1377 +        return rv;
  1.1378 +    }
  1.1379 +
  1.1380 +    NS_NOTREACHED("not an RDF container type");
  1.1381 +    return NS_ERROR_FAILURE;
  1.1382 +}
  1.1383 +
  1.1384 +
  1.1385 +
  1.1386 +nsresult
  1.1387 +RDFContentSinkImpl::ReinitContainer(nsIRDFResource* aContainerType, nsIRDFResource* aContainer)
  1.1388 +{
  1.1389 +    // Mega-kludge to deal with the fact that Make[Seq|Alt|Bag] is
  1.1390 +    // idempotent, and as such, containers will have state (e.g.,
  1.1391 +    // RDF:nextVal) maintained in the graph across loads. This
  1.1392 +    // re-initializes each container's RDF:nextVal to '1', and 'marks'
  1.1393 +    // the container as such.
  1.1394 +    nsresult rv;
  1.1395 +
  1.1396 +    nsCOMPtr<nsIRDFLiteral> one;
  1.1397 +    rv = gRDFService->GetLiteral(MOZ_UTF16("1"), getter_AddRefs(one));
  1.1398 +    if (NS_FAILED(rv)) return rv;
  1.1399 +
  1.1400 +    // Re-initialize the 'nextval' property
  1.1401 +    nsCOMPtr<nsIRDFNode> nextval;
  1.1402 +    rv = mDataSource->GetTarget(aContainer, kRDF_nextVal, true, getter_AddRefs(nextval));
  1.1403 +    if (NS_FAILED(rv)) return rv;
  1.1404 +
  1.1405 +    rv = mDataSource->Change(aContainer, kRDF_nextVal, nextval, one);
  1.1406 +    if (NS_FAILED(rv)) return rv;
  1.1407 +
  1.1408 +    // Re-mark as a container. XXX should be kRDF_type
  1.1409 +    rv = mDataSource->Assert(aContainer, kRDF_instanceOf, aContainerType, true);
  1.1410 +    NS_ASSERTION(NS_SUCCEEDED(rv), "unable to mark container as such");
  1.1411 +    if (NS_FAILED(rv)) return rv;
  1.1412 +
  1.1413 +    return NS_OK;
  1.1414 +}
  1.1415 +
  1.1416 +////////////////////////////////////////////////////////////////////////
  1.1417 +// Content stack management
  1.1418 +
  1.1419 +nsIRDFResource* 
  1.1420 +RDFContentSinkImpl::GetContextElement(int32_t ancestor /* = 0 */)
  1.1421 +{
  1.1422 +    if ((nullptr == mContextStack) ||
  1.1423 +        (uint32_t(ancestor) >= mContextStack->Length())) {
  1.1424 +        return nullptr;
  1.1425 +    }
  1.1426 +
  1.1427 +    return mContextStack->ElementAt(
  1.1428 +           mContextStack->Length()-ancestor-1).mResource;
  1.1429 +}
  1.1430 +
  1.1431 +int32_t 
  1.1432 +RDFContentSinkImpl::PushContext(nsIRDFResource         *aResource,
  1.1433 +                                RDFContentSinkState     aState,
  1.1434 +                                RDFContentSinkParseMode aParseMode)
  1.1435 +{
  1.1436 +    if (! mContextStack) {
  1.1437 +        mContextStack = new nsAutoTArray<RDFContextStackElement, 8>();
  1.1438 +        if (! mContextStack)
  1.1439 +            return 0;
  1.1440 +    }
  1.1441 +
  1.1442 +    RDFContextStackElement* e = mContextStack->AppendElement();
  1.1443 +    if (! e)
  1.1444 +        return mContextStack->Length();
  1.1445 +
  1.1446 +    e->mResource  = aResource;
  1.1447 +    e->mState     = aState;
  1.1448 +    e->mParseMode = aParseMode;
  1.1449 +  
  1.1450 +    return mContextStack->Length();
  1.1451 +}
  1.1452 + 
  1.1453 +nsresult
  1.1454 +RDFContentSinkImpl::PopContext(nsIRDFResource         *&aResource,
  1.1455 +                               RDFContentSinkState     &aState,
  1.1456 +                               RDFContentSinkParseMode &aParseMode)
  1.1457 +{
  1.1458 +    if ((nullptr == mContextStack) ||
  1.1459 +        (mContextStack->IsEmpty())) {
  1.1460 +        return NS_ERROR_NULL_POINTER;
  1.1461 +    }
  1.1462 +
  1.1463 +    uint32_t i = mContextStack->Length() - 1;
  1.1464 +    RDFContextStackElement &e = mContextStack->ElementAt(i);
  1.1465 +
  1.1466 +    aResource  = e.mResource;
  1.1467 +    NS_IF_ADDREF(aResource);
  1.1468 +    aState     = e.mState;
  1.1469 +    aParseMode = e.mParseMode;
  1.1470 +
  1.1471 +    mContextStack->RemoveElementAt(i);
  1.1472 +    return NS_OK;
  1.1473 +}
  1.1474 + 
  1.1475 +
  1.1476 +////////////////////////////////////////////////////////////////////////
  1.1477 +
  1.1478 +nsresult
  1.1479 +NS_NewRDFContentSink(nsIRDFContentSink** aResult)
  1.1480 +{
  1.1481 +    NS_PRECONDITION(aResult != nullptr, "null ptr");
  1.1482 +    if (! aResult)
  1.1483 +        return NS_ERROR_NULL_POINTER;
  1.1484 +
  1.1485 +    RDFContentSinkImpl* sink = new RDFContentSinkImpl();
  1.1486 +    if (! sink)
  1.1487 +        return NS_ERROR_OUT_OF_MEMORY;
  1.1488 +
  1.1489 +    NS_ADDREF(sink);
  1.1490 +    *aResult = sink;
  1.1491 +    return NS_OK;
  1.1492 +}

mercurial