Bug 70707. Pulled generic transport implementation out of new memory cache

and created netwerk/base/src/nsStorageTransport.{h,cpp}
This commit is contained in:
darin%netscape.com 2001-03-03 01:57:37 +00:00
Родитель e06eff1a36
Коммит 18d9e7803f
4 изменённых файлов: 1062 добавлений и 0 удалений

Просмотреть файл

@ -59,6 +59,7 @@ CPPSRCS = \
nsProtocolProxyService.cpp \
nsProxyAutoConfigUtils.cpp \
nsAsyncStreamListener.cpp \
nsStorageTransport.cpp \
$(NULL)
# we don't want the shared lib, but we want to force the creation of a

Просмотреть файл

@ -55,6 +55,7 @@ CPP_OBJS = \
.\$(OBJDIR)\nsProtocolProxyService.obj \
.\$(OBJDIR)\nsProxyAutoConfigUtils.obj \
.\$(OBJDIR)\nsAsyncStreamListener.obj \
.\$(OBJDIR)\nsStorageTransport.obj \
$(NULL)
INCS = $(INCS) \

Просмотреть файл

@ -0,0 +1,858 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is nsStorageTransport.cpp, released February 26, 2001.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Darin Fisher <darin@netscape.com> (original author)
*/
#include "nsStorageTransport.h"
#include "nsIProxyObjectManager.h"
#include "nsIServiceManager.h"
#include "nsCRT.h"
#include "prmem.h"
#include "netCore.h"
#define MAX_IO_CHUNK 8192 // maximum count reported per OnDataAvailable
#define MAX_COUNT ((PRUint32) -1)
static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID);
//----------------------------------------------------------------------------
// helper functions...
//----------------------------------------------------------------------------
static NS_METHOD
nsWriteToBuffer(nsIInputStream *aInput,
void *aClosure,
const char *aFromBuf,
PRUint32 aOffset,
PRUint32 aCount,
PRUint32 *aWriteCount)
{
char *toBuf = NS_REINTERPRET_CAST(char *, aClosure);
nsCRT::memcpy(toBuf + aOffset, aFromBuf, aCount);
*aWriteCount = aCount;
return NS_OK;
}
static NS_METHOD
nsReadFromBuffer(nsIOutputStream *aOutput,
void *aClosure,
char *aToBuf,
PRUint32 aOffset,
PRUint32 aCount,
PRUint32 *aReadCount)
{
const char *fromBuf = NS_REINTERPRET_CAST(const char *, aClosure);
nsCRT::memcpy(aToBuf, fromBuf + aOffset, aCount);
*aReadCount = aCount;
return NS_OK;
}
static NS_METHOD
nsReadFromInputStream(nsIOutputStream *aOutput,
void *aClosure,
char *aToBuf,
PRUint32 aOffset,
PRUint32 aCount,
PRUint32 *aReadCount)
{
nsIInputStream *fromStream = NS_REINTERPRET_CAST(nsIInputStream *, aClosure);
return fromStream->Read(aToBuf, aCount, aReadCount);
}
//----------------------------------------------------------------------------
// nsStorageTransport
//----------------------------------------------------------------------------
nsStorageTransport::nsStorageTransport()
: mOutputStream(nsnull)
, mSegmentSize(DEFAULT_SEGMENT_SIZE)
, mMaxSize(DEFAULT_BUFFER_SIZE)
, mSegments(nsnull)
, mWriteSegment(nsnull)
, mWriteCursor(0)
{
NS_INIT_ISUPPORTS();
PR_INIT_CLIST(&mReadRequests);
PR_INIT_CLIST(&mInputStreams);
}
nsStorageTransport::~nsStorageTransport()
{
if (mOutputStream)
CloseOutputStream();
DeleteAllSegments();
}
nsresult
nsStorageTransport::Init(PRUint32 aBufSegmentSize, PRUint32 aBufMaxSize)
{
mSegmentSize = aBufSegmentSize;
mMaxSize = aBufMaxSize;
return NS_OK;
}
nsresult
nsStorageTransport::GetReadSegment(PRUint32 aOffset, char **aPtr, PRUint32 *aCount)
{
*aPtr = nsnull;
*aCount = 0;
if (aOffset < mWriteCursor) {
PRUint32 index = aOffset / mSegmentSize;
nsSegment *s = GetNthSegment(index);
if (s) {
PRUint32 offset = aOffset % mSegmentSize;
*aPtr = s->Data() + offset;
*aCount = mSegmentSize - offset;
}
}
return NS_OK;
}
nsresult
nsStorageTransport::GetWriteSegment(char **aPtr, PRUint32 *aCount)
{
NS_ENSURE_ARG_POINTER(aPtr);
NS_ENSURE_ARG_POINTER(aCount);
if (mWriteSegment) {
PRUint32 offset = mWriteCursor % mSegmentSize;
*aPtr = mWriteSegment->Data() + offset;
*aCount = mSegmentSize - offset;
return NS_OK;
}
else {
// add a new segment for writing and redo...
nsresult rv = AddWriteSegment();
return NS_FAILED(rv) ? rv : GetWriteSegment(aPtr, aCount);
}
}
nsresult
nsStorageTransport::AddToBytesWritten(PRUint32 aCount)
{
// advance write cursor
mWriteCursor += aCount;
// clear write segment if we have written to the end
if (!(mWriteCursor % mSegmentSize))
mWriteSegment = nsnull;
// process waiting readers
PRCList *link = PR_LIST_HEAD(&mReadRequests);
for (; link != &mReadRequests; link = PR_NEXT_LINK(link)) {
nsReadRequest *req = NS_STATIC_CAST(nsReadRequest *, link);
if (req->IsWaitingForWrite())
req->Process();
}
return NS_OK;
}
nsresult
nsStorageTransport::CloseOutputStream()
{
if (mOutputStream) {
mOutputStream->SetTransport(nsnull);
mOutputStream = nsnull;
// XXX wake up blocked reads
}
return NS_OK;
}
nsresult
nsStorageTransport::ReadRequestCompleted(nsReadRequest *aReader)
{
// remove the reader from the list of readers
PR_REMOVE_AND_INIT_LINK(aReader);
aReader->SetTransport(nsnull);
return NS_OK;
}
nsresult
nsStorageTransport::Available(PRUint32 aStartingFrom, PRUint32 *aCount)
{
*aCount = mWriteCursor - aStartingFrom;
return NS_OK;
}
nsresult
nsStorageTransport::AddWriteSegment()
{
NS_ASSERTION(mWriteSegment == nsnull, "write segment is non-null");
mWriteSegment = (nsSegment *) PR_Malloc(sizeof(nsSegment) + mSegmentSize);
if (!mWriteSegment)
return NS_ERROR_OUT_OF_MEMORY;
mWriteSegment->next = nsnull;
AppendSegment(mWriteSegment);
return NS_OK;
}
void
nsStorageTransport::AppendSegment(nsSegment *aSegment)
{
if (!mSegments)
mSegments = aSegment;
else {
nsSegment *s = mSegments;
for (; s && s->next; s = s->next);
s->next = aSegment;
}
}
void
nsStorageTransport::DeleteSegments(nsSegment *segments)
{
while (segments) {
nsSegment *s = segments->next;
PR_Free(segments);
segments = s;
}
}
void
nsStorageTransport::TruncateTo(PRUint32 aOffset)
{
if (aOffset < mWriteCursor) {
if (aOffset == 0) {
DeleteSegments(mSegments);
mSegments = nsnull;
mWriteSegment = nsnull;
}
else {
PRUint32 offset = 0;
nsSegment *s = mSegments;
for (; s; s = s->next) {
if ((offset + mSegmentSize) > aOffset)
break;
offset += mSegmentSize;
}
// "s" now points to the last segment that we should keep
if (s->next) {
DeleteSegments(s->next);
s->next = nsnull;
}
mWriteSegment = s;
}
}
mWriteCursor = aOffset;
}
nsStorageTransport::nsSegment *
nsStorageTransport::GetNthSegment(PRUint32 index)
{
nsSegment *s = mSegments;
for (; s && index; s = s->next, --index);
return s;
}
NS_IMPL_THREADSAFE_ISUPPORTS1(nsStorageTransport,
nsITransport)
NS_IMETHODIMP
nsStorageTransport::GetSecurityInfo(nsISupports **aSecurityInfo)
{
NS_ENSURE_ARG_POINTER(aSecurityInfo);
*aSecurityInfo = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsStorageTransport::GetProgressEventSink(nsIProgressEventSink **aSink)
{
NS_ENSURE_ARG_POINTER(aSink);
*aSink = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsStorageTransport::SetProgressEventSink(nsIProgressEventSink *aSink)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsStorageTransport::OpenInputStream(PRUint32 aOffset,
PRUint32 aCount,
PRUint32 aFlags,
nsIInputStream **aInput)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsStorageTransport::OpenOutputStream(PRUint32 aOffset,
PRUint32 aCount,
PRUint32 aFlags,
nsIOutputStream **aOutput)
{
NS_ENSURE_TRUE(!mOutputStream, NS_ERROR_IN_PROGRESS);
if (!PR_CLIST_IS_EMPTY(&mInputStreams) || !PR_CLIST_IS_EMPTY(&mReadRequests)) {
NS_NOTREACHED("Attempt to open a memory cache output stream while "
"read is in progress!");
return NS_ERROR_FAILURE;
}
NS_NEWXPCOM(mOutputStream, nsOutputStream);
if (!mOutputStream)
return NS_ERROR_OUT_OF_MEMORY;
mOutputStream->SetTransport(this);
mOutputStream->SetTransferCount(aCount);
TruncateTo(aOffset);
NS_ADDREF(*aOutput = mOutputStream);
return NS_OK;
}
NS_IMETHODIMP
nsStorageTransport::AsyncRead(nsIStreamListener *aListener,
nsISupports *aContext,
PRUint32 aOffset,
PRUint32 aCount,
PRUint32 aFlags,
nsIRequest **aRequest)
{
nsresult rv = NS_OK;
nsReadRequest *reader;
NS_NEWXPCOM(reader, nsReadRequest);
if (!reader)
return NS_ERROR_OUT_OF_MEMORY;
reader->SetTransport(this);
reader->SetTransferOffset(aOffset);
reader->SetTransferCount(aCount);
// append the read request to the list of existing read requests.
// it is important to do this before the possibility of failure.
PR_APPEND_LINK(reader, &mReadRequests);
rv = reader->SetListener(aListener, aContext);
if (NS_FAILED(rv)) goto error;
rv = reader->Process();
if (NS_FAILED(rv)) goto error;
NS_ADDREF(*aRequest = reader);
return NS_OK;
error:
NS_DELETEXPCOM(reader);
return rv;
}
NS_IMETHODIMP
nsStorageTransport::AsyncWrite(nsIStreamProvider *aProvider,
nsISupports *aContext,
PRUint32 aOffset,
PRUint32 aCount,
PRUint32 aFlags,
nsIRequest **aRequest)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//----------------------------------------------------------------------------
// nsStorageTransport::nsReadRequest
//----------------------------------------------------------------------------
nsStorageTransport::nsReadRequest::nsReadRequest()
: mTransport(nsnull)
, mTransferOffset(0)
, mTransferCount(MAX_COUNT)
, mStatus(NS_OK)
, mCanceled(PR_FALSE)
, mOnStartFired(PR_FALSE)
, mWaitingForWrite(PR_FALSE)
{
NS_INIT_ISUPPORTS();
PR_INIT_CLIST(this);
}
nsStorageTransport::nsReadRequest::~nsReadRequest()
{
if (mTransport)
mTransport->ReadRequestCompleted(this);
}
nsresult
nsStorageTransport::nsReadRequest::SetListener(nsIStreamListener *aListener,
nsISupports *aListenerContext)
{
nsresult rv = NS_OK;
mListener = aListener;
mListenerContext = aListenerContext;
// We proxy listener events to ourself and then forward them onto
// the real listener (on the listener's thread).
nsCOMPtr<nsIProxyObjectManager> proxyMgr =
do_GetService(kProxyObjectManagerCID, &rv);
if (NS_SUCCEEDED(rv))
rv = proxyMgr->GetProxyForObject(NS_CURRENT_EVENTQ,
NS_GET_IID(nsIStreamListener),
NS_STATIC_CAST(nsIStreamListener *, this),
PROXY_ASYNC | PROXY_ALWAYS,
getter_AddRefs(mListenerProxy));
return rv;
}
nsresult
nsStorageTransport::nsReadRequest::Process()
{
nsresult rv = NS_OK;
// this method must always be called on the client's thread
NS_ENSURE_TRUE(mTransport, NS_ERROR_NOT_INITIALIZED);
// always clear this flag initially
mWaitingForWrite = PR_FALSE;
PRUint32 count = 0;
rv = mTransport->Available(mTransferOffset, &count);
if (NS_FAILED(rv)) return rv;
if (!mOnStartFired) {
// no need to proxy this callback
(void) mListener->OnStartRequest(this, mListenerContext);
mOnStartFired = PR_TRUE;
}
count = PR_MIN(count, mTransferCount);
if (count) {
count = PR_MIN(count, MAX_IO_CHUNK);
// proxy this callback
(void) mListenerProxy->OnDataAvailable(this, mListenerContext,
this,
mTransferOffset,
count);
}
else if ((mTransferCount == 0) || !mTransport->HasWriter()) {
// there is no more data to read and there is no writer, so we
// must stop this read request.
// first let the transport know that we are done
mTransport->ReadRequestCompleted(this);
// no need to proxy this callback
(void) mListener->OnStopRequest(this, mListenerContext, mStatus, nsnull);
}
else
mWaitingForWrite = PR_TRUE;
return rv;
}
NS_IMPL_THREADSAFE_ISUPPORTS5(nsStorageTransport::nsReadRequest,
nsITransportRequest,
nsIRequest,
nsIStreamListener,
nsIStreamObserver,
nsIInputStream)
NS_IMETHODIMP
nsStorageTransport::nsReadRequest::GetTransport(nsITransport **aTransport)
{
NS_ENSURE_ARG_POINTER(aTransport);
NS_IF_ADDREF(*aTransport = mTransport);
return NS_OK;
}
NS_IMETHODIMP
nsStorageTransport::nsReadRequest::GetName(PRUnichar **aName)
{
NS_ENSURE_ARG_POINTER(aName);
*aName = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsStorageTransport::nsReadRequest::IsPending(PRBool *aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
*aResult = (mTransport ? PR_TRUE : PR_FALSE);
return NS_OK;
}
NS_IMETHODIMP
nsStorageTransport::nsReadRequest::GetStatus(nsresult *aStatus)
{
NS_ENSURE_ARG_POINTER(aStatus);
*aStatus = mStatus;
return NS_OK;
}
NS_IMETHODIMP
nsStorageTransport::nsReadRequest::Cancel(nsresult aStatus)
{
mCanceled = PR_TRUE;
mStatus = aStatus;
return NS_OK;
}
NS_IMETHODIMP
nsStorageTransport::nsReadRequest::Suspend()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsStorageTransport::nsReadRequest::Resume()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsStorageTransport::nsReadRequest::OnStartRequest(nsIRequest *aRequest,
nsISupports *aContext)
{
NS_NOTREACHED("nsStorageTransport::nsReadRequest::OnStartRequest");
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsStorageTransport::nsReadRequest::OnStopRequest(nsIRequest *aRequest,
nsISupports *aContext,
nsresult aStatus,
const PRUnichar *aStatusText)
{
NS_NOTREACHED("nsStorageTransport::nsReadRequest::OnStopRequest");
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsStorageTransport::nsReadRequest::OnDataAvailable(nsIRequest *aRequest,
nsISupports *aContext,
nsIInputStream *aInput,
PRUint32 aOffset,
PRUint32 aCount)
{
nsresult rv = NS_OK;
rv = mListener->OnDataAvailable(aRequest, aContext, aInput, aOffset, aCount);
NS_ASSERTION(rv != NS_BASE_STREAM_WOULD_BLOCK, "not implemented");
if (NS_FAILED(rv)) return rv;
// post the next message...
return Process();
}
NS_IMETHODIMP
nsStorageTransport::nsReadRequest::Close()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsStorageTransport::nsReadRequest::Available(PRUint32 *aCount)
{
NS_ENSURE_TRUE(mTransport, NS_BASE_STREAM_CLOSED);
return mTransport->Available(mTransferOffset, aCount);
}
NS_IMETHODIMP
nsStorageTransport::nsReadRequest::Read(char *aBuf, PRUint32 aCount, PRUint32 *aBytesRead)
{
return ReadSegments(nsWriteToBuffer, aBuf, aCount, aBytesRead);
}
NS_IMETHODIMP
nsStorageTransport::nsReadRequest::ReadSegments(nsWriteSegmentFun aWriter,
void *aClosure,
PRUint32 aCount,
PRUint32 *aBytesRead)
{
NS_ENSURE_TRUE(mTransport, NS_BASE_STREAM_CLOSED);
nsresult rv = NS_OK;
*aBytesRead = 0;
// limit the number of bytes that can be read
aCount = PR_MIN(aCount, mTransferCount);
while (aCount) {
char *ptr = nsnull;
PRUint32 count = 0;
rv = mTransport->GetReadSegment(mTransferOffset, &ptr, &count);
if (NS_FAILED(rv)) return rv;
count = PR_MIN(count, aCount);
while (count) {
PRUint32 writeCount = 0;
rv = aWriter(this, aClosure, ptr, *aBytesRead, count, &writeCount);
if (rv == NS_BASE_STREAM_WOULD_BLOCK)
return NS_OK; // mask this error
else if (NS_FAILED(rv))
return rv;
ptr += writeCount;
count -= writeCount;
aCount -= writeCount;
*aBytesRead += writeCount;
// decrement the total number of bytes remaining to be read
mTransferCount -= writeCount;
mTransferOffset += writeCount;
}
}
return rv;
}
NS_IMETHODIMP
nsStorageTransport::nsReadRequest::GetNonBlocking(PRBool *aNonBlocking)
{
NS_ENSURE_ARG_POINTER(aNonBlocking);
*aNonBlocking = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsStorageTransport::nsReadRequest::GetObserver(nsIInputStreamObserver **aObserver)
{
NS_ENSURE_ARG_POINTER(aObserver);
*aObserver = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsStorageTransport::nsReadRequest::SetObserver(nsIInputStreamObserver *aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//----------------------------------------------------------------------------
// nsStorageTransport::nsBlockingStream
//----------------------------------------------------------------------------
nsStorageTransport::nsBlockingStream::nsBlockingStream()
: mTransport(nsnull)
, mTransferCount(MAX_COUNT)
{
}
nsStorageTransport::nsBlockingStream::~nsBlockingStream()
{
}
//----------------------------------------------------------------------------
// nsStorageTransport::nsInputStream
//----------------------------------------------------------------------------
nsStorageTransport::nsInputStream::nsInputStream()
: mOffset(0)
{
NS_INIT_ISUPPORTS();
}
nsStorageTransport::nsInputStream::~nsInputStream()
{
}
NS_IMPL_THREADSAFE_ISUPPORTS1(nsStorageTransport::nsInputStream,
nsIInputStream)
NS_IMETHODIMP
nsStorageTransport::nsInputStream::Close()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsStorageTransport::nsInputStream::Available(PRUint32 *aCount)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsStorageTransport::nsInputStream::Read(char *aBuf, PRUint32 aCount, PRUint32 *aBytesRead)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsStorageTransport::nsInputStream::ReadSegments(nsWriteSegmentFun aWriter,
void *aClosure,
PRUint32 aCount,
PRUint32 *aBytesRead)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsStorageTransport::nsInputStream::GetNonBlocking(PRBool *aNonBlocking)
{
NS_ENSURE_ARG_POINTER(aNonBlocking);
*aNonBlocking = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP
nsStorageTransport::nsInputStream::GetObserver(nsIInputStreamObserver **aObserver)
{
NS_ENSURE_ARG_POINTER(aObserver);
*aObserver = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsStorageTransport::nsInputStream::SetObserver(nsIInputStreamObserver *aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//----------------------------------------------------------------------------
// nsStorageTransport::nsOutputStream
//----------------------------------------------------------------------------
nsStorageTransport::nsOutputStream::nsOutputStream()
{
NS_INIT_ISUPPORTS();
}
nsStorageTransport::nsOutputStream::~nsOutputStream()
{
if (mTransport)
mTransport->CloseOutputStream();
}
NS_IMPL_THREADSAFE_ISUPPORTS1(nsStorageTransport::nsOutputStream,
nsIOutputStream)
NS_IMETHODIMP
nsStorageTransport::nsOutputStream::Close()
{
NS_ENSURE_TRUE(mTransport, NS_BASE_STREAM_CLOSED);
return mTransport->CloseOutputStream();
}
NS_IMETHODIMP
nsStorageTransport::nsOutputStream::Flush()
{
return NS_OK;
}
NS_IMETHODIMP
nsStorageTransport::nsOutputStream::Write(const char *aBuf,
PRUint32 aCount,
PRUint32 *aBytesWritten)
{
return WriteSegments(nsReadFromBuffer, (void *) aBuf, aCount, aBytesWritten);
}
NS_IMETHODIMP
nsStorageTransport::nsOutputStream::WriteFrom(nsIInputStream *aInput,
PRUint32 aCount,
PRUint32 *aBytesWritten)
{
return WriteSegments(nsReadFromInputStream, aInput, aCount, aBytesWritten);
}
NS_IMETHODIMP
nsStorageTransport::nsOutputStream::WriteSegments(nsReadSegmentFun aReader,
void *aClosure,
PRUint32 aCount,
PRUint32 *aBytesWritten)
{
NS_ENSURE_TRUE(mTransport, NS_BASE_STREAM_CLOSED);
nsresult rv = NS_OK;
*aBytesWritten = 0;
// XXX need to honor mTransferCount
while (aCount) {
char *ptr;
PRUint32 count;
rv = mTransport->GetWriteSegment(&ptr, &count);
if (NS_FAILED(rv)) return rv;
count = PR_MIN(count, aCount);
while (count) {
PRUint32 readCount;
rv = aReader(this, aClosure, ptr, *aBytesWritten, count, &readCount);
if (NS_FAILED(rv))
break;
count -= readCount;
aCount -= readCount;
*aBytesWritten += readCount;
rv = mTransport->AddToBytesWritten(readCount);
}
}
return rv;
}
NS_IMETHODIMP
nsStorageTransport::nsOutputStream::GetNonBlocking(PRBool *aNonBlocking)
{
NS_ENSURE_ARG_POINTER(aNonBlocking);
*aNonBlocking = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP
nsStorageTransport::nsOutputStream::SetNonBlocking(PRBool aNonBlocking)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsStorageTransport::nsOutputStream::GetObserver(nsIOutputStreamObserver **aObserver)
{
NS_ENSURE_ARG_POINTER(aObserver);
*aObserver = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsStorageTransport::nsOutputStream::SetObserver(nsIOutputStreamObserver *aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}

Просмотреть файл

@ -0,0 +1,202 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is nsStorageTransport.h, released February 26, 2001.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Darin Fisher <darin@netscape.com> (original author)
*/
#ifndef nsStorageTransport_h__
#define nsStorageTransport_h__
#include "nsITransport.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "nsIStreamListener.h"
#include "prclist.h"
#include "nsCOMPtr.h"
/**
* Each "stream-based" memory cache entry has one transport
* associated with it. The transport supports multiple
* simultaneous read requests and a single write request.
*/
class nsStorageTransport : public nsITransport
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSITRANSPORT
enum { DEFAULT_SEGMENT_SIZE = 1024 };
enum { DEFAULT_BUFFER_SIZE = 1024 * 1024 };
nsStorageTransport();
virtual ~nsStorageTransport();
nsresult Init(PRUint32 aSegmentSize = DEFAULT_SEGMENT_SIZE,
PRUint32 aBufferSize = DEFAULT_BUFFER_SIZE);
private:
/**
* The transport request object returned by AsyncRead
*/
class nsReadRequest : public PRCList
, public nsITransportRequest
, public nsIStreamListener
, public nsIInputStream
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSITRANSPORTREQUEST
NS_DECL_NSIREQUEST
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSISTREAMOBSERVER
NS_DECL_NSIINPUTSTREAM
nsReadRequest();
virtual ~nsReadRequest();
void SetTransport(nsStorageTransport *t) { mTransport = t; }
void SetTransferOffset(PRUint32 o) { mTransferOffset = o; }
void SetTransferCount(PRUint32 c) { mTransferCount = c; }
nsresult SetListener(nsIStreamListener *, nsISupports *);
nsresult Process();
PRBool IsWaitingForWrite() { return mWaitingForWrite; }
private:
nsStorageTransport *mTransport; // weak ref
PRUint32 mTransferOffset;
PRUint32 mTransferCount;
nsresult mStatus;
nsCOMPtr<nsIStreamListener> mListenerProxy;
nsCOMPtr<nsIStreamListener> mListener;
nsCOMPtr<nsISupports> mListenerContext;
PRPackedBool mCanceled;
PRPackedBool mOnStartFired;
PRPackedBool mWaitingForWrite;
};
/**
* A base class for the blocking streams
*/
class nsBlockingStream
{
public:
nsBlockingStream();
virtual ~nsBlockingStream();
void SetTransport(nsStorageTransport *t) { mTransport = t; }
void SetTransferCount(PRUint32 c) { mTransferCount = c; }
protected:
nsStorageTransport *mTransport; // weak ref
PRUint32 mTransferCount;
};
/**
* The blocking input stream object returned by OpenInputStream
*/
class nsInputStream : public PRCList
, public nsBlockingStream
, public nsIInputStream
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIINPUTSTREAM
nsInputStream();
virtual ~nsInputStream();
private:
PRUint32 mOffset;
};
/**
* The blocking output stream object returned by OpenOutputStream
*/
class nsOutputStream : public nsBlockingStream
, public nsIOutputStream
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOUTPUTSTREAM
nsOutputStream();
virtual ~nsOutputStream();
};
friend class nsReadRequest;
friend class nsBlockingStream;
friend class nsInputStream;
friend class nsOutputStream;
/**
* Methods called from the friend classes
*/
nsresult GetReadSegment(PRUint32 aOffset, char **aPtr, PRUint32 *aCount);
nsresult GetWriteSegment(char **aPtr, PRUint32 *aCount);
nsresult AddToBytesWritten(PRUint32 aCount);
nsresult CloseOutputStream();
nsresult ReadRequestCompleted(nsReadRequest *);
nsresult Available(PRUint32 aStartingFrom, PRUint32 *aCount);
PRBool HasWriter() { return (mOutputStream != nsnull); }
private:
/**
* Data is stored in a singly-linked list of segments
*/
struct nsSegment
{
struct nsSegment *next;
char *Data() { return NS_REINTERPRET_CAST(char *, this) + sizeof(*this); }
// the data follows this structure (the two are allocated together)
};
/**
* Internal methods
*/
nsresult AddWriteSegment();
void AppendSegment(nsSegment *);
void DeleteSegments(nsSegment *);
void DeleteAllSegments() { TruncateTo(0); }
void TruncateTo(PRUint32 aOffset);
nsSegment *GetNthSegment(PRUint32 aIndex);
private:
nsOutputStream *mOutputStream; // weak ref
PRCList mInputStreams; // weak ref to objects
PRCList mReadRequests; // weak ref to objects
PRUint32 mSegmentSize;
PRUint32 mMaxSize;
nsSegment *mSegments;
nsSegment *mWriteSegment;
PRUint32 mWriteCursor;
};
#endif