rdf/base/src/nsRDFXMLDataSource.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial