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