Back to index

lightning-sunbird  0.9+nobinonly
EmbedStream.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  *  Zack Rusin <zack@kde.org>.
00020  * Portions created by the Initial Developer are Copyright (C) 2004
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Lars Knoll <knoll@kde.org>
00025  *   Zack Rusin <zack@kde.org>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either the GNU General Public License Version 2 or later (the "GPL"), or
00029  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 #include <nsIPipe.h>
00041 #include <nsIInputStream.h>
00042 #include <nsIOutputStream.h>
00043 #include <nsIContentViewerContainer.h>
00044 #include <nsIDocumentLoaderFactory.h>
00045 #include <nsNetUtil.h>
00046 #include <prmem.h>
00047 
00048 #include "nsXPCOMCID.h"
00049 #include "nsICategoryManager.h"
00050 
00051 #include "nsIContentViewer.h"
00052 
00053 #include "EmbedStream.h"
00054 #include "qgeckoembed.h"
00055 #include "EmbedWindow.h"
00056 #include "nsReadableUtils.h"
00057 
00058 // nsIInputStream interface
00059 
00060 NS_IMPL_ISUPPORTS1(EmbedStream, nsIInputStream)
00061 
00062     EmbedStream::EmbedStream()
00063 {
00064     mOwner       = nsnull;
00065     mOffset      = 0;
00066     mDoingStream = PR_FALSE;
00067 }
00068 
00069 EmbedStream::~EmbedStream()
00070 {
00071 }
00072 
00073 void
00074 EmbedStream::InitOwner(QGeckoEmbed *aOwner)
00075 {
00076     mOwner = aOwner;
00077 }
00078 
00079 NS_METHOD
00080 EmbedStream::Init(void)
00081 {
00082     nsresult rv = NS_OK;
00083 
00084     nsCOMPtr<nsIInputStream> bufInStream;
00085     nsCOMPtr<nsIOutputStream> bufOutStream;
00086 
00087     rv = NS_NewPipe(getter_AddRefs(bufInStream),
00088                     getter_AddRefs(bufOutStream));
00089 
00090     if (NS_FAILED(rv)) return rv;
00091 
00092     mInputStream  = bufInStream;
00093     mOutputStream = bufOutStream;
00094     return NS_OK;
00095 }
00096 
00097 NS_METHOD
00098 EmbedStream::OpenStream(const char *aBaseURI, const char *aContentType)
00099 {
00100     qDebug("==================> OpenStream: %s (%s)", aBaseURI, aContentType);
00101     NS_ENSURE_ARG_POINTER(aBaseURI);
00102     NS_ENSURE_ARG_POINTER(aContentType);
00103 
00104     nsresult rv = NS_OK;
00105 
00106     // if we're already doing a stream then close the current one
00107     if (mDoingStream)
00108         CloseStream();
00109 
00110     // set our state
00111     mDoingStream = PR_TRUE;
00112 
00113     // initialize our streams
00114     rv = Init();
00115     if (NS_FAILED(rv))
00116         return rv;
00117 
00118     // get the content area of our web browser
00119     nsCOMPtr<nsIWebBrowser> browser;
00120 
00121 
00122     mOwner->window()->GetWebBrowser(getter_AddRefs(browser));
00123 
00124     // get the viewer container
00125     nsCOMPtr<nsIContentViewerContainer> viewerContainer;
00126     viewerContainer = do_GetInterface(browser);
00127 
00128     // create a new uri object
00129     nsCOMPtr<nsIURI> uri;
00130     nsCAutoString spec(aBaseURI);
00131     rv = NS_NewURI(getter_AddRefs(uri), spec.get());
00132 
00133     if (NS_FAILED(rv))
00134         return rv;
00135 
00136     // create a new load group
00137     rv = NS_NewLoadGroup(getter_AddRefs(mLoadGroup), nsnull);
00138     if (NS_FAILED(rv))
00139         return rv;
00140 
00141     // create a new input stream channel
00142     rv = NS_NewInputStreamChannel(getter_AddRefs(mChannel), uri,
00143                                   this,
00144                                   nsDependentCString(aContentType));
00145     if (NS_FAILED(rv))
00146         return rv;
00147 
00148     // set the channel's load group
00149     rv = mChannel->SetLoadGroup(mLoadGroup);
00150     if (NS_FAILED(rv))
00151         return rv;
00152 
00153     // find a document loader for this content type
00154 
00155     nsXPIDLCString docLoaderContractID;
00156     nsCOMPtr<nsICategoryManager> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv));
00157     if (NS_FAILED(rv))
00158         return rv;
00159     rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", aContentType,
00160                                   getter_Copies(docLoaderContractID));
00161     if (NS_FAILED(rv))
00162         return rv;
00163 
00164     nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory;
00165     docLoaderFactory = do_GetService(docLoaderContractID.get(), &rv);
00166     if (NS_FAILED(rv))
00167         return rv;
00168 
00169     // ok, create an instance of the content viewer for that command and
00170     // mime type
00171     nsCOMPtr<nsIContentViewer> contentViewer;
00172     rv = docLoaderFactory->CreateInstance("view", mChannel, mLoadGroup,
00173                                           aContentType, viewerContainer,
00174                                           nsnull,
00175                                           getter_AddRefs(mStreamListener),
00176                                           getter_AddRefs(contentViewer));
00177     if (NS_FAILED(rv))
00178         return rv;
00179 
00180     // set the container viewer container for this content view
00181     rv = contentViewer->SetContainer(viewerContainer);
00182     if (NS_FAILED(rv))
00183         return rv;
00184 
00185     // embed this sucker
00186     rv = viewerContainer->Embed(contentViewer, "view", nsnull);
00187     if (NS_FAILED(rv))
00188         return rv;
00189 
00190     // start our request
00191     nsCOMPtr<nsIRequest> request = do_QueryInterface(mChannel);
00192     rv = mStreamListener->OnStartRequest(request, NULL);
00193     if (NS_FAILED(rv))
00194         return rv;
00195 
00196     return NS_OK;
00197 }
00198 
00199 NS_METHOD
00200 EmbedStream::AppendToStream(const char *aData, PRInt32 aLen)
00201 {
00202     nsresult rv;
00203 
00204     // append the data
00205     rv = Append(aData, aLen);
00206     if (NS_FAILED(rv))
00207         return rv;
00208 
00209     // notify our listeners
00210     nsCOMPtr<nsIRequest> request = do_QueryInterface(mChannel);
00211     rv = mStreamListener->OnDataAvailable(request,
00212                                           NULL,
00213                                           NS_STATIC_CAST(nsIInputStream *, this),
00214                                           mOffset, /* offset */
00215                                           aLen); /* len */
00216     // move our counter
00217     mOffset += aLen;
00218     if (NS_FAILED(rv))
00219         return rv;
00220 
00221     return NS_OK;
00222 }
00223 
00224 NS_METHOD
00225 EmbedStream::CloseStream(void)
00226 {
00227     nsresult rv = NS_OK;
00228 
00229     NS_ENSURE_STATE(mDoingStream);
00230     mDoingStream = PR_FALSE;
00231 
00232     nsCOMPtr<nsIRequest> request = do_QueryInterface(mChannel, &rv);
00233     if (NS_FAILED(rv))
00234         goto loser;
00235 
00236     rv = mStreamListener->OnStopRequest(request, NULL, NS_OK);
00237     if (NS_FAILED(rv))
00238         return rv;
00239 
00240  loser:
00241     mLoadGroup = nsnull;
00242     mChannel = nsnull;
00243     mStreamListener = nsnull;
00244     mOffset = 0;
00245 
00246     return rv;
00247 }
00248 
00249 NS_METHOD
00250 EmbedStream::Append(const char *aData, PRUint32 aLen)
00251 {
00252     nsresult rv = NS_OK;
00253     PRUint32 bytesWritten = 0;
00254     rv = mOutputStream->Write(aData, aLen, &bytesWritten);
00255     if (NS_FAILED(rv))
00256         return rv;
00257 
00258     NS_ASSERTION(bytesWritten == aLen,
00259                  "underlying byffer couldn't handle the write");
00260     return rv;
00261 }
00262 
00263 NS_IMETHODIMP
00264 EmbedStream::Available(PRUint32 *_retval)
00265 {
00266     return mInputStream->Available(_retval);
00267 }
00268 
00269 NS_IMETHODIMP
00270 EmbedStream::Read(char * aBuf, PRUint32 aCount, PRUint32 *_retval)
00271 {
00272     return mInputStream->Read(aBuf, aCount, _retval);
00273 }
00274 
00275 NS_IMETHODIMP EmbedStream::Close(void)
00276 {
00277     return mInputStream->Close();
00278 }
00279 
00280 NS_IMETHODIMP
00281 EmbedStream::ReadSegments(nsWriteSegmentFun aWriter, void * aClosure,
00282                           PRUint32 aCount, PRUint32 *_retval)
00283 {
00284     char *readBuf = (char *)nsMemory::Alloc(aCount);
00285     PRUint32 nBytes;
00286 
00287     if (!readBuf)
00288         return NS_ERROR_OUT_OF_MEMORY;
00289 
00290     nsresult rv = mInputStream->Read(readBuf, aCount, &nBytes);
00291 
00292     *_retval = 0;
00293 
00294     if (NS_SUCCEEDED(rv)) {
00295         PRUint32 writeCount = 0;
00296         rv = aWriter(this, aClosure, readBuf, 0, nBytes, &writeCount);
00297 
00298         // XXX writeCount may be less than nBytes!!  This is the wrong
00299         // way to synthesize ReadSegments.
00300         NS_ASSERTION(writeCount == nBytes, "data loss");
00301 
00302         // errors returned from the writer end here!
00303         rv = NS_OK;
00304     }
00305 
00306     nsMemory::Free(readBuf);
00307 
00308     return rv;
00309 }
00310 
00311 NS_IMETHODIMP
00312 EmbedStream::IsNonBlocking(PRBool *aNonBlocking)
00313 {
00314     return mInputStream->IsNonBlocking(aNonBlocking);
00315 }