Added NS_NewPipe and cleaned up ByteBufferInputStreams.
git-svn-id: svn://10.0.0.236/trunk@27339 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
9c99105f3e
commit
ec8aed1d77
@ -15,10 +15,12 @@
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef nsIByteBufferInputStream_h___
|
||||
#define nsIByteBufferInputStream_h___
|
||||
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
|
||||
#define NS_IBYTEBUFFERINPUTSTREAM_IID \
|
||||
{ /* 40767100-eb9c-11d2-931c-00104ba0fd40 */ \
|
||||
@ -30,14 +32,46 @@
|
||||
|
||||
class nsIByteBufferInputStream : public nsIInputStream {
|
||||
public:
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IBYTEBUFFERINPUTSTREAM_IID);
|
||||
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_IBYTEBUFFERINPUTSTREAM_IID; return iid; }
|
||||
NS_IMETHOD Fill(nsIInputStream* stream, PRUint32 *aWriteCount) = 0;
|
||||
|
||||
NS_IMETHOD Fill(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount) = 0;
|
||||
|
||||
NS_IMETHOD Fill(nsIInputStream* stream, PRUint32 *filledAmount) = 0;
|
||||
};
|
||||
|
||||
// Makes an byte buffer input stream:
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// XXX regenerate:
|
||||
#define NS_IBYTEBUFFEROUTPUTSTREAM_IID \
|
||||
{ /* 924df6d0-f192-11d2-9322-000000000000 */ \
|
||||
0x924df6d0, \
|
||||
0xf192, \
|
||||
0x11d2, \
|
||||
{0x93, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} \
|
||||
}
|
||||
|
||||
class nsIByteBufferOutputStream : public nsIOutputStream {
|
||||
public:
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IBYTEBUFFEROUTPUTSTREAM_IID);
|
||||
|
||||
NS_IMETHOD Write(nsIInputStream* fromStream, PRUint32 *aWriteCount) = 0;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern NS_BASE nsresult
|
||||
NS_NewByteBufferInputStream(PRUint32 size, nsIByteBufferInputStream* *result);
|
||||
NS_NewByteBufferInputStream(nsIByteBufferInputStream* *result,
|
||||
PRBool blocking = PR_FALSE,
|
||||
PRUint32 size = 4096);
|
||||
|
||||
extern NS_BASE nsresult
|
||||
NS_NewPipe(nsIInputStream* *inStrResult,
|
||||
nsIOutputStream* *outStrResult,
|
||||
PRBool blocking = PR_TRUE,
|
||||
PRUint32 bufferSize = 4096);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif /* nsByteBufferInputStream_h___ */
|
||||
|
||||
@ -18,6 +18,35 @@
|
||||
|
||||
#include "nsIByteBufferInputStream.h"
|
||||
#include "nsCRT.h"
|
||||
#include "prcmon.h"
|
||||
|
||||
class nsByteBufferInputStream;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsByteBufferOutputStream : public nsIByteBufferOutputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIBaseStream methods:
|
||||
NS_IMETHOD Close(void);
|
||||
|
||||
// nsIOutputStream methods:
|
||||
NS_IMETHOD Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount);
|
||||
|
||||
// nsIByteBufferOutputStream methods:
|
||||
NS_IMETHOD Write(nsIInputStream* fromStream, PRUint32 *aWriteCount);
|
||||
|
||||
// nsByteBufferOutputStream methods:
|
||||
nsByteBufferOutputStream(nsByteBufferInputStream* in);
|
||||
virtual ~nsByteBufferOutputStream();
|
||||
|
||||
protected:
|
||||
nsByteBufferInputStream* mInputStream;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsByteBufferInputStream : public nsIByteBufferInputStream
|
||||
{
|
||||
@ -32,13 +61,37 @@ public:
|
||||
NS_IMETHOD Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount);
|
||||
|
||||
// nsIByteBufferInputStream methods:
|
||||
NS_IMETHOD Fill(nsIInputStream* stream, PRUint32 *filledAmount);
|
||||
|
||||
NS_IMETHOD Fill(nsIInputStream* stream, PRUint32 *aWriteCount);
|
||||
NS_IMETHOD Fill(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount);
|
||||
|
||||
// nsByteBufferInputStream methods:
|
||||
nsByteBufferInputStream();
|
||||
nsByteBufferInputStream(PRBool blocking, PRUint32 size);
|
||||
virtual ~nsByteBufferInputStream();
|
||||
|
||||
nsresult Init(PRUint32 size);
|
||||
friend class nsByteBufferOutputStream;
|
||||
|
||||
nsresult Init(void);
|
||||
void SetEOF(void);
|
||||
|
||||
PRBool AtEOF() { return mEOF && (mReadCursor == mWriteCursor) && !mFull; }
|
||||
|
||||
PRUint32 ReadableAmount() {
|
||||
if (mReadCursor < mWriteCursor)
|
||||
return mWriteCursor - mReadCursor;
|
||||
else if (mReadCursor == mWriteCursor && !mFull)
|
||||
return 0;
|
||||
else
|
||||
return (mLength - mReadCursor) + mWriteCursor;
|
||||
}
|
||||
|
||||
PRUint32 WritableAmount() {
|
||||
if (mWriteCursor < mReadCursor)
|
||||
return mWriteCursor - mReadCursor;
|
||||
else if (mReadCursor == mWriteCursor && mFull)
|
||||
return 0;
|
||||
else
|
||||
return (mLength - mWriteCursor) + mReadCursor;
|
||||
}
|
||||
|
||||
void ReadChunk(char* toBuf, PRUint32 max,
|
||||
PRUint32 end, PRUint32 *totalRef)
|
||||
@ -48,15 +101,19 @@ public:
|
||||
PRInt32 amt = PR_MIN(max, diff);
|
||||
if (amt > 0) {
|
||||
nsCRT::memcpy(toBuf, &mBuffer[mReadCursor], amt);
|
||||
#ifdef NS_DEBUG
|
||||
nsCRT::memset(&mBuffer[mReadCursor], 0xDD, amt);
|
||||
#endif
|
||||
mReadCursor += amt;
|
||||
*totalRef += amt;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult WriteChunk(nsIInputStream* in, PRUint32 end, PRUint32 *totalRef)
|
||||
nsresult WriteChunk(nsIInputStream* in,
|
||||
PRUint32 end, PRUint32 *totalRef)
|
||||
{
|
||||
NS_ASSERTION(mWriteCursor <= end, "bad range");
|
||||
PRInt32 amt = end - mWriteCursor;
|
||||
PRUint32 amt = end - mWriteCursor;
|
||||
if (amt > 0) {
|
||||
PRUint32 readAmt;
|
||||
nsresult rv = in->Read(&mBuffer[mWriteCursor], amt, &readAmt);
|
||||
@ -68,34 +125,100 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
char* mBuffer;
|
||||
PRUint32 mLength;
|
||||
PRUint32 mReadCursor;
|
||||
PRUint32 mWriteCursor;
|
||||
PRBool mFull;
|
||||
char* mBuffer;
|
||||
PRUint32 mLength;
|
||||
PRUint32 mReadCursor;
|
||||
PRUint32 mWriteCursor;
|
||||
PRBool mFull;
|
||||
PRBool mClosed;
|
||||
PRBool mEOF;
|
||||
PRBool mBlocking;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsByteBufferInputStream::nsByteBufferInputStream()
|
||||
: mBuffer(nsnull), mLength(0), mReadCursor(0), mWriteCursor(0), mFull(PR_FALSE)
|
||||
class nsDummyBufferStream : public nsIInputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIBaseStream methods:
|
||||
NS_IMETHOD Close(void) {
|
||||
NS_NOTREACHED("nsDummyBufferStream::Close");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// nsIInputStream methods:
|
||||
NS_IMETHOD GetLength(PRUint32 *aLength) {
|
||||
*aLength = mLength;
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount) {
|
||||
PRUint32 amt = PR_MIN(aCount, mLength);
|
||||
if (amt > 0) {
|
||||
nsCRT::memcpy(aBuf, mBuffer, amt);
|
||||
mBuffer += amt;
|
||||
mLength -= amt;
|
||||
}
|
||||
*aReadCount = amt;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsDummyBufferStream methods:
|
||||
nsDummyBufferStream(const char* buffer, PRUint32 length)
|
||||
: mBuffer(buffer), mLength(length) {}
|
||||
~nsDummyBufferStream() {}
|
||||
|
||||
protected:
|
||||
const char* mBuffer;
|
||||
PRUint32 mLength;
|
||||
};
|
||||
|
||||
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(PRUint32 size)
|
||||
nsByteBufferInputStream::Init(void)
|
||||
{
|
||||
mBuffer = new char[size];
|
||||
mBuffer = new char[mLength];
|
||||
if (mBuffer == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
mLength = size;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsByteBufferInputStream::~nsByteBufferInputStream()
|
||||
{
|
||||
Close();
|
||||
(void)Close();
|
||||
if (mBuffer) delete mBuffer;
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(nsByteBufferInputStream);
|
||||
@ -108,7 +231,8 @@ nsByteBufferInputStream::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
if (aIID.Equals(nsIByteBufferInputStream::GetIID()) ||
|
||||
aIID.Equals(nsIInputStream::GetIID()) ||
|
||||
aIID.Equals(nsIBaseStream::GetIID())) {
|
||||
aIID.Equals(nsIBaseStream::GetIID()) ||
|
||||
aIID.Equals(nsISupports::GetIID())) {
|
||||
*aInstancePtr = this;
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
@ -119,105 +243,288 @@ nsByteBufferInputStream::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
||||
NS_IMETHODIMP
|
||||
nsByteBufferInputStream::Close(void)
|
||||
{
|
||||
if (mBuffer == nsnull)
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
|
||||
delete mBuffer;
|
||||
mBuffer = nsnull;
|
||||
mLength = 0;
|
||||
mReadCursor = 0;
|
||||
mWriteCursor = 0;
|
||||
if (mBlocking)
|
||||
PR_CEnterMonitor(this);
|
||||
mClosed = PR_TRUE;
|
||||
if (mBlocking) {
|
||||
PR_CNotify(this); // wake up the writer
|
||||
PR_CExitMonitor(this);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsByteBufferInputStream::GetLength(PRUint32 *aLength)
|
||||
{
|
||||
if (mBuffer == nsnull)
|
||||
if (mClosed)
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
|
||||
if (mReadCursor < mWriteCursor)
|
||||
*aLength = mWriteCursor - mReadCursor;
|
||||
else
|
||||
*aLength = (mLength - mReadCursor) + mWriteCursor;
|
||||
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)
|
||||
{
|
||||
if (mBuffer == nsnull)
|
||||
nsresult rv = NS_OK;
|
||||
if (mClosed)
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
|
||||
// wrap-around buffer:
|
||||
if (mReadCursor == mWriteCursor && !mFull) {
|
||||
if (AtEOF())
|
||||
return NS_BASE_STREAM_EOF;
|
||||
}
|
||||
|
||||
if (mBlocking)
|
||||
PR_CEnterMonitor(this);
|
||||
*aReadCount = 0;
|
||||
if (mReadCursor >= mWriteCursor || mFull) {
|
||||
|
||||
/*while (aCount > 0)*/ { // XXX should this block trying to fill the buffer, or return ASAP?
|
||||
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;
|
||||
ReadChunk(aBuf, aCount, mLength, &amt);
|
||||
*aReadCount += amt;
|
||||
if (mReadCursor == mLength) {
|
||||
mReadCursor = 0;
|
||||
if (mReadCursor >= mWriteCursor || mFull) {
|
||||
ReadChunk(aBuf, aCount, mLength, &amt);
|
||||
*aReadCount += amt;
|
||||
aBuf += amt;
|
||||
aCount -= amt;
|
||||
ReadChunk(aBuf, aCount, mWriteCursor, aReadCount);
|
||||
if (mReadCursor == mWriteCursor)
|
||||
mFull = PR_FALSE;
|
||||
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)
|
||||
PR_CNotify(this); // tell the writer there's space
|
||||
}
|
||||
else {
|
||||
ReadChunk(aBuf, aCount, mWriteCursor, aReadCount);
|
||||
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, aWriteCount);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsByteBufferInputStream::Fill(nsIInputStream* stream, PRUint32 *aWriteCount)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (mClosed || mEOF)
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
|
||||
*aWriteCount = 0;
|
||||
PRUint32 aCount;
|
||||
rv = stream->GetLength(&aCount);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
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)
|
||||
PR_CNotify(this); // tell the reader there's more
|
||||
}
|
||||
done:
|
||||
if (mBlocking)
|
||||
PR_CExitMonitor(this);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
nsByteBufferInputStream::SetEOF()
|
||||
{
|
||||
if (mBlocking)
|
||||
PR_CEnterMonitor(this);
|
||||
mEOF = PR_TRUE;
|
||||
if (mBlocking) {
|
||||
PR_CNotify(this); // wake up the reader
|
||||
PR_CExitMonitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsByteBufferOutputStream methods:
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsByteBufferOutputStream::nsByteBufferOutputStream(nsByteBufferInputStream* in)
|
||||
: mInputStream(in)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
NS_ADDREF(mInputStream);
|
||||
}
|
||||
|
||||
nsByteBufferOutputStream::~nsByteBufferOutputStream()
|
||||
{
|
||||
(void)Close();
|
||||
NS_IF_RELEASE(mInputStream);
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(nsByteBufferOutputStream);
|
||||
NS_IMPL_RELEASE(nsByteBufferOutputStream);
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsByteBufferOutputStream::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
||||
{
|
||||
if (aInstancePtr == nsnull)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
if (aIID.Equals(nsIByteBufferOutputStream::GetIID()) ||
|
||||
aIID.Equals(nsIOutputStream::GetIID()) ||
|
||||
aIID.Equals(nsIBaseStream::GetIID()) ||
|
||||
aIID.Equals(nsISupports::GetIID())) {
|
||||
*aInstancePtr = this;
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsByteBufferOutputStream::Close(void)
|
||||
{
|
||||
mInputStream->SetEOF();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsByteBufferInputStream::Fill(nsIInputStream* stream, PRUint32 *filledAmount)
|
||||
nsByteBufferOutputStream::Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount)
|
||||
{
|
||||
if (mBuffer == nsnull)
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
return mInputStream->Fill(aBuf, aCount, aWriteCount);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsByteBufferOutputStream::Write(nsIInputStream* fromStream, PRUint32 *aWriteCount)
|
||||
{
|
||||
return mInputStream->Fill(fromStream, aWriteCount);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_BASE nsresult
|
||||
NS_NewByteBufferInputStream(nsIByteBufferInputStream* *result,
|
||||
PRBool blocking, PRUint32 size)
|
||||
{
|
||||
nsresult rv;
|
||||
nsByteBufferInputStream* inStr = nsnull;
|
||||
|
||||
// wrap-around buffer:
|
||||
*filledAmount = 0;
|
||||
if (mReadCursor <= mWriteCursor && !mFull) {
|
||||
rv = WriteChunk(stream, mLength, filledAmount);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (mWriteCursor == mLength) {
|
||||
mWriteCursor = 0;
|
||||
rv = WriteChunk(stream, mReadCursor, filledAmount);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (mWriteCursor == mReadCursor)
|
||||
mFull = PR_TRUE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
rv = WriteChunk(stream, mReadCursor, filledAmount);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
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_BASE nsresult
|
||||
NS_NewByteBufferInputStream(PRUint32 size, nsIByteBufferInputStream* *result)
|
||||
NS_NewPipe(nsIInputStream* *inStrResult,
|
||||
nsIOutputStream* *outStrResult,
|
||||
PRBool blocking, PRUint32 size)
|
||||
{
|
||||
nsByteBufferInputStream* str =
|
||||
new nsByteBufferInputStream();
|
||||
if (str == nsnull)
|
||||
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;
|
||||
nsresult rv = str->Init(size);
|
||||
if (NS_FAILED(rv)) {
|
||||
delete str;
|
||||
return rv;
|
||||
}
|
||||
NS_ADDREF(str);
|
||||
*result = str;
|
||||
NS_ADDREF(outStr);
|
||||
|
||||
*inStrResult = inStr;
|
||||
*outStrResult = outStr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -52,6 +52,8 @@ public:
|
||||
#define NS_BASE_STREAM_NO_CONVERTER NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 5)
|
||||
/// For unichar streams
|
||||
#define NS_BASE_STREAM_BAD_CONVERSION NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 6)
|
||||
|
||||
#define NS_BASE_STREAM_WOULD_BLOCK NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_BASE, 7)
|
||||
//@}
|
||||
|
||||
|
||||
|
||||
100
mozilla/base/tests/TestPipes.cpp
Normal file
100
mozilla/base/tests/TestPipes.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
/* -*- 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 "nsIThread.h"
|
||||
#include "nsIByteBufferInputStream.h"
|
||||
#include "prprf.h"
|
||||
#include "plstr.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define KEY 0xa7
|
||||
#define ITERATIONS 333
|
||||
char kTestPattern[] = "My hovercraft is full of eels.\n";
|
||||
|
||||
class nsReceiver : public nsIRunnable {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
nsresult rv;
|
||||
char buf[101];
|
||||
PRUint32 count;
|
||||
while (PR_TRUE) {
|
||||
rv = mIn->Read(buf, 100, &count);
|
||||
if (rv == NS_BASE_STREAM_EOF) {
|
||||
printf("EOF count = %d\n", mCount);
|
||||
return NS_OK;
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
printf("read failed\n");
|
||||
return rv;
|
||||
}
|
||||
|
||||
buf[count] = '\0';
|
||||
printf(buf);
|
||||
|
||||
mCount += count;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsReceiver(nsIInputStream* in) : mIn(in), mCount(0) {
|
||||
NS_INIT_REFCNT();
|
||||
NS_ADDREF(in);
|
||||
}
|
||||
|
||||
virtual ~nsReceiver() {
|
||||
NS_RELEASE(mIn);
|
||||
}
|
||||
|
||||
protected:
|
||||
nsIInputStream* mIn;
|
||||
PRUint32 mCount;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsReceiver, nsIRunnable::GetIID());
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
nsresult rv;
|
||||
nsIInputStream* in;
|
||||
nsIOutputStream* out;
|
||||
|
||||
rv = NS_NewPipe(&in, &out, PR_TRUE, 40);
|
||||
if (NS_FAILED(rv)) return -1;
|
||||
|
||||
nsIThread* receiver;
|
||||
rv = NS_NewThread(&receiver, new nsReceiver(in));
|
||||
NS_RELEASE(in);
|
||||
|
||||
for (PRUint32 i = 0; i < ITERATIONS; i++) {
|
||||
PRUint32 writeCount;
|
||||
char* buf = PR_smprintf("%d %s", i, kTestPattern);
|
||||
rv = out->Write(buf, PL_strlen(buf), &writeCount);
|
||||
PR_smprintf_free(buf);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "write failed");
|
||||
}
|
||||
rv = out->Close();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "close failed");
|
||||
|
||||
receiver->Join();
|
||||
NS_RELEASE(receiver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -27,6 +27,7 @@ PROG5 = .\$(OBJDIR)\PropertiesTest.exe
|
||||
PROG6 = .\$(OBJDIR)\TestAutoLock.exe
|
||||
PROG7 = .\$(OBJDIR)\TestThreads.exe
|
||||
PROG8 = .\$(OBJDIR)\TestObserverService.exe
|
||||
PROG9 = .\$(OBJDIR)\TestPipes.exe
|
||||
RESFILE = timer.res
|
||||
PROGRAMS = $(PROG0) $(PROG1) \
|
||||
!ifdef MODULAR_NETLIB
|
||||
@ -37,7 +38,8 @@ PROGRAMS = $(PROG0) $(PROG1) \
|
||||
$(PROG4) \
|
||||
$(PROG6) \
|
||||
$(PROG7) \
|
||||
$(PROG8) \
|
||||
$(PROG8) \
|
||||
$(PROG9) \
|
||||
$(NULL)
|
||||
|
||||
LINCS=-I..\src -I$(PUBLIC)\xpcom -I$(PUBLIC)\netlib -I$(PUBLIC)\raptor
|
||||
@ -69,7 +71,8 @@ install:: $(PROGRAMS)
|
||||
$(MAKE_INSTALL) $(PROG4) $(DIST)\bin
|
||||
$(MAKE_INSTALL) $(PROG6) $(DIST)\bin
|
||||
$(MAKE_INSTALL) $(PROG7) $(DIST)\bin
|
||||
$(MAKE_INSTALL) $(PROG8) $(DIST)\bin
|
||||
$(MAKE_INSTALL) $(PROG8) $(DIST)\bin
|
||||
$(MAKE_INSTALL) $(PROG9) $(DIST)\bin
|
||||
|
||||
clobber::
|
||||
rm -f $(DIST)\bin\TimerTest.exe
|
||||
@ -120,5 +123,4 @@ $(PROG7): $(OBJDIR) TestThreads.cpp
|
||||
|
||||
$(PROG8): $(OBJDIR) TestObserverService.cpp
|
||||
|
||||
|
||||
|
||||
$(PROG9): $(OBJDIR) TestPipes.cpp
|
||||
|
||||
@ -18,6 +18,35 @@
|
||||
|
||||
#include "nsIByteBufferInputStream.h"
|
||||
#include "nsCRT.h"
|
||||
#include "prcmon.h"
|
||||
|
||||
class nsByteBufferInputStream;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsByteBufferOutputStream : public nsIByteBufferOutputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIBaseStream methods:
|
||||
NS_IMETHOD Close(void);
|
||||
|
||||
// nsIOutputStream methods:
|
||||
NS_IMETHOD Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount);
|
||||
|
||||
// nsIByteBufferOutputStream methods:
|
||||
NS_IMETHOD Write(nsIInputStream* fromStream, PRUint32 *aWriteCount);
|
||||
|
||||
// nsByteBufferOutputStream methods:
|
||||
nsByteBufferOutputStream(nsByteBufferInputStream* in);
|
||||
virtual ~nsByteBufferOutputStream();
|
||||
|
||||
protected:
|
||||
nsByteBufferInputStream* mInputStream;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsByteBufferInputStream : public nsIByteBufferInputStream
|
||||
{
|
||||
@ -32,13 +61,37 @@ public:
|
||||
NS_IMETHOD Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount);
|
||||
|
||||
// nsIByteBufferInputStream methods:
|
||||
NS_IMETHOD Fill(nsIInputStream* stream, PRUint32 *filledAmount);
|
||||
|
||||
NS_IMETHOD Fill(nsIInputStream* stream, PRUint32 *aWriteCount);
|
||||
NS_IMETHOD Fill(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount);
|
||||
|
||||
// nsByteBufferInputStream methods:
|
||||
nsByteBufferInputStream();
|
||||
nsByteBufferInputStream(PRBool blocking, PRUint32 size);
|
||||
virtual ~nsByteBufferInputStream();
|
||||
|
||||
nsresult Init(PRUint32 size);
|
||||
friend class nsByteBufferOutputStream;
|
||||
|
||||
nsresult Init(void);
|
||||
void SetEOF(void);
|
||||
|
||||
PRBool AtEOF() { return mEOF && (mReadCursor == mWriteCursor) && !mFull; }
|
||||
|
||||
PRUint32 ReadableAmount() {
|
||||
if (mReadCursor < mWriteCursor)
|
||||
return mWriteCursor - mReadCursor;
|
||||
else if (mReadCursor == mWriteCursor && !mFull)
|
||||
return 0;
|
||||
else
|
||||
return (mLength - mReadCursor) + mWriteCursor;
|
||||
}
|
||||
|
||||
PRUint32 WritableAmount() {
|
||||
if (mWriteCursor < mReadCursor)
|
||||
return mWriteCursor - mReadCursor;
|
||||
else if (mReadCursor == mWriteCursor && mFull)
|
||||
return 0;
|
||||
else
|
||||
return (mLength - mWriteCursor) + mReadCursor;
|
||||
}
|
||||
|
||||
void ReadChunk(char* toBuf, PRUint32 max,
|
||||
PRUint32 end, PRUint32 *totalRef)
|
||||
@ -48,15 +101,19 @@ public:
|
||||
PRInt32 amt = PR_MIN(max, diff);
|
||||
if (amt > 0) {
|
||||
nsCRT::memcpy(toBuf, &mBuffer[mReadCursor], amt);
|
||||
#ifdef NS_DEBUG
|
||||
nsCRT::memset(&mBuffer[mReadCursor], 0xDD, amt);
|
||||
#endif
|
||||
mReadCursor += amt;
|
||||
*totalRef += amt;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult WriteChunk(nsIInputStream* in, PRUint32 end, PRUint32 *totalRef)
|
||||
nsresult WriteChunk(nsIInputStream* in,
|
||||
PRUint32 end, PRUint32 *totalRef)
|
||||
{
|
||||
NS_ASSERTION(mWriteCursor <= end, "bad range");
|
||||
PRInt32 amt = end - mWriteCursor;
|
||||
PRUint32 amt = end - mWriteCursor;
|
||||
if (amt > 0) {
|
||||
PRUint32 readAmt;
|
||||
nsresult rv = in->Read(&mBuffer[mWriteCursor], amt, &readAmt);
|
||||
@ -68,34 +125,100 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
char* mBuffer;
|
||||
PRUint32 mLength;
|
||||
PRUint32 mReadCursor;
|
||||
PRUint32 mWriteCursor;
|
||||
PRBool mFull;
|
||||
char* mBuffer;
|
||||
PRUint32 mLength;
|
||||
PRUint32 mReadCursor;
|
||||
PRUint32 mWriteCursor;
|
||||
PRBool mFull;
|
||||
PRBool mClosed;
|
||||
PRBool mEOF;
|
||||
PRBool mBlocking;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsByteBufferInputStream::nsByteBufferInputStream()
|
||||
: mBuffer(nsnull), mLength(0), mReadCursor(0), mWriteCursor(0), mFull(PR_FALSE)
|
||||
class nsDummyBufferStream : public nsIInputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIBaseStream methods:
|
||||
NS_IMETHOD Close(void) {
|
||||
NS_NOTREACHED("nsDummyBufferStream::Close");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// nsIInputStream methods:
|
||||
NS_IMETHOD GetLength(PRUint32 *aLength) {
|
||||
*aLength = mLength;
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount) {
|
||||
PRUint32 amt = PR_MIN(aCount, mLength);
|
||||
if (amt > 0) {
|
||||
nsCRT::memcpy(aBuf, mBuffer, amt);
|
||||
mBuffer += amt;
|
||||
mLength -= amt;
|
||||
}
|
||||
*aReadCount = amt;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsDummyBufferStream methods:
|
||||
nsDummyBufferStream(const char* buffer, PRUint32 length)
|
||||
: mBuffer(buffer), mLength(length) {}
|
||||
~nsDummyBufferStream() {}
|
||||
|
||||
protected:
|
||||
const char* mBuffer;
|
||||
PRUint32 mLength;
|
||||
};
|
||||
|
||||
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(PRUint32 size)
|
||||
nsByteBufferInputStream::Init(void)
|
||||
{
|
||||
mBuffer = new char[size];
|
||||
mBuffer = new char[mLength];
|
||||
if (mBuffer == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
mLength = size;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsByteBufferInputStream::~nsByteBufferInputStream()
|
||||
{
|
||||
Close();
|
||||
(void)Close();
|
||||
if (mBuffer) delete mBuffer;
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(nsByteBufferInputStream);
|
||||
@ -108,7 +231,8 @@ nsByteBufferInputStream::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
if (aIID.Equals(nsIByteBufferInputStream::GetIID()) ||
|
||||
aIID.Equals(nsIInputStream::GetIID()) ||
|
||||
aIID.Equals(nsIBaseStream::GetIID())) {
|
||||
aIID.Equals(nsIBaseStream::GetIID()) ||
|
||||
aIID.Equals(nsISupports::GetIID())) {
|
||||
*aInstancePtr = this;
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
@ -119,105 +243,288 @@ nsByteBufferInputStream::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
||||
NS_IMETHODIMP
|
||||
nsByteBufferInputStream::Close(void)
|
||||
{
|
||||
if (mBuffer == nsnull)
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
|
||||
delete mBuffer;
|
||||
mBuffer = nsnull;
|
||||
mLength = 0;
|
||||
mReadCursor = 0;
|
||||
mWriteCursor = 0;
|
||||
if (mBlocking)
|
||||
PR_CEnterMonitor(this);
|
||||
mClosed = PR_TRUE;
|
||||
if (mBlocking) {
|
||||
PR_CNotify(this); // wake up the writer
|
||||
PR_CExitMonitor(this);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsByteBufferInputStream::GetLength(PRUint32 *aLength)
|
||||
{
|
||||
if (mBuffer == nsnull)
|
||||
if (mClosed)
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
|
||||
if (mReadCursor < mWriteCursor)
|
||||
*aLength = mWriteCursor - mReadCursor;
|
||||
else
|
||||
*aLength = (mLength - mReadCursor) + mWriteCursor;
|
||||
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)
|
||||
{
|
||||
if (mBuffer == nsnull)
|
||||
nsresult rv = NS_OK;
|
||||
if (mClosed)
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
|
||||
// wrap-around buffer:
|
||||
if (mReadCursor == mWriteCursor && !mFull) {
|
||||
if (AtEOF())
|
||||
return NS_BASE_STREAM_EOF;
|
||||
}
|
||||
|
||||
if (mBlocking)
|
||||
PR_CEnterMonitor(this);
|
||||
*aReadCount = 0;
|
||||
if (mReadCursor >= mWriteCursor || mFull) {
|
||||
|
||||
/*while (aCount > 0)*/ { // XXX should this block trying to fill the buffer, or return ASAP?
|
||||
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;
|
||||
ReadChunk(aBuf, aCount, mLength, &amt);
|
||||
*aReadCount += amt;
|
||||
if (mReadCursor == mLength) {
|
||||
mReadCursor = 0;
|
||||
if (mReadCursor >= mWriteCursor || mFull) {
|
||||
ReadChunk(aBuf, aCount, mLength, &amt);
|
||||
*aReadCount += amt;
|
||||
aBuf += amt;
|
||||
aCount -= amt;
|
||||
ReadChunk(aBuf, aCount, mWriteCursor, aReadCount);
|
||||
if (mReadCursor == mWriteCursor)
|
||||
mFull = PR_FALSE;
|
||||
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)
|
||||
PR_CNotify(this); // tell the writer there's space
|
||||
}
|
||||
else {
|
||||
ReadChunk(aBuf, aCount, mWriteCursor, aReadCount);
|
||||
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, aWriteCount);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsByteBufferInputStream::Fill(nsIInputStream* stream, PRUint32 *aWriteCount)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (mClosed || mEOF)
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
|
||||
*aWriteCount = 0;
|
||||
PRUint32 aCount;
|
||||
rv = stream->GetLength(&aCount);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
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)
|
||||
PR_CNotify(this); // tell the reader there's more
|
||||
}
|
||||
done:
|
||||
if (mBlocking)
|
||||
PR_CExitMonitor(this);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
nsByteBufferInputStream::SetEOF()
|
||||
{
|
||||
if (mBlocking)
|
||||
PR_CEnterMonitor(this);
|
||||
mEOF = PR_TRUE;
|
||||
if (mBlocking) {
|
||||
PR_CNotify(this); // wake up the reader
|
||||
PR_CExitMonitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsByteBufferOutputStream methods:
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsByteBufferOutputStream::nsByteBufferOutputStream(nsByteBufferInputStream* in)
|
||||
: mInputStream(in)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
NS_ADDREF(mInputStream);
|
||||
}
|
||||
|
||||
nsByteBufferOutputStream::~nsByteBufferOutputStream()
|
||||
{
|
||||
(void)Close();
|
||||
NS_IF_RELEASE(mInputStream);
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(nsByteBufferOutputStream);
|
||||
NS_IMPL_RELEASE(nsByteBufferOutputStream);
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsByteBufferOutputStream::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
||||
{
|
||||
if (aInstancePtr == nsnull)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
if (aIID.Equals(nsIByteBufferOutputStream::GetIID()) ||
|
||||
aIID.Equals(nsIOutputStream::GetIID()) ||
|
||||
aIID.Equals(nsIBaseStream::GetIID()) ||
|
||||
aIID.Equals(nsISupports::GetIID())) {
|
||||
*aInstancePtr = this;
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsByteBufferOutputStream::Close(void)
|
||||
{
|
||||
mInputStream->SetEOF();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsByteBufferInputStream::Fill(nsIInputStream* stream, PRUint32 *filledAmount)
|
||||
nsByteBufferOutputStream::Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount)
|
||||
{
|
||||
if (mBuffer == nsnull)
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
return mInputStream->Fill(aBuf, aCount, aWriteCount);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsByteBufferOutputStream::Write(nsIInputStream* fromStream, PRUint32 *aWriteCount)
|
||||
{
|
||||
return mInputStream->Fill(fromStream, aWriteCount);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_BASE nsresult
|
||||
NS_NewByteBufferInputStream(nsIByteBufferInputStream* *result,
|
||||
PRBool blocking, PRUint32 size)
|
||||
{
|
||||
nsresult rv;
|
||||
nsByteBufferInputStream* inStr = nsnull;
|
||||
|
||||
// wrap-around buffer:
|
||||
*filledAmount = 0;
|
||||
if (mReadCursor <= mWriteCursor && !mFull) {
|
||||
rv = WriteChunk(stream, mLength, filledAmount);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (mWriteCursor == mLength) {
|
||||
mWriteCursor = 0;
|
||||
rv = WriteChunk(stream, mReadCursor, filledAmount);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (mWriteCursor == mReadCursor)
|
||||
mFull = PR_TRUE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
rv = WriteChunk(stream, mReadCursor, filledAmount);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
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_BASE nsresult
|
||||
NS_NewByteBufferInputStream(PRUint32 size, nsIByteBufferInputStream* *result)
|
||||
NS_NewPipe(nsIInputStream* *inStrResult,
|
||||
nsIOutputStream* *outStrResult,
|
||||
PRBool blocking, PRUint32 size)
|
||||
{
|
||||
nsByteBufferInputStream* str =
|
||||
new nsByteBufferInputStream();
|
||||
if (str == nsnull)
|
||||
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;
|
||||
nsresult rv = str->Init(size);
|
||||
if (NS_FAILED(rv)) {
|
||||
delete str;
|
||||
return rv;
|
||||
}
|
||||
NS_ADDREF(str);
|
||||
*result = str;
|
||||
NS_ADDREF(outStr);
|
||||
|
||||
*inStrResult = inStr;
|
||||
*outStrResult = outStr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -52,6 +52,8 @@ public:
|
||||
#define NS_BASE_STREAM_NO_CONVERTER NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 5)
|
||||
/// For unichar streams
|
||||
#define NS_BASE_STREAM_BAD_CONVERSION NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 6)
|
||||
|
||||
#define NS_BASE_STREAM_WOULD_BLOCK NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_BASE, 7)
|
||||
//@}
|
||||
|
||||
|
||||
|
||||
@ -15,10 +15,12 @@
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef nsIByteBufferInputStream_h___
|
||||
#define nsIByteBufferInputStream_h___
|
||||
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
|
||||
#define NS_IBYTEBUFFERINPUTSTREAM_IID \
|
||||
{ /* 40767100-eb9c-11d2-931c-00104ba0fd40 */ \
|
||||
@ -30,14 +32,46 @@
|
||||
|
||||
class nsIByteBufferInputStream : public nsIInputStream {
|
||||
public:
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IBYTEBUFFERINPUTSTREAM_IID);
|
||||
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_IBYTEBUFFERINPUTSTREAM_IID; return iid; }
|
||||
NS_IMETHOD Fill(nsIInputStream* stream, PRUint32 *aWriteCount) = 0;
|
||||
|
||||
NS_IMETHOD Fill(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount) = 0;
|
||||
|
||||
NS_IMETHOD Fill(nsIInputStream* stream, PRUint32 *filledAmount) = 0;
|
||||
};
|
||||
|
||||
// Makes an byte buffer input stream:
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// XXX regenerate:
|
||||
#define NS_IBYTEBUFFEROUTPUTSTREAM_IID \
|
||||
{ /* 924df6d0-f192-11d2-9322-000000000000 */ \
|
||||
0x924df6d0, \
|
||||
0xf192, \
|
||||
0x11d2, \
|
||||
{0x93, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} \
|
||||
}
|
||||
|
||||
class nsIByteBufferOutputStream : public nsIOutputStream {
|
||||
public:
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IBYTEBUFFEROUTPUTSTREAM_IID);
|
||||
|
||||
NS_IMETHOD Write(nsIInputStream* fromStream, PRUint32 *aWriteCount) = 0;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern NS_BASE nsresult
|
||||
NS_NewByteBufferInputStream(PRUint32 size, nsIByteBufferInputStream* *result);
|
||||
NS_NewByteBufferInputStream(nsIByteBufferInputStream* *result,
|
||||
PRBool blocking = PR_FALSE,
|
||||
PRUint32 size = 4096);
|
||||
|
||||
extern NS_BASE nsresult
|
||||
NS_NewPipe(nsIInputStream* *inStrResult,
|
||||
nsIOutputStream* *outStrResult,
|
||||
PRBool blocking = PR_TRUE,
|
||||
PRUint32 bufferSize = 4096);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif /* nsByteBufferInputStream_h___ */
|
||||
|
||||
100
mozilla/xpcom/tests/TestPipes.cpp
Normal file
100
mozilla/xpcom/tests/TestPipes.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
/* -*- 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 "nsIThread.h"
|
||||
#include "nsIByteBufferInputStream.h"
|
||||
#include "prprf.h"
|
||||
#include "plstr.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define KEY 0xa7
|
||||
#define ITERATIONS 333
|
||||
char kTestPattern[] = "My hovercraft is full of eels.\n";
|
||||
|
||||
class nsReceiver : public nsIRunnable {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
nsresult rv;
|
||||
char buf[101];
|
||||
PRUint32 count;
|
||||
while (PR_TRUE) {
|
||||
rv = mIn->Read(buf, 100, &count);
|
||||
if (rv == NS_BASE_STREAM_EOF) {
|
||||
printf("EOF count = %d\n", mCount);
|
||||
return NS_OK;
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
printf("read failed\n");
|
||||
return rv;
|
||||
}
|
||||
|
||||
buf[count] = '\0';
|
||||
printf(buf);
|
||||
|
||||
mCount += count;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsReceiver(nsIInputStream* in) : mIn(in), mCount(0) {
|
||||
NS_INIT_REFCNT();
|
||||
NS_ADDREF(in);
|
||||
}
|
||||
|
||||
virtual ~nsReceiver() {
|
||||
NS_RELEASE(mIn);
|
||||
}
|
||||
|
||||
protected:
|
||||
nsIInputStream* mIn;
|
||||
PRUint32 mCount;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsReceiver, nsIRunnable::GetIID());
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
nsresult rv;
|
||||
nsIInputStream* in;
|
||||
nsIOutputStream* out;
|
||||
|
||||
rv = NS_NewPipe(&in, &out, PR_TRUE, 40);
|
||||
if (NS_FAILED(rv)) return -1;
|
||||
|
||||
nsIThread* receiver;
|
||||
rv = NS_NewThread(&receiver, new nsReceiver(in));
|
||||
NS_RELEASE(in);
|
||||
|
||||
for (PRUint32 i = 0; i < ITERATIONS; i++) {
|
||||
PRUint32 writeCount;
|
||||
char* buf = PR_smprintf("%d %s", i, kTestPattern);
|
||||
rv = out->Write(buf, PL_strlen(buf), &writeCount);
|
||||
PR_smprintf_free(buf);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "write failed");
|
||||
}
|
||||
rv = out->Close();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "close failed");
|
||||
|
||||
receiver->Join();
|
||||
NS_RELEASE(receiver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user