aboutsummaryrefslogblamecommitdiffstats
path: root/embed/xulrunner/src/EmbedStream.cpp
blob: c6c2778e0ee92dd5c047ff50dbbb057809d1d1bf (plain) (tree)

































                                                                                                                               
                         



















































































































































































































































































                                                                                         
/*
 *  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 <blizzard@mozilla.org>
 *  ---------------------------------------------------------------------------
 *
 *  $Id$
 */

#include <xpcom-config.h>
#include <config.h>

#include <nsIPipe.h>
#include <nsIInputStream.h>
#include <nsIOutputStream.h>
#include <nsIContentViewerContainer.h>
#include <nsIDocumentLoaderFactory.h>
#include <nsNetUtil.h>
#include <prmem.h>

#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<nsIInputStream> bufInStream;
  nsCOMPtr<nsIOutputStream> 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<nsIWebBrowser> browser;
  mOwner->mWindow->GetWebBrowser(getter_AddRefs(browser));

  // get the viewer container
  nsCOMPtr<nsIContentViewerContainer> viewerContainer;
  viewerContainer = do_GetInterface(browser);

  // create a new uri object
  nsCOMPtr<nsIURI> 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<nsIInputStream *>(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<nsICategoryManager> 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<nsIDocumentLoaderFactory> 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<nsIContentViewer> 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<nsIRequest> 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<nsIRequest> request = do_QueryInterface(mChannel); 
  rv = mStreamListener->OnDataAvailable(request,
                    NULL,
                    static_cast<nsIInputStream *>(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<nsIRequest> 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);
}