зеркало из https://github.com/mozilla/gecko-dev.git
425 строки
11 KiB
C++
425 строки
11 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 "nsIBuffer.h"
|
|
#include "nsIInputStream.h"
|
|
#include "nsIOutputStream.h"
|
|
#include "nsAutoLock.h"
|
|
|
|
class nsBufferInputStream;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class nsBufferInputStream : public nsIInputStream
|
|
{
|
|
public:
|
|
NS_DECL_ISUPPORTS
|
|
|
|
// nsIBaseStream methods:
|
|
NS_IMETHOD Close(void);
|
|
|
|
// nsIInputStream methods:
|
|
NS_IMETHOD GetLength(PRUint32 *aLength);
|
|
NS_IMETHOD Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount);
|
|
|
|
// nsBufferInputStream methods:
|
|
nsBufferInputStream(nsIBuffer* buf, PRBool blocking);
|
|
virtual ~nsBufferInputStream();
|
|
|
|
PRUint32 ReadableAmount() {
|
|
nsresult rv;
|
|
PRUint32 amt;
|
|
char* buf;
|
|
rv = mBuffer->GetReadBuffer(&amt, &buf); // should never fail
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "GetInputBuffer failed");
|
|
return amt;
|
|
}
|
|
|
|
nsresult SetEOF();
|
|
nsresult Fill();
|
|
|
|
protected:
|
|
nsIBuffer* mBuffer;
|
|
PRBool mBlocking;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class nsBufferOutputStream : public nsIOutputStream
|
|
{
|
|
public:
|
|
NS_DECL_ISUPPORTS
|
|
|
|
// nsIBaseStream methods:
|
|
NS_IMETHOD Close(void);
|
|
|
|
// nsIOutputStream methods:
|
|
NS_IMETHOD Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount);
|
|
NS_IMETHOD Write(nsIInputStream* fromStream, PRUint32 *aWriteCount);
|
|
NS_IMETHOD Flush(void);
|
|
|
|
// nsBufferOutputStream methods:
|
|
nsBufferOutputStream(nsIBuffer* buf, PRBool blocking);
|
|
virtual ~nsBufferOutputStream();
|
|
|
|
protected:
|
|
nsIBuffer* mBuffer;
|
|
PRBool mBlocking;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// nsBufferInputStream methods:
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
nsBufferInputStream::nsBufferInputStream(nsIBuffer* buf, PRBool blocking)
|
|
: mBuffer(buf), mBlocking(blocking)
|
|
{
|
|
NS_INIT_REFCNT();
|
|
NS_ADDREF(mBuffer);
|
|
}
|
|
|
|
nsBufferInputStream::~nsBufferInputStream()
|
|
{
|
|
(void)Close();
|
|
}
|
|
|
|
NS_IMPL_ADDREF(nsBufferInputStream);
|
|
NS_IMPL_RELEASE(nsBufferInputStream);
|
|
|
|
NS_IMETHODIMP
|
|
nsBufferInputStream::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
|
{
|
|
if (aInstancePtr == nsnull)
|
|
return NS_ERROR_NULL_POINTER;
|
|
if (aIID.Equals(nsIInputStream::GetIID()) ||
|
|
aIID.Equals(nsIBaseStream::GetIID()) ||
|
|
aIID.Equals(nsISupports::GetIID())) {
|
|
*aInstancePtr = this;
|
|
NS_ADDREF_THIS();
|
|
return NS_OK;
|
|
}
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsBufferInputStream::Close(void)
|
|
{
|
|
if (mBuffer == nsnull)
|
|
return NS_BASE_STREAM_CLOSED;
|
|
|
|
if (mBlocking) {
|
|
nsAutoMonitor mon(mBuffer);
|
|
NS_RELEASE(mBuffer);
|
|
mBuffer = nsnull;
|
|
nsresult rv = mon.Notify(); // wake up the writer
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
else {
|
|
NS_RELEASE(mBuffer);
|
|
mBuffer = nsnull;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsBufferInputStream::GetLength(PRUint32 *aLength)
|
|
{
|
|
if (mBuffer == nsnull)
|
|
return NS_BASE_STREAM_CLOSED;
|
|
|
|
char* buf;
|
|
return mBuffer->GetReadBuffer(aLength, &buf);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsBufferInputStream::Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount)
|
|
{
|
|
if (mBuffer == nsnull)
|
|
return NS_BASE_STREAM_CLOSED;
|
|
|
|
nsresult rv = NS_OK;
|
|
*aReadCount = 0;
|
|
|
|
while (aCount > 0) {
|
|
PRUint32 amt;
|
|
rv = mBuffer->Read(aBuf, aCount, &amt);
|
|
if (rv == NS_BASE_STREAM_EOF)
|
|
return *aReadCount > 0 ? NS_OK : rv;
|
|
if (NS_FAILED(rv)) return rv;
|
|
if (amt == 0) {
|
|
rv = Fill();
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
else {
|
|
*aReadCount += amt;
|
|
aBuf += amt;
|
|
aCount -= amt;
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsBufferInputStream::SetEOF()
|
|
{
|
|
if (mBuffer == nsnull)
|
|
return NS_BASE_STREAM_CLOSED;
|
|
|
|
if (mBlocking) {
|
|
nsAutoMonitor mon(mBuffer);
|
|
mBuffer->SetEOF();
|
|
nsresult rv = mon.Notify(); // wake up the writer
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
else {
|
|
mBuffer->SetEOF();
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsBufferInputStream::Fill()
|
|
{
|
|
if (mBuffer == nsnull)
|
|
return NS_BASE_STREAM_CLOSED;
|
|
|
|
if (mBlocking) {
|
|
nsAutoMonitor mon(mBuffer);
|
|
while (PR_TRUE) {
|
|
nsresult rv;
|
|
|
|
// check read buffer again while in the monitor
|
|
PRUint32 amt;
|
|
char* buf;
|
|
rv = mBuffer->GetReadBuffer(&amt, &buf);
|
|
if (rv == NS_BASE_STREAM_EOF) return rv;
|
|
if (NS_SUCCEEDED(rv) && amt > 0) return NS_OK;
|
|
|
|
// else notify the writer and wait
|
|
rv = mon.Notify();
|
|
if (NS_FAILED(rv)) return rv; // interrupted
|
|
rv = mon.Wait();
|
|
if (NS_FAILED(rv)) return rv; // interrupted
|
|
}
|
|
}
|
|
else {
|
|
return NS_BASE_STREAM_WOULD_BLOCK;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
NS_BASE nsresult
|
|
NS_NewBufferInputStream(nsIInputStream* *result, nsIBuffer* buffer, PRBool blocking)
|
|
{
|
|
nsBufferInputStream* str = new nsBufferInputStream(buffer, blocking);
|
|
if (str == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
NS_ADDREF(str);
|
|
*result = str;
|
|
return NS_OK;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// nsBufferOutputStream methods:
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
nsBufferOutputStream::nsBufferOutputStream(nsIBuffer* buf, PRBool blocking)
|
|
: mBuffer(buf), mBlocking(blocking)
|
|
{
|
|
NS_INIT_REFCNT();
|
|
NS_ADDREF(mBuffer);
|
|
}
|
|
|
|
nsBufferOutputStream::~nsBufferOutputStream()
|
|
{
|
|
(void)Close();
|
|
}
|
|
|
|
NS_IMPL_ADDREF(nsBufferOutputStream);
|
|
NS_IMPL_RELEASE(nsBufferOutputStream);
|
|
|
|
NS_IMETHODIMP
|
|
nsBufferOutputStream::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
|
{
|
|
if (aInstancePtr == nsnull)
|
|
return NS_ERROR_NULL_POINTER;
|
|
if (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
|
|
nsBufferOutputStream::Close(void)
|
|
{
|
|
if (mBuffer == nsnull)
|
|
return NS_BASE_STREAM_CLOSED;
|
|
|
|
if (mBlocking) {
|
|
nsAutoMonitor mon(mBuffer);
|
|
mBuffer->SetEOF();
|
|
NS_RELEASE(mBuffer);
|
|
mBuffer = nsnull;
|
|
nsresult rv = mon.Notify(); // wake up the writer
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
else {
|
|
NS_RELEASE(mBuffer);
|
|
mBuffer = nsnull;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsBufferOutputStream::Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount)
|
|
{
|
|
if (mBuffer == nsnull)
|
|
return NS_BASE_STREAM_CLOSED;
|
|
|
|
nsresult rv = NS_OK;
|
|
*aWriteCount = 0;
|
|
|
|
while (aCount > 0) {
|
|
PRUint32 amt;
|
|
rv = mBuffer->Write(aBuf, aCount, &amt);
|
|
if (rv == NS_BASE_STREAM_EOF)
|
|
return *aWriteCount > 0 ? NS_OK : rv;
|
|
if (NS_FAILED(rv)) return rv;
|
|
if (amt == 0) {
|
|
rv = Flush();
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
else {
|
|
aBuf += amt;
|
|
aCount -= amt;
|
|
*aWriteCount += amt;
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsBufferOutputStream::Write(nsIInputStream* fromStream, PRUint32 *aWriteCount)
|
|
{
|
|
if (mBuffer == nsnull)
|
|
return NS_BASE_STREAM_CLOSED;
|
|
|
|
nsresult rv = NS_OK;
|
|
*aWriteCount = 0;
|
|
|
|
while (PR_TRUE) { // write until fromStream gets EOF
|
|
PRUint32 amt;
|
|
rv = mBuffer->Write(fromStream, &amt);
|
|
if (rv == NS_BASE_STREAM_EOF)
|
|
return *aWriteCount > 0 ? NS_OK : rv;
|
|
if (NS_FAILED(rv)) return rv;
|
|
if (amt == 0) {
|
|
rv = Flush();
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
else {
|
|
*aWriteCount += amt;
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsBufferOutputStream::Flush(void)
|
|
{
|
|
if (mBuffer == nsnull)
|
|
return NS_BASE_STREAM_CLOSED;
|
|
|
|
if (mBlocking) {
|
|
nsresult rv;
|
|
nsAutoMonitor mon(mBuffer);
|
|
|
|
// check write buffer again while in the monitor
|
|
PRUint32 amt;
|
|
char* buf;
|
|
rv = mBuffer->GetWriteBuffer(&amt, &buf);
|
|
if (rv == NS_BASE_STREAM_EOF) return rv;
|
|
if (NS_SUCCEEDED(rv) && amt > 0) return NS_OK;
|
|
|
|
// else notify the reader and wait
|
|
rv = mon.Notify();
|
|
if (NS_FAILED(rv)) return rv; // interrupted
|
|
rv = mon.Wait();
|
|
if (NS_FAILED(rv)) return rv; // interrupted
|
|
}
|
|
else {
|
|
return NS_BASE_STREAM_WOULD_BLOCK;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
NS_BASE nsresult
|
|
NS_NewBufferOutputStream(nsIOutputStream* *result, nsIBuffer* buffer, PRBool blocking)
|
|
{
|
|
nsBufferOutputStream* ostr = new nsBufferOutputStream(buffer, blocking);
|
|
if (ostr == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
NS_ADDREF(ostr);
|
|
*result = ostr;
|
|
return NS_OK;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
NS_BASE nsresult
|
|
NS_NewPipe2(nsIInputStream* *inStrResult,
|
|
nsIOutputStream* *outStrResult,
|
|
PRUint32 growBySize, PRUint32 maxSize)
|
|
{
|
|
nsresult rv;
|
|
nsIInputStream* inStr = nsnull;
|
|
nsIOutputStream* outStr = nsnull;
|
|
nsIBuffer* buf = nsnull;
|
|
|
|
rv = NS_NewPageBuffer(&buf, growBySize, maxSize);
|
|
if (NS_FAILED(rv)) goto error;
|
|
|
|
rv = NS_NewBufferInputStream(&inStr, buf, PR_TRUE);
|
|
if (NS_FAILED(rv)) goto error;
|
|
|
|
rv = NS_NewBufferOutputStream(&outStr, buf, PR_TRUE);
|
|
if (NS_FAILED(rv)) goto error;
|
|
|
|
NS_RELEASE(buf);
|
|
*inStrResult = inStr;
|
|
*outStrResult = outStr;
|
|
return NS_OK;
|
|
|
|
error:
|
|
NS_IF_RELEASE(inStr);
|
|
NS_IF_RELEASE(outStr);
|
|
NS_IF_RELEASE(buf);
|
|
return rv;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|