/* * Copyright © Christopher Blizzard * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * --------------------------------------------------------------------------- * Derived from Mozilla.org code, which had the following attributions: * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. * Portions created by the Initial Developer are Copyright © 2001 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Christopher Blizzard * --------------------------------------------------------------------------- * * $Id$ */ #include #include #include #include #include #include #include #include #include #include "nsXPCOMCID.h" #include "nsICategoryManager.h" #include "nsIContentViewer.h" #include "EmbedStream.h" #include "EmbedPrivate.h" #include "EmbedWindow.h" #include "nsReadableUtils.h" // nsIInputStream interface NS_IMPL_ISUPPORTS1(EmbedStream, nsIInputStream) EmbedStream::EmbedStream() { mOwner = nsnull; mOffset = 0; mDoingStream = PR_FALSE; } EmbedStream::~EmbedStream() { } void EmbedStream::InitOwner(EmbedPrivate *aOwner) { mOwner = aOwner; } NS_METHOD EmbedStream::Init(void) { nsresult rv = NS_OK; nsCOMPtr bufInStream; nsCOMPtr bufOutStream; rv = NS_NewPipe(getter_AddRefs(bufInStream), getter_AddRefs(bufOutStream)); if (NS_FAILED(rv)) return rv; mInputStream = bufInStream; mOutputStream = bufOutStream; return NS_OK; } NS_METHOD EmbedStream::OpenStream(const char *aBaseURI, const char *aContentType) { NS_ENSURE_ARG_POINTER(aBaseURI); NS_ENSURE_ARG_POINTER(aContentType); nsresult rv = NS_OK; // if we're already doing a stream then close the current one if (mDoingStream) CloseStream(); // set our state mDoingStream = PR_TRUE; // initialize our streams rv = Init(); if (NS_FAILED(rv)) return rv; // get the content area of our web browser nsCOMPtr browser; mOwner->mWindow->GetWebBrowser(getter_AddRefs(browser)); // get the viewer container nsCOMPtr viewerContainer; viewerContainer = do_GetInterface(browser); // create a new uri object nsCOMPtr uri; nsCAutoString spec(aBaseURI); rv = NS_NewURI(getter_AddRefs(uri), spec.get()); if (NS_FAILED(rv)) return rv; // create a new load group rv = NS_NewLoadGroup(getter_AddRefs(mLoadGroup), nsnull); if (NS_FAILED(rv)) return rv; // create a new input stream channel rv = NS_NewInputStreamChannel(getter_AddRefs(mChannel), uri, static_cast(this), nsDependentCString(aContentType), EmptyCString()); if (NS_FAILED(rv)) return rv; // set the channel's load group rv = mChannel->SetLoadGroup(mLoadGroup); if (NS_FAILED(rv)) return rv; // find a document loader for this content type nsXPIDLCString docLoaderContractID; nsCOMPtr catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv)); if (NS_FAILED(rv)) return rv; rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", aContentType, getter_Copies(docLoaderContractID)); if (NS_FAILED(rv)) return rv; nsCOMPtr docLoaderFactory; docLoaderFactory = do_GetService(docLoaderContractID.get(), &rv); if (NS_FAILED(rv)) return rv; // ok, create an instance of the content viewer for that command and // mime type nsCOMPtr contentViewer; rv = docLoaderFactory->CreateInstance("view", mChannel, mLoadGroup, aContentType, viewerContainer, nsnull, getter_AddRefs(mStreamListener), getter_AddRefs(contentViewer)); if (NS_FAILED(rv)) return rv; // set the container viewer container for this content view rv = contentViewer->SetContainer(viewerContainer); if (NS_FAILED(rv)) return rv; // embed this sucker rv = viewerContainer->Embed(contentViewer, "view", nsnull); if (NS_FAILED(rv)) return rv; // start our request nsCOMPtr request = do_QueryInterface(mChannel); rv = mStreamListener->OnStartRequest(request, NULL); if (NS_FAILED(rv)) return rv; return NS_OK; } NS_METHOD EmbedStream::AppendToStream(const char *aData, gint32 aLen) { nsresult rv; // append the data rv = Append(aData, aLen); if (NS_FAILED(rv)) return rv; // notify our listeners nsCOMPtr request = do_QueryInterface(mChannel); rv = mStreamListener->OnDataAvailable(request, NULL, static_cast(this), mOffset, /* offset */ aLen); /* len */ // move our counter mOffset += aLen; if (NS_FAILED(rv)) return rv; return NS_OK; } NS_METHOD EmbedStream::CloseStream(void) { nsresult rv = NS_OK; NS_ENSURE_STATE(mDoingStream); mDoingStream = PR_FALSE; nsCOMPtr request = do_QueryInterface(mChannel, &rv); if (NS_FAILED(rv)) goto loser; rv = mStreamListener->OnStopRequest(request, NULL, NS_OK); if (NS_FAILED(rv)) return rv; loser: mLoadGroup = nsnull; mChannel = nsnull; mStreamListener = nsnull; mOffset = 0; return rv; } NS_METHOD EmbedStream::Append(const char *aData, PRUint32 aLen) { nsresult rv = NS_OK; PRUint32 bytesWritten = 0; rv = mOutputStream->Write(aData, aLen, &bytesWritten); if (NS_FAILED(rv)) return rv; NS_ASSERTION(bytesWritten == aLen, "underlying byffer couldn't handle the write"); return rv; } NS_IMETHODIMP EmbedStream::Available(PRUint32 *_retval) { return mInputStream->Available(_retval); } NS_IMETHODIMP EmbedStream::Read(char * aBuf, PRUint32 aCount, PRUint32 *_retval) { return mInputStream->Read(aBuf, aCount, _retval); } NS_IMETHODIMP EmbedStream::Close(void) { return mInputStream->Close(); } NS_IMETHODIMP EmbedStream::ReadSegments(nsWriteSegmentFun aWriter, void * aClosure, PRUint32 aCount, PRUint32 *_retval) { char *readBuf = (char *)nsMemory::Alloc(aCount); PRUint32 nBytes; if (!readBuf) return NS_ERROR_OUT_OF_MEMORY; nsresult rv = mInputStream->Read(readBuf, aCount, &nBytes); *_retval = 0; if (NS_SUCCEEDED(rv)) { PRUint32 writeCount = 0; rv = aWriter(this, aClosure, readBuf, 0, nBytes, &writeCount); // XXX writeCount may be less than nBytes!! This is the wrong // way to synthesize ReadSegments. NS_ASSERTION(writeCount == nBytes, "data loss"); // errors returned from the writer end here! rv = NS_OK; } nsMemory::Free(readBuf); return rv; } NS_IMETHODIMP EmbedStream::IsNonBlocking(PRBool *aNonBlocking) { return mInputStream->IsNonBlocking(aNonBlocking); }