Page MenuHome GnuPG

nsIPCBuffer.cpp
No OneTemporary

nsIPCBuffer.cpp

/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "MPL"); you may not use this file
* except in compliance with the MPL. You may obtain a copy of
* the MPL at http://www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the MPL for the specific language governing
* rights and limitations under the MPL.
*
* The Original Code is protoZilla.
*
* The Initial Developer of the Original Code is Ramalingam Saravanan.
* Portions created by Ramalingam Saravanan <svn@xmlterm.org> are
* Copyright (C) 2000 Ramalingam Saravanan. All Rights Reserved.
*
* Contributor(s):
* Patrick Brunschwig <patrick@mozilla-enigmail.org>
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License (the "GPL"), in which case
* the provisions of the GPL are applicable instead of
* those above. If you wish to allow use of your version of this
* file only under the terms of the GPL and not to allow
* others to use your version of this file under the MPL, indicate
* your decision by deleting the provisions above and replace them
* with the notice and other provisions required by the GPL.
* If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
// Logging of debug output
// The following define statement should occur before any include statements
#define FORCE_PR_LOG /* Allow logging even in release build */
#include "ipc.h"
#include "prlog.h"
#include "nsCOMPtr.h"
#include "nsAutoLock.h"
#include "nsIInputStream.h"
#include "nsIThread.h"
#include "nsIHttpChannel.h"
#include "nsNetUtil.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsNetCID.h"
#ifndef _IPC_FORCE_INTERNAL_API
#include "nsStringAPI.h"
#else
#include "nsString.h"
#endif
#include "nsIPCBuffer.h"
#ifdef PR_LOGGING
PRLogModuleInfo* gIPCBufferLog = NULL;
#endif
#define ERROR_LOG(args) PR_LOG(gIPCBufferLog,PR_LOG_ERROR,args)
#define WARNING_LOG(args) PR_LOG(gIPCBufferLog,PR_LOG_WARNING,args)
#define DEBUG_LOG(args) PR_LOG(gIPCBufferLog,PR_LOG_DEBUG,args)
#define NS_PIPE_CONSOLE_BUFFER_SIZE (1024)
static const PRUint32 kCharMax = NS_PIPE_CONSOLE_BUFFER_SIZE;
///////////////////////////////////////////////////////////////////////////////
// nsIPCBuffer implementation
// nsISupports implementation
NS_IMPL_THREADSAFE_ISUPPORTS5(nsIPCBuffer,
nsIStreamListener,
nsIPipeListener,
nsIIPCBuffer,
nsIInputStream,
nsIRunnable)
// nsIPCBuffer implementation
nsIPCBuffer::nsIPCBuffer()
: mFinalized(PR_FALSE),
mThreadJoined(PR_FALSE),
mOverflowed(PR_FALSE),
mOverflowFile(PR_FALSE),
mRequestStarted(PR_FALSE),
mRequestStopped(PR_FALSE),
mLock(nsnull),
mMaxBytes(0),
mByteCount(0),
mByteBuf(""),
mPipeWrite(IPC_NULL_HANDLE),
mPipeRead(IPC_NULL_HANDLE),
mTempFile(nsnull),
mTempOutStream(nsnull),
mTempInStream(nsnull),
mPipeThread(nsnull),
mObserver(nsnull),
mObserverContext(nsnull)
{
NS_INIT_ISUPPORTS();
#ifdef PR_LOGGING
if (gIPCBufferLog == nsnull) {
gIPCBufferLog = PR_NewLogModule("nsIPCBuffer");
}
#endif
#ifdef FORCE_PR_LOG
nsresult rv;
nsCOMPtr<nsIThread> myThread;
rv = IPC_GET_THREAD(myThread);
DEBUG_LOG(("nsIPCBuffer:: <<<<<<<<< CTOR(%p): myThread=%p\n",
this, myThread.get()));
#endif
}
nsIPCBuffer::~nsIPCBuffer()
{
nsresult rv;
#ifdef FORCE_PR_LOG
nsCOMPtr<nsIThread> myThread;
rv = IPC_GET_THREAD(myThread);
DEBUG_LOG(("nsIPCBuffer:: >>>>>>>>> DTOR(%p): myThread=%p\n",
this, myThread.get()));
#endif
Finalize(PR_TRUE);
if (mLock)
PR_DestroyLock(mLock);
}
///////////////////////////////////////////////////////////////////////////////
// nsIPCBuffer methods:
///////////////////////////////////////////////////////////////////////////////
nsresult
nsIPCBuffer::Finalize(PRBool destructor)
{
DEBUG_LOG(("nsIPCBuffer::Finalize: \n"));
if (mFinalized)
return NS_OK;
mFinalized = PR_TRUE;
nsCOMPtr<nsIIPCBuffer> self;
if (!destructor) {
// Hold a reference to ourselves to prevent our DTOR from being called
// while finalizing. Automatically released upon returning.
self = this;
}
// Close write pipe
if (mPipeWrite) {
IPC_Close(mPipeWrite);
mPipeWrite = IPC_NULL_HANDLE;
}
// Release owning refs
mPipeThread = nsnull;
mObserver = nsnull;
mObserverContext = nsnull;
RemoveTempFile();
// Clear console
mByteBuf.Assign("");
return NS_OK;
}
nsresult
nsIPCBuffer::Init()
{
DEBUG_LOG(("nsIPCBuffer::Init: \n"));
if (mLock == nsnull) {
mLock = PR_NewLock();
if (mLock == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
NS_IMETHODIMP
nsIPCBuffer::Open(PRUint32 maxBytes, PRBool overflowFile)
{
nsresult rv;
DEBUG_LOG(("nsIPCBuffer::Open: %d, %d\n", maxBytes, (int) overflowFile));
rv = Init();
NS_ENSURE_SUCCESS(rv, rv);
if (maxBytes == -1) {
mMaxBytes = PR_INT32_MAX;
}
else {
mMaxBytes = maxBytes;
}
mOverflowFile = overflowFile;
return NS_OK;
}
NS_IMETHODIMP
nsIPCBuffer::OpenURI(nsIURI* aURI, PRInt32 maxBytes, PRBool synchronous,
nsIRequestObserver* observer, nsISupports* context)
{
DEBUG_LOG(("nsIPCBuffer::OpenURI: \n"));
nsresult rv;
rv = Init();
NS_ENSURE_SUCCESS(rv, rv);
mMaxBytes = maxBytes;
mObserver = observer;
mObserverContext = context;
nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIChannel> channel;
rv = ioService->NewChannelFromURI(aURI, getter_AddRefs(channel));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISupports> ctxt = do_QueryInterface(aURI);
if (!synchronous) {
// Initiate asynchronous loading of URI
rv = channel->AsyncOpen( (nsIStreamListener*) this, ctxt );
NS_ENSURE_SUCCESS(rv, rv);
DEBUG_LOG(("nsIPCBuffer::OpenURI: Starting asynchronous load ...\n"));
return NS_OK;
}
// Synchronous loading (DOESN'T USUALLY WORK!!!)
DEBUG_LOG(("nsIPCBuffer::OpenURI: Starting synchronous load ...\n"));
nsCOMPtr<nsIInputStream> inputStream;
rv = channel->Open(getter_AddRefs(inputStream));
NS_ENSURE_SUCCESS(rv, rv);
OnStartRequest(nsnull, mObserverContext);
PRUint32 readCount;
char buf[1024];
while (1) {
// Read and append output until end-of-file
rv = inputStream->Read((char *) buf, 1024, &readCount);
NS_ENSURE_SUCCESS(rv, rv);
if (!readCount) break;
rv = WriteBuf(buf, readCount);
NS_ENSURE_SUCCESS(rv, rv);
}
// Close input stream
inputStream->Close();
OnStopRequest(nsnull, mObserverContext, 0);
return NS_OK;
}
NS_IMETHODIMP
nsIPCBuffer::GetStopped(PRBool* _retval)
{
NS_ENSURE_ARG(_retval);
*_retval = mRequestStopped;
return NS_OK;
}
NS_IMETHODIMP
nsIPCBuffer::GetTotalBytes(PRUint32* _retval)
{
NS_ENSURE_ARG(_retval);
*_retval = mByteCount;
return NS_OK;
}
NS_IMETHODIMP
nsIPCBuffer::OpenInputStream(nsIInputStream** result)
{
nsresult rv;
DEBUG_LOG(("nsIPCBuffer::OpenInputStream: \n"));
if (!mRequestStopped) {
ERROR_LOG(("nsIPCBuffer::OpenInputStream: ERROR - request not stopped\n"));
return NS_ERROR_NOT_INITIALIZED;
}
mStreamOffset = 0;
if (mByteCount && mTempFile) {
rv = OpenTempInStream();
NS_ENSURE_SUCCESS(rv, rv);
}
return this->QueryInterface(NS_GET_IID(nsIInputStream), (void**)result);
}
#define SAFE_TMP_FILENAME "nsenig.tmp"
NS_IMETHODIMP
nsIPCBuffer::CreateTempFile()
{
nsresult rv;
DEBUG_LOG(("nsIPCBuffer::CreateTempFile: \n"));
if (mTempFile)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIProperties> directoryService =
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
directoryService->Get(NS_OS_TEMP_DIR, NS_GET_IID(nsIFile), getter_AddRefs(mTempFile));
if (! mTempFile)
return NS_ERROR_OUT_OF_MEMORY;
mTempFile->AppendNative(nsDependentCString(SAFE_TMP_FILENAME));
if (NS_FAILED(mTempFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 00600))) {
return NS_ERROR_FAILURE;
}
nsCAutoString nativePath;
mTempFile->GetNativePath(nativePath);
DEBUG_LOG(("nsIPCBuffer::CreateTempFile: %s\n",
nativePath.get()));
mTempOutStream = do_CreateInstance("@mozilla.org/network/file-output-stream;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = mTempOutStream->Init(mTempFile, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 00600, 0);
return rv;
}
NS_IMETHODIMP
nsIPCBuffer::WriteTempOutStream(const char* buf, PRUint32 count)
{
if (!mTempOutStream)
return NS_ERROR_FAILURE;
if (!count)
return NS_OK;
PRUint32 writeCount;
nsresult rv = mTempOutStream->Write(buf, count, &writeCount);
if (writeCount != count)
return NS_ERROR_FAILURE;
return rv;
}
NS_IMETHODIMP
nsIPCBuffer::CloseTempOutStream()
{
nsresult rv = NS_OK;
DEBUG_LOG(("nsIPCBuffer::CloseTempOutStream: \n"));
if (mTempOutStream) {
if (NS_FAILED(mTempOutStream->Flush())) {
rv = NS_ERROR_FAILURE;
}
if (NS_FAILED(mTempOutStream->Close())) {
rv = NS_ERROR_FAILURE;
}
mTempOutStream = nsnull;
}
return rv;
}
NS_IMETHODIMP
nsIPCBuffer::OpenTempInStream()
{
nsresult rv;
DEBUG_LOG(("nsIPCBuffer::OpenTempInStream: \n"));
if (!mTempFile)
return NS_ERROR_FAILURE;
if (mTempOutStream) {
ERROR_LOG(("nsIPCBuffer::OpenTempInStream: ERROR - TempOutStream still open!\n"));
return NS_ERROR_FAILURE;
}
mTempInStream = do_CreateInstance("@mozilla.org/network/file-input-stream;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = mTempInStream->Init(mTempFile, PR_RDONLY, 00600, 0);
return rv;
}
NS_IMETHODIMP
nsIPCBuffer::CloseTempInStream()
{
DEBUG_LOG(("nsIPCBuffer::CloseTempInStream: \n"));
nsresult rv = NS_OK;
if (mTempInStream) {
rv = mTempInStream->Close();
//delete mTempInStream;
mTempInStream = nsnull;
}
return rv;
}
NS_IMETHODIMP
nsIPCBuffer::RemoveTempFile()
{
DEBUG_LOG(("nsIPCBuffer::RemoveTempFile: \n"));
if (mTempOutStream) {
// Close overflow file
CloseTempOutStream();
}
if (mTempInStream) {
// Close overflow file
CloseTempInStream();
}
if (mTempFile) {
// delete temp file
nsCAutoString nativePath;
mTempFile->GetNativePath(nativePath);
DEBUG_LOG(("nsIPCBuffer::RemoveTempFile: Removing %s\n",
nativePath.get()));
if (NS_FAILED(mTempFile->Remove(PR_FALSE))) {
return NS_ERROR_FAILURE;
}
mTempFile = nsnull;
}
return NS_OK;
}
NS_IMETHODIMP
nsIPCBuffer::GetData(char** _retval)
{
nsAutoLock lock(mLock);
if (!_retval)
return NS_ERROR_NULL_POINTER;
// Copy portion of console data to be returned
nsCAutoString bufCopy (mByteBuf);
// Replace any NULs with '0'
PRInt32 nulIndex = 0;
while (nulIndex != -1) {
nulIndex = bufCopy.FindChar(char(0));
if (nulIndex != -1) {
bufCopy.Replace(nulIndex, 1, "0", 1);
}
}
// Duplicate new C string
*_retval = ToNewCString(bufCopy);
if (!*_retval)
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////////
// nsIPipeListener methods (thread-safe)
///////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsIPCBuffer::Observe(nsIRequestObserver* observer, nsISupports* context)
{
nsAutoLock lock(mLock);
DEBUG_LOG(("nsIPCBuffer::Observe: %p, %p\n", observer, context));
mObserver = observer;
mObserverContext = context;
return NS_OK;
}
NS_IMETHODIMP
nsIPCBuffer::GetJoinable(PRBool *_retval)
{
DEBUG_LOG(("nsIPCBuffer::GetJoinable: 1\n"));
*_retval = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP
nsIPCBuffer::Shutdown()
{
nsAutoLock lock(mLock);
DEBUG_LOG(("nsIPCBuffer::Shutdown:\n"));
Finalize(PR_FALSE);
return NS_OK;
}
NS_IMETHODIMP
nsIPCBuffer::GetByteData(PRUint32 *count, char **data)
{
nsAutoLock lock(mLock);
DEBUG_LOG(("nsIPCBuffer::GetByteData:\n"));
if (!count || !data)
return NS_ERROR_NULL_POINTER;
// Copy bytes
*count = mByteBuf.Length();
*data = reinterpret_cast<char*>(nsMemory::Alloc((*count)+1));
if (!*data)
return NS_ERROR_OUT_OF_MEMORY;
memcpy(*data, mByteBuf.get(), *count);
// NUL terminate byte array (just to be safe!)
(*data)[*count] = '\0';
return NS_OK;
}
NS_IMETHODIMP
nsIPCBuffer::GetOverflowed(PRBool *_retval)
{
nsAutoLock lock(mLock);
DEBUG_LOG(("nsIPCBuffer::GetOverflowed: %d\n", (int) mOverflowed));
*_retval = mOverflowed;
return NS_OK;
}
NS_IMETHODIMP
nsIPCBuffer::Write(const char* str)
{
// Note: Locking occurs in WriteBuf
DEBUG_LOG(("nsIPCBuffer::Write: %s\n", str));
PRUint32 len = strlen(str);
if (!len)
return NS_OK;
return WriteBuf(str, len);
}
NS_IMETHODIMP
nsIPCBuffer::WriteBuf(const char* buf, PRUint32 count)
{
nsresult rv;
nsAutoLock lock(mLock);
DEBUG_LOG(("nsIPCBuffer::WriteBuf: %d (%d)\n", count, mByteCount));
if (count <= 0)
return NS_OK;
mByteCount += count;
if (mOverflowed) {
if (!mOverflowFile)
return NS_OK;
rv = WriteTempOutStream(buf, count);
return rv;
}
// Find space available in buffer
PRInt32 nAvail = mMaxBytes - mByteBuf.Length();
if (nAvail >= (int) count) {
mByteBuf.Append(buf, count);
return NS_OK;
}
if (nAvail > 0) {
mByteBuf.Append(buf, nAvail);
}
mOverflowed = PR_TRUE;
DEBUG_LOG(("nsIPCBuffer::WriteBuf: buffer overflow\n"));
if (!mOverflowFile)
return NS_OK;
CreateTempFile();
// Write out previously buffered data first
rv = WriteTempOutStream(mByteBuf.get(), mByteBuf.Length());
NS_ENSURE_SUCCESS(rv, rv);
rv = WriteTempOutStream(buf+nAvail, count-nAvail);
return rv;
}
NS_IMETHODIMP
nsIPCBuffer::Join()
{
nsresult rv;
{
// Nested lock to avoid deadlock while waiting for Join
nsAutoLock lock(mLock);
DEBUG_LOG(("nsIPCBuffer::Join:\n"));
if (mThreadJoined || !mPipeThread)
return NS_OK;
if (mPipeWrite) {
// Close write pipe before joining
IPC_Close(mPipeWrite);
mPipeWrite = IPC_NULL_HANDLE;
}
}
rv = mPipeThread->Shutdown();
NS_ENSURE_SUCCESS(rv, rv);
mThreadJoined = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP
nsIPCBuffer::GetFileDesc(IPCFileDesc* *_retval)
{
nsresult rv;
nsAutoLock lock(mLock);
DEBUG_LOG(("nsIPCBuffer::GetFileDesc:\n"));
if (!_retval)
return NS_ERROR_NULL_POINTER;
if (!mFinalized && !mPipeThread) {
// Create pipe pair
PRStatus status = IPC_CreateInheritablePipe(&mPipeRead, &mPipeWrite,
PR_FALSE, PR_TRUE);
if (status != PR_SUCCESS) {
ERROR_LOG(("nsIPCBuffer::GetFileDesc: IPC_CreateInheritablePipe failed\n"));
return NS_ERROR_FAILURE;
}
// Spin up a new thread to handle STDOUT polling
rv = NS_NewThread(getter_AddRefs(mPipeThread), this);
NS_ENSURE_SUCCESS(rv, rv);
}
if (mPipeWrite == IPC_NULL_HANDLE)
return NS_ERROR_FAILURE;
*_retval = mPipeWrite;
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////////
// nsIRequestObserver methods
///////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsIPCBuffer::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
{
DEBUG_LOG(("nsIPCBuffer::OnStartRequest:\n"));
nsCOMPtr<nsIRequestObserver> observer;
nsCOMPtr<nsISupports> observerContext;
{
nsAutoLock lock(mLock);
mRequestStarted = PR_TRUE;
if (!mObserver)
return NS_OK;
observer = mObserver;
observerContext = mObserverContext;
}
return observer->OnStartRequest(aRequest, observerContext);
}
NS_IMETHODIMP
nsIPCBuffer::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
nsresult aStatus)
{
DEBUG_LOG(("nsIPCBuffer::OnStopRequest:\n"));
nsCOMPtr<nsIRequestObserver> observer;
nsCOMPtr<nsISupports> observerContext;
{
nsAutoLock lock(mLock);
mRequestStopped = PR_TRUE;
CloseTempOutStream();
if (!mObserver)
return NS_OK;
observer = mObserver;
observerContext = mObserverContext;
}
return observer->OnStopRequest(aRequest, observerContext, aStatus);
}
///////////////////////////////////////////////////////////////////////////////
// nsIStreamListener method
///////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsIPCBuffer::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext,
nsIInputStream *aInputStream,
PRUint32 aSourceOffset,
PRUint32 aLength)
{
nsresult rv = NS_OK;
DEBUG_LOG(("nsIPCBuffer::OnDataAVailable: %d\n", aLength));
char buf[kCharMax];
PRUint32 readCount, readMax;
while (aLength > 0) {
readMax = (aLength < kCharMax) ? aLength : kCharMax;
rv = aInputStream->Read((char *) buf, readMax, &readCount);
if (NS_FAILED(rv)){
ERROR_LOG(("nsIPCBuffer::OnDataAvailable: Error in reading from input stream, %x\n", rv));
return rv;
}
if (readCount <= 0) return NS_OK;
rv = WriteBuf(buf, readCount);
if (NS_FAILED(rv)) return rv;
aLength -= readCount;
}
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////////
// nsIRunnable methods:
// (runs as a new thread)
///////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsIPCBuffer::Run()
{
nsresult rv = NS_OK;
#ifdef FORCE_PR_LOG
nsCOMPtr<nsIThread> myThread;
rv = IPC_GET_THREAD(myThread);
DEBUG_LOG(("nsIPCBuffer::Run: myThread=%p\n", myThread.get()));
#endif
// Blocked read loop
while (1) {
char buf[kCharMax];
PRInt32 readCount;
// Read data from pipe (blocking)
readCount = IPC_Read(mPipeRead, (char *) buf, kCharMax);
DEBUG_LOG(("nsIPCBuffer::Run: Read %d chars\n", readCount));
if (readCount <= 0)
break;
#if 0
// Debugging code
if (readCount < (int) kCharMax) {
buf[readCount] = '\0';
DEBUG_LOG(("nsIPCBuffer::Run: buf='%s'\n", buf));
}
#endif
// Append data read to console
WriteBuf(buf, readCount);
}
// Clear any NSPR interrupt
PR_ClearInterrupt();
// Close read pipe
IPC_Close(mPipeRead);
mPipeRead = IPC_NULL_HANDLE;
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////////
// nsIInputStream methods
///////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsIPCBuffer::Available(PRUint32* _retval)
{
if (!_retval)
return NS_ERROR_NULL_POINTER;
*_retval = (mByteCount > mStreamOffset) ?
mByteCount - mStreamOffset : 0;
DEBUG_LOG(("nsIPCBuffer::Available: %d (%d)\n", *_retval, mByteCount));
return NS_OK;
}
NS_IMETHODIMP
nsIPCBuffer::Read(char* buf, PRUint32 count,
PRUint32 *readCount)
{
DEBUG_LOG(("nsIPCBuffer::Read: %d\n", count));
nsresult rv;
if (!buf || !readCount)
return NS_ERROR_NULL_POINTER;
PRInt32 avail = (mByteCount > mStreamOffset) ?
mByteCount - mStreamOffset : 0;
PRUint32 readyCount = ((PRUint32) avail > count) ? count : avail;
if (readyCount) {
if (mTempInStream) {
rv = mTempInStream->Read((char *)buf, readyCount, readCount);
NS_ENSURE_SUCCESS(rv, rv);
} else {
memcpy(buf, mByteBuf.get()+mStreamOffset, readyCount);
*readCount = readyCount;
}
}
mStreamOffset += *readCount;
if (mStreamOffset >= mByteCount) {
Close();
}
return NS_OK;
}
NS_IMETHODIMP
nsIPCBuffer::ReadSegments(nsWriteSegmentFun writer,
void * aClosure, PRUint32 count,
PRUint32 *readCount)
{
nsresult rv;
DEBUG_LOG(("nsIPCBuffer::ReadSegments: %d\n", count));
if (!readCount)
return NS_ERROR_NULL_POINTER;
PRUint32 avail, readyCount, writeCount;
*readCount = 0;
if (!mTempInStream) {
while ((count > 0) && (mStreamOffset < mByteCount)) {
avail = mByteCount - mStreamOffset;
readyCount = ((PRUint32) avail > count) ? count : avail;
rv = writer((nsIInputStream*)(this),
aClosure, mByteBuf.get()+mStreamOffset,
mStreamOffset, readyCount, &writeCount);
NS_ENSURE_SUCCESS(rv, rv);
if (!writeCount)
return (NS_ERROR_FAILURE);
DEBUG_LOG(("nsIPCBuffer::ReadSegments: writer %d\n", writeCount));
*readCount += writeCount;
mStreamOffset += writeCount;
count -= writeCount;
}
} else {
char buf[kCharMax];
while ((count > 0) && (mStreamOffset < mByteCount)) {
avail = (count < kCharMax) ? count : kCharMax;
rv = mTempInStream->Read((char *) buf, avail, &readyCount);
NS_ENSURE_SUCCESS(rv, rv);
if (!readyCount) {
ERROR_LOG(("nsIPCBuffer::ReadSegments: Error in reading from TempInputStream\n"));
return NS_ERROR_FAILURE;
}
rv = writer((nsIInputStream*)(this),
aClosure, buf,
mStreamOffset, readyCount, &writeCount);
NS_ENSURE_SUCCESS(rv, rv);
if (!writeCount)
return NS_ERROR_FAILURE;
DEBUG_LOG(("nsIPCBuffer::ReadSegments: writer %d (Temp)\n", writeCount));
*readCount += writeCount;
mStreamOffset += writeCount;
count -= writeCount;
}
}
if (mStreamOffset >= mByteCount) {
// End-of-file
Close();
}
return NS_OK;
}
NS_IMETHODIMP
nsIPCBuffer::IsNonBlocking(PRBool *aNonBlocking)
{
DEBUG_LOG(("nsIPCBuffer::IsNonBlocking: \n"));
*aNonBlocking = (mTempInStream == nsnull);
return NS_OK;
}
NS_IMETHODIMP
nsIPCBuffer::Close()
{
DEBUG_LOG(("nsIPCBuffer::Close: \n"));
mStreamOffset = 0;
mByteCount = 0;
mByteBuf.Assign("");
RemoveTempFile();
return NS_OK;
}

File Metadata

Mime Type
text/x-c
Expires
Thu, Feb 26, 7:15 PM (16 h, 33 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
b0/c4/ce5e92679a0e6d7a131140738c91

Event Timeline