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
4 : *
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/
9 : *
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
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
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.
21 : *
22 : * Contributor(s):
23 : * Pierre Phaneuf <pp@ludusdesign.com>
24 : *
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.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : /*
40 :
41 : A data source that can read itself from and write itself to an
42 : RDF/XML stream.
43 :
44 : For more information on the RDF/XML syntax,
45 : see http://www.w3.org/TR/REC-rdf-syntax/.
46 :
47 : This code is based on the final W3C Recommendation,
48 : http://www.w3.org/TR/1999/REC-rdf-syntax-19990222.
49 :
50 :
51 : TO DO
52 : -----
53 :
54 : 1) Right now, the only kind of stream data sources that are _really_
55 : writable are "file:" URIs. (In fact, _all_ "file:" URIs are
56 : writable, modulo file system permissions; this may lead to some
57 : surprising behavior.) Eventually, it'd be great if we could open
58 : an arbitrary nsIOutputStream on *any* URL, and Netlib could just
59 : do the magic.
60 :
61 : 2) Implement a more terse output for "typed" nodes; that is, instead
62 : of "RDF:Description type='ns:foo'", just output "ns:foo".
63 :
64 : 3) When re-serializing, we "cheat" for Descriptions that talk about
65 : inline resources (i.e.., using the `ID' attribute specified in
66 : [6.21]). Instead of writing an `ID="foo"' for the first instance,
67 : and then `about="#foo"' for each subsequent instance, we just
68 : _always_ write `about="#foo"'.
69 :
70 : We do this so that we can handle the case where an RDF container
71 : has been assigned arbitrary properties: the spec says we can't
72 : dangle the attributes directly off the container, so we need to
73 : refer to it. Of course, with a little cleverness, we could fix
74 : this. But who cares?
75 :
76 : 4) When re-serializing containers. We have to cheat on some
77 : containers, and use an illegal "about=" construct. We do this to
78 : handle containers that have been assigned URIs outside of the
79 : local document.
80 :
81 :
82 : Logging
83 : -------
84 :
85 : To turn on logging for this module, set
86 :
87 : NSPR_LOG_MODULES=nsRDFXMLDataSource:5
88 :
89 : */
90 :
91 : #include "nsIFileStreams.h"
92 : #include "nsIOutputStream.h"
93 : #include "nsIFile.h"
94 : #include "nsIFileChannel.h"
95 : #include "nsIDTD.h"
96 : #include "nsIRDFPurgeableDataSource.h"
97 : #include "nsIInputStream.h"
98 : #include "nsIOutputStream.h"
99 : #include "nsIRDFContainerUtils.h"
100 : #include "nsIRDFNode.h"
101 : #include "nsIRDFRemoteDataSource.h"
102 : #include "nsIRDFService.h"
103 : #include "nsIRDFXMLParser.h"
104 : #include "nsIRDFXMLSerializer.h"
105 : #include "nsIRDFXMLSink.h"
106 : #include "nsIRDFXMLSource.h"
107 : #include "nsIServiceManager.h"
108 : #include "nsIStreamListener.h"
109 : #include "nsIURL.h"
110 : #include "nsIFileURL.h"
111 : #include "nsNetUtil.h"
112 : #include "nsIChannel.h"
113 : #include "nsRDFCID.h"
114 : #include "nsRDFBaseDataSources.h"
115 : #include "nsCOMArray.h"
116 : #include "nsXPIDLString.h"
117 : #include "plstr.h"
118 : #include "prio.h"
119 : #include "prthread.h"
120 : #include "rdf.h"
121 : #include "rdfutil.h"
122 : #include "prlog.h"
123 : #include "nsNameSpaceMap.h"
124 : #include "nsCRT.h"
125 : #include "nsCycleCollectionParticipant.h"
126 : #include "nsIScriptSecurityManager.h"
127 : #include "nsIChannelEventSink.h"
128 : #include "nsIAsyncVerifyRedirectCallback.h"
129 : #include "nsNetUtil.h"
130 :
131 : #include "rdfIDataSource.h"
132 :
133 : //----------------------------------------------------------------------
134 :
135 : static NS_DEFINE_CID(kRDFInMemoryDataSourceCID, NS_RDFINMEMORYDATASOURCE_CID);
136 : static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
137 :
138 : #ifdef PR_LOGGING
139 : static PRLogModuleInfo* gLog;
140 : #endif
141 :
142 : //----------------------------------------------------------------------
143 : //
144 : // RDFXMLDataSourceImpl
145 : //
146 :
147 : class RDFXMLDataSourceImpl : public nsIRDFDataSource,
148 : public nsIRDFRemoteDataSource,
149 : public nsIRDFXMLSink,
150 : public nsIRDFXMLSource,
151 : public nsIStreamListener,
152 : public rdfIDataSource,
153 : public nsIInterfaceRequestor,
154 : public nsIChannelEventSink
155 : {
156 : protected:
157 : enum LoadState {
158 : eLoadState_Unloaded,
159 : eLoadState_Pending,
160 : eLoadState_Loading,
161 : eLoadState_Loaded
162 : };
163 :
164 : nsCOMPtr<nsIRDFDataSource> mInner;
165 : bool mIsWritable; // true if the document can be written back
166 : bool mIsDirty; // true if the document should be written back
167 : LoadState mLoadState; // what we're doing now
168 : nsCOMArray<nsIRDFXMLSinkObserver> mObservers;
169 : nsCOMPtr<nsIURI> mURL;
170 : nsCOMPtr<nsIStreamListener> mListener;
171 : nsNameSpaceMap mNameSpaces;
172 :
173 : // pseudo-constants
174 : static PRInt32 gRefCnt;
175 : static nsIRDFService* gRDFService;
176 :
177 : nsresult Init();
178 : RDFXMLDataSourceImpl(void);
179 : virtual ~RDFXMLDataSourceImpl(void);
180 : nsresult rdfXMLFlush(nsIURI *aURI);
181 :
182 : friend nsresult
183 : NS_NewRDFXMLDataSource(nsIRDFDataSource** aResult);
184 :
185 758 : inline bool IsLoading() {
186 : return (mLoadState == eLoadState_Pending) ||
187 758 : (mLoadState == eLoadState_Loading);
188 : }
189 :
190 : public:
191 : // nsISupports
192 2 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
193 2768 : NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(RDFXMLDataSourceImpl,
194 : nsIRDFDataSource)
195 :
196 : // nsIRDFDataSource
197 : NS_IMETHOD GetURI(char* *uri);
198 :
199 1 : NS_IMETHOD GetSource(nsIRDFResource* property,
200 : nsIRDFNode* target,
201 : bool tv,
202 : nsIRDFResource** source) {
203 1 : return mInner->GetSource(property, target, tv, source);
204 : }
205 :
206 5 : NS_IMETHOD GetSources(nsIRDFResource* property,
207 : nsIRDFNode* target,
208 : bool tv,
209 : nsISimpleEnumerator** sources) {
210 5 : return mInner->GetSources(property, target, tv, sources);
211 : }
212 :
213 767 : NS_IMETHOD GetTarget(nsIRDFResource* source,
214 : nsIRDFResource* property,
215 : bool tv,
216 : nsIRDFNode** target) {
217 767 : return mInner->GetTarget(source, property, tv, target);
218 : }
219 :
220 1431 : NS_IMETHOD GetTargets(nsIRDFResource* source,
221 : nsIRDFResource* property,
222 : bool tv,
223 : nsISimpleEnumerator** targets) {
224 1431 : return mInner->GetTargets(source, property, tv, targets);
225 : }
226 :
227 : NS_IMETHOD Assert(nsIRDFResource* aSource,
228 : nsIRDFResource* aProperty,
229 : nsIRDFNode* aTarget,
230 : bool tv);
231 :
232 : NS_IMETHOD Unassert(nsIRDFResource* source,
233 : nsIRDFResource* property,
234 : nsIRDFNode* target);
235 :
236 : NS_IMETHOD Change(nsIRDFResource* aSource,
237 : nsIRDFResource* aProperty,
238 : nsIRDFNode* aOldTarget,
239 : nsIRDFNode* aNewTarget);
240 :
241 : NS_IMETHOD Move(nsIRDFResource* aOldSource,
242 : nsIRDFResource* aNewSource,
243 : nsIRDFResource* aProperty,
244 : nsIRDFNode* aTarget);
245 :
246 1271 : NS_IMETHOD HasAssertion(nsIRDFResource* source,
247 : nsIRDFResource* property,
248 : nsIRDFNode* target,
249 : bool tv,
250 : bool* hasAssertion) {
251 1271 : return mInner->HasAssertion(source, property, target, tv, hasAssertion);
252 : }
253 :
254 0 : NS_IMETHOD AddObserver(nsIRDFObserver* aObserver) {
255 0 : return mInner->AddObserver(aObserver);
256 : }
257 :
258 0 : NS_IMETHOD RemoveObserver(nsIRDFObserver* aObserver) {
259 0 : return mInner->RemoveObserver(aObserver);
260 : }
261 :
262 6 : NS_IMETHOD HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *_retval) {
263 6 : return mInner->HasArcIn(aNode, aArc, _retval);
264 : }
265 :
266 431 : NS_IMETHOD HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *_retval) {
267 431 : return mInner->HasArcOut(aSource, aArc, _retval);
268 : }
269 :
270 19 : NS_IMETHOD ArcLabelsIn(nsIRDFNode* node,
271 : nsISimpleEnumerator** labels) {
272 19 : return mInner->ArcLabelsIn(node, labels);
273 : }
274 :
275 573 : NS_IMETHOD ArcLabelsOut(nsIRDFResource* source,
276 : nsISimpleEnumerator** labels) {
277 573 : return mInner->ArcLabelsOut(source, labels);
278 : }
279 :
280 19 : NS_IMETHOD GetAllResources(nsISimpleEnumerator** aResult) {
281 19 : return mInner->GetAllResources(aResult);
282 : }
283 :
284 0 : NS_IMETHOD GetAllCmds(nsIRDFResource* source,
285 : nsISimpleEnumerator/*<nsIRDFResource>*/** commands) {
286 0 : return mInner->GetAllCmds(source, commands);
287 : }
288 :
289 0 : NS_IMETHOD IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
290 : nsIRDFResource* aCommand,
291 : nsISupportsArray/*<nsIRDFResource>*/* aArguments,
292 : bool* aResult) {
293 0 : return mInner->IsCommandEnabled(aSources, aCommand, aArguments, aResult);
294 : }
295 :
296 0 : NS_IMETHOD DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
297 : nsIRDFResource* aCommand,
298 : nsISupportsArray/*<nsIRDFResource>*/* aArguments) {
299 : // XXX Uh oh, this could cause problems wrt. the "dirty" flag
300 : // if it changes the in-memory store's internal state.
301 0 : return mInner->DoCommand(aSources, aCommand, aArguments);
302 : }
303 :
304 0 : NS_IMETHOD BeginUpdateBatch() {
305 0 : return mInner->BeginUpdateBatch();
306 : }
307 :
308 0 : NS_IMETHOD EndUpdateBatch() {
309 0 : return mInner->EndUpdateBatch();
310 : }
311 :
312 : // nsIRDFRemoteDataSource interface
313 : NS_DECL_NSIRDFREMOTEDATASOURCE
314 :
315 : // nsIRDFXMLSink interface
316 : NS_DECL_NSIRDFXMLSINK
317 :
318 : // nsIRDFXMLSource interface
319 : NS_DECL_NSIRDFXMLSOURCE
320 :
321 : // nsIRequestObserver
322 : NS_DECL_NSIREQUESTOBSERVER
323 :
324 : // nsIStreamListener
325 : NS_DECL_NSISTREAMLISTENER
326 :
327 : // nsIInterfaceRequestor
328 : NS_DECL_NSIINTERFACEREQUESTOR
329 :
330 : // nsIChannelEventSink
331 : NS_DECL_NSICHANNELEVENTSINK
332 :
333 : // rdfIDataSource
334 0 : NS_IMETHOD VisitAllSubjects(rdfITripleVisitor *aVisitor) {
335 : nsresult rv;
336 0 : nsCOMPtr<rdfIDataSource> rdfds = do_QueryInterface(mInner, &rv);
337 0 : if (NS_FAILED(rv)) return rv;
338 0 : return rdfds->VisitAllSubjects(aVisitor);
339 : }
340 :
341 19 : NS_IMETHOD VisitAllTriples(rdfITripleVisitor *aVisitor) {
342 : nsresult rv;
343 38 : nsCOMPtr<rdfIDataSource> rdfds = do_QueryInterface(mInner, &rv);
344 19 : if (NS_FAILED(rv)) return rv;
345 19 : return rdfds->VisitAllTriples(aVisitor);
346 : }
347 :
348 : // Implementation methods
349 : bool
350 : MakeQName(nsIRDFResource* aResource,
351 : nsString& property,
352 : nsString& nameSpacePrefix,
353 : nsString& nameSpaceURI);
354 :
355 : nsresult
356 : SerializeAssertion(nsIOutputStream* aStream,
357 : nsIRDFResource* aResource,
358 : nsIRDFResource* aProperty,
359 : nsIRDFNode* aValue);
360 :
361 : nsresult
362 : SerializeProperty(nsIOutputStream* aStream,
363 : nsIRDFResource* aResource,
364 : nsIRDFResource* aProperty);
365 :
366 : bool
367 : IsContainerProperty(nsIRDFResource* aProperty);
368 :
369 : nsresult
370 : SerializeDescription(nsIOutputStream* aStream,
371 : nsIRDFResource* aResource);
372 :
373 : nsresult
374 : SerializeMember(nsIOutputStream* aStream,
375 : nsIRDFResource* aContainer,
376 : nsIRDFNode* aMember);
377 :
378 : nsresult
379 : SerializeContainer(nsIOutputStream* aStream,
380 : nsIRDFResource* aContainer);
381 :
382 : nsresult
383 : SerializePrologue(nsIOutputStream* aStream);
384 :
385 : nsresult
386 : SerializeEpilogue(nsIOutputStream* aStream);
387 :
388 : bool
389 : IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType);
390 :
391 : protected:
392 : nsresult
393 : BlockingParse(nsIURI* aURL, nsIStreamListener* aConsumer);
394 : };
395 :
396 : PRInt32 RDFXMLDataSourceImpl::gRefCnt = 0;
397 : nsIRDFService* RDFXMLDataSourceImpl::gRDFService;
398 :
399 : static const char kFileURIPrefix[] = "file:";
400 : static const char kResourceURIPrefix[] = "resource:";
401 :
402 :
403 : //----------------------------------------------------------------------
404 :
405 : nsresult
406 10 : NS_NewRDFXMLDataSource(nsIRDFDataSource** aResult)
407 : {
408 10 : NS_PRECONDITION(aResult != nsnull, "null ptr");
409 10 : if (! aResult)
410 0 : return NS_ERROR_NULL_POINTER;
411 :
412 10 : RDFXMLDataSourceImpl* datasource = new RDFXMLDataSourceImpl();
413 10 : if (! datasource)
414 0 : return NS_ERROR_OUT_OF_MEMORY;
415 :
416 : nsresult rv;
417 10 : rv = datasource->Init();
418 :
419 10 : if (NS_FAILED(rv)) {
420 0 : delete datasource;
421 0 : return rv;
422 : }
423 :
424 10 : NS_ADDREF(datasource);
425 10 : *aResult = datasource;
426 10 : return NS_OK;
427 : }
428 :
429 :
430 10 : RDFXMLDataSourceImpl::RDFXMLDataSourceImpl(void)
431 : : mIsWritable(true),
432 : mIsDirty(false),
433 10 : mLoadState(eLoadState_Unloaded)
434 : {
435 : #ifdef PR_LOGGING
436 10 : if (! gLog)
437 7 : gLog = PR_NewLogModule("nsRDFXMLDataSource");
438 : #endif
439 10 : }
440 :
441 :
442 : nsresult
443 10 : RDFXMLDataSourceImpl::Init()
444 : {
445 : nsresult rv;
446 10 : mInner = do_CreateInstance(kRDFInMemoryDataSourceCID, &rv);
447 10 : if (NS_FAILED(rv)) return rv;
448 :
449 10 : if (gRefCnt++ == 0) {
450 7 : rv = CallGetService(kRDFServiceCID, &gRDFService);
451 :
452 7 : NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service");
453 7 : if (NS_FAILED(rv)) return rv;
454 : }
455 :
456 10 : return NS_OK;
457 : }
458 :
459 :
460 30 : RDFXMLDataSourceImpl::~RDFXMLDataSourceImpl(void)
461 : {
462 : nsresult rv;
463 :
464 : // Unregister first so that nobody else tries to get us.
465 10 : rv = gRDFService->UnregisterDataSource(this);
466 :
467 : // Now flush contents
468 10 : rv = Flush();
469 :
470 : // Release RDF/XML sink observers
471 10 : mObservers.Clear();
472 :
473 10 : if (--gRefCnt == 0)
474 7 : NS_IF_RELEASE(gRDFService);
475 40 : }
476 :
477 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(RDFXMLDataSourceImpl)
478 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_0(RDFXMLDataSourceImpl)
479 2 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(RDFXMLDataSourceImpl)
480 2 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mInner)
481 2 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
482 :
483 647 : NS_IMPL_CYCLE_COLLECTING_ADDREF(RDFXMLDataSourceImpl)
484 647 : NS_IMPL_CYCLE_COLLECTING_RELEASE(RDFXMLDataSourceImpl)
485 :
486 1069 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RDFXMLDataSourceImpl)
487 602 : NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource)
488 448 : NS_INTERFACE_MAP_ENTRY(nsIRDFRemoteDataSource)
489 436 : NS_INTERFACE_MAP_ENTRY(nsIRDFXMLSink)
490 208 : NS_INTERFACE_MAP_ENTRY(nsIRDFXMLSource)
491 208 : NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
492 208 : NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
493 200 : NS_INTERFACE_MAP_ENTRY(rdfIDataSource)
494 181 : NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
495 167 : NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
496 163 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRDFDataSource)
497 126 : NS_INTERFACE_MAP_END
498 :
499 : // nsIInterfaceRequestor
500 : NS_IMETHODIMP
501 17 : RDFXMLDataSourceImpl::GetInterface(const nsIID& aIID, void** aSink)
502 : {
503 17 : return QueryInterface(aIID, aSink);
504 : }
505 :
506 : nsresult
507 6 : RDFXMLDataSourceImpl::BlockingParse(nsIURI* aURL, nsIStreamListener* aConsumer)
508 : {
509 : nsresult rv;
510 :
511 : // XXX I really hate the way that we're spoon-feeding this stuff
512 : // to the parser: it seems like this is something that netlib
513 : // should be able to do by itself.
514 :
515 12 : nsCOMPtr<nsIChannel> channel;
516 12 : nsCOMPtr<nsIRequest> request;
517 :
518 : // Null LoadGroup ?
519 6 : rv = NS_NewChannel(getter_AddRefs(channel), aURL, nsnull);
520 6 : if (NS_FAILED(rv)) return rv;
521 12 : nsCOMPtr<nsIInputStream> in;
522 6 : rv = channel->Open(getter_AddRefs(in));
523 :
524 : // Report success if the file doesn't exist, but propagate other errors.
525 6 : if (rv == NS_ERROR_FILE_NOT_FOUND) return NS_OK;
526 4 : if (NS_FAILED(rv)) return rv;
527 :
528 4 : if (! in) {
529 0 : NS_ERROR("no input stream");
530 0 : return NS_ERROR_FAILURE;
531 : }
532 :
533 : // Wrap the channel's input stream in a buffered stream to ensure that
534 : // ReadSegments is implemented (which OnDataAvailable expects).
535 8 : nsCOMPtr<nsIInputStream> bufStream;
536 4 : rv = NS_NewBufferedInputStream(getter_AddRefs(bufStream), in,
537 4 : 4096 /* buffer size */);
538 4 : if (NS_FAILED(rv)) return rv;
539 :
540 : // Notify load observers
541 : PRInt32 i;
542 4 : for (i = mObservers.Count() - 1; i >= 0; --i) {
543 : // Make sure to hold a strong reference to the observer so
544 : // that it doesn't go away in this call if it removes itself
545 : // as an observer
546 0 : nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
547 :
548 0 : if (obs) {
549 0 : obs->OnBeginLoad(this);
550 : }
551 : }
552 :
553 4 : rv = aConsumer->OnStartRequest(channel, nsnull);
554 :
555 4 : PRUint32 offset = 0;
556 12 : while (NS_SUCCEEDED(rv)) {
557 : // Skip ODA if the channel is canceled
558 8 : channel->GetStatus(&rv);
559 8 : if (NS_FAILED(rv))
560 0 : break;
561 :
562 : PRUint32 avail;
563 8 : if (NS_FAILED(rv = bufStream->Available(&avail)))
564 0 : break; // error
565 :
566 8 : if (avail == 0)
567 4 : break; // eof
568 :
569 4 : rv = aConsumer->OnDataAvailable(channel, nsnull, bufStream, offset, avail);
570 4 : if (NS_SUCCEEDED(rv))
571 4 : offset += avail;
572 : }
573 :
574 4 : if (NS_FAILED(rv))
575 0 : channel->Cancel(rv);
576 :
577 4 : channel->GetStatus(&rv);
578 4 : aConsumer->OnStopRequest(channel, nsnull, rv);
579 :
580 : // Notify load observers
581 4 : for (i = mObservers.Count() - 1; i >= 0; --i) {
582 : // Make sure to hold a strong reference to the observer so
583 : // that it doesn't go away in this call if it removes itself
584 : // as an observer
585 0 : nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
586 :
587 0 : if (obs) {
588 0 : if (NS_FAILED(rv))
589 0 : obs->OnError(this, rv, nsnull);
590 :
591 0 : obs->OnEndLoad(this);
592 : }
593 : }
594 :
595 4 : return rv;
596 : }
597 :
598 : NS_IMETHODIMP
599 0 : RDFXMLDataSourceImpl::GetLoaded(bool* _result)
600 : {
601 0 : *_result = (mLoadState == eLoadState_Loaded);
602 0 : return NS_OK;
603 : }
604 :
605 : NS_IMETHODIMP
606 10 : RDFXMLDataSourceImpl::Init(const char* uri)
607 : {
608 10 : NS_PRECONDITION(mInner != nsnull, "not initialized");
609 10 : if (! mInner)
610 0 : return NS_ERROR_OUT_OF_MEMORY;
611 :
612 : nsresult rv;
613 :
614 10 : rv = NS_NewURI(getter_AddRefs(mURL), nsDependentCString(uri));
615 10 : if (NS_FAILED(rv)) return rv;
616 :
617 : // XXX this is a hack: any "file:" URI is considered writable. All
618 : // others are considered read-only.
619 14 : if ((PL_strncmp(uri, kFileURIPrefix, sizeof(kFileURIPrefix) - 1) != 0) &&
620 4 : (PL_strncmp(uri, kResourceURIPrefix, sizeof(kResourceURIPrefix) - 1) != 0)) {
621 4 : mIsWritable = false;
622 : }
623 :
624 10 : rv = gRDFService->RegisterDataSource(this, false);
625 10 : if (NS_FAILED(rv)) return rv;
626 :
627 10 : return NS_OK;
628 : }
629 :
630 :
631 : NS_IMETHODIMP
632 39 : RDFXMLDataSourceImpl::GetURI(char* *aURI)
633 : {
634 39 : *aURI = nsnull;
635 39 : if (!mURL) {
636 0 : return NS_OK;
637 : }
638 :
639 78 : nsCAutoString spec;
640 39 : mURL->GetSpec(spec);
641 39 : *aURI = ToNewCString(spec);
642 39 : if (!*aURI) {
643 0 : return NS_ERROR_OUT_OF_MEMORY;
644 : }
645 :
646 39 : return NS_OK;
647 : }
648 :
649 : NS_IMETHODIMP
650 524 : RDFXMLDataSourceImpl::Assert(nsIRDFResource* aSource,
651 : nsIRDFResource* aProperty,
652 : nsIRDFNode* aTarget,
653 : bool aTruthValue)
654 : {
655 : // We don't accept assertions unless we're writable (except in the
656 : // case that we're actually _reading_ the datasource in).
657 : nsresult rv;
658 :
659 524 : if (IsLoading()) {
660 371 : bool hasAssertion = false;
661 :
662 742 : nsCOMPtr<nsIRDFPurgeableDataSource> gcable = do_QueryInterface(mInner);
663 371 : if (gcable) {
664 371 : rv = gcable->Mark(aSource, aProperty, aTarget, aTruthValue, &hasAssertion);
665 371 : if (NS_FAILED(rv)) return rv;
666 : }
667 :
668 371 : rv = NS_RDF_ASSERTION_ACCEPTED;
669 :
670 371 : if (! hasAssertion) {
671 371 : rv = mInner->Assert(aSource, aProperty, aTarget, aTruthValue);
672 :
673 371 : if (NS_SUCCEEDED(rv) && gcable) {
674 : // Now mark the new assertion, so it doesn't get
675 : // removed when we sweep. Ignore rv, because we want
676 : // to return what mInner->Assert() gave us.
677 : bool didMark;
678 371 : (void) gcable->Mark(aSource, aProperty, aTarget, aTruthValue, &didMark);
679 : }
680 :
681 371 : if (NS_FAILED(rv)) return rv;
682 : }
683 :
684 371 : return rv;
685 : }
686 153 : else if (mIsWritable) {
687 153 : rv = mInner->Assert(aSource, aProperty, aTarget, aTruthValue);
688 :
689 153 : if (rv == NS_RDF_ASSERTION_ACCEPTED)
690 153 : mIsDirty = true;
691 :
692 153 : return rv;
693 : }
694 : else {
695 0 : return NS_RDF_ASSERTION_REJECTED;
696 : }
697 : }
698 :
699 :
700 : NS_IMETHODIMP
701 78 : RDFXMLDataSourceImpl::Unassert(nsIRDFResource* source,
702 : nsIRDFResource* property,
703 : nsIRDFNode* target)
704 : {
705 : // We don't accept assertions unless we're writable (except in the
706 : // case that we're actually _reading_ the datasource in).
707 : nsresult rv;
708 :
709 78 : if (IsLoading() || mIsWritable) {
710 78 : rv = mInner->Unassert(source, property, target);
711 78 : if (!IsLoading() && rv == NS_RDF_ASSERTION_ACCEPTED)
712 46 : mIsDirty = true;
713 : }
714 : else {
715 0 : rv = NS_RDF_ASSERTION_REJECTED;
716 : }
717 :
718 78 : return rv;
719 : }
720 :
721 : NS_IMETHODIMP
722 34 : RDFXMLDataSourceImpl::Change(nsIRDFResource* aSource,
723 : nsIRDFResource* aProperty,
724 : nsIRDFNode* aOldTarget,
725 : nsIRDFNode* aNewTarget)
726 : {
727 : nsresult rv;
728 :
729 34 : if (IsLoading() || mIsWritable) {
730 34 : rv = mInner->Change(aSource, aProperty, aOldTarget, aNewTarget);
731 :
732 34 : if (!IsLoading() && rv == NS_RDF_ASSERTION_ACCEPTED)
733 34 : mIsDirty = true;
734 : }
735 : else {
736 0 : rv = NS_RDF_ASSERTION_REJECTED;
737 : }
738 :
739 34 : return rv;
740 : }
741 :
742 : NS_IMETHODIMP
743 0 : RDFXMLDataSourceImpl::Move(nsIRDFResource* aOldSource,
744 : nsIRDFResource* aNewSource,
745 : nsIRDFResource* aProperty,
746 : nsIRDFNode* aTarget)
747 : {
748 : nsresult rv;
749 :
750 0 : if (IsLoading() || mIsWritable) {
751 0 : rv = mInner->Move(aOldSource, aNewSource, aProperty, aTarget);
752 0 : if (!IsLoading() && rv == NS_RDF_ASSERTION_ACCEPTED)
753 0 : mIsDirty = true;
754 : }
755 : else {
756 0 : rv = NS_RDF_ASSERTION_REJECTED;
757 : }
758 :
759 0 : return rv;
760 : }
761 :
762 :
763 : nsresult
764 20 : RDFXMLDataSourceImpl::rdfXMLFlush(nsIURI *aURI)
765 : {
766 :
767 : nsresult rv;
768 :
769 : {
770 : // Quick and dirty check to see if we're in XPCOM shutdown. If
771 : // we are, we're screwed: it's too late to serialize because
772 : // many of the services that we'll need to acquire to properly
773 : // write the file will be unaquirable.
774 40 : nsCOMPtr<nsIRDFService> dummy = do_GetService(kRDFServiceCID, &rv);
775 20 : if (NS_FAILED(rv)) {
776 1 : NS_WARNING("unable to Flush() diry datasource during XPCOM shutdown");
777 1 : return rv;
778 : }
779 : }
780 :
781 : // Is it a file? If so, we can write to it. Some day, it'd be nice
782 : // if we didn't care what kind of stream this was...
783 38 : nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aURI);
784 :
785 19 : if (fileURL) {
786 38 : nsCOMPtr<nsIFile> file;
787 19 : fileURL->GetFile(getter_AddRefs(file));
788 19 : if (file) {
789 : // get a safe output stream, so we don't clobber the datasource file unless
790 : // all the writes succeeded.
791 38 : nsCOMPtr<nsIOutputStream> out;
792 19 : rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(out),
793 : file,
794 : PR_WRONLY | PR_CREATE_FILE,
795 : /*octal*/ 0666,
796 19 : 0);
797 19 : if (NS_FAILED(rv)) return rv;
798 :
799 38 : nsCOMPtr<nsIOutputStream> bufferedOut;
800 19 : rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOut), out, 4096);
801 19 : if (NS_FAILED(rv)) return rv;
802 :
803 19 : rv = Serialize(bufferedOut);
804 19 : if (NS_FAILED(rv)) return rv;
805 :
806 : // All went ok. Maybe except for problems in Write(), but the stream detects
807 : // that for us
808 38 : nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(bufferedOut, &rv);
809 19 : if (NS_FAILED(rv)) return rv;
810 :
811 19 : rv = safeStream->Finish();
812 19 : if (NS_FAILED(rv)) {
813 0 : NS_WARNING("failed to save datasource file! possible dataloss");
814 0 : return rv;
815 : }
816 : }
817 : }
818 :
819 19 : return NS_OK;
820 : }
821 :
822 :
823 : NS_IMETHODIMP
824 0 : RDFXMLDataSourceImpl::FlushTo(const char *aURI)
825 : {
826 0 : NS_PRECONDITION(aURI != nsnull, "not initialized");
827 0 : if (!aURI)
828 0 : return NS_ERROR_NULL_POINTER;
829 :
830 : // XXX this is a hack: any "file:" URI is considered writable. All
831 : // others are considered read-only.
832 0 : if ((PL_strncmp(aURI, kFileURIPrefix, sizeof(kFileURIPrefix) - 1) != 0) &&
833 0 : (PL_strncmp(aURI, kResourceURIPrefix, sizeof(kResourceURIPrefix) - 1) != 0))
834 : {
835 0 : return NS_ERROR_ILLEGAL_VALUE;
836 : }
837 :
838 0 : nsCOMPtr<nsIURI> url;
839 0 : nsresult rv = NS_NewURI(getter_AddRefs(url), aURI);
840 0 : if (NS_FAILED(rv))
841 0 : return rv;
842 0 : rv = rdfXMLFlush(url);
843 0 : return rv;
844 : }
845 :
846 :
847 : NS_IMETHODIMP
848 29 : RDFXMLDataSourceImpl::Flush(void)
849 : {
850 29 : if (!mIsWritable || !mIsDirty)
851 9 : return NS_OK;
852 :
853 : // while it is not fatal if mURL is not set,
854 : // indicate failure since we can't flush back to an unknown origin
855 20 : if (! mURL)
856 0 : return NS_ERROR_NOT_INITIALIZED;
857 :
858 : #ifdef PR_LOGGING
859 40 : nsCAutoString spec;
860 20 : mURL->GetSpec(spec);
861 20 : PR_LOG(gLog, PR_LOG_NOTICE,
862 : ("rdfxml[%p] flush(%s)", this, spec.get()));
863 : #endif
864 :
865 : nsresult rv;
866 20 : if (NS_SUCCEEDED(rv = rdfXMLFlush(mURL)))
867 : {
868 19 : mIsDirty = false;
869 : }
870 20 : return rv;
871 : }
872 :
873 :
874 : //----------------------------------------------------------------------
875 : //
876 : // nsIRDFXMLDataSource methods
877 : //
878 :
879 : NS_IMETHODIMP
880 0 : RDFXMLDataSourceImpl::GetReadOnly(bool* aIsReadOnly)
881 : {
882 0 : *aIsReadOnly = !mIsWritable;
883 0 : return NS_OK;
884 : }
885 :
886 :
887 : NS_IMETHODIMP
888 0 : RDFXMLDataSourceImpl::SetReadOnly(bool aIsReadOnly)
889 : {
890 0 : if (mIsWritable && aIsReadOnly)
891 0 : mIsWritable = false;
892 :
893 0 : return NS_OK;
894 : }
895 :
896 : // nsIChannelEventSink
897 :
898 : // This code is copied from nsSameOriginChecker::OnChannelRedirect. See
899 : // bug 475940 on providing this code in a shared location.
900 : NS_IMETHODIMP
901 2 : RDFXMLDataSourceImpl::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
902 : nsIChannel *aNewChannel,
903 : PRUint32 aFlags,
904 : nsIAsyncVerifyRedirectCallback *cb)
905 : {
906 2 : NS_PRECONDITION(aNewChannel, "Redirecting to null channel?");
907 :
908 : nsresult rv;
909 : nsCOMPtr<nsIScriptSecurityManager> secMan =
910 4 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
911 2 : NS_ENSURE_SUCCESS(rv, rv);
912 :
913 4 : nsCOMPtr<nsIPrincipal> oldPrincipal;
914 2 : secMan->GetChannelPrincipal(aOldChannel, getter_AddRefs(oldPrincipal));
915 :
916 4 : nsCOMPtr<nsIURI> newURI;
917 2 : aNewChannel->GetURI(getter_AddRefs(newURI));
918 4 : nsCOMPtr<nsIURI> newOriginalURI;
919 2 : aNewChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
920 :
921 2 : NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI);
922 :
923 2 : rv = oldPrincipal->CheckMayLoad(newURI, false);
924 2 : if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
925 0 : rv = oldPrincipal->CheckMayLoad(newOriginalURI, false);
926 : }
927 :
928 2 : if (NS_FAILED(rv))
929 1 : return rv;
930 :
931 1 : cb->OnRedirectVerifyCallback(NS_OK);
932 1 : return NS_OK;
933 : }
934 :
935 : NS_IMETHODIMP
936 10 : RDFXMLDataSourceImpl::Refresh(bool aBlocking)
937 : {
938 : #ifdef PR_LOGGING
939 20 : nsCAutoString spec;
940 10 : if (mURL) {
941 10 : mURL->GetSpec(spec);
942 : }
943 10 : PR_LOG(gLog, PR_LOG_NOTICE,
944 : ("rdfxml[%p] refresh(%s) %sblocking", this, spec.get(), (aBlocking ? "" : "non")));
945 : #endif
946 :
947 : // If an asynchronous load is already pending, then just let it do
948 : // the honors.
949 10 : if (IsLoading()) {
950 0 : PR_LOG(gLog, PR_LOG_NOTICE,
951 : ("rdfxml[%p] refresh(%s) a load was pending", this, spec.get()));
952 :
953 0 : if (aBlocking) {
954 0 : NS_WARNING("blocking load requested when async load pending");
955 0 : return NS_ERROR_FAILURE;
956 : }
957 : else {
958 0 : return NS_OK;
959 : }
960 : }
961 :
962 10 : if (! mURL)
963 0 : return NS_ERROR_FAILURE;
964 20 : nsCOMPtr<nsIRDFXMLParser> parser = do_CreateInstance("@mozilla.org/rdf/xml-parser;1");
965 10 : if (! parser)
966 0 : return NS_ERROR_FAILURE;
967 :
968 10 : nsresult rv = parser->ParseAsync(this, mURL, getter_AddRefs(mListener));
969 10 : if (NS_FAILED(rv)) return rv;
970 :
971 10 : if (aBlocking) {
972 6 : rv = BlockingParse(mURL, this);
973 :
974 6 : mListener = nsnull; // release the parser
975 :
976 6 : if (NS_FAILED(rv)) return rv;
977 : }
978 : else {
979 : // Null LoadGroup ?
980 4 : rv = NS_OpenURI(this, nsnull, mURL, nsnull, nsnull, this);
981 4 : if (NS_FAILED(rv)) return rv;
982 :
983 : // So we don't try to issue two asynchronous loads at once.
984 4 : mLoadState = eLoadState_Pending;
985 : }
986 :
987 10 : return NS_OK;
988 : }
989 :
990 : NS_IMETHODIMP
991 8 : RDFXMLDataSourceImpl::BeginLoad(void)
992 : {
993 : #ifdef PR_LOGGING
994 16 : nsCAutoString spec;
995 8 : if (mURL) {
996 8 : mURL->GetSpec(spec);
997 : }
998 8 : PR_LOG(gLog, PR_LOG_NOTICE,
999 : ("rdfxml[%p] begin-load(%s)", this, spec.get()));
1000 : #endif
1001 :
1002 8 : mLoadState = eLoadState_Loading;
1003 12 : for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
1004 : // Make sure to hold a strong reference to the observer so
1005 : // that it doesn't go away in this call if it removes itself
1006 : // as an observer
1007 8 : nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
1008 :
1009 4 : if (obs) {
1010 4 : obs->OnBeginLoad(this);
1011 : }
1012 : }
1013 8 : return NS_OK;
1014 : }
1015 :
1016 : NS_IMETHODIMP
1017 7 : RDFXMLDataSourceImpl::Interrupt(void)
1018 : {
1019 : #ifdef PR_LOGGING
1020 14 : nsCAutoString spec;
1021 7 : if (mURL) {
1022 7 : mURL->GetSpec(spec);
1023 : }
1024 7 : PR_LOG(gLog, PR_LOG_NOTICE,
1025 : ("rdfxml[%p] interrupt(%s)", this, spec.get()));
1026 : #endif
1027 :
1028 10 : for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
1029 : // Make sure to hold a strong reference to the observer so
1030 : // that it doesn't go away in this call if it removes itself
1031 : // as an observer
1032 6 : nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
1033 :
1034 3 : if (obs) {
1035 3 : obs->OnInterrupt(this);
1036 : }
1037 : }
1038 7 : return NS_OK;
1039 : }
1040 :
1041 : NS_IMETHODIMP
1042 15 : RDFXMLDataSourceImpl::Resume(void)
1043 : {
1044 : #ifdef PR_LOGGING
1045 30 : nsCAutoString spec;
1046 15 : if (mURL) {
1047 15 : mURL->GetSpec(spec);
1048 : }
1049 15 : PR_LOG(gLog, PR_LOG_NOTICE,
1050 : ("rdfxml[%p] resume(%s)", this, spec.get()));
1051 : #endif
1052 :
1053 22 : for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
1054 : // Make sure to hold a strong reference to the observer so
1055 : // that it doesn't go away in this call if it removes itself
1056 : // as an observer
1057 14 : nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
1058 :
1059 7 : if (obs) {
1060 7 : obs->OnResume(this);
1061 : }
1062 : }
1063 15 : return NS_OK;
1064 : }
1065 :
1066 : NS_IMETHODIMP
1067 8 : RDFXMLDataSourceImpl::EndLoad(void)
1068 : {
1069 : #ifdef PR_LOGGING
1070 16 : nsCAutoString spec;
1071 8 : if (mURL) {
1072 8 : mURL->GetSpec(spec);
1073 : }
1074 8 : PR_LOG(gLog, PR_LOG_NOTICE,
1075 : ("rdfxml[%p] end-load(%s)", this, spec.get()));
1076 : #endif
1077 :
1078 8 : mLoadState = eLoadState_Loaded;
1079 :
1080 : // Clear out any unmarked assertions from the datasource.
1081 16 : nsCOMPtr<nsIRDFPurgeableDataSource> gcable = do_QueryInterface(mInner);
1082 8 : if (gcable) {
1083 8 : gcable->Sweep();
1084 : }
1085 :
1086 : // Notify load observers
1087 12 : for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
1088 : // Make sure to hold a strong reference to the observer so
1089 : // that it doesn't go away in this call if it removes itself
1090 : // as an observer
1091 8 : nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
1092 :
1093 4 : if (obs) {
1094 4 : obs->OnEndLoad(this);
1095 : }
1096 : }
1097 8 : return NS_OK;
1098 : }
1099 :
1100 : NS_IMETHODIMP
1101 18 : RDFXMLDataSourceImpl::AddNameSpace(nsIAtom* aPrefix, const nsString& aURI)
1102 : {
1103 18 : mNameSpaces.Put(aURI, aPrefix);
1104 18 : return NS_OK;
1105 : }
1106 :
1107 :
1108 : NS_IMETHODIMP
1109 4 : RDFXMLDataSourceImpl::AddXMLSinkObserver(nsIRDFXMLSinkObserver* aObserver)
1110 : {
1111 4 : if (! aObserver)
1112 0 : return NS_ERROR_NULL_POINTER;
1113 :
1114 4 : mObservers.AppendObject(aObserver);
1115 4 : return NS_OK;
1116 : }
1117 :
1118 : NS_IMETHODIMP
1119 4 : RDFXMLDataSourceImpl::RemoveXMLSinkObserver(nsIRDFXMLSinkObserver* aObserver)
1120 : {
1121 4 : if (! aObserver)
1122 0 : return NS_ERROR_NULL_POINTER;
1123 :
1124 4 : mObservers.RemoveObject(aObserver);
1125 :
1126 4 : return NS_OK;
1127 : }
1128 :
1129 :
1130 : //----------------------------------------------------------------------
1131 : //
1132 : // nsIRequestObserver
1133 : //
1134 :
1135 : NS_IMETHODIMP
1136 8 : RDFXMLDataSourceImpl::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
1137 : {
1138 8 : return mListener->OnStartRequest(request, ctxt);
1139 : }
1140 :
1141 : NS_IMETHODIMP
1142 8 : RDFXMLDataSourceImpl::OnStopRequest(nsIRequest *request,
1143 : nsISupports *ctxt,
1144 : nsresult status)
1145 : {
1146 8 : if (NS_FAILED(status)) {
1147 0 : for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
1148 : // Make sure to hold a strong reference to the observer so
1149 : // that it doesn't go away in this call if it removes
1150 : // itself as an observer
1151 0 : nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
1152 :
1153 0 : if (obs) {
1154 0 : obs->OnError(this, status, nsnull);
1155 : }
1156 : }
1157 : }
1158 :
1159 : nsresult rv;
1160 8 : rv = mListener->OnStopRequest(request, ctxt, status);
1161 :
1162 8 : mListener = nsnull; // release the parser
1163 :
1164 8 : return rv;
1165 : }
1166 :
1167 : //----------------------------------------------------------------------
1168 : //
1169 : // nsIStreamListener
1170 : //
1171 :
1172 : NS_IMETHODIMP
1173 7 : RDFXMLDataSourceImpl::OnDataAvailable(nsIRequest *request,
1174 : nsISupports *ctxt,
1175 : nsIInputStream *inStr,
1176 : PRUint32 sourceOffset,
1177 : PRUint32 count)
1178 : {
1179 7 : return mListener->OnDataAvailable(request, ctxt, inStr, sourceOffset, count);
1180 : }
1181 :
1182 : //----------------------------------------------------------------------
1183 : //
1184 : // nsIRDFXMLSource
1185 : //
1186 :
1187 : NS_IMETHODIMP
1188 19 : RDFXMLDataSourceImpl::Serialize(nsIOutputStream* aStream)
1189 : {
1190 : nsresult rv;
1191 : nsCOMPtr<nsIRDFXMLSerializer> serializer
1192 38 : = do_CreateInstance("@mozilla.org/rdf/xml-serializer;1", &rv);
1193 :
1194 19 : if (! serializer)
1195 0 : return rv;
1196 :
1197 19 : rv = serializer->Init(this);
1198 19 : if (NS_FAILED(rv)) return rv;
1199 :
1200 : // Add any namespace information that we picked up when reading
1201 : // the RDF/XML
1202 19 : nsNameSpaceMap::const_iterator last = mNameSpaces.last();
1203 19 : for (nsNameSpaceMap::const_iterator iter = mNameSpaces.first();
1204 : iter != last; ++iter) {
1205 : // We might wanna change nsIRDFXMLSerializer to nsACString and
1206 : // use a heap allocated buffer here in the future.
1207 0 : NS_ConvertUTF8toUTF16 uri(iter->mURI);
1208 0 : serializer->AddNameSpace(iter->mPrefix, uri);
1209 : }
1210 :
1211 : // Serialize!
1212 38 : nsCOMPtr<nsIRDFXMLSource> source = do_QueryInterface(serializer);
1213 19 : if (! source)
1214 0 : return NS_ERROR_FAILURE;
1215 :
1216 19 : return source->Serialize(aStream);
1217 4392 : }
|