1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * Pierre Phaneuf <pp@ludusdesign.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
41 An implementation for an NGLayout-style content sink that knows how
42 to build an RDF content model from XML-serialized RDF.
44 For more information on the RDF/XML syntax,
45 see http://www.w3.org/TR/REC-rdf-syntax/
47 This code is based on the final W3C Recommendation,
48 http://www.w3.org/TR/1999/REC-rdf-syntax-19990222.
50 Open Issues ------------------
52 1) factoring code with nsXMLContentSink - There's some amount of
53 common code between this and the HTML content sink. This will
54 increase as we support more and more HTML elements. How can code
55 from XML/HTML be factored?
57 2) We don't support the `parseType' attribute on the Description
58 tag; therefore, it is impossible to "inline" raw XML in this
61 3) We don't build the reifications at parse time due to the
62 footprint overhead it would incur for large RDF documents. (It
63 may be possible to attach a "reification" wrapper datasource that
64 would present this information at query-time.) Because of this,
65 the `bagID' attribute is not processed correctly.
67 4) No attempt is made to `resolve URIs' to a canonical form (the
68 specification hints that an implementation should do this). This
69 is omitted for the obvious reason that we can ill afford to
70 resolve each URI reference.
75 #include "nsInterfaceHashtable.h"
76 #include "nsIContentSink.h"
77 #include "nsIRDFContainer.h"
78 #include "nsIRDFContainerUtils.h"
79 #include "nsIRDFContentSink.h"
80 #include "nsIRDFNode.h"
81 #include "nsIRDFService.h"
82 #include "nsIRDFXMLSink.h"
83 #include "nsIServiceManager.h"
85 #include "nsIXMLContentSink.h"
88 #include "nsXPIDLString.h"
93 #include "nsReadableUtils.h"
94 #include "nsIExpatSink.h"
97 #include "nsStaticAtom.h"
98 #include "nsIScriptError.h"
101 ////////////////////////////////////////////////////////////////////////
104 static NS_DEFINE_IID(kIContentSinkIID
, NS_ICONTENT_SINK_IID
); // XXX grr...
105 static NS_DEFINE_IID(kIExpatSinkIID
, NS_IEXPATSINK_IID
);
106 static NS_DEFINE_IID(kIRDFServiceIID
, NS_IRDFSERVICE_IID
);
107 static NS_DEFINE_IID(kISupportsIID
, NS_ISUPPORTS_IID
);
108 static NS_DEFINE_IID(kIXMLContentSinkIID
, NS_IXMLCONTENT_SINK_IID
);
109 static NS_DEFINE_IID(kIRDFContentSinkIID
, NS_IRDFCONTENTSINK_IID
);
111 static NS_DEFINE_CID(kRDFServiceCID
, NS_RDFSERVICE_CID
);
112 static NS_DEFINE_CID(kRDFContainerUtilsCID
, NS_RDFCONTAINERUTILS_CID
);
114 ////////////////////////////////////////////////////////////////////////
117 static PRLogModuleInfo
* gLog
;
120 ///////////////////////////////////////////////////////////////////////
122 enum RDFContentSinkState
{
123 eRDFContentSinkState_InProlog
,
124 eRDFContentSinkState_InDocumentElement
,
125 eRDFContentSinkState_InDescriptionElement
,
126 eRDFContentSinkState_InContainerElement
,
127 eRDFContentSinkState_InPropertyElement
,
128 eRDFContentSinkState_InMemberElement
,
129 eRDFContentSinkState_InEpilog
132 enum RDFContentSinkParseMode
{
133 eRDFContentSinkParseMode_Resource
,
134 eRDFContentSinkParseMode_Literal
,
135 eRDFContentSinkParseMode_Int
,
136 eRDFContentSinkParseMode_Date
140 NS_STDCALL_FUNCPROTO(nsresult
,
142 nsIRDFContainerUtils
, IsAlt
,
143 (nsIRDFDataSource
*, nsIRDFResource
*, PRBool
*));
146 NS_STDCALL_FUNCPROTO(nsresult
,
148 nsIRDFContainerUtils
, MakeAlt
,
149 (nsIRDFDataSource
*, nsIRDFResource
*, nsIRDFContainer
**));
151 class RDFContentSinkImpl
: public nsIRDFContentSink
,
155 RDFContentSinkImpl();
156 virtual ~RDFContentSinkImpl();
163 NS_IMETHOD
WillParse(void);
164 NS_IMETHOD
WillBuildModel(nsDTDMode aDTDMode
);
165 NS_IMETHOD
DidBuildModel(PRBool aTerminated
);
166 NS_IMETHOD
WillInterrupt(void);
167 NS_IMETHOD
WillResume(void);
168 NS_IMETHOD
SetParser(nsIParser
* aParser
);
169 virtual void FlushPendingNotifications(mozFlushType aType
) { }
170 NS_IMETHOD
SetDocumentCharset(nsACString
& aCharset
) { return NS_OK
; }
171 virtual nsISupports
*GetTarget() { return nsnull
; }
174 NS_IMETHOD
Init(nsIURI
* aURL
);
175 NS_IMETHOD
SetDataSource(nsIRDFDataSource
* aDataSource
);
176 NS_IMETHOD
GetDataSource(nsIRDFDataSource
*& aDataSource
);
179 static PRInt32 gRefCnt
;
180 static nsIRDFService
* gRDFService
;
181 static nsIRDFContainerUtils
* gRDFContainerUtils
;
182 static nsIRDFResource
* kRDF_type
;
183 static nsIRDFResource
* kRDF_instanceOf
; // XXX should be RDF:type
184 static nsIRDFResource
* kRDF_Alt
;
185 static nsIRDFResource
* kRDF_Bag
;
186 static nsIRDFResource
* kRDF_Seq
;
187 static nsIRDFResource
* kRDF_nextVal
;
189 #define RDF_ATOM(name_, value_) static nsIAtom* name_;
190 #include "nsRDFContentSinkAtomList.h"
193 typedef struct ContainerInfo
{
194 nsIRDFResource
** mType
;
195 nsContainerTestFn mTestFn
;
196 nsMakeContainerFn mMakeFn
;
201 void ParseText(nsIRDFNode
**aResult
);
203 nsresult
FlushText();
204 nsresult
AddText(const PRUnichar
* aText
, PRInt32 aLength
);
206 // RDF-specific parsing
207 nsresult
OpenRDF(const PRUnichar
* aName
);
208 nsresult
OpenObject(const PRUnichar
* aName
,const PRUnichar
** aAttributes
);
209 nsresult
OpenProperty(const PRUnichar
* aName
, const PRUnichar
** aAttributes
);
210 nsresult
OpenMember(const PRUnichar
* aName
, const PRUnichar
** aAttributes
);
211 nsresult
OpenValue(const PRUnichar
* aName
, const PRUnichar
** aAttributes
);
213 nsresult
GetIdAboutAttribute(const PRUnichar
** aAttributes
, nsIRDFResource
** aResource
, PRBool
* aIsAnonymous
= nsnull
);
214 nsresult
GetResourceAttribute(const PRUnichar
** aAttributes
, nsIRDFResource
** aResource
);
215 nsresult
AddProperties(const PRUnichar
** aAttributes
, nsIRDFResource
* aSubject
, PRInt32
* aCount
= nsnull
);
216 void SetParseMode(const PRUnichar
**aAttributes
);
223 * From the set of given attributes, this method extracts the
224 * namespace definitions and feeds them to the datasource.
225 * These can then be suggested to the serializer to be used again.
226 * Hopefully, this will keep namespace definitions intact in a
227 * parse - serialize cycle.
229 void RegisterNamespaces(const PRUnichar
**aAttributes
);
232 * Extracts the localname from aExpatName, the name that the Expat parser
234 * aLocalName will contain the localname in aExpatName.
235 * The return value is a dependent string containing just the namespace.
237 const nsDependentSubstring
SplitExpatName(const PRUnichar
*aExpatName
,
238 nsIAtom
**aLocalName
);
240 enum eContainerType
{ eBag
, eSeq
, eAlt
};
241 nsresult
InitContainer(nsIRDFResource
* aContainerType
, nsIRDFResource
* aContainer
);
242 nsresult
ReinitContainer(nsIRDFResource
* aContainerType
, nsIRDFResource
* aContainer
);
244 // The datasource in which we're assigning assertions
245 nsCOMPtr
<nsIRDFDataSource
> mDataSource
;
247 // A hash of all the node IDs referred to
248 nsInterfaceHashtable
<nsStringHashKey
, nsIRDFResource
> mNodeIDMap
;
250 // The current state of the content sink
251 RDFContentSinkState mState
;
252 RDFContentSinkParseMode mParseMode
;
254 // content stack management
256 PushContext(nsIRDFResource
*aContext
,
257 RDFContentSinkState aState
,
258 RDFContentSinkParseMode aParseMode
);
261 PopContext(nsIRDFResource
*&aContext
,
262 RDFContentSinkState
&aState
,
263 RDFContentSinkParseMode
&aParseMode
);
265 nsIRDFResource
* GetContextElement(PRInt32 ancestor
= 0);
268 struct RDFContextStackElement
{
269 nsCOMPtr
<nsIRDFResource
> mResource
;
270 RDFContentSinkState mState
;
271 RDFContentSinkParseMode mParseMode
;
274 nsAutoTArray
<RDFContextStackElement
, 8>* mContextStack
;
276 nsIURI
* mDocumentURL
;
279 PRInt32
RDFContentSinkImpl::gRefCnt
= 0;
280 nsIRDFService
* RDFContentSinkImpl::gRDFService
;
281 nsIRDFContainerUtils
* RDFContentSinkImpl::gRDFContainerUtils
;
282 nsIRDFResource
* RDFContentSinkImpl::kRDF_type
;
283 nsIRDFResource
* RDFContentSinkImpl::kRDF_instanceOf
;
284 nsIRDFResource
* RDFContentSinkImpl::kRDF_Alt
;
285 nsIRDFResource
* RDFContentSinkImpl::kRDF_Bag
;
286 nsIRDFResource
* RDFContentSinkImpl::kRDF_Seq
;
287 nsIRDFResource
* RDFContentSinkImpl::kRDF_nextVal
;
289 ////////////////////////////////////////////////////////////////////////
291 #define RDF_ATOM(name_, value_) nsIAtom* RDFContentSinkImpl::name_;
292 #include "nsRDFContentSinkAtomList.h"
295 #define RDF_ATOM(name_, value_) NS_STATIC_ATOM_BUFFER(name_##_buffer, value_)
296 #include "nsRDFContentSinkAtomList.h"
299 static const nsStaticAtom rdf_atoms
[] = {
300 #define RDF_ATOM(name_, value_) NS_STATIC_ATOM(name_##_buffer, &RDFContentSinkImpl::name_),
301 #include "nsRDFContentSinkAtomList.h"
305 RDFContentSinkImpl::RDFContentSinkImpl()
309 mState(eRDFContentSinkState_InProlog
),
310 mParseMode(eRDFContentSinkParseMode_Literal
),
311 mContextStack(nsnull
),
314 if (gRefCnt
++ == 0) {
315 nsresult rv
= CallGetService(kRDFServiceCID
, &gRDFService
);
317 NS_ASSERTION(NS_SUCCEEDED(rv
), "unable to get RDF service");
318 if (NS_SUCCEEDED(rv
)) {
319 rv
= gRDFService
->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI
"type"),
321 rv
= gRDFService
->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI
"instanceOf"),
323 rv
= gRDFService
->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI
"Alt"),
325 rv
= gRDFService
->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI
"Bag"),
327 rv
= gRDFService
->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI
"Seq"),
329 rv
= gRDFService
->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI
"nextVal"),
334 rv
= CallGetService(kRDFContainerUtilsCID
, &gRDFContainerUtils
);
336 NS_RegisterStaticAtoms(rdf_atoms
, NS_ARRAY_LENGTH(rdf_atoms
));
343 gLog
= PR_NewLogModule("nsRDFContentSink");
348 RDFContentSinkImpl::~RDFContentSinkImpl()
352 fprintf(stdout
, "%d - RDF: RDFContentSinkImpl\n", gInstanceCount
);
355 NS_IF_RELEASE(mDocumentURL
);
358 PR_LOG(gLog
, PR_LOG_WARNING
,
359 ("rdfxml: warning! unclosed tag"));
361 // XXX we should never need to do this, but, we'll write the
362 // code all the same. If someone left the content stack dirty,
363 // pop all the elements off the stack and release them.
364 PRInt32 i
= mContextStack
->Length();
366 nsIRDFResource
* resource
= nsnull
;
367 RDFContentSinkState state
;
368 RDFContentSinkParseMode parseMode
;
369 PopContext(resource
, state
, parseMode
);
372 // print some fairly useless debugging info
373 // XXX we should save line numbers on the context stack: this'd
374 // be about 1000x more helpful.
377 resource
->GetValue(getter_Copies(uri
));
378 PR_LOG(gLog
, PR_LOG_NOTICE
,
379 ("rdfxml: uri=%s", (const char*) uri
));
383 NS_IF_RELEASE(resource
);
386 delete mContextStack
;
391 if (--gRefCnt
== 0) {
392 NS_IF_RELEASE(gRDFService
);
393 NS_IF_RELEASE(gRDFContainerUtils
);
394 NS_IF_RELEASE(kRDF_type
);
395 NS_IF_RELEASE(kRDF_instanceOf
);
396 NS_IF_RELEASE(kRDF_Alt
);
397 NS_IF_RELEASE(kRDF_Bag
);
398 NS_IF_RELEASE(kRDF_Seq
);
399 NS_IF_RELEASE(kRDF_nextVal
);
403 ////////////////////////////////////////////////////////////////////////
404 // nsISupports interface
406 NS_IMPL_ADDREF(RDFContentSinkImpl
)
407 NS_IMPL_RELEASE(RDFContentSinkImpl
)
410 RDFContentSinkImpl::QueryInterface(REFNSIID iid
, void** result
)
412 NS_PRECONDITION(result
, "null ptr");
414 return NS_ERROR_NULL_POINTER
;
417 if (iid
.Equals(kIRDFContentSinkIID
) ||
418 iid
.Equals(kIXMLContentSinkIID
) ||
419 iid
.Equals(kIContentSinkIID
) ||
420 iid
.Equals(kISupportsIID
)) {
421 *result
= static_cast<nsIXMLContentSink
*>(this);
425 else if (iid
.Equals(kIExpatSinkIID
)) {
426 *result
= static_cast<nsIExpatSink
*>(this);
430 return NS_NOINTERFACE
;
434 RDFContentSinkImpl::HandleStartElement(const PRUnichar
*aName
,
435 const PRUnichar
**aAtts
,
438 PRUint32 aLineNumber
)
442 nsresult rv
= NS_ERROR_UNEXPECTED
; // XXX
444 RegisterNamespaces(aAtts
);
447 case eRDFContentSinkState_InProlog
:
451 case eRDFContentSinkState_InDocumentElement
:
452 rv
= OpenObject(aName
,aAtts
);
455 case eRDFContentSinkState_InDescriptionElement
:
456 rv
= OpenProperty(aName
,aAtts
);
459 case eRDFContentSinkState_InContainerElement
:
460 rv
= OpenMember(aName
,aAtts
);
463 case eRDFContentSinkState_InPropertyElement
:
464 case eRDFContentSinkState_InMemberElement
:
465 rv
= OpenValue(aName
,aAtts
);
468 case eRDFContentSinkState_InEpilog
:
469 PR_LOG(gLog
, PR_LOG_WARNING
,
470 ("rdfxml: unexpected content in epilog at line %d",
479 RDFContentSinkImpl::HandleEndElement(const PRUnichar
*aName
)
483 nsIRDFResource
* resource
;
484 if (NS_FAILED(PopContext(resource
, mState
, mParseMode
))) {
485 // XXX parser didn't catch unmatched tags?
487 if (PR_LOG_TEST(gLog
, PR_LOG_WARNING
)) {
488 nsAutoString
tagStr(aName
);
489 char* tagCStr
= ToNewCString(tagStr
);
492 ("rdfxml: extra close tag '%s' at line %d",
493 tagCStr
, 0/*XXX fix me */);
499 return NS_ERROR_UNEXPECTED
; // XXX
502 // If we've just popped a member or property element, _now_ is the
503 // time to add that element to the graph.
505 case eRDFContentSinkState_InMemberElement
:
507 nsCOMPtr
<nsIRDFContainer
> container
;
508 NS_NewRDFContainer(getter_AddRefs(container
));
509 container
->Init(mDataSource
, GetContextElement(1));
510 container
->AppendElement(resource
);
514 case eRDFContentSinkState_InPropertyElement
:
516 mDataSource
->Assert(GetContextElement(1), GetContextElement(0), resource
, PR_TRUE
);
522 if (mContextStack
->IsEmpty())
523 mState
= eRDFContentSinkState_InEpilog
;
525 NS_IF_RELEASE(resource
);
530 RDFContentSinkImpl::HandleComment(const PRUnichar
*aName
)
536 RDFContentSinkImpl::HandleCDataSection(const PRUnichar
*aData
,
539 return aData
? AddText(aData
, aLength
) : NS_OK
;
543 RDFContentSinkImpl::HandleDoctypeDecl(const nsAString
& aSubset
,
544 const nsAString
& aName
,
545 const nsAString
& aSystemId
,
546 const nsAString
& aPublicId
,
547 nsISupports
* aCatalogData
)
553 RDFContentSinkImpl::HandleCharacterData(const PRUnichar
*aData
,
556 return aData
? AddText(aData
, aLength
) : NS_OK
;
560 RDFContentSinkImpl::HandleProcessingInstruction(const PRUnichar
*aTarget
,
561 const PRUnichar
*aData
)
567 RDFContentSinkImpl::HandleXMLDeclaration(const PRUnichar
*aVersion
,
568 const PRUnichar
*aEncoding
,
575 RDFContentSinkImpl::ReportError(const PRUnichar
* aErrorText
,
576 const PRUnichar
* aSourceText
,
577 nsIScriptError
*aError
,
580 NS_PRECONDITION(aError
&& aSourceText
&& aErrorText
, "Check arguments!!!");
582 // The expat driver should report the error.
587 ////////////////////////////////////////////////////////////////////////
588 // nsIContentSink interface
591 RDFContentSinkImpl::WillParse(void)
598 RDFContentSinkImpl::WillBuildModel(nsDTDMode
)
601 nsCOMPtr
<nsIRDFXMLSink
> sink
= do_QueryInterface(mDataSource
);
603 return sink
->BeginLoad();
609 RDFContentSinkImpl::DidBuildModel(PRBool aTerminated
)
612 nsCOMPtr
<nsIRDFXMLSink
> sink
= do_QueryInterface(mDataSource
);
614 return sink
->EndLoad();
620 RDFContentSinkImpl::WillInterrupt(void)
623 nsCOMPtr
<nsIRDFXMLSink
> sink
= do_QueryInterface(mDataSource
);
625 return sink
->Interrupt();
631 RDFContentSinkImpl::WillResume(void)
634 nsCOMPtr
<nsIRDFXMLSink
> sink
= do_QueryInterface(mDataSource
);
636 return sink
->Resume();
642 RDFContentSinkImpl::SetParser(nsIParser
* aParser
)
647 ////////////////////////////////////////////////////////////////////////
648 // nsIRDFContentSink interface
651 RDFContentSinkImpl::Init(nsIURI
* aURL
)
653 NS_PRECONDITION(aURL
!= nsnull
, "null ptr");
655 return NS_ERROR_NULL_POINTER
;
660 mState
= eRDFContentSinkState_InProlog
;
665 RDFContentSinkImpl::SetDataSource(nsIRDFDataSource
* aDataSource
)
667 NS_PRECONDITION(aDataSource
!= nsnull
, "SetDataSource null ptr");
668 mDataSource
= aDataSource
;
669 NS_ASSERTION(mDataSource
!= nsnull
,"Couldn't QI RDF DataSource");
675 RDFContentSinkImpl::GetDataSource(nsIRDFDataSource
*& aDataSource
)
677 aDataSource
= mDataSource
;
678 NS_IF_ADDREF(aDataSource
);
682 ////////////////////////////////////////////////////////////////////////
686 rdf_IsDataInBuffer(PRUnichar
* buffer
, PRInt32 length
)
688 for (PRInt32 i
= 0; i
< length
; ++i
) {
689 if (buffer
[i
] == ' ' ||
701 RDFContentSinkImpl::ParseText(nsIRDFNode
**aResult
)
703 // XXXwaterson wasteful, but we'd need to make a copy anyway to be
704 // able to call nsIRDFService::Get[Resource|Literal|...]().
706 value
.Append(mText
, mTextLength
);
707 value
.Trim(" \t\n\r");
709 switch (mParseMode
) {
710 case eRDFContentSinkParseMode_Literal
:
712 nsIRDFLiteral
*result
;
713 gRDFService
->GetLiteral(value
.get(), &result
);
718 case eRDFContentSinkParseMode_Resource
:
720 nsIRDFResource
*result
;
721 gRDFService
->GetUnicodeResource(value
, &result
);
726 case eRDFContentSinkParseMode_Int
:
729 i
= value
.ToInteger(&err
);
731 gRDFService
->GetIntLiteral(i
, &result
);
736 case eRDFContentSinkParseMode_Date
:
738 PRTime t
= rdf_ParseDate(nsDependentCString(NS_LossyConvertUTF16toASCII(value
).get(), value
.Length()));
740 gRDFService
->GetDateLiteral(t
, &result
);
746 NS_NOTREACHED("unknown parse type");
752 RDFContentSinkImpl::FlushText()
755 if (0 != mTextLength
) {
756 if (rdf_IsDataInBuffer(mText
, mTextLength
)) {
757 // XXX if there's anything but whitespace, then we'll
758 // create a text node.
761 case eRDFContentSinkState_InMemberElement
: {
762 nsCOMPtr
<nsIRDFNode
> node
;
763 ParseText(getter_AddRefs(node
));
765 nsCOMPtr
<nsIRDFContainer
> container
;
766 NS_NewRDFContainer(getter_AddRefs(container
));
767 container
->Init(mDataSource
, GetContextElement(1));
769 container
->AppendElement(node
);
772 case eRDFContentSinkState_InPropertyElement
: {
773 nsCOMPtr
<nsIRDFNode
> node
;
774 ParseText(getter_AddRefs(node
));
776 mDataSource
->Assert(GetContextElement(1), GetContextElement(0), node
, PR_TRUE
);
791 RDFContentSinkImpl::AddText(const PRUnichar
* aText
, PRInt32 aLength
)
793 // Create buffer when we first need it
794 if (0 == mTextSize
) {
795 mText
= (PRUnichar
*) PR_MALLOC(sizeof(PRUnichar
) * 4096);
797 return NS_ERROR_OUT_OF_MEMORY
;
802 // Copy data from string into our buffer; grow the buffer as needed.
803 // It never shrinks, but since the content sink doesn't stick around,
804 // this shouldn't be a bloat issue.
805 PRInt32 amount
= mTextSize
- mTextLength
;
806 if (amount
< aLength
) {
807 // Grow the buffer by at least a factor of two to prevent thrashing.
808 // Since PR_REALLOC will leave mText intact if the call fails,
809 // don't clobber mText or mTextSize until the new mem is allocated.
810 PRInt32 newSize
= (2 * mTextSize
> (mTextSize
+ aLength
)) ?
811 (2 * mTextSize
) : (mTextSize
+ aLength
);
813 (PRUnichar
*) PR_REALLOC(mText
, sizeof(PRUnichar
) * newSize
);
815 return NS_ERROR_OUT_OF_MEMORY
;
819 memcpy(&mText
[mTextLength
], aText
, sizeof(PRUnichar
) * aLength
);
820 mTextLength
+= aLength
;
826 rdf_RequiresAbsoluteURI(const nsString
& uri
)
828 // cheap shot at figuring out if this requires an absolute url translation
829 return !(StringBeginsWith(uri
, NS_LITERAL_STRING("urn:")) ||
830 StringBeginsWith(uri
, NS_LITERAL_STRING("chrome:")));
834 RDFContentSinkImpl::GetIdAboutAttribute(const PRUnichar
** aAttributes
,
835 nsIRDFResource
** aResource
,
836 PRBool
* aIsAnonymous
)
838 // This corresponds to the dirty work of production [6.5]
843 nsCOMPtr
<nsIAtom
> localName
;
844 for (; *aAttributes
; aAttributes
+= 2) {
845 const nsDependentSubstring
& nameSpaceURI
=
846 SplitExpatName(aAttributes
[0], getter_AddRefs(localName
));
848 // We'll accept either `ID' or `rdf:ID' (ibid with `about' or
849 // `rdf:about') in the spirit of being liberal towards the
850 // input that we receive.
851 if (!nameSpaceURI
.IsEmpty() &&
852 !nameSpaceURI
.EqualsLiteral(RDF_NAMESPACE_URI
)) {
856 // XXX you can't specify both, but we'll just pick up the
857 // first thing that was specified and ignore the other.
859 if (localName
== kAboutAtom
) {
861 *aIsAnonymous
= PR_FALSE
;
863 nsAutoString
relURI(aAttributes
[1]);
864 if (rdf_RequiresAbsoluteURI(relURI
)) {
866 rv
= mDocumentURL
->Resolve(NS_ConvertUTF16toUTF8(aAttributes
[1]), uri
);
867 if (NS_FAILED(rv
)) return rv
;
869 return gRDFService
->GetResource(uri
,
872 return gRDFService
->GetResource(NS_ConvertUTF16toUTF8(aAttributes
[1]),
875 else if (localName
== kIdAtom
) {
877 *aIsAnonymous
= PR_FALSE
;
878 // In the spirit of leniency, we do not bother trying to
879 // enforce that this be a valid "XML Name" (see
880 // http://www.w3.org/TR/REC-xml#NT-Nmtoken), as per
881 // 6.21. If we wanted to, this would be where to do it.
883 // Construct an in-line resource whose URI is the
884 // document's URI plus the XML name specified in the ID
887 nsCAutoString
ref('#');
888 AppendUTF16toUTF8(aAttributes
[1], ref
);
890 rv
= mDocumentURL
->Resolve(ref
, name
);
891 if (NS_FAILED(rv
)) return rv
;
893 return gRDFService
->GetResource(name
, aResource
);
895 else if (localName
== kNodeIdAtom
) {
896 nodeID
.Assign(aAttributes
[1]);
898 else if (localName
== kAboutEachAtom
) {
899 // XXX we don't deal with aboutEach...
900 //PR_LOG(gLog, PR_LOG_WARNING,
901 // ("rdfxml: ignoring aboutEach at line %d",
902 // aNode.GetSourceLineNumber()));
906 // Otherwise, we couldn't find anything, so just gensym one...
908 *aIsAnonymous
= PR_TRUE
;
910 // If nodeID is present, check if we already know about it. If we've seen
911 // the nodeID before, use the same resource, otherwise generate a new one.
912 if (!nodeID
.IsEmpty()) {
913 mNodeIDMap
.Get(nodeID
,aResource
);
916 rv
= gRDFService
->GetAnonymousResource(aResource
);
917 mNodeIDMap
.Put(nodeID
,*aResource
);
921 rv
= gRDFService
->GetAnonymousResource(aResource
);
928 RDFContentSinkImpl::GetResourceAttribute(const PRUnichar
** aAttributes
,
929 nsIRDFResource
** aResource
)
931 nsCOMPtr
<nsIAtom
> localName
;
935 for (; *aAttributes
; aAttributes
+= 2) {
936 const nsDependentSubstring
& nameSpaceURI
=
937 SplitExpatName(aAttributes
[0], getter_AddRefs(localName
));
939 // We'll accept `resource' or `rdf:resource', under the spirit
940 // that we should be liberal towards the input that we
942 if (!nameSpaceURI
.IsEmpty() &&
943 !nameSpaceURI
.EqualsLiteral(RDF_NAMESPACE_URI
)) {
947 // XXX you can't specify both, but we'll just pick up the
948 // first thing that was specified and ignore the other.
950 if (localName
== kResourceAtom
) {
951 // XXX Take the URI and make it fully qualified by
952 // sticking it into the document's URL. This may not be
954 nsAutoString
relURI(aAttributes
[1]);
955 if (rdf_RequiresAbsoluteURI(relURI
)) {
959 rv
= mDocumentURL
->Resolve(NS_ConvertUTF16toUTF8(aAttributes
[1]), uri
);
960 if (NS_FAILED(rv
)) return rv
;
962 return gRDFService
->GetResource(uri
, aResource
);
964 return gRDFService
->GetResource(NS_ConvertUTF16toUTF8(aAttributes
[1]),
967 else if (localName
== kNodeIdAtom
) {
968 nodeID
.Assign(aAttributes
[1]);
972 // If nodeID is present, check if we already know about it. If we've seen
973 // the nodeID before, use the same resource, otherwise generate a new one.
974 if (!nodeID
.IsEmpty()) {
975 mNodeIDMap
.Get(nodeID
,aResource
);
979 rv
= gRDFService
->GetAnonymousResource(aResource
);
983 mNodeIDMap
.Put(nodeID
,*aResource
);
988 return NS_ERROR_FAILURE
;
992 RDFContentSinkImpl::AddProperties(const PRUnichar
** aAttributes
,
993 nsIRDFResource
* aSubject
,
999 nsCOMPtr
<nsIAtom
> localName
;
1000 for (; *aAttributes
; aAttributes
+= 2) {
1001 const nsDependentSubstring
& nameSpaceURI
=
1002 SplitExpatName(aAttributes
[0], getter_AddRefs(localName
));
1004 // skip 'xmlns' directives, these are "meta" information
1005 if (nameSpaceURI
.EqualsLiteral("http://www.w3.org/2000/xmlns/")) {
1009 // skip `about', `ID', `resource', and 'nodeID' attributes (either with or
1010 // without the `rdf:' prefix); these are all "special" and
1011 // should've been dealt with by the caller.
1012 if (localName
== kAboutAtom
|| localName
== kIdAtom
||
1013 localName
== kResourceAtom
|| localName
== kNodeIdAtom
) {
1014 if (nameSpaceURI
.IsEmpty() ||
1015 nameSpaceURI
.EqualsLiteral(RDF_NAMESPACE_URI
))
1019 // Skip `parseType', `RDF:parseType', and `NC:parseType'. This
1020 // is meta-information that will be handled in SetParseMode.
1021 if (localName
== kParseTypeAtom
) {
1022 if (nameSpaceURI
.IsEmpty() ||
1023 nameSpaceURI
.EqualsLiteral(RDF_NAMESPACE_URI
) ||
1024 nameSpaceURI
.EqualsLiteral(NC_NAMESPACE_URI
)) {
1029 NS_ConvertUTF16toUTF8
propertyStr(nameSpaceURI
);
1030 propertyStr
.Append(nsAtomCString(localName
));
1032 // Add the assertion to RDF
1033 nsCOMPtr
<nsIRDFResource
> property
;
1034 gRDFService
->GetResource(propertyStr
, getter_AddRefs(property
));
1036 nsCOMPtr
<nsIRDFLiteral
> target
;
1037 gRDFService
->GetLiteral(aAttributes
[1],
1038 getter_AddRefs(target
));
1040 mDataSource
->Assert(aSubject
, property
, target
, PR_TRUE
);
1046 RDFContentSinkImpl::SetParseMode(const PRUnichar
**aAttributes
)
1048 nsCOMPtr
<nsIAtom
> localName
;
1049 for (; *aAttributes
; aAttributes
+= 2) {
1050 const nsDependentSubstring
& nameSpaceURI
=
1051 SplitExpatName(aAttributes
[0], getter_AddRefs(localName
));
1053 if (localName
== kParseTypeAtom
) {
1054 nsDependentString
v(aAttributes
[1]);
1056 if (nameSpaceURI
.IsEmpty() ||
1057 nameSpaceURI
.EqualsLiteral(RDF_NAMESPACE_URI
)) {
1058 if (v
.EqualsLiteral("Resource"))
1059 mParseMode
= eRDFContentSinkParseMode_Resource
;
1063 else if (nameSpaceURI
.EqualsLiteral(NC_NAMESPACE_URI
)) {
1064 if (v
.EqualsLiteral("Date"))
1065 mParseMode
= eRDFContentSinkParseMode_Date
;
1066 else if (v
.EqualsLiteral("Integer"))
1067 mParseMode
= eRDFContentSinkParseMode_Int
;
1075 ////////////////////////////////////////////////////////////////////////
1076 // RDF-specific routines used to build the model
1079 RDFContentSinkImpl::OpenRDF(const PRUnichar
* aName
)
1081 // ensure that we're actually reading RDF by making sure that the
1082 // opening tag is <rdf:RDF>, where "rdf:" corresponds to whatever
1083 // they've declared the standard RDF namespace to be.
1084 nsCOMPtr
<nsIAtom
> localName
;
1085 const nsDependentSubstring
& nameSpaceURI
=
1086 SplitExpatName(aName
, getter_AddRefs(localName
));
1088 if (!nameSpaceURI
.EqualsLiteral(RDF_NAMESPACE_URI
) || localName
!= kRDFAtom
) {
1089 // PR_LOG(gLog, PR_LOG_ALWAYS,
1090 // ("rdfxml: expected RDF:RDF at line %d",
1091 // aNode.GetSourceLineNumber()));
1093 return NS_ERROR_UNEXPECTED
;
1096 PushContext(nsnull
, mState
, mParseMode
);
1097 mState
= eRDFContentSinkState_InDocumentElement
;
1102 RDFContentSinkImpl::OpenObject(const PRUnichar
* aName
,
1103 const PRUnichar
** aAttributes
)
1105 // an "object" non-terminal is either a "description", a "typed
1106 // node", or a "container", so this change the content sink's
1107 // state appropriately.
1108 nsCOMPtr
<nsIAtom
> localName
;
1109 const nsDependentSubstring
& nameSpaceURI
=
1110 SplitExpatName(aName
, getter_AddRefs(localName
));
1112 // Figure out the URI of this object, and create an RDF node for it.
1113 nsCOMPtr
<nsIRDFResource
> source
;
1114 GetIdAboutAttribute(aAttributes
, getter_AddRefs(source
));
1116 // If there is no `ID' or `about', then there's not much we can do.
1118 return NS_ERROR_FAILURE
;
1120 // Push the element onto the context stack
1121 PushContext(source
, mState
, mParseMode
);
1123 // Now figure out what kind of state transition we need to
1124 // make. We'll either be going into a mode where we parse a
1125 // description or a container.
1126 PRBool isaTypedNode
= PR_TRUE
;
1128 if (nameSpaceURI
.EqualsLiteral(RDF_NAMESPACE_URI
)) {
1129 isaTypedNode
= PR_FALSE
;
1131 if (localName
== kDescriptionAtom
) {
1132 // it's a description
1133 mState
= eRDFContentSinkState_InDescriptionElement
;
1135 else if (localName
== kBagAtom
) {
1136 // it's a bag container
1137 InitContainer(kRDF_Bag
, source
);
1138 mState
= eRDFContentSinkState_InContainerElement
;
1140 else if (localName
== kSeqAtom
) {
1141 // it's a seq container
1142 InitContainer(kRDF_Seq
, source
);
1143 mState
= eRDFContentSinkState_InContainerElement
;
1145 else if (localName
== kAltAtom
) {
1146 // it's an alt container
1147 InitContainer(kRDF_Alt
, source
);
1148 mState
= eRDFContentSinkState_InContainerElement
;
1151 // heh, that's not *in* the RDF namespace: just treat it
1152 // like a typed node
1153 isaTypedNode
= PR_TRUE
;
1158 NS_ConvertUTF16toUTF8
typeStr(nameSpaceURI
);
1159 typeStr
.Append(nsAtomCString(localName
));
1161 nsCOMPtr
<nsIRDFResource
> type
;
1162 nsresult rv
= gRDFService
->GetResource(typeStr
, getter_AddRefs(type
));
1163 if (NS_FAILED(rv
)) return rv
;
1165 rv
= mDataSource
->Assert(source
, kRDF_type
, type
, PR_TRUE
);
1166 if (NS_FAILED(rv
)) return rv
;
1168 mState
= eRDFContentSinkState_InDescriptionElement
;
1171 AddProperties(aAttributes
, source
);
1176 RDFContentSinkImpl::OpenProperty(const PRUnichar
* aName
, const PRUnichar
** aAttributes
)
1180 // an "object" non-terminal is either a "description", a "typed
1181 // node", or a "container", so this change the content sink's
1182 // state appropriately.
1183 nsCOMPtr
<nsIAtom
> localName
;
1184 const nsDependentSubstring
& nameSpaceURI
=
1185 SplitExpatName(aName
, getter_AddRefs(localName
));
1187 NS_ConvertUTF16toUTF8
propertyStr(nameSpaceURI
);
1188 propertyStr
.Append(nsAtomCString(localName
));
1190 nsCOMPtr
<nsIRDFResource
> property
;
1191 rv
= gRDFService
->GetResource(propertyStr
, getter_AddRefs(property
));
1192 if (NS_FAILED(rv
)) return rv
;
1194 // See if they've specified a 'resource' attribute, in which case
1195 // they mean *that* to be the object of this property.
1196 nsCOMPtr
<nsIRDFResource
> target
;
1197 GetResourceAttribute(aAttributes
, getter_AddRefs(target
));
1199 PRBool isAnonymous
= PR_FALSE
;
1202 // See if an 'ID' attribute has been specified, in which case
1203 // this corresponds to the fourth form of [6.12].
1205 // XXX strictly speaking, we should reject the RDF/XML as
1206 // invalid if they've specified both an 'ID' and a 'resource'
1209 // XXX strictly speaking, 'about=' isn't allowed here, but
1211 GetIdAboutAttribute(aAttributes
, getter_AddRefs(target
), &isAnonymous
);
1215 // They specified an inline resource for the value of this
1216 // property. Create an RDF resource for the inline resource
1217 // URI, add the properties to it, and attach the inline
1218 // resource to its parent.
1220 rv
= AddProperties(aAttributes
, target
, &count
);
1221 NS_ASSERTION(NS_SUCCEEDED(rv
), "problem adding properties");
1222 if (NS_FAILED(rv
)) return rv
;
1224 if (count
|| !isAnonymous
) {
1225 // If the resource was "anonymous" (i.e., they hadn't
1226 // explicitly set an ID or resource attribute), then we'll
1227 // only assert this property from the context element *if*
1228 // there were properties specified on the anonymous
1230 rv
= mDataSource
->Assert(GetContextElement(0), property
, target
, PR_TRUE
);
1231 if (NS_FAILED(rv
)) return rv
;
1234 // XXX Technically, we should _not_ fall through here and push
1235 // the element onto the stack: this is supposed to be a closed
1236 // node. But right now I'm lazy and the code will just Do The
1237 // Right Thing so long as the RDF is well-formed.
1240 // Push the element onto the context stack and change state.
1241 PushContext(property
, mState
, mParseMode
);
1242 mState
= eRDFContentSinkState_InPropertyElement
;
1243 SetParseMode(aAttributes
);
1249 RDFContentSinkImpl::OpenMember(const PRUnichar
* aName
,
1250 const PRUnichar
** aAttributes
)
1252 // ensure that we're actually reading a member element by making
1253 // sure that the opening tag is <rdf:li>, where "rdf:" corresponds
1254 // to whatever they've declared the standard RDF namespace to be.
1257 nsCOMPtr
<nsIAtom
> localName
;
1258 const nsDependentSubstring
& nameSpaceURI
=
1259 SplitExpatName(aName
, getter_AddRefs(localName
));
1261 if (!nameSpaceURI
.EqualsLiteral(RDF_NAMESPACE_URI
) ||
1262 localName
!= kLiAtom
) {
1263 PR_LOG(gLog
, PR_LOG_ALWAYS
,
1264 ("rdfxml: expected RDF:li at line %d",
1265 -1)); // XXX pass in line number
1267 return NS_ERROR_UNEXPECTED
;
1270 // The parent element is the container.
1271 nsIRDFResource
* container
= GetContextElement(0);
1273 return NS_ERROR_NULL_POINTER
;
1275 nsIRDFResource
* resource
;
1276 if (NS_SUCCEEDED(rv
= GetResourceAttribute(aAttributes
, &resource
))) {
1277 // Okay, this node has an RDF:resource="..." attribute. That
1278 // means that it's a "referenced item," as covered in [6.29].
1279 nsCOMPtr
<nsIRDFContainer
> c
;
1280 NS_NewRDFContainer(getter_AddRefs(c
));
1281 c
->Init(mDataSource
, container
);
1282 c
->AppendElement(resource
);
1284 // XXX Technically, we should _not_ fall through here and push
1285 // the element onto the stack: this is supposed to be a closed
1286 // node. But right now I'm lazy and the code will just Do The
1287 // Right Thing so long as the RDF is well-formed.
1288 NS_RELEASE(resource
);
1291 // Change state. Pushing a null context element is a bit weird,
1292 // but the idea is that there really is _no_ context "property".
1293 // The contained element will use nsIRDFContainer::AppendElement() to add
1294 // the element to the container, which requires only the container
1295 // and the element to be added.
1296 PushContext(nsnull
, mState
, mParseMode
);
1297 mState
= eRDFContentSinkState_InMemberElement
;
1298 SetParseMode(aAttributes
);
1305 RDFContentSinkImpl::OpenValue(const PRUnichar
* aName
, const PRUnichar
** aAttributes
)
1307 // a "value" can either be an object or a string: we'll only get
1308 // *here* if it's an object, as raw text is added as a leaf.
1309 return OpenObject(aName
,aAttributes
);
1312 ////////////////////////////////////////////////////////////////////////
1313 // namespace resolution
1315 RDFContentSinkImpl::RegisterNamespaces(const PRUnichar
**aAttributes
)
1317 nsCOMPtr
<nsIRDFXMLSink
> sink
= do_QueryInterface(mDataSource
);
1321 NS_NAMED_LITERAL_STRING(xmlns
, "http://www.w3.org/2000/xmlns/");
1322 for (; *aAttributes
; aAttributes
+= 2) {
1323 // check the namespace
1324 const PRUnichar
* attr
= aAttributes
[0];
1325 const PRUnichar
* xmlnsP
= xmlns
.BeginReading();
1326 while (*attr
== *xmlnsP
) {
1330 if (*attr
!= 0xFFFF ||
1331 xmlnsP
!= xmlns
.EndReading()) {
1334 // get the localname (or "xmlns" for the default namespace)
1335 const PRUnichar
* endLocal
= ++attr
;
1336 while (*endLocal
&& *endLocal
!= 0xFFFF) {
1339 nsDependentSubstring
lname(attr
, endLocal
);
1340 nsCOMPtr
<nsIAtom
> preferred
= do_GetAtom(lname
);
1341 if (preferred
== kXMLNSAtom
) {
1344 sink
->AddNameSpace(preferred
, nsDependentString(aAttributes
[1]));
1348 ////////////////////////////////////////////////////////////////////////
1349 // Qualified name resolution
1351 const nsDependentSubstring
1352 RDFContentSinkImpl::SplitExpatName(const PRUnichar
*aExpatName
,
1353 nsIAtom
**aLocalName
)
1356 * Expat can send the following:
1358 * namespaceURI<separator>localName
1359 * namespaceURI<separator>localName<separator>prefix
1361 * and we use 0xFFFF for the <separator>.
1365 const PRUnichar
*uriEnd
= aExpatName
;
1366 const PRUnichar
*nameStart
= aExpatName
;
1367 const PRUnichar
*pos
;
1368 for (pos
= aExpatName
; *pos
; ++pos
) {
1369 if (*pos
== 0xFFFF) {
1370 if (uriEnd
!= aExpatName
) {
1375 nameStart
= pos
+ 1;
1379 const nsDependentSubstring
& nameSpaceURI
= Substring(aExpatName
, uriEnd
);
1380 *aLocalName
= NS_NewAtom(Substring(nameStart
, pos
));
1381 return nameSpaceURI
;
1385 RDFContentSinkImpl::InitContainer(nsIRDFResource
* aContainerType
, nsIRDFResource
* aContainer
)
1387 // Do the right kind of initialization based on the container
1388 // 'type' resource, and the state of the container (i.e., 'make' a
1389 // new container vs. 'reinitialize' the container).
1392 static const ContainerInfo gContainerInfo
[] = {
1393 { &RDFContentSinkImpl::kRDF_Alt
, &nsIRDFContainerUtils::IsAlt
, &nsIRDFContainerUtils::MakeAlt
},
1394 { &RDFContentSinkImpl::kRDF_Bag
, &nsIRDFContainerUtils::IsBag
, &nsIRDFContainerUtils::MakeBag
},
1395 { &RDFContentSinkImpl::kRDF_Seq
, &nsIRDFContainerUtils::IsSeq
, &nsIRDFContainerUtils::MakeSeq
},
1399 for (const ContainerInfo
* info
= gContainerInfo
; info
->mType
!= 0; ++info
) {
1400 if (*info
->mType
!= aContainerType
)
1404 rv
= (gRDFContainerUtils
->*(info
->mTestFn
))(mDataSource
, aContainer
, &isContainer
);
1406 rv
= ReinitContainer(aContainerType
, aContainer
);
1409 rv
= (gRDFContainerUtils
->*(info
->mMakeFn
))(mDataSource
, aContainer
, nsnull
);
1414 NS_NOTREACHED("not an RDF container type");
1415 return NS_ERROR_FAILURE
;
1421 RDFContentSinkImpl::ReinitContainer(nsIRDFResource
* aContainerType
, nsIRDFResource
* aContainer
)
1423 // Mega-kludge to deal with the fact that Make[Seq|Alt|Bag] is
1424 // idempotent, and as such, containers will have state (e.g.,
1425 // RDF:nextVal) maintained in the graph across loads. This
1426 // re-initializes each container's RDF:nextVal to '1', and 'marks'
1427 // the container as such.
1430 nsCOMPtr
<nsIRDFLiteral
> one
;
1431 rv
= gRDFService
->GetLiteral(NS_LITERAL_STRING("1").get(), getter_AddRefs(one
));
1432 if (NS_FAILED(rv
)) return rv
;
1434 // Re-initialize the 'nextval' property
1435 nsCOMPtr
<nsIRDFNode
> nextval
;
1436 rv
= mDataSource
->GetTarget(aContainer
, kRDF_nextVal
, PR_TRUE
, getter_AddRefs(nextval
));
1437 if (NS_FAILED(rv
)) return rv
;
1439 rv
= mDataSource
->Change(aContainer
, kRDF_nextVal
, nextval
, one
);
1440 if (NS_FAILED(rv
)) return rv
;
1442 // Re-mark as a container. XXX should be kRDF_type
1443 rv
= mDataSource
->Assert(aContainer
, kRDF_instanceOf
, aContainerType
, PR_TRUE
);
1444 NS_ASSERTION(NS_SUCCEEDED(rv
), "unable to mark container as such");
1445 if (NS_FAILED(rv
)) return rv
;
1450 ////////////////////////////////////////////////////////////////////////
1451 // Content stack management
1454 RDFContentSinkImpl::GetContextElement(PRInt32 ancestor
/* = 0 */)
1456 if ((nsnull
== mContextStack
) ||
1457 (PRUint32(ancestor
) >= mContextStack
->Length())) {
1461 return mContextStack
->ElementAt(
1462 mContextStack
->Length()-ancestor
-1).mResource
;
1466 RDFContentSinkImpl::PushContext(nsIRDFResource
*aResource
,
1467 RDFContentSinkState aState
,
1468 RDFContentSinkParseMode aParseMode
)
1470 if (! mContextStack
) {
1471 mContextStack
= new nsAutoTArray
<RDFContextStackElement
, 8>();
1472 if (! mContextStack
)
1476 RDFContextStackElement
* e
= mContextStack
->AppendElement();
1478 return mContextStack
->Length();
1480 e
->mResource
= aResource
;
1482 e
->mParseMode
= aParseMode
;
1484 return mContextStack
->Length();
1488 RDFContentSinkImpl::PopContext(nsIRDFResource
*&aResource
,
1489 RDFContentSinkState
&aState
,
1490 RDFContentSinkParseMode
&aParseMode
)
1492 if ((nsnull
== mContextStack
) ||
1493 (mContextStack
->IsEmpty())) {
1494 return NS_ERROR_NULL_POINTER
;
1497 PRUint32 i
= mContextStack
->Length() - 1;
1498 RDFContextStackElement
&e
= mContextStack
->ElementAt(i
);
1500 aResource
= e
.mResource
;
1501 NS_IF_ADDREF(aResource
);
1503 aParseMode
= e
.mParseMode
;
1505 mContextStack
->RemoveElementAt(i
);
1510 ////////////////////////////////////////////////////////////////////////
1513 NS_NewRDFContentSink(nsIRDFContentSink
** aResult
)
1515 NS_PRECONDITION(aResult
!= nsnull
, "null ptr");
1517 return NS_ERROR_NULL_POINTER
;
1519 RDFContentSinkImpl
* sink
= new RDFContentSinkImpl();
1521 return NS_ERROR_OUT_OF_MEMORY
;