1999-04-30 22:55:12 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 4; 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 "nsBuffer.h"
|
|
|
|
#include "nsAutoLock.h"
|
|
|
|
#include "nsCRT.h"
|
|
|
|
#include "nsIInputStream.h"
|
|
|
|
#include "nsIServiceManager.h"
|
|
|
|
#include "nsIPageManager.h"
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
nsBuffer::nsBuffer()
|
|
|
|
: mGrowBySize(0),
|
|
|
|
mMaxSize(0),
|
|
|
|
mAllocator(nsnull),
|
|
|
|
mBufferSize(0),
|
|
|
|
mReadSegment(nsnull),
|
|
|
|
mReadCursor(0),
|
|
|
|
mWriteSegment(nsnull),
|
|
|
|
mWriteCursor(0),
|
1999-06-19 22:23:18 +00:00
|
|
|
mReaderClosed(PR_FALSE),
|
|
|
|
mCondition(NS_OK)
|
1999-04-30 22:55:12 +00:00
|
|
|
{
|
|
|
|
NS_INIT_REFCNT();
|
|
|
|
PR_INIT_CLIST(&mSegments);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBuffer::Init(PRUint32 growBySize, PRUint32 maxSize,
|
1999-06-15 04:57:07 +00:00
|
|
|
nsIBufferObserver* observer, nsIAllocator* allocator)
|
1999-04-30 22:55:12 +00:00
|
|
|
{
|
1999-06-05 01:15:00 +00:00
|
|
|
NS_ASSERTION(sizeof(PRCList) <= SEGMENT_OVERHEAD,
|
|
|
|
"need to change SEGMENT_OVERHEAD size");
|
|
|
|
NS_ASSERTION(growBySize > SEGMENT_OVERHEAD, "bad growBySize");
|
1999-04-30 22:55:12 +00:00
|
|
|
mGrowBySize = growBySize;
|
|
|
|
mMaxSize = maxSize;
|
1999-06-15 04:57:07 +00:00
|
|
|
mObserver = observer;
|
|
|
|
NS_IF_ADDREF(mObserver);
|
1999-04-30 22:55:12 +00:00
|
|
|
mAllocator = allocator;
|
|
|
|
NS_ADDREF(mAllocator);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsBuffer::~nsBuffer()
|
|
|
|
{
|
1999-06-15 04:57:07 +00:00
|
|
|
NS_IF_RELEASE(mObserver);
|
1999-04-30 22:55:12 +00:00
|
|
|
NS_IF_RELEASE(mAllocator);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS(nsBuffer, nsIBuffer::GetIID());
|
|
|
|
|
1999-05-26 01:38:36 +00:00
|
|
|
NS_METHOD
|
|
|
|
nsBuffer::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
|
|
|
|
{
|
|
|
|
if (aOuter)
|
|
|
|
return NS_ERROR_NO_AGGREGATION;
|
|
|
|
|
|
|
|
nsBuffer* buf = new nsBuffer();
|
|
|
|
if (buf == nsnull)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
NS_ADDREF(buf);
|
|
|
|
nsresult rv = buf->QueryInterface(aIID, aResult);
|
|
|
|
NS_RELEASE(buf);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
1999-04-30 22:55:12 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsBuffer::PushWriteSegment()
|
|
|
|
{
|
1999-06-16 04:15:08 +00:00
|
|
|
nsAutoCMonitor mon(this); // protect mSegments
|
1999-04-30 22:55:12 +00:00
|
|
|
|
|
|
|
if (mBufferSize >= mMaxSize) {
|
1999-06-15 04:57:07 +00:00
|
|
|
if (mObserver) {
|
1999-06-19 22:23:18 +00:00
|
|
|
nsresult rv = mObserver->OnFull(this);
|
1999-06-15 04:57:07 +00:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
}
|
1999-04-30 22:55:12 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// allocate a new segment to write into
|
|
|
|
PRCList* header;
|
|
|
|
|
1999-06-05 01:15:00 +00:00
|
|
|
header = (PRCList*)mAllocator->Alloc(mGrowBySize);
|
|
|
|
if (header == nsnull)
|
1999-04-30 22:55:12 +00:00
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
mBufferSize += mGrowBySize;
|
|
|
|
|
|
|
|
PR_INSERT_BEFORE(header, &mSegments); // insert at end
|
|
|
|
|
|
|
|
// initialize the write segment
|
1999-06-05 01:15:00 +00:00
|
|
|
mWriteSegment = header;
|
|
|
|
mWriteSegmentEnd = (char*)mWriteSegment + mGrowBySize;
|
|
|
|
mWriteCursor = (char*)mWriteSegment + sizeof(PRCList);
|
1999-04-30 22:55:12 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsBuffer::PopReadSegment()
|
|
|
|
{
|
|
|
|
nsresult rv;
|
1999-06-16 04:15:08 +00:00
|
|
|
nsAutoCMonitor mon(this); // protect mSegments
|
1999-04-30 22:55:12 +00:00
|
|
|
|
|
|
|
PRCList* header = (PRCList*)mSegments.next;
|
|
|
|
char* segment = (char*)header;
|
|
|
|
|
1999-06-05 01:15:00 +00:00
|
|
|
NS_ASSERTION(mReadSegment == header, "wrong segment");
|
1999-04-30 22:55:12 +00:00
|
|
|
|
|
|
|
// make sure that the writer isn't still in this segment (that the
|
|
|
|
// reader is removing)
|
|
|
|
NS_ASSERTION(!(segment <= mWriteCursor && mWriteCursor < segment + mGrowBySize),
|
|
|
|
"removing writer's segment");
|
|
|
|
|
|
|
|
PR_REMOVE_LINK(header); // unlink from mSegments
|
|
|
|
|
|
|
|
mBufferSize -= mGrowBySize;
|
|
|
|
|
1999-05-07 06:22:11 +00:00
|
|
|
rv = mAllocator->Free(segment);
|
1999-04-30 22:55:12 +00:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
// initialize the read segment
|
|
|
|
if (PR_CLIST_IS_EMPTY(&mSegments)) {
|
|
|
|
mReadSegment = nsnull;
|
|
|
|
mReadSegmentEnd = nsnull;
|
|
|
|
mReadCursor = nsnull;
|
1999-06-15 04:57:07 +00:00
|
|
|
if (mObserver) {
|
1999-06-19 22:23:18 +00:00
|
|
|
rv = mObserver->OnEmpty(this);
|
1999-06-15 04:57:07 +00:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
}
|
1999-04-30 22:55:12 +00:00
|
|
|
}
|
|
|
|
else {
|
1999-06-05 01:15:00 +00:00
|
|
|
mReadSegment = mSegments.next;
|
|
|
|
mReadSegmentEnd = (char*)mReadSegment + mGrowBySize;
|
|
|
|
mReadCursor = (char*)mReadSegment + sizeof(PRCList);
|
1999-04-30 22:55:12 +00:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// nsIBuffer methods:
|
|
|
|
|
1999-06-09 04:52:47 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBuffer::ReadSegments(nsWriteSegmentFun writer, void* closure, PRUint32 count,
|
|
|
|
PRUint32 *readCount)
|
|
|
|
{
|
1999-06-19 22:23:18 +00:00
|
|
|
NS_ASSERTION(!mReaderClosed, "state change error");
|
|
|
|
|
|
|
|
nsAutoCMonitor mon(this);
|
|
|
|
nsresult rv = NS_OK;
|
1999-06-09 04:52:47 +00:00
|
|
|
PRUint32 readBufferLen;
|
1999-06-09 06:41:32 +00:00
|
|
|
const char* readBuffer;
|
1999-06-09 04:52:47 +00:00
|
|
|
|
|
|
|
*readCount = 0;
|
|
|
|
while (count > 0) {
|
1999-06-09 06:41:32 +00:00
|
|
|
rv = GetReadSegment(0, &readBuffer, &readBufferLen);
|
1999-06-19 22:23:18 +00:00
|
|
|
if (rv == NS_BASE_STREAM_EOF) { // all we're going to get
|
1999-06-15 04:57:07 +00:00
|
|
|
return *readCount == 0 ? rv : NS_OK;
|
1999-06-19 22:23:18 +00:00
|
|
|
}
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "GetReadSegment failed -- shouldn't happen");
|
|
|
|
if (readBufferLen == 0) {
|
|
|
|
return *readCount == 0 ? NS_BASE_STREAM_WOULD_BLOCK : NS_OK;
|
|
|
|
}
|
1999-06-09 04:52:47 +00:00
|
|
|
|
|
|
|
readBufferLen = PR_MIN(readBufferLen, count);
|
|
|
|
while (readBufferLen > 0) {
|
|
|
|
PRUint32 writeCount;
|
|
|
|
rv = writer(closure, readBuffer, *readCount, readBufferLen, &writeCount);
|
1999-06-19 22:23:18 +00:00
|
|
|
NS_ASSERTION(rv != NS_BASE_STREAM_EOF, "Write should not return EOF");
|
|
|
|
if (rv == NS_BASE_STREAM_WOULD_BLOCK || NS_FAILED(rv)) {
|
1999-06-09 04:52:47 +00:00
|
|
|
// if we failed to write just report what we were
|
|
|
|
// able to read so far
|
1999-06-19 22:23:18 +00:00
|
|
|
return *readCount == 0 ? rv : NS_OK;
|
1999-06-09 04:52:47 +00:00
|
|
|
}
|
|
|
|
NS_ASSERTION(writeCount <= readBufferLen, "writer returned bad writeCount");
|
|
|
|
readBuffer += writeCount;
|
|
|
|
readBufferLen -= writeCount;
|
|
|
|
*readCount += writeCount;
|
|
|
|
count -= writeCount;
|
|
|
|
|
|
|
|
if (mReadCursor + writeCount == mReadSegmentEnd) {
|
|
|
|
rv = PopReadSegment();
|
1999-06-19 22:23:18 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return *readCount == 0 ? rv : NS_OK;
|
|
|
|
}
|
1999-06-09 04:52:47 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
mReadCursor += writeCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-06-15 04:57:07 +00:00
|
|
|
static NS_METHOD
|
1999-06-09 04:52:47 +00:00
|
|
|
nsWriteToRawBuffer(void* closure,
|
|
|
|
const char* fromRawSegment,
|
|
|
|
PRUint32 offset,
|
|
|
|
PRUint32 count,
|
|
|
|
PRUint32 *writeCount)
|
|
|
|
{
|
|
|
|
char* toBuf = (char*)closure;
|
|
|
|
nsCRT::memcpy(&toBuf[offset], fromRawSegment, count);
|
|
|
|
*writeCount = count;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-04-30 22:55:12 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBuffer::Read(char* toBuf, PRUint32 bufLen, PRUint32 *readCount)
|
|
|
|
{
|
1999-06-09 04:52:47 +00:00
|
|
|
return ReadSegments(nsWriteToRawBuffer, toBuf, bufLen, readCount);
|
1999-04-30 22:55:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-06-09 06:41:32 +00:00
|
|
|
nsBuffer::GetReadSegment(PRUint32 segmentLogicalOffset,
|
|
|
|
const char* *resultSegment,
|
|
|
|
PRUint32 *resultSegmentLen)
|
1999-04-30 22:55:12 +00:00
|
|
|
{
|
1999-06-19 22:23:18 +00:00
|
|
|
nsAutoCMonitor mon(this);
|
|
|
|
|
|
|
|
// set the read segment and cursor if not already set
|
1999-04-30 22:55:12 +00:00
|
|
|
if (mReadSegment == nsnull) {
|
|
|
|
if (PR_CLIST_IS_EMPTY(&mSegments)) {
|
1999-06-09 06:41:32 +00:00
|
|
|
*resultSegmentLen = 0;
|
|
|
|
*resultSegment = nsnull;
|
1999-06-19 22:23:18 +00:00
|
|
|
return mCondition ? mCondition : NS_OK;
|
1999-04-30 22:55:12 +00:00
|
|
|
}
|
|
|
|
else {
|
1999-06-05 01:15:00 +00:00
|
|
|
mReadSegment = mSegments.next;
|
|
|
|
mReadSegmentEnd = (char*)mReadSegment + mGrowBySize;
|
|
|
|
mReadCursor = (char*)mReadSegment + sizeof(PRCList);
|
1999-04-30 22:55:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-06-09 06:41:32 +00:00
|
|
|
// now search for the segment starting from segmentLogicalOffset and return it
|
1999-06-05 01:15:00 +00:00
|
|
|
PRCList* curSeg = mReadSegment;
|
|
|
|
char* curSegStart = mReadCursor;
|
|
|
|
char* curSegEnd = mReadSegmentEnd;
|
|
|
|
PRInt32 amt;
|
1999-06-09 06:41:32 +00:00
|
|
|
PRInt32 offset = (PRInt32)segmentLogicalOffset;
|
1999-06-05 01:15:00 +00:00
|
|
|
while (offset >= 0) {
|
|
|
|
// snapshot the write cursor into a local variable -- this allows
|
|
|
|
// a writer to freely change it while we're reading while avoiding
|
|
|
|
// using a lock
|
|
|
|
char* snapshotWriteCursor = mWriteCursor; // atomic
|
|
|
|
|
|
|
|
// next check if the write cursor is in our segment
|
|
|
|
if (curSegStart <= snapshotWriteCursor &&
|
|
|
|
snapshotWriteCursor < curSegEnd) {
|
|
|
|
// same segment -- read up to the snapshotWriteCursor
|
|
|
|
curSegEnd = snapshotWriteCursor;
|
|
|
|
|
|
|
|
amt = curSegEnd - curSegStart;
|
|
|
|
if (offset < amt) {
|
1999-06-09 06:41:32 +00:00
|
|
|
// segmentLogicalOffset is in this segment, so read up to its end
|
|
|
|
*resultSegmentLen = amt - offset;
|
|
|
|
*resultSegment = curSegStart + offset;
|
1999-06-05 01:15:00 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// don't continue past the write segment
|
1999-06-09 06:41:32 +00:00
|
|
|
*resultSegmentLen = 0;
|
|
|
|
*resultSegment = nsnull;
|
1999-06-19 22:23:18 +00:00
|
|
|
return mCondition ? mCondition : NS_OK;
|
1999-06-05 01:15:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
amt = curSegEnd - curSegStart;
|
|
|
|
if (offset < amt) {
|
1999-06-09 06:41:32 +00:00
|
|
|
// segmentLogicalOffset is in this segment, so read up to its end
|
|
|
|
*resultSegmentLen = amt - offset;
|
|
|
|
*resultSegment = curSegStart + offset;
|
1999-06-05 01:15:00 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
curSeg = PR_NEXT_LINK(curSeg);
|
|
|
|
if (curSeg == mReadSegment) {
|
|
|
|
// been all the way around
|
1999-06-09 06:41:32 +00:00
|
|
|
*resultSegmentLen = 0;
|
|
|
|
*resultSegment = nsnull;
|
1999-06-19 22:23:18 +00:00
|
|
|
return mCondition ? mCondition : NS_OK;
|
1999-06-05 01:15:00 +00:00
|
|
|
}
|
|
|
|
curSegEnd = (char*)curSeg + mGrowBySize;
|
|
|
|
curSegStart = (char*)curSeg + sizeof(PRCList);
|
|
|
|
offset -= amt;
|
|
|
|
}
|
|
|
|
}
|
1999-04-30 22:55:12 +00:00
|
|
|
}
|
1999-06-19 22:23:18 +00:00
|
|
|
NS_NOTREACHED("nsBuffer::GetReadSegment failed");
|
1999-06-05 01:15:00 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
1999-04-30 22:55:12 +00:00
|
|
|
}
|
|
|
|
|
1999-06-15 04:57:07 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBuffer::GetReadableAmount(PRUint32 *result)
|
|
|
|
{
|
1999-06-19 22:23:18 +00:00
|
|
|
NS_ASSERTION(!mReaderClosed, "state change error");
|
|
|
|
|
|
|
|
nsAutoCMonitor mon(this);
|
1999-06-21 21:05:07 +00:00
|
|
|
*result = 0;
|
|
|
|
|
1999-06-15 04:57:07 +00:00
|
|
|
// first set the read segment and cursor if not already set
|
|
|
|
if (mReadSegment == nsnull) {
|
|
|
|
if (PR_CLIST_IS_EMPTY(&mSegments)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mReadSegment = mSegments.next;
|
|
|
|
mReadSegmentEnd = (char*)mReadSegment + mGrowBySize;
|
|
|
|
mReadCursor = (char*)mReadSegment + sizeof(PRCList);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// now search for the segment starting from segmentLogicalOffset and return it
|
|
|
|
PRCList* curSeg = mReadSegment;
|
|
|
|
char* curSegStart = mReadCursor;
|
|
|
|
char* curSegEnd = mReadSegmentEnd;
|
|
|
|
PRInt32 amt;
|
|
|
|
while (PR_TRUE) {
|
|
|
|
// snapshot the write cursor into a local variable -- this allows
|
|
|
|
// a writer to freely change it while we're reading while avoiding
|
|
|
|
// using a lock
|
|
|
|
char* snapshotWriteCursor = mWriteCursor; // atomic
|
|
|
|
|
|
|
|
// next check if the write cursor is in our segment
|
|
|
|
if (curSegStart <= snapshotWriteCursor &&
|
|
|
|
snapshotWriteCursor < curSegEnd) {
|
|
|
|
// same segment -- read up to the snapshotWriteCursor
|
|
|
|
curSegEnd = snapshotWriteCursor;
|
|
|
|
|
|
|
|
amt = curSegEnd - curSegStart;
|
|
|
|
*result += amt;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
amt = curSegEnd - curSegStart;
|
|
|
|
*result += amt;
|
|
|
|
curSeg = PR_NEXT_LINK(curSeg);
|
|
|
|
if (curSeg == mReadSegment) {
|
|
|
|
// been all the way around
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
curSegEnd = (char*)curSeg + mGrowBySize;
|
|
|
|
curSegStart = (char*)curSeg + sizeof(PRCList);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
1999-06-19 22:23:18 +00:00
|
|
|
typedef PRInt32 (*compare_t)(const char*, const char*, PRUint32);
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBuffer::Search(const char* string, PRBool ignoreCase,
|
|
|
|
PRBool *found, PRUint32 *offsetSearchedTo)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!mReaderClosed, "state change error");
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
const char* bufSeg1;
|
|
|
|
PRUint32 bufSegLen1;
|
|
|
|
PRUint32 segmentPos = 0;
|
|
|
|
PRUint32 strLen = nsCRT::strlen(string);
|
|
|
|
compare_t compare =
|
|
|
|
ignoreCase ? (compare_t)nsCRT::strncasecmp : (compare_t)nsCRT::strncmp;
|
|
|
|
|
|
|
|
rv = GetReadSegment(segmentPos, &bufSeg1, &bufSegLen1);
|
|
|
|
if (NS_FAILED(rv) || bufSegLen1 == 0) {
|
|
|
|
*found = PR_FALSE;
|
|
|
|
*offsetSearchedTo = segmentPos;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (PR_TRUE) {
|
|
|
|
PRUint32 i;
|
|
|
|
// check if the string is in the buffer segment
|
|
|
|
for (i = 0; i < bufSegLen1 - strLen + 1; i++) {
|
|
|
|
if (compare(&bufSeg1[i], string, strLen) == 0) {
|
|
|
|
*found = PR_TRUE;
|
|
|
|
*offsetSearchedTo = segmentPos + i;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the next segment
|
|
|
|
const char* bufSeg2;
|
|
|
|
PRUint32 bufSegLen2;
|
|
|
|
segmentPos += bufSegLen1;
|
|
|
|
rv = GetReadSegment(segmentPos, &bufSeg2, &bufSegLen2);
|
|
|
|
if (NS_FAILED(rv) || bufSegLen2 == 0) {
|
|
|
|
*found = PR_FALSE;
|
|
|
|
if (mCondition != NS_OK) // XXX NS_FAILED?
|
|
|
|
*offsetSearchedTo = segmentPos - bufSegLen1;
|
|
|
|
else
|
|
|
|
*offsetSearchedTo = segmentPos - bufSegLen1 - strLen + 1;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if the string is straddling the next buffer segment
|
|
|
|
PRUint32 limit = PR_MIN(strLen, bufSegLen2 + 1);
|
|
|
|
for (i = 0; i < limit; i++) {
|
|
|
|
PRUint32 strPart1Len = strLen - i - 1;
|
|
|
|
PRUint32 strPart2Len = strLen - strPart1Len;
|
|
|
|
const char* strPart2 = &string[strLen - strPart2Len];
|
|
|
|
PRUint32 bufSeg1Offset = bufSegLen1 - strPart1Len;
|
|
|
|
if (compare(&bufSeg1[bufSeg1Offset], string, strPart1Len) == 0 &&
|
|
|
|
compare(bufSeg2, strPart2, strPart2Len) == 0) {
|
|
|
|
*found = PR_TRUE;
|
|
|
|
*offsetSearchedTo = segmentPos - strPart1Len;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// finally continue with the next buffer
|
|
|
|
bufSeg1 = bufSeg2;
|
|
|
|
bufSegLen1 = bufSegLen2;
|
|
|
|
}
|
|
|
|
NS_NOTREACHED("can't get here");
|
|
|
|
return NS_ERROR_FAILURE; // keep compiler happy
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBuffer::ReaderClosed()
|
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
nsAutoCMonitor mon(this); // protect mSegments
|
|
|
|
|
|
|
|
// first prevent any more writing
|
|
|
|
mReaderClosed = PR_TRUE;
|
|
|
|
|
|
|
|
// then free any unread segments...
|
|
|
|
|
|
|
|
// first set the read segment and cursor if not already set
|
|
|
|
if (mReadSegment == nsnull) {
|
|
|
|
if (!PR_CLIST_IS_EMPTY(&mSegments)) {
|
|
|
|
mReadSegment = mSegments.next;
|
|
|
|
mReadSegmentEnd = (char*)mReadSegment + mGrowBySize;
|
|
|
|
mReadCursor = (char*)mReadSegment + sizeof(PRCList);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (mReadSegment) {
|
|
|
|
// snapshot the write cursor into a local variable -- this allows
|
|
|
|
// a writer to freely change it while we're reading while avoiding
|
|
|
|
// using a lock
|
|
|
|
char* snapshotWriteCursor = mWriteCursor; // atomic
|
|
|
|
|
|
|
|
// next check if the write cursor is in our segment
|
|
|
|
if (mReadCursor <= snapshotWriteCursor &&
|
|
|
|
snapshotWriteCursor < mReadSegmentEnd) {
|
|
|
|
// same segment -- we've discarded all the unread segments we
|
|
|
|
// can, so just updatethe read cursor
|
|
|
|
mReadCursor = mWriteCursor;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// else advance to the next segment, freeing this one
|
|
|
|
rv = PopReadSegment();
|
|
|
|
if (NS_FAILED(rv)) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
PRUint32 amt;
|
|
|
|
const char* buf;
|
|
|
|
rv = GetReadSegment(0, &buf, &amt);
|
|
|
|
NS_ASSERTION(rv == NS_BASE_STREAM_EOF ||
|
|
|
|
(NS_SUCCEEDED(rv) && amt == 0), "ReaderClosed failed");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBuffer::GetCondition(nsresult *result)
|
|
|
|
{
|
|
|
|
*result = mCondition;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-04-30 22:55:12 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
1999-06-09 04:52:47 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBuffer::WriteSegments(nsReadSegmentFun reader, void* closure, PRUint32 count,
|
|
|
|
PRUint32 *writeCount)
|
|
|
|
{
|
1999-06-19 22:23:18 +00:00
|
|
|
nsAutoCMonitor mon(this);
|
1999-06-09 04:52:47 +00:00
|
|
|
nsresult rv;
|
1999-06-19 22:23:18 +00:00
|
|
|
if (mReaderClosed)
|
|
|
|
return NS_BASE_STREAM_CLOSED;
|
1999-06-09 04:52:47 +00:00
|
|
|
|
1999-06-19 22:23:18 +00:00
|
|
|
if (NS_FAILED(mCondition))
|
|
|
|
return mCondition;
|
1999-06-09 04:52:47 +00:00
|
|
|
|
|
|
|
*writeCount = 0;
|
|
|
|
while (count > 0) {
|
|
|
|
PRUint32 writeBufLen;
|
|
|
|
char* writeBuf;
|
1999-06-09 06:41:32 +00:00
|
|
|
rv = GetWriteSegment(&writeBuf, &writeBufLen);
|
1999-06-19 22:23:18 +00:00
|
|
|
if (NS_FAILED(rv) || writeBufLen == 0) {
|
1999-06-09 04:52:47 +00:00
|
|
|
// if we failed to allocate a new segment, we're probably out
|
|
|
|
// of memory, but we don't care -- just report what we were
|
|
|
|
// able to write so far
|
1999-06-19 22:23:18 +00:00
|
|
|
return (*writeCount == 0) ? rv : NS_OK;
|
1999-06-09 04:52:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
writeBufLen = PR_MIN(writeBufLen, count);
|
|
|
|
while (writeBufLen > 0) {
|
|
|
|
PRUint32 readCount;
|
|
|
|
rv = reader(closure, writeBuf, *writeCount, writeBufLen, &readCount);
|
1999-06-19 22:23:18 +00:00
|
|
|
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
|
|
|
|
// if the place we're putting the data would block (probably ran
|
|
|
|
// out of room) just return what we were able to write so far
|
1999-06-15 04:57:07 +00:00
|
|
|
return (*writeCount == 0) ? rv : NS_OK;
|
1999-06-09 04:52:47 +00:00
|
|
|
}
|
1999-06-19 22:23:18 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
// save the failure condition so that we can get it again later
|
|
|
|
nsresult rv2 = SetCondition(rv);
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv2), "SetCondition failed");
|
1999-06-09 04:52:47 +00:00
|
|
|
// if we failed to read just report what we were
|
|
|
|
// able to write so far
|
1999-06-19 22:23:18 +00:00
|
|
|
return (*writeCount == 0) ? rv : NS_OK;
|
1999-06-09 04:52:47 +00:00
|
|
|
}
|
|
|
|
NS_ASSERTION(readCount <= writeBufLen, "reader returned bad readCount");
|
|
|
|
writeBuf += readCount;
|
|
|
|
writeBufLen -= readCount;
|
|
|
|
*writeCount += readCount;
|
|
|
|
count -= readCount;
|
|
|
|
|
|
|
|
// set the write cursor after the data is valid
|
|
|
|
if (mWriteCursor + readCount == mWriteSegmentEnd) {
|
|
|
|
mWriteSegment = nsnull; // allocate a new segment next time around
|
|
|
|
mWriteSegmentEnd = nsnull;
|
|
|
|
mWriteCursor = nsnull;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
mWriteCursor += readCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-06-15 04:57:07 +00:00
|
|
|
static NS_METHOD
|
1999-06-09 04:52:47 +00:00
|
|
|
nsReadFromRawBuffer(void* closure,
|
|
|
|
char* toRawSegment,
|
|
|
|
PRUint32 offset,
|
|
|
|
PRUint32 count,
|
|
|
|
PRUint32 *readCount)
|
|
|
|
{
|
|
|
|
const char* fromBuf = (const char*)closure;
|
|
|
|
nsCRT::memcpy(toRawSegment, &fromBuf[offset], count);
|
|
|
|
*readCount = count;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-04-30 22:55:12 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBuffer::Write(const char* fromBuf, PRUint32 bufLen, PRUint32 *writeCount)
|
|
|
|
{
|
1999-06-09 04:52:47 +00:00
|
|
|
return WriteSegments(nsReadFromRawBuffer, (void*)fromBuf, bufLen, writeCount);
|
|
|
|
}
|
|
|
|
|
1999-06-15 04:57:07 +00:00
|
|
|
static NS_METHOD
|
1999-06-09 04:52:47 +00:00
|
|
|
nsReadFromInputStream(void* closure,
|
|
|
|
char* toRawSegment,
|
|
|
|
PRUint32 offset,
|
|
|
|
PRUint32 count,
|
|
|
|
PRUint32 *readCount)
|
|
|
|
{
|
|
|
|
nsIInputStream* fromStream = (nsIInputStream*)closure;
|
|
|
|
return fromStream->Read(toRawSegment, count, readCount);
|
1999-04-30 22:55:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-06-03 21:51:09 +00:00
|
|
|
nsBuffer::WriteFrom(nsIInputStream* fromStream, PRUint32 count, PRUint32 *writeCount)
|
1999-04-30 22:55:12 +00:00
|
|
|
{
|
1999-06-09 04:52:47 +00:00
|
|
|
return WriteSegments(nsReadFromInputStream, fromStream, count, writeCount);
|
1999-04-30 22:55:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-06-09 06:41:32 +00:00
|
|
|
nsBuffer::GetWriteSegment(char* *resultSegment,
|
|
|
|
PRUint32 *resultSegmentLen)
|
1999-04-30 22:55:12 +00:00
|
|
|
{
|
1999-06-19 22:23:18 +00:00
|
|
|
nsAutoCMonitor mon(this);
|
|
|
|
if (mReaderClosed)
|
|
|
|
return NS_BASE_STREAM_CLOSED;
|
1999-04-30 22:55:12 +00:00
|
|
|
|
|
|
|
nsresult rv;
|
1999-06-19 22:23:18 +00:00
|
|
|
*resultSegmentLen = 0;
|
|
|
|
*resultSegment = nsnull;
|
1999-04-30 22:55:12 +00:00
|
|
|
if (mWriteSegment == nsnull) {
|
|
|
|
rv = PushWriteSegment();
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
NS_ASSERTION(mWriteSegment != nsnull, "failed to allocate segment");
|
|
|
|
}
|
|
|
|
|
1999-06-09 06:41:32 +00:00
|
|
|
*resultSegmentLen = mWriteSegmentEnd - mWriteCursor;
|
|
|
|
*resultSegment = mWriteCursor;
|
1999-06-19 22:23:18 +00:00
|
|
|
NS_ASSERTION(*resultSegmentLen > 0, "Failed to get write segment.");
|
1999-04-30 22:55:12 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-06-15 04:57:07 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBuffer::GetWritableAmount(PRUint32 *amount)
|
|
|
|
{
|
1999-06-19 22:23:18 +00:00
|
|
|
if (mReaderClosed)
|
|
|
|
return NS_BASE_STREAM_CLOSED;
|
|
|
|
|
1999-06-15 04:57:07 +00:00
|
|
|
nsresult rv;
|
|
|
|
PRUint32 readableAmount;
|
|
|
|
rv = GetReadableAmount(&readableAmount);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
*amount = mMaxSize - readableAmount;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-04-30 22:55:12 +00:00
|
|
|
NS_IMETHODIMP
|
1999-06-19 22:23:18 +00:00
|
|
|
nsBuffer::GetReaderClosed(PRBool *result)
|
1999-04-30 22:55:12 +00:00
|
|
|
{
|
1999-06-19 22:23:18 +00:00
|
|
|
*result = mReaderClosed;
|
1999-06-05 01:15:00 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-06-19 22:23:18 +00:00
|
|
|
nsBuffer::SetCondition(nsresult condition)
|
1999-06-05 01:15:00 +00:00
|
|
|
{
|
1999-06-19 22:23:18 +00:00
|
|
|
nsAutoCMonitor mon(this);
|
|
|
|
if (mReaderClosed)
|
|
|
|
return NS_BASE_STREAM_CLOSED;
|
1999-06-05 01:15:00 +00:00
|
|
|
|
1999-06-19 22:23:18 +00:00
|
|
|
mCondition = condition;
|
|
|
|
mWriteSegment = nsnull; // allows reader to free last segment w/o asserting
|
|
|
|
mWriteSegmentEnd = nsnull;
|
|
|
|
// don't reset mWriteCursor here -- we need it for the EOF point in the buffer
|
|
|
|
return NS_OK;
|
1999-06-05 01:15:00 +00:00
|
|
|
}
|
|
|
|
|
1999-04-30 22:55:12 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
static NS_DEFINE_CID(kAllocatorCID, NS_ALLOCATOR_CID);
|
|
|
|
|
1999-05-26 01:38:36 +00:00
|
|
|
NS_COM nsresult
|
1999-04-30 22:55:12 +00:00
|
|
|
NS_NewBuffer(nsIBuffer* *result,
|
1999-06-15 04:57:07 +00:00
|
|
|
PRUint32 growBySize, PRUint32 maxSize,
|
|
|
|
nsIBufferObserver* observer)
|
1999-04-30 22:55:12 +00:00
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
NS_WITH_SERVICE(nsIAllocator, alloc, kAllocatorCID, &rv);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
1999-05-26 01:38:36 +00:00
|
|
|
nsBuffer* buf;
|
|
|
|
rv = nsBuffer::Create(NULL, nsIBuffer::GetIID(), (void**)&buf);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
1999-04-30 22:55:12 +00:00
|
|
|
|
1999-06-15 04:57:07 +00:00
|
|
|
rv = buf->Init(growBySize, maxSize, observer, alloc);
|
1999-04-30 22:55:12 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
1999-05-26 01:38:36 +00:00
|
|
|
NS_RELEASE(buf);
|
1999-04-30 22:55:12 +00:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
*result = buf;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static NS_DEFINE_CID(kPageManagerCID, NS_PAGEMANAGER_CID);
|
|
|
|
|
1999-05-26 01:38:36 +00:00
|
|
|
NS_COM nsresult
|
1999-04-30 22:55:12 +00:00
|
|
|
NS_NewPageBuffer(nsIBuffer* *result,
|
1999-06-15 04:57:07 +00:00
|
|
|
PRUint32 growBySize, PRUint32 maxSize,
|
|
|
|
nsIBufferObserver* observer)
|
1999-04-30 22:55:12 +00:00
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
NS_WITH_SERVICE(nsIAllocator, alloc, kPageManagerCID, &rv);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
1999-05-26 01:38:36 +00:00
|
|
|
nsBuffer* buf;
|
|
|
|
rv = nsBuffer::Create(NULL, nsIBuffer::GetIID(), (void**)&buf);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
1999-04-30 22:55:12 +00:00
|
|
|
|
1999-06-15 04:57:07 +00:00
|
|
|
rv = buf->Init(growBySize, maxSize, observer, alloc);
|
1999-04-30 22:55:12 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
1999-05-26 01:38:36 +00:00
|
|
|
NS_RELEASE(buf);
|
1999-04-30 22:55:12 +00:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
*result = buf;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|