mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-15 03:00:30 +00:00
387 lines
10 KiB
C++
387 lines
10 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
#include "nsByteBufferInputStream.h"
|
|
#include "prcmon.h"
|
|
|
|
NS_IMETHODIMP
|
|
nsDummyBufferStream::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
|
{
|
|
NS_NOTREACHED("nsDummyBufferStream::QueryInterface");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_IMETHODIMP_(nsrefcnt)
|
|
nsDummyBufferStream::AddRef(void)
|
|
{
|
|
NS_NOTREACHED("nsDummyBufferStream::AddRef");
|
|
return 1;
|
|
}
|
|
|
|
NS_IMETHODIMP_(nsrefcnt)
|
|
nsDummyBufferStream::Release(void)
|
|
{
|
|
NS_NOTREACHED("nsDummyBufferStream::Release");
|
|
return 1;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// nsByteBufferInputStream methods:
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
nsByteBufferInputStream::nsByteBufferInputStream(PRBool blocking, PRUint32 size)
|
|
: mBuffer(nsnull), mLength(size), mReadCursor(0), mWriteCursor(0),
|
|
mFull(PR_FALSE), mClosed(PR_FALSE), mEOF(PR_FALSE), mBlocking(blocking)
|
|
{
|
|
NS_INIT_REFCNT();
|
|
}
|
|
|
|
nsresult
|
|
nsByteBufferInputStream::Init(void)
|
|
{
|
|
mBuffer = new char[mLength];
|
|
if (mBuffer == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsByteBufferInputStream::~nsByteBufferInputStream()
|
|
{
|
|
(void)Close();
|
|
if (mBuffer) delete mBuffer;
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS3(nsByteBufferInputStream, nsIByteBufferInputStream, nsIInputStream, nsIBaseStream)
|
|
|
|
NS_IMETHODIMP
|
|
nsByteBufferInputStream::Close(void)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
if (mBlocking)
|
|
PR_CEnterMonitor(this);
|
|
mClosed = PR_TRUE;
|
|
if (mBlocking) {
|
|
PRStatus status = PR_CNotify(this); // wake up the writer
|
|
if (status != PR_SUCCESS)
|
|
rv = NS_ERROR_FAILURE;
|
|
PR_CExitMonitor(this);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsByteBufferInputStream::GetLength(PRUint32 *aLength)
|
|
{
|
|
if (mClosed)
|
|
return NS_BASE_STREAM_CLOSED;
|
|
|
|
if (mBlocking)
|
|
PR_CEnterMonitor(this);
|
|
*aLength = ReadableAmount();
|
|
if (mBlocking)
|
|
PR_CExitMonitor(this);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsByteBufferInputStream::Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
if (mClosed)
|
|
return NS_BASE_STREAM_CLOSED;
|
|
|
|
if (AtEOF())
|
|
return NS_BASE_STREAM_EOF;
|
|
|
|
if (mBlocking)
|
|
PR_CEnterMonitor(this);
|
|
*aReadCount = 0;
|
|
|
|
/*while (aCount > 0)*/ {
|
|
if (ReadableAmount() == 0) {
|
|
if (mBlocking) {
|
|
PRStatus status = PR_CWait(this, PR_INTERVAL_NO_TIMEOUT);
|
|
if (status != PR_SUCCESS) {
|
|
rv = NS_ERROR_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
if (mEOF) {
|
|
rv = NS_BASE_STREAM_EOF;
|
|
goto done;
|
|
}
|
|
else if (!mBlocking) {
|
|
rv = NS_BASE_STREAM_WOULD_BLOCK;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
// wrap-around buffer:
|
|
PRUint32 amt = 0;
|
|
if (mReadCursor >= mWriteCursor || mFull) {
|
|
ReadChunk(aBuf, aCount, mLength, &amt);
|
|
*aReadCount += amt;
|
|
aBuf += amt;
|
|
aCount -= amt;
|
|
if (mReadCursor == mLength) {
|
|
mReadCursor = 0;
|
|
amt = 0;
|
|
ReadChunk(aBuf, aCount, mWriteCursor, &amt);
|
|
*aReadCount += amt;
|
|
aBuf += amt;
|
|
aCount -= amt;
|
|
}
|
|
}
|
|
else {
|
|
ReadChunk(aBuf, aCount, mWriteCursor, &amt);
|
|
*aReadCount += amt;
|
|
aBuf += amt;
|
|
aCount -= amt;
|
|
}
|
|
if (*aReadCount)
|
|
mFull = PR_FALSE;
|
|
|
|
if (mBlocking) {
|
|
PRStatus status = PR_CNotify(this); // tell the writer there's space
|
|
if (status != PR_SUCCESS)
|
|
rv = NS_ERROR_FAILURE;
|
|
}
|
|
}
|
|
done:
|
|
if (mBlocking)
|
|
PR_CExitMonitor(this);
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsByteBufferInputStream::Fill(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount)
|
|
{
|
|
nsDummyBufferStream in(aBuf, aCount);
|
|
return Fill(&in, aCount, aWriteCount);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsByteBufferInputStream::Fill(nsIInputStream* stream, PRUint32 aCount, PRUint32 *aWriteCount)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (mClosed || mEOF)
|
|
return NS_BASE_STREAM_CLOSED;
|
|
|
|
*aWriteCount = 0;
|
|
|
|
if (mBlocking)
|
|
PR_CEnterMonitor(this);
|
|
|
|
while (aCount > 0) {
|
|
if (WritableAmount() == 0) {
|
|
if (mBlocking) {
|
|
PRStatus status = PR_CWait(this, PR_INTERVAL_NO_TIMEOUT);
|
|
if (status != PR_SUCCESS) {
|
|
rv = NS_ERROR_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
if (mClosed) {
|
|
rv = NS_BASE_STREAM_CLOSED;
|
|
goto done;
|
|
}
|
|
else if (!mBlocking) {
|
|
rv = NS_BASE_STREAM_WOULD_BLOCK;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
// wrap-around buffer:
|
|
PRUint32 amt = 0;
|
|
if (mReadCursor <= mWriteCursor && !mFull) {
|
|
rv = WriteChunk(stream, mLength, &amt);
|
|
if (NS_FAILED(rv)) goto done;
|
|
*aWriteCount += amt;
|
|
aCount -= amt;
|
|
if (mWriteCursor == mLength) {
|
|
mWriteCursor = 0;
|
|
amt = 0;
|
|
rv = WriteChunk(stream, mReadCursor, &amt);
|
|
if (NS_FAILED(rv)) goto done;
|
|
*aWriteCount += amt;
|
|
aCount -= amt;
|
|
}
|
|
}
|
|
else {
|
|
rv = WriteChunk(stream, mReadCursor, &amt);
|
|
if (NS_FAILED(rv)) goto done;
|
|
*aWriteCount += amt;
|
|
aCount -= amt;
|
|
}
|
|
if (mWriteCursor == mReadCursor)
|
|
mFull = PR_TRUE;
|
|
|
|
if (mBlocking) {
|
|
PRStatus status = PR_CNotify(this); // tell the reader there's more
|
|
if (status != PR_SUCCESS)
|
|
rv = NS_ERROR_FAILURE;
|
|
}
|
|
}
|
|
done:
|
|
if (mBlocking)
|
|
PR_CExitMonitor(this);
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsByteBufferInputStream::SetEOF()
|
|
{
|
|
nsresult rv = NS_OK;
|
|
if (mBlocking)
|
|
PR_CEnterMonitor(this);
|
|
mEOF = PR_TRUE;
|
|
if (mBlocking) {
|
|
PRStatus status = PR_CNotify(this); // wake up the reader
|
|
if (status != PR_SUCCESS)
|
|
rv = NS_ERROR_FAILURE;
|
|
PR_CExitMonitor(this);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsByteBufferInputStream::Drain()
|
|
{
|
|
nsresult rv = NS_OK;
|
|
if (mBlocking) {
|
|
PR_CEnterMonitor(this);
|
|
while (ReadableAmount() != 0) {
|
|
PRStatus status = PR_CNotify(this); // wake up the reader
|
|
if (status != PR_SUCCESS) {
|
|
rv = NS_ERROR_FAILURE;
|
|
break;
|
|
}
|
|
else {
|
|
// wait for the reader to take all the data
|
|
status = PR_CWait(this, PR_INTERVAL_NO_TIMEOUT);
|
|
if (status != PR_SUCCESS) {
|
|
rv = NS_ERROR_FAILURE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
PR_CExitMonitor(this);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// nsByteBufferOutputStream methods:
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
nsByteBufferOutputStream::nsByteBufferOutputStream(nsByteBufferInputStream* in)
|
|
: mInputStream(in)
|
|
{
|
|
NS_INIT_REFCNT();
|
|
NS_ADDREF(mInputStream);
|
|
}
|
|
|
|
nsByteBufferOutputStream::~nsByteBufferOutputStream()
|
|
{
|
|
(void)Close();
|
|
NS_IF_RELEASE(mInputStream);
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS2(nsByteBufferOutputStream, nsIOutputStream, nsIBaseStream)
|
|
|
|
NS_IMETHODIMP
|
|
nsByteBufferOutputStream::Close(void)
|
|
{
|
|
mInputStream->SetEOF();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsByteBufferOutputStream::Write(const char* aBuf, PRUint32 aCount,
|
|
PRUint32 *aWriteCount)
|
|
{
|
|
return mInputStream->Fill(aBuf, aCount, aWriteCount);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsByteBufferOutputStream::WriteFrom(nsIInputStream* fromStream, PRUint32 aCount,
|
|
PRUint32 *aWriteCount)
|
|
{
|
|
return mInputStream->Fill(fromStream, aCount, aWriteCount);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsByteBufferOutputStream::Flush(void)
|
|
{
|
|
return mInputStream->Drain();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
NS_COM nsresult
|
|
NS_NewByteBufferInputStream(nsIByteBufferInputStream* *result,
|
|
PRBool blocking, PRUint32 size)
|
|
{
|
|
nsresult rv;
|
|
nsByteBufferInputStream* inStr = nsnull;
|
|
|
|
inStr = new nsByteBufferInputStream(blocking, size);
|
|
if (inStr == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
rv = inStr->Init();
|
|
if (NS_FAILED(rv)) {
|
|
delete inStr;
|
|
return rv;
|
|
}
|
|
NS_ADDREF(inStr);
|
|
*result = inStr;
|
|
return NS_OK;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
NS_COM nsresult
|
|
NS_NewPipe(nsIInputStream* *inStrResult,
|
|
nsIOutputStream* *outStrResult,
|
|
PRBool blocking, PRUint32 size)
|
|
{
|
|
nsresult rv;
|
|
nsIByteBufferInputStream* in;
|
|
nsByteBufferInputStream* inStr;
|
|
nsByteBufferOutputStream* outStr;
|
|
|
|
rv = NS_NewByteBufferInputStream(&in, blocking, size);
|
|
if (NS_FAILED(rv)) return rv;
|
|
// this cast is safe, because we know how NS_NewByteBufferInputStream works:
|
|
inStr = NS_STATIC_CAST(nsByteBufferInputStream*, in);
|
|
|
|
outStr = new nsByteBufferOutputStream(inStr);
|
|
if (outStr == nsnull) {
|
|
NS_RELEASE(inStr);
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
NS_ADDREF(outStr);
|
|
|
|
*inStrResult = inStr;
|
|
*outStrResult = outStr;
|
|
return NS_OK;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|