Back to index

lightning-sunbird  0.9+nobinonly
nsDOMParser.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "jsapi.h"
00039 #include "nsDOMParser.h"
00040 #include "nsIURI.h"
00041 #include "nsIChannel.h"
00042 #include "nsILoadGroup.h"
00043 #include "nsIInputStream.h"
00044 #include "nsNetUtil.h"
00045 #include "nsIByteArrayInputStream.h"
00046 #include "nsIXPConnect.h"
00047 #include "nsIUnicodeEncoder.h"
00048 #include "nsIServiceManager.h"
00049 #include "nsICharsetConverterManager.h"
00050 #include "nsLayoutCID.h"
00051 #include "nsIDocument.h"
00052 #include "nsIDOMDocument.h"
00053 #include "nsIDOMDOMImplementation.h"
00054 #include "nsIDOMWindow.h"
00055 #include "nsIPrivateDOMImplementation.h"
00056 #include "nsIJSContextStack.h"
00057 #include "nsIScriptSecurityManager.h"
00058 #include "nsIPrincipal.h"
00059 #include "nsIScriptContext.h"
00060 #include "nsIScriptGlobalObject.h"
00061 #include "nsIDOMClassInfo.h"
00062 #include "nsReadableUtils.h"
00063 #include "nsCRT.h"
00064 #include "nsIDOMEventReceiver.h"
00065 #include "nsLoadListenerProxy.h"
00066 #include "nsStreamUtils.h"
00067 #include "nsNetCID.h"
00068 #include "nsContentUtils.h"
00069 #include "nsPIDOMWindow.h"
00070 
00071 static NS_DEFINE_IID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
00072 
00073 static const char* kLoadAsData = "loadAsData";
00074 
00075 static NS_DEFINE_CID(kIDOMDOMImplementationCID, NS_DOM_IMPLEMENTATION_CID);
00076 static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
00077 
00079 //
00080 //
00082 
00083 class nsDOMParserChannel : public nsIChannel {
00084 public:
00085   nsDOMParserChannel(nsIURI* aURI, const nsACString& aContentType);
00086   virtual ~nsDOMParserChannel();
00087 
00088   NS_DECL_ISUPPORTS
00089   NS_DECL_NSIREQUEST
00090   NS_DECL_NSICHANNEL
00091 
00092 protected:
00093   nsCString mContentType;
00094   nsCString mContentCharset;
00095   nsresult mStatus;
00096   PRInt32 mContentLength;
00097   nsCOMPtr<nsIURI> mURI;
00098   nsCOMPtr<nsISupports> mOwner;
00099   nsCOMPtr<nsILoadGroup> mLoadGroup;
00100 };
00101 
00102 nsDOMParserChannel::nsDOMParserChannel(nsIURI* aURI, const nsACString& aContentType)
00103 {
00104   mURI = aURI;
00105   mContentType.Assign(aContentType);
00106   mStatus = NS_OK;
00107   mContentLength = -1;
00108 }
00109 
00110 nsDOMParserChannel::~nsDOMParserChannel()
00111 {
00112 }
00113 
00114 NS_IMPL_ISUPPORTS2(nsDOMParserChannel, 
00115                    nsIChannel,
00116                    nsIRequest)
00117 
00118 /* boolean isPending (); */
00119 NS_IMETHODIMP nsDOMParserChannel::GetName(nsACString &result)
00120 {
00121     NS_NOTREACHED("nsDOMParserChannel::GetName");
00122     return NS_ERROR_NOT_IMPLEMENTED;
00123 }
00124 
00125 NS_IMETHODIMP 
00126 nsDOMParserChannel::IsPending(PRBool *aResult)
00127 {
00128   NS_ENSURE_ARG(aResult);
00129   *aResult = PR_FALSE;
00130   return NS_OK;
00131 }
00132 
00133 /* readonly attribute nsresult status; */
00134 NS_IMETHODIMP 
00135 nsDOMParserChannel::GetStatus(nsresult *aStatus)
00136 {
00137   NS_ENSURE_ARG(aStatus);
00138   *aStatus = mStatus;
00139   return NS_OK;
00140 }
00141 
00142 /* void cancel (in nsresult status); */
00143 NS_IMETHODIMP 
00144 nsDOMParserChannel::Cancel(nsresult status)
00145 {
00146   mStatus = status;
00147   return NS_OK;
00148 }
00149 
00150 /* void suspend (); */
00151 NS_IMETHODIMP 
00152 nsDOMParserChannel::Suspend()
00153 {
00154   return NS_ERROR_NOT_IMPLEMENTED;
00155 }
00156 
00157 /* void resume (); */
00158 NS_IMETHODIMP 
00159 nsDOMParserChannel::Resume()
00160 {
00161   return NS_ERROR_NOT_IMPLEMENTED;
00162 }
00163 
00164 /* attribute nsIURI originalURI; */
00165 NS_IMETHODIMP 
00166 nsDOMParserChannel::GetOriginalURI(nsIURI * *aOriginalURI)
00167 {
00168   NS_ENSURE_ARG_POINTER(aOriginalURI);
00169   *aOriginalURI = mURI;
00170   NS_ADDREF(*aOriginalURI);
00171   return NS_OK;
00172 }
00173 NS_IMETHODIMP nsDOMParserChannel::SetOriginalURI(nsIURI * aOriginalURI)
00174 {
00175   mURI = aOriginalURI;
00176   return NS_OK;
00177 }
00178 
00179 /* attribute nsIURI URI; */
00180 NS_IMETHODIMP nsDOMParserChannel::GetURI(nsIURI * *aURI)
00181 {
00182   NS_ENSURE_ARG_POINTER(aURI);
00183   *aURI = mURI;
00184   NS_ADDREF(*aURI);
00185   return NS_OK;
00186 }
00187 
00188 /* attribute ACString contentType; */
00189 NS_IMETHODIMP nsDOMParserChannel::GetContentType(nsACString &aContentType)
00190 {
00191   aContentType = mContentType;
00192   return NS_OK;
00193 }
00194 NS_IMETHODIMP nsDOMParserChannel::SetContentType(const nsACString &aContentType)
00195 {
00196   mContentType = aContentType;
00197   return NS_OK;
00198 }
00199 
00200 /* attribute ACString contentCharset; */
00201 NS_IMETHODIMP nsDOMParserChannel::GetContentCharset(nsACString &aContentCharset)
00202 {
00203   aContentCharset = mContentCharset;
00204   return NS_OK;
00205 }
00206 NS_IMETHODIMP nsDOMParserChannel::SetContentCharset(const nsACString &aContentCharset)
00207 {
00208   mContentCharset = aContentCharset;
00209   return NS_OK;
00210 }
00211 
00212 /* attribute long contentLength; */
00213 NS_IMETHODIMP nsDOMParserChannel::GetContentLength(PRInt32 *aContentLength)
00214 {
00215   NS_ENSURE_ARG(aContentLength);
00216   *aContentLength = mContentLength;
00217   return NS_OK;
00218 }
00219 NS_IMETHODIMP nsDOMParserChannel::SetContentLength(PRInt32 aContentLength)
00220 {
00221   mContentLength = aContentLength;
00222   return NS_OK;
00223 }
00224 
00225 /* attribute nsISupports owner; */
00226 NS_IMETHODIMP nsDOMParserChannel::GetOwner(nsISupports * *aOwner)
00227 {
00228   NS_ENSURE_ARG_POINTER(aOwner);
00229   *aOwner = mOwner;
00230   NS_IF_ADDREF(*aOwner);
00231   return NS_OK;
00232 }
00233 NS_IMETHODIMP nsDOMParserChannel::SetOwner(nsISupports * aOwner)
00234 {
00235   mOwner = aOwner;
00236   return NS_OK;
00237 }
00238 
00239 /* attribute nsLoadFlags loadFlags; */
00240 NS_IMETHODIMP nsDOMParserChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
00241 {
00242     return NS_ERROR_NOT_IMPLEMENTED;
00243 }
00244 NS_IMETHODIMP nsDOMParserChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
00245 {
00246     return NS_ERROR_NOT_IMPLEMENTED;
00247 }
00248 
00249 /* attribute nsILoadGroup loadGroup; */
00250 NS_IMETHODIMP nsDOMParserChannel::GetLoadGroup(nsILoadGroup * *aLoadGroup)
00251 {
00252   NS_ENSURE_ARG_POINTER(aLoadGroup);
00253   *aLoadGroup = mLoadGroup;
00254   NS_IF_ADDREF(*aLoadGroup);
00255   return NS_OK;
00256 }
00257 NS_IMETHODIMP nsDOMParserChannel::SetLoadGroup(nsILoadGroup * aLoadGroup)
00258 {
00259   mLoadGroup = aLoadGroup;
00260   return NS_OK;
00261 }
00262 
00263 /* attribute nsIInterfaceRequestor notificationCallbacks; */
00264 NS_IMETHODIMP nsDOMParserChannel::GetNotificationCallbacks(nsIInterfaceRequestor * *aNotificationCallbacks)
00265 {
00266   return NS_ERROR_NOT_IMPLEMENTED;
00267 }
00268 NS_IMETHODIMP nsDOMParserChannel::SetNotificationCallbacks(nsIInterfaceRequestor * aNotificationCallbacks)
00269 {
00270   return NS_ERROR_NOT_IMPLEMENTED;
00271 }
00272 
00273 /* readonly attribute nsISupports securityInfo; */
00274 NS_IMETHODIMP nsDOMParserChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
00275 {
00276   return NS_ERROR_NOT_IMPLEMENTED;
00277 }
00278 
00279 NS_IMETHODIMP nsDOMParserChannel::Open(nsIInputStream **aResult)
00280 {
00281   return NS_ERROR_NOT_IMPLEMENTED;
00282 }
00283 
00284 NS_IMETHODIMP nsDOMParserChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
00285 {
00286   return NS_ERROR_NOT_IMPLEMENTED;
00287 }
00288 
00289 // nsIDOMEventListener
00290 nsresult
00291 nsDOMParser::HandleEvent(nsIDOMEvent* aEvent)
00292 {
00293   return NS_OK;
00294 }
00295 
00296 // nsIDOMLoadListener
00297 nsresult
00298 nsDOMParser::Load(nsIDOMEvent* aEvent)
00299 {
00300   mLoopingForSyncLoad = PR_FALSE;
00301 
00302   return NS_OK;
00303 }
00304 
00305 nsresult
00306 nsDOMParser::BeforeUnload(nsIDOMEvent* aEvent)
00307 {
00308   return NS_OK;
00309 }
00310 
00311 nsresult
00312 nsDOMParser::Unload(nsIDOMEvent* aEvent)
00313 {
00314   return NS_OK;
00315 }
00316 
00317 nsresult
00318 nsDOMParser::Abort(nsIDOMEvent* aEvent)
00319 {
00320   mLoopingForSyncLoad = PR_FALSE;
00321 
00322   return NS_OK;
00323 }
00324 
00325 nsresult
00326 nsDOMParser::Error(nsIDOMEvent* aEvent)
00327 {
00328   mLoopingForSyncLoad = PR_FALSE;
00329 
00330   return NS_OK;
00331 }
00332 
00333 nsDOMParser::nsDOMParser()
00334   : mLoopingForSyncLoad(PR_FALSE)
00335 {
00336   mEventQService = do_GetService(kEventQueueServiceCID);
00337 }
00338 
00339 nsDOMParser::~nsDOMParser()
00340 {
00341   NS_ABORT_IF_FALSE(!mLoopingForSyncLoad, "we rather crash than hang");
00342   mLoopingForSyncLoad = PR_FALSE;
00343 }
00344 
00345 
00346 // QueryInterface implementation for nsDOMParser
00347 NS_INTERFACE_MAP_BEGIN(nsDOMParser)
00348   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMParser)
00349   NS_INTERFACE_MAP_ENTRY(nsIDOMParser)
00350   NS_INTERFACE_MAP_ENTRY(nsIDOMLoadListener)
00351   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00352   NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer_MOZILLA_1_8_BRANCH)
00353   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(DOMParser)
00354 NS_INTERFACE_MAP_END
00355 
00356 
00357 NS_IMPL_ADDREF(nsDOMParser)
00358 NS_IMPL_RELEASE(nsDOMParser)
00359 
00360 static nsresult
00361 ConvertWStringToStream(const PRUnichar* aStr,
00362                        PRInt32 aLength,
00363                        nsIInputStream** aStream,
00364                        PRInt32* aContentLength)
00365 {
00366   nsresult rv;
00367   nsCOMPtr<nsIUnicodeEncoder> encoder;
00368   char* charBuf;
00369 
00370   // We want to encode the string as utf-8, so get the right encoder
00371   nsCOMPtr<nsICharsetConverterManager> charsetConv = 
00372            do_GetService(kCharsetConverterManagerCID, &rv);
00373   NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
00374   
00375   rv = charsetConv->GetUnicodeEncoderRaw("UTF-8",
00376                                       getter_AddRefs(encoder));
00377   NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
00378   
00379   // Convert to utf-8
00380   PRInt32 charLength;
00381   const PRUnichar* unicodeBuf = aStr;
00382   PRInt32 unicodeLength = aLength;
00383     
00384   rv = encoder->GetMaxLength(unicodeBuf, unicodeLength, &charLength);
00385   if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
00386   
00387   charBuf = (char*)nsMemory::Alloc(charLength + 1);
00388   if (!charBuf) {
00389     return NS_ERROR_OUT_OF_MEMORY;
00390   }
00391   rv = encoder->Convert(unicodeBuf, 
00392                         &unicodeLength, 
00393                         charBuf, 
00394                         &charLength);
00395   if (NS_FAILED(rv)) {
00396     nsMemory::Free(charBuf);
00397     return NS_ERROR_FAILURE;
00398   }
00399 
00400   // The new stream takes ownership of the buffer
00401   rv = NS_NewByteArrayInputStream((nsIByteArrayInputStream**)aStream, 
00402                                   charBuf, 
00403                                   charLength);
00404   if (NS_FAILED(rv)) {
00405     nsMemory::Free(charBuf);
00406     return NS_ERROR_FAILURE;
00407   }
00408   
00409   *aContentLength = charLength;
00410 
00411   return NS_OK;
00412 }
00413 
00414 NS_IMETHODIMP 
00415 nsDOMParser::ParseFromString(const PRUnichar *str, 
00416                              const char *contentType,
00417                              nsIDOMDocument **aResult)
00418 {
00419   NS_ENSURE_ARG(str);
00420   NS_ENSURE_ARG_POINTER(aResult);
00421 
00422   nsCOMPtr<nsIInputStream> stream;
00423   PRInt32 contentLength;
00424 
00425   nsresult rv = ConvertWStringToStream(str, nsCRT::strlen(str), getter_AddRefs(stream), &contentLength);
00426   if (NS_FAILED(rv)) {
00427     *aResult = nsnull;
00428     return rv;
00429   }
00430 
00431   return ParseFromStream(stream, "UTF-8", contentLength, contentType, aResult);
00432 }
00433 
00434 NS_IMETHODIMP 
00435 nsDOMParser::ParseFromBuffer(const PRUint8 *buf,
00436                              PRUint32 bufLen,
00437                              const char *contentType,
00438                              nsIDOMDocument **aResult)
00439 {
00440   NS_ENSURE_ARG_POINTER(buf);
00441   NS_ENSURE_ARG_POINTER(aResult);
00442 
00443   nsCOMPtr<nsIInputStream> stream;
00444   nsCOMPtr<nsIByteArrayInputStream> baiStream;
00445 
00446   PRUint8 *streamBuf = (PRUint8*)nsMemory::Clone(buf, bufLen);
00447   if (streamBuf == nsnull) {
00448     *aResult = nsnull;
00449     return NS_ERROR_OUT_OF_MEMORY;
00450   }
00451 
00452   // The new stream takes ownership of the buffer
00453   nsresult rv = NS_NewByteArrayInputStream(getter_AddRefs(baiStream), (char*)streamBuf, bufLen);
00454   if (NS_FAILED(rv)) {
00455     nsMemory::Free(streamBuf);
00456     *aResult = nsnull;
00457     return rv;
00458   }
00459 
00460   stream = do_QueryInterface(baiStream);
00461   if (!stream) {
00462     *aResult = nsnull;
00463     return NS_ERROR_FAILURE;
00464   }
00465 
00466   return ParseFromStream(stream, nsnull, bufLen, contentType, aResult);
00467 }
00468 
00469 
00470 NS_IMETHODIMP 
00471 nsDOMParser::ParseFromStream(nsIInputStream *stream, 
00472                              const char *charset, 
00473                              PRInt32 contentLength,
00474                              const char *contentType,
00475                              nsIDOMDocument **aResult)
00476 {
00477   NS_ENSURE_ARG(stream);
00478   NS_ENSURE_ARG(contentType);
00479   NS_ENSURE_ARG_POINTER(aResult);
00480   *aResult = nsnull;
00481 
00482   // For now, we can only create XML documents.
00483   if ((nsCRT::strcmp(contentType, "text/xml") != 0) &&
00484       (nsCRT::strcmp(contentType, "application/xml") != 0) &&
00485       (nsCRT::strcmp(contentType, "application/xhtml+xml") != 0))
00486     return NS_ERROR_NOT_IMPLEMENTED;
00487 
00488   // Put the nsCOMPtr out here so we hold a ref to the stream as needed
00489   nsresult rv;
00490   nsCOMPtr<nsIBufferedInputStream> bufferedStream;
00491   if (!NS_InputStreamIsBuffered(stream)) {
00492     bufferedStream = do_CreateInstance(NS_BUFFEREDINPUTSTREAM_CONTRACTID, &rv);
00493     NS_ENSURE_SUCCESS(rv, rv);
00494     rv = bufferedStream->Init(stream, 4096);
00495     NS_ENSURE_SUCCESS(rv, rv);
00496     stream = bufferedStream;
00497   }
00498   
00499   nsCOMPtr<nsIPrincipal> principal;
00500   nsCOMPtr<nsIScriptSecurityManager> secMan = 
00501     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
00502   if (NS_SUCCEEDED(rv)) {
00503     secMan->GetSubjectPrincipal(getter_AddRefs(principal));
00504   }
00505 
00506   // Try to find a base URI for the document we're creating.
00507   nsCOMPtr<nsIURI> baseURI;
00508   nsCOMPtr<nsIDOMDocument> contextDoc;
00509   if (mOwner) {
00510     nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mOwner);
00511     NS_ENSURE_STATE(win);
00512     nsPIDOMWindow* outer = win->GetOuterWindow();
00513     NS_ENSURE_STATE(outer && outer->GetCurrentInnerWindow() == win);
00514     nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(win);
00515     if (window) {
00516       window->GetDocument(getter_AddRefs(contextDoc));
00517     }
00518   } else {
00519     nsCOMPtr<nsIXPCNativeCallContext> cc;
00520     nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
00521     if(NS_SUCCEEDED(rv)) {
00522       rv = xpc->GetCurrentNativeCallContext(getter_AddRefs(cc));
00523     }
00524 
00525     if (NS_SUCCEEDED(rv) && cc) {
00526       JSContext* cx;
00527       rv = cc->GetJSContext(&cx);
00528       if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
00529 
00530       nsIScriptContext *scriptContext = GetScriptContextFromJSContext(cx);
00531       if (scriptContext) {
00532         nsCOMPtr<nsIDOMWindow> window =
00533           do_QueryInterface(scriptContext->GetGlobalObject());
00534 
00535         if (window) {
00536           window->GetDocument(getter_AddRefs(contextDoc));
00537         }
00538       }
00539     }
00540   }
00541 
00542   nsCOMPtr<nsIDocument> doc = do_QueryInterface(contextDoc);
00543   if (doc) {
00544     baseURI = doc->GetBaseURI();
00545   }
00546 
00547   if (!baseURI) {
00548     // No URI from script environment (we are running from command line, for example).
00549     // Create a dummy one.
00550     // XXX Is this safe? Could we get the URI from stream or something?
00551     if (!mBaseURI) {
00552       rv = NS_NewURI(getter_AddRefs(baseURI),
00553                      "about:blank" );
00554       if (NS_FAILED(rv)) return rv;    
00555     } else {
00556       baseURI = mBaseURI;
00557     }
00558   }
00559 
00560   // Get and initialize a DOMImplementation
00561   nsCOMPtr<nsIDOMDOMImplementation> implementation;
00562   if (contextDoc) {
00563     rv = contextDoc->GetImplementation(getter_AddRefs(implementation));
00564     NS_ENSURE_SUCCESS(rv, rv);
00565   } else {
00566     implementation = do_CreateInstance(kIDOMDOMImplementationCID, &rv);
00567     if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
00568 
00569     if (baseURI) {
00570       nsCOMPtr<nsIPrivateDOMImplementation> privImpl =
00571         do_QueryInterface(implementation);
00572       if (privImpl) {
00573         privImpl->Init(baseURI);
00574       }
00575     }
00576   }
00577 
00578   // Create an empty document from it
00579   nsCOMPtr<nsIDOMDocument> domDocument;
00580   nsAutoString emptyStr;
00581   rv = implementation->CreateDocument(emptyStr, 
00582                                       emptyStr, 
00583                                       nsnull, 
00584                                       getter_AddRefs(domDocument));
00585   if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
00586 
00587   // Register as a load listener on the document
00588   nsCOMPtr<nsIDOMEventReceiver> target(do_QueryInterface(domDocument));
00589   if (target) {
00590     nsWeakPtr requestWeak(do_GetWeakReference(NS_STATIC_CAST(nsIDOMParser*, this)));
00591     nsLoadListenerProxy* proxy = new nsLoadListenerProxy(requestWeak);
00592     if (!proxy) return NS_ERROR_OUT_OF_MEMORY;
00593 
00594     // This will addref the proxy
00595     rv = target->AddEventListenerByIID(NS_STATIC_CAST(nsIDOMEventListener*, 
00596                                                       proxy), 
00597                                        NS_GET_IID(nsIDOMLoadListener));
00598     if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
00599   }
00600 
00601   // Create a fake channel 
00602   nsDOMParserChannel* parserChannel = new nsDOMParserChannel(baseURI, nsDependentCString(contentType));
00603   if (!parserChannel) return NS_ERROR_OUT_OF_MEMORY;
00604 
00605   // Hold a reference to it in this method
00606   nsCOMPtr<nsIChannel> channel = NS_STATIC_CAST(nsIChannel*, parserChannel);
00607   if (principal) {
00608     channel->SetOwner(principal);
00609   }
00610 
00611   if (charset) {
00612     parserChannel->SetContentCharset(nsDependentCString(charset));
00613   }
00614 
00615   nsCOMPtr<nsIRequest> request = NS_STATIC_CAST(nsIRequest*, parserChannel);
00616 
00617   // Tell the document to start loading
00618   nsCOMPtr<nsIStreamListener> listener;
00619   nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
00620   if (!document) return NS_ERROR_FAILURE;
00621 
00622   nsCOMPtr<nsIEventQueue> modalEventQueue;
00623 
00624   if(!mEventQService) {
00625     return NS_ERROR_FAILURE;
00626   }
00627 
00628   mLoopingForSyncLoad = PR_TRUE;
00629 
00630   rv = mEventQService->PushThreadEventQueue(getter_AddRefs(modalEventQueue));
00631   if (NS_FAILED(rv)) {
00632     return rv;
00633   }
00634 
00635   // Have to pass PR_FALSE for reset here, else the reset will remove
00636   // our event listener.  Should that listener addition move to later
00637   // than this call?
00638   rv = document->StartDocumentLoad(kLoadAsData, channel, 
00639                                    nsnull, nsnull, 
00640                                    getter_AddRefs(listener),
00641                                    PR_FALSE);
00642 
00643   if (principal) {
00644     // Make sure to give this document the right principal
00645     document->SetPrincipal(principal);
00646   }
00647 
00648   if (NS_FAILED(rv) || !listener) {
00649     if (modalEventQueue) {
00650       mEventQService->PopThreadEventQueue(modalEventQueue);
00651     }
00652     return NS_ERROR_FAILURE;
00653   }
00654 
00655   // Now start pumping data to the listener
00656   nsresult status;
00657 
00658   rv = listener->OnStartRequest(request, nsnull);
00659   request->GetStatus(&status);
00660 
00661   if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(status)) {
00662     rv = listener->OnDataAvailable(request, nsnull, stream, 0, contentLength);
00663     request->GetStatus(&status);
00664   }
00665 
00666   rv = listener->OnStopRequest(request, nsnull, status);
00667 
00668   if (NS_FAILED(rv)) {
00669     if (modalEventQueue) {
00670       mEventQService->PopThreadEventQueue(modalEventQueue);
00671     }
00672     return NS_ERROR_FAILURE;
00673   }
00674 
00675   while (mLoopingForSyncLoad) {
00676     modalEventQueue->ProcessPendingEvents();
00677   }
00678 
00679   mEventQService->PopThreadEventQueue(modalEventQueue);
00680 
00681   domDocument.swap(*aResult);
00682 
00683   return NS_OK;
00684 }
00685 
00686 NS_IMETHODIMP 
00687 nsDOMParser::GetBaseURI(nsIURI **aBaseURI)
00688 {
00689   NS_ENSURE_ARG_POINTER(aBaseURI);
00690 
00691   NS_IF_ADDREF(*aBaseURI = mBaseURI);
00692 
00693   return NS_OK;
00694 }
00695 
00696 NS_IMETHODIMP 
00697 nsDOMParser::SetBaseURI(nsIURI *aBaseURI)
00698 {
00699   mBaseURI = aBaseURI;
00700 
00701   return NS_OK;
00702 }
00703 
00704 NS_IMETHODIMP
00705 nsDOMParser::Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
00706                         PRUint32 argc, jsval *argv)
00707 {
00708   mOwner = do_GetWeakReference(aOwner);
00709   return NS_OK;
00710 }