(again) bug 116023 Parser recycling buffers. Protects all cases of

usage of mCurrentPosition without checking mSlidingBuffer. r=harishd,
sr=sfraser, a=asa
This commit is contained in:
dp%netscape.com 2002-03-07 15:43:12 +00:00
parent 74a917c925
commit 6164595e54
6 changed files with 252 additions and 74 deletions

View File

@ -53,6 +53,7 @@
//#include "nsTextTokenizer.h" //#include "nsTextTokenizer.h"
#include "nsElementTable.h" #include "nsElementTable.h"
#include "nsParserService.h" #include "nsParserService.h"
#include "nsScanner.h"
#ifdef NS_DEBUG #ifdef NS_DEBUG
#include "nsLoggingSink.h" #include "nsLoggingSink.h"
@ -118,6 +119,8 @@ Shutdown(nsIModule* aSelf)
DeleteElementTable(); DeleteElementTable();
CNewlineToken::FreeNewline(); CNewlineToken::FreeNewline();
gInitialized = PR_FALSE; gInitialized = PR_FALSE;
delete nsScanner::gAllocator;
nsScanner::gAllocator = nsnull;
} }
} }

View File

@ -46,9 +46,48 @@
#include "nsFileSpec.h" #include "nsFileSpec.h"
#include "nsReadableUtils.h" #include "nsReadableUtils.h"
nsScannerString::nsScannerString(PRUnichar* aStorageStart, nsRecyclingAllocator* nsScanner::gAllocator = nsnull;
PRUnichar* aDataEnd,
PRUnichar* aStorageEnd) : nsSlidingString(aStorageStart, aDataEnd, aStorageEnd) static void nsScannerRecycle(void *aPtr, void *aClientData)
{
nsScanner::gAllocator->Free(aPtr);
}
static void *nsScannerAllocate(PRUint32 size)
{
return nsScanner::gAllocator->Malloc(size);
}
/**
* Helper funciton to convert raw 8bit char * to unicode
*
* aStr : input 8bit string
* aLen : length of input string aStr
* aDest : Destination unicode buffer. Null terminated.
* aDestLength : size of destination buffer. Must be atleast aLen+1.
*
* return 0 if conversion succeeded
* returns -1, if there is not enough space in destination buffer,
*/
static int RawToUnicode(const char *aStr, PRInt32 aLen, PRUnichar *aDest, PRUint32 aDestLength)
{
// Alert if someone if passing null buffers to us
NS_ASSERTION(aStr && aDest, "Null buffers");
// Error checking
if (!aStr || !aDest || (PRInt32)aDestLength < aLen+1)
return -1;
while (*aStr)
*aDest++ = (PRUnichar) (unsigned char) *aStr++;
*aDest = 0;
return 0;
}
nsScannerString::nsScannerString(PRUnichar* aStorageStart, PRUnichar* aDataEnd,
PRUnichar* aStorageEnd, nsFreeProc *aFreeProc)
: nsSlidingString(aStorageStart, aDataEnd, aStorageEnd, aFreeProc)
{ {
} }
@ -107,14 +146,17 @@ MOZ_DECL_CTOR_COUNTER(nsScanner)
nsScanner::nsScanner(const nsAString& anHTMLString, const nsString& aCharset, PRInt32 aSource) nsScanner::nsScanner(const nsAString& anHTMLString, const nsString& aCharset, PRInt32 aSource)
{ {
MOZ_COUNT_CTOR(nsScanner); MOZ_COUNT_CTOR(nsScanner);
InitAllocator();
PRUnichar* buffer = ToNewUnicode(anHTMLString);
mTotalRead = anHTMLString.Length();
mSlidingBuffer = nsnull; mSlidingBuffer = nsnull;
mTotalRead = anHTMLString.Length();
if (mTotalRead) {
// Append to buffer will take care of initializing mCurrentPosition
// and mMarkPosition. If we didnt get here, mCurrentPosition and
// mMarkPosition would be uninitialized and hence we protect using these
// variables with if (mSlidingBuffer) checks all over the code.
AppendToBuffer(anHTMLString);
}
mCountRemaining = 0; mCountRemaining = 0;
AppendToBuffer(buffer, buffer+mTotalRead, buffer+mTotalRead);
mSlidingBuffer->BeginReading(mCurrentPosition);
mMarkPosition = mCurrentPosition;
mIncremental=PR_FALSE; mIncremental=PR_FALSE;
mOwnsStream=PR_FALSE; mOwnsStream=PR_FALSE;
mInputStream=0; mInputStream=0;
@ -137,7 +179,7 @@ nsScanner::nsScanner(nsString& aFilename,PRBool aCreateStream, const nsString& a
mFilename(aFilename) mFilename(aFilename)
{ {
MOZ_COUNT_CTOR(nsScanner); MOZ_COUNT_CTOR(nsScanner);
InitAllocator();
mSlidingBuffer = nsnull; mSlidingBuffer = nsnull;
mIncremental=PR_TRUE; mIncremental=PR_TRUE;
mCountRemaining = 0; mCountRemaining = 0;
@ -166,7 +208,7 @@ nsScanner::nsScanner(const nsAString& aFilename,nsInputStream& aStream,const nsS
mFilename(aFilename) mFilename(aFilename)
{ {
MOZ_COUNT_CTOR(nsScanner); MOZ_COUNT_CTOR(nsScanner);
InitAllocator();
mSlidingBuffer = nsnull; mSlidingBuffer = nsnull;
mIncremental=PR_FALSE; mIncremental=PR_FALSE;
mCountRemaining = 0; mCountRemaining = 0;
@ -262,8 +304,10 @@ nsScanner::~nsScanner() {
* @return * @return
*/ */
void nsScanner::RewindToMark(void){ void nsScanner::RewindToMark(void){
mCountRemaining += (Distance(mMarkPosition, mCurrentPosition)); if (mSlidingBuffer) {
mCurrentPosition = mMarkPosition; mCountRemaining += (Distance(mMarkPosition, mCurrentPosition));
mCurrentPosition = mMarkPosition;
}
} }
@ -293,9 +337,15 @@ void nsScanner::Mark() {
*/ */
PRBool nsScanner::UngetReadable(const nsAReadableString& aBuffer) { PRBool nsScanner::UngetReadable(const nsAReadableString& aBuffer) {
mSlidingBuffer->UngetReadable(aBuffer,mCurrentPosition); if (!mSlidingBuffer) {
mSlidingBuffer->BeginReading(mCurrentPosition); // Insertion invalidated our iterators // This happens to be the first buffer. Just append it.
mSlidingBuffer->EndReading(mEndPosition); AppendToBuffer(aBuffer);
}
else {
mSlidingBuffer->UngetReadable(aBuffer,mCurrentPosition);
mSlidingBuffer->BeginReading(mCurrentPosition); // Insertion invalidated our iterators
mSlidingBuffer->EndReading(mEndPosition);
}
mTotalRead += aBuffer.Length(); mTotalRead += aBuffer.Length();
return PR_TRUE; return PR_TRUE;
@ -309,12 +359,8 @@ PRBool nsScanner::UngetReadable(const nsAReadableString& aBuffer) {
* @return error code * @return error code
*/ */
nsresult nsScanner::Append(const nsAReadableString& aBuffer) { nsresult nsScanner::Append(const nsAReadableString& aBuffer) {
AppendToBuffer(aBuffer);
PRUnichar* buffer = ToNewUnicode(aBuffer); mTotalRead += aBuffer.Length();
PRUint32 bufLen = aBuffer.Length();
mTotalRead += bufLen;
AppendToBuffer(buffer, buffer+bufLen, buffer+bufLen);
return NS_OK; return NS_OK;
} }
@ -332,8 +378,8 @@ nsresult nsScanner::Append(const char* aBuffer, PRUint32 aLen){
if(mUnicodeDecoder) { if(mUnicodeDecoder) {
PRInt32 unicharBufLen = 0; PRInt32 unicharBufLen = 0;
mUnicodeDecoder->GetMaxLength(aBuffer, aLen, &unicharBufLen); mUnicodeDecoder->GetMaxLength(aBuffer, aLen, &unicharBufLen);
start = unichars = (PRUnichar*)nsMemory::Alloc((unicharBufLen+1) * sizeof(PRUnichar)); start = unichars = (PRUnichar*) nsScannerAllocate((unicharBufLen+1) * sizeof(PRUnichar));
NS_ENSURE_TRUE(unichars,NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_TRUE(unichars, NS_ERROR_OUT_OF_MEMORY);
PRInt32 totalChars = 0; PRInt32 totalChars = 0;
PRInt32 unicharLength = unicharBufLen; PRInt32 unicharLength = unicharBufLen;
@ -375,9 +421,7 @@ nsresult nsScanner::Append(const char* aBuffer, PRUint32 aLen){
res = NS_OK; res = NS_OK;
} }
else { else {
nsDependentCString str(aBuffer, aLen); AppendToBuffer(aBuffer, aLen);
unichars = ToNewUnicode(str);
AppendToBuffer(unichars, unichars+aLen, unichars+aLen);
mTotalRead+=aLen; mTotalRead+=aLen;
} }
@ -411,23 +455,18 @@ nsresult nsScanner::FillBuffer(void) {
} }
else { else {
PRInt32 numread=0; PRInt32 numread=0;
char* buf = new char[kBufsize+1]; char buf[kBufsize+1];
buf[kBufsize]=0; buf[kBufsize]=0;
if(mInputStream) { if(mInputStream) {
numread = mInputStream->read(buf, kBufsize); numread = mInputStream->read(buf, kBufsize);
if (0 == numread) { if (0 == numread)
delete [] buf;
return kEOF; return kEOF;
}
} }
if((0<numread) && (0==result)) { if((0<numread) && (0==result)) {
nsDependentCString str(buf, numread); AppendToBuffer(buf, numread);
PRUnichar* unichars = ToNewUnicode(str);
AppendToBuffer(unichars, unichars+numread, unichars+kBufsize+1);
} }
delete [] buf;
mTotalRead+=numread; mTotalRead+=numread;
} }
@ -1359,11 +1398,13 @@ void nsScanner::BindSubstring(nsSlidingSubstring& aSubstring, const nsReadingIte
void nsScanner::CurrentPosition(nsReadingIterator<PRUnichar>& aPosition) void nsScanner::CurrentPosition(nsReadingIterator<PRUnichar>& aPosition)
{ {
NS_ASSERTION(mSlidingBuffer, "No data yet. CurrentPosition in invalid");
aPosition = mCurrentPosition; aPosition = mCurrentPosition;
} }
void nsScanner::EndReading(nsReadingIterator<PRUnichar>& aPosition) void nsScanner::EndReading(nsReadingIterator<PRUnichar>& aPosition)
{ {
NS_ASSERTION(mSlidingBuffer, "No data yet. EndPosition in invalid");
aPosition = mEndPosition; aPosition = mEndPosition;
} }
@ -1392,12 +1433,32 @@ void nsScanner::ReplaceCharacter(nsReadingIterator<PRUnichar>& aPosition,
} }
} }
void nsScanner::AppendToBuffer(const nsAString &aData)
{
PRUint32 len = aData.Length();
PRUnichar* buffer = (PRUnichar *) nsScannerAllocate(len * sizeof(PRUnichar));
if (buffer) {
CopyUnicodeTo(aData, 0, buffer, len);
AppendToBuffer(buffer, buffer+len, buffer+len);
}
}
void nsScanner::AppendToBuffer(const char *aData, PRUint32 aLen)
{
PRUnichar *buffer = (PRUnichar*) nsScannerAllocate((aLen+1) * sizeof(PRUnichar));
if (buffer)
{
RawToUnicode(aData, aLen, buffer, aLen+1);
AppendToBuffer(buffer, buffer+aLen, buffer+aLen);
}
}
void nsScanner::AppendToBuffer(PRUnichar* aStorageStart, void nsScanner::AppendToBuffer(PRUnichar* aStorageStart,
PRUnichar* aDataEnd, PRUnichar* aDataEnd,
PRUnichar* aStorageEnd) PRUnichar* aStorageEnd)
{ {
if (!mSlidingBuffer) { if (!mSlidingBuffer) {
mSlidingBuffer = new nsScannerString(aStorageStart, aDataEnd, aStorageEnd); mSlidingBuffer = new nsScannerString(aStorageStart, aDataEnd, aStorageEnd, nsScannerRecycle);
mSlidingBuffer->BeginReading(mCurrentPosition); mSlidingBuffer->BeginReading(mCurrentPosition);
mMarkPosition = mCurrentPosition; mMarkPosition = mCurrentPosition;
mSlidingBuffer->EndReading(mEndPosition); mSlidingBuffer->EndReading(mEndPosition);
@ -1422,6 +1483,9 @@ void nsScanner::AppendToBuffer(PRUnichar* aStorageStart,
* @return nada * @return nada
*/ */
void nsScanner::CopyUnusedData(nsString& aCopyBuffer) { void nsScanner::CopyUnusedData(nsString& aCopyBuffer) {
if (!mSlidingBuffer)
return;
nsReadingIterator<PRUnichar> start, end; nsReadingIterator<PRUnichar> start, end;
start = mCurrentPosition; start = mCurrentPosition;
end = mEndPosition; end = mEndPosition;

View File

@ -58,12 +58,17 @@
#include "nsIUnicodeDecoder.h" #include "nsIUnicodeDecoder.h"
#include "nsFileStream.h" #include "nsFileStream.h"
#include "nsSlidingString.h" #include "nsSlidingString.h"
#include "nsRecyclingAllocator.h"
// Recycling memory used by scanner
#define NS_SCANNER_BUCKETS 10
class nsScannerString : public nsSlidingString { class nsScannerString : public nsSlidingString {
public: public:
nsScannerString(PRUnichar* aStorageStart, nsScannerString(PRUnichar* aStorageStart,
PRUnichar* aDataEnd, PRUnichar* aDataEnd,
PRUnichar* aStorageEnd); PRUnichar* aStorageEnd,
nsFreeProc* aFreeProc);
virtual void UngetReadable(const nsAReadableString& aReadable, const nsReadingIterator<PRUnichar>& aCurrentPosition) { InsertReadable(aReadable,aCurrentPosition); } virtual void UngetReadable(const nsAReadableString& aReadable, const nsReadingIterator<PRUnichar>& aCurrentPosition) { InsertReadable(aReadable,aCurrentPosition); }
virtual void ReplaceCharacter(nsReadingIterator<PRUnichar>& aPosition, virtual void ReplaceCharacter(nsReadingIterator<PRUnichar>& aPosition,
@ -382,6 +387,19 @@ class nsScanner {
PRUnichar* aDataEnd, PRUnichar* aDataEnd,
PRUnichar* aStorageEnd); PRUnichar* aStorageEnd);
/**
* These versions of AppendToBuffer allocate from the recyclingallocator,
* convert to unicode if necessary and then add the buffer into the sliding
* string
*/
void AppendToBuffer(const nsAString &aData);
void AppendToBuffer(const char* aData, PRUint32 aLen);
static void InitAllocator() {
if (!gAllocator)
gAllocator = new nsRecyclingAllocator(NS_SCANNER_BUCKETS, NS_DEFAULT_RECYCLE_TIMEOUT, "parser");
}
nsInputStream* mInputStream; nsInputStream* mInputStream;
nsScannerString* mSlidingBuffer; nsScannerString* mSlidingBuffer;
nsReadingIterator<PRUnichar> mCurrentPosition; // The position we will next read from in the scanner buffer nsReadingIterator<PRUnichar> mCurrentPosition; // The position we will next read from in the scanner buffer
@ -397,6 +415,10 @@ class nsScanner {
nsString mCharset; nsString mCharset;
nsIUnicodeDecoder *mUnicodeDecoder; nsIUnicodeDecoder *mUnicodeDecoder;
PRInt32 mNewlinesSkipped; PRInt32 mNewlinesSkipped;
public:
// Allocator to recycle memory used by scanner
static nsRecyclingAllocator *gAllocator;
}; };
#endif #endif

View File

@ -53,6 +53,7 @@
//#include "nsTextTokenizer.h" //#include "nsTextTokenizer.h"
#include "nsElementTable.h" #include "nsElementTable.h"
#include "nsParserService.h" #include "nsParserService.h"
#include "nsScanner.h"
#ifdef NS_DEBUG #ifdef NS_DEBUG
#include "nsLoggingSink.h" #include "nsLoggingSink.h"
@ -118,6 +119,8 @@ Shutdown(nsIModule* aSelf)
DeleteElementTable(); DeleteElementTable();
CNewlineToken::FreeNewline(); CNewlineToken::FreeNewline();
gInitialized = PR_FALSE; gInitialized = PR_FALSE;
delete nsScanner::gAllocator;
nsScanner::gAllocator = nsnull;
} }
} }

View File

@ -46,9 +46,48 @@
#include "nsFileSpec.h" #include "nsFileSpec.h"
#include "nsReadableUtils.h" #include "nsReadableUtils.h"
nsScannerString::nsScannerString(PRUnichar* aStorageStart, nsRecyclingAllocator* nsScanner::gAllocator = nsnull;
PRUnichar* aDataEnd,
PRUnichar* aStorageEnd) : nsSlidingString(aStorageStart, aDataEnd, aStorageEnd) static void nsScannerRecycle(void *aPtr, void *aClientData)
{
nsScanner::gAllocator->Free(aPtr);
}
static void *nsScannerAllocate(PRUint32 size)
{
return nsScanner::gAllocator->Malloc(size);
}
/**
* Helper funciton to convert raw 8bit char * to unicode
*
* aStr : input 8bit string
* aLen : length of input string aStr
* aDest : Destination unicode buffer. Null terminated.
* aDestLength : size of destination buffer. Must be atleast aLen+1.
*
* return 0 if conversion succeeded
* returns -1, if there is not enough space in destination buffer,
*/
static int RawToUnicode(const char *aStr, PRInt32 aLen, PRUnichar *aDest, PRUint32 aDestLength)
{
// Alert if someone if passing null buffers to us
NS_ASSERTION(aStr && aDest, "Null buffers");
// Error checking
if (!aStr || !aDest || (PRInt32)aDestLength < aLen+1)
return -1;
while (*aStr)
*aDest++ = (PRUnichar) (unsigned char) *aStr++;
*aDest = 0;
return 0;
}
nsScannerString::nsScannerString(PRUnichar* aStorageStart, PRUnichar* aDataEnd,
PRUnichar* aStorageEnd, nsFreeProc *aFreeProc)
: nsSlidingString(aStorageStart, aDataEnd, aStorageEnd, aFreeProc)
{ {
} }
@ -107,14 +146,17 @@ MOZ_DECL_CTOR_COUNTER(nsScanner)
nsScanner::nsScanner(const nsAString& anHTMLString, const nsString& aCharset, PRInt32 aSource) nsScanner::nsScanner(const nsAString& anHTMLString, const nsString& aCharset, PRInt32 aSource)
{ {
MOZ_COUNT_CTOR(nsScanner); MOZ_COUNT_CTOR(nsScanner);
InitAllocator();
PRUnichar* buffer = ToNewUnicode(anHTMLString);
mTotalRead = anHTMLString.Length();
mSlidingBuffer = nsnull; mSlidingBuffer = nsnull;
mTotalRead = anHTMLString.Length();
if (mTotalRead) {
// Append to buffer will take care of initializing mCurrentPosition
// and mMarkPosition. If we didnt get here, mCurrentPosition and
// mMarkPosition would be uninitialized and hence we protect using these
// variables with if (mSlidingBuffer) checks all over the code.
AppendToBuffer(anHTMLString);
}
mCountRemaining = 0; mCountRemaining = 0;
AppendToBuffer(buffer, buffer+mTotalRead, buffer+mTotalRead);
mSlidingBuffer->BeginReading(mCurrentPosition);
mMarkPosition = mCurrentPosition;
mIncremental=PR_FALSE; mIncremental=PR_FALSE;
mOwnsStream=PR_FALSE; mOwnsStream=PR_FALSE;
mInputStream=0; mInputStream=0;
@ -137,7 +179,7 @@ nsScanner::nsScanner(nsString& aFilename,PRBool aCreateStream, const nsString& a
mFilename(aFilename) mFilename(aFilename)
{ {
MOZ_COUNT_CTOR(nsScanner); MOZ_COUNT_CTOR(nsScanner);
InitAllocator();
mSlidingBuffer = nsnull; mSlidingBuffer = nsnull;
mIncremental=PR_TRUE; mIncremental=PR_TRUE;
mCountRemaining = 0; mCountRemaining = 0;
@ -166,7 +208,7 @@ nsScanner::nsScanner(const nsAString& aFilename,nsInputStream& aStream,const nsS
mFilename(aFilename) mFilename(aFilename)
{ {
MOZ_COUNT_CTOR(nsScanner); MOZ_COUNT_CTOR(nsScanner);
InitAllocator();
mSlidingBuffer = nsnull; mSlidingBuffer = nsnull;
mIncremental=PR_FALSE; mIncremental=PR_FALSE;
mCountRemaining = 0; mCountRemaining = 0;
@ -262,8 +304,10 @@ nsScanner::~nsScanner() {
* @return * @return
*/ */
void nsScanner::RewindToMark(void){ void nsScanner::RewindToMark(void){
mCountRemaining += (Distance(mMarkPosition, mCurrentPosition)); if (mSlidingBuffer) {
mCurrentPosition = mMarkPosition; mCountRemaining += (Distance(mMarkPosition, mCurrentPosition));
mCurrentPosition = mMarkPosition;
}
} }
@ -293,9 +337,15 @@ void nsScanner::Mark() {
*/ */
PRBool nsScanner::UngetReadable(const nsAReadableString& aBuffer) { PRBool nsScanner::UngetReadable(const nsAReadableString& aBuffer) {
mSlidingBuffer->UngetReadable(aBuffer,mCurrentPosition); if (!mSlidingBuffer) {
mSlidingBuffer->BeginReading(mCurrentPosition); // Insertion invalidated our iterators // This happens to be the first buffer. Just append it.
mSlidingBuffer->EndReading(mEndPosition); AppendToBuffer(aBuffer);
}
else {
mSlidingBuffer->UngetReadable(aBuffer,mCurrentPosition);
mSlidingBuffer->BeginReading(mCurrentPosition); // Insertion invalidated our iterators
mSlidingBuffer->EndReading(mEndPosition);
}
mTotalRead += aBuffer.Length(); mTotalRead += aBuffer.Length();
return PR_TRUE; return PR_TRUE;
@ -309,12 +359,8 @@ PRBool nsScanner::UngetReadable(const nsAReadableString& aBuffer) {
* @return error code * @return error code
*/ */
nsresult nsScanner::Append(const nsAReadableString& aBuffer) { nsresult nsScanner::Append(const nsAReadableString& aBuffer) {
AppendToBuffer(aBuffer);
PRUnichar* buffer = ToNewUnicode(aBuffer); mTotalRead += aBuffer.Length();
PRUint32 bufLen = aBuffer.Length();
mTotalRead += bufLen;
AppendToBuffer(buffer, buffer+bufLen, buffer+bufLen);
return NS_OK; return NS_OK;
} }
@ -332,8 +378,8 @@ nsresult nsScanner::Append(const char* aBuffer, PRUint32 aLen){
if(mUnicodeDecoder) { if(mUnicodeDecoder) {
PRInt32 unicharBufLen = 0; PRInt32 unicharBufLen = 0;
mUnicodeDecoder->GetMaxLength(aBuffer, aLen, &unicharBufLen); mUnicodeDecoder->GetMaxLength(aBuffer, aLen, &unicharBufLen);
start = unichars = (PRUnichar*)nsMemory::Alloc((unicharBufLen+1) * sizeof(PRUnichar)); start = unichars = (PRUnichar*) nsScannerAllocate((unicharBufLen+1) * sizeof(PRUnichar));
NS_ENSURE_TRUE(unichars,NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_TRUE(unichars, NS_ERROR_OUT_OF_MEMORY);
PRInt32 totalChars = 0; PRInt32 totalChars = 0;
PRInt32 unicharLength = unicharBufLen; PRInt32 unicharLength = unicharBufLen;
@ -375,9 +421,7 @@ nsresult nsScanner::Append(const char* aBuffer, PRUint32 aLen){
res = NS_OK; res = NS_OK;
} }
else { else {
nsDependentCString str(aBuffer, aLen); AppendToBuffer(aBuffer, aLen);
unichars = ToNewUnicode(str);
AppendToBuffer(unichars, unichars+aLen, unichars+aLen);
mTotalRead+=aLen; mTotalRead+=aLen;
} }
@ -411,23 +455,18 @@ nsresult nsScanner::FillBuffer(void) {
} }
else { else {
PRInt32 numread=0; PRInt32 numread=0;
char* buf = new char[kBufsize+1]; char buf[kBufsize+1];
buf[kBufsize]=0; buf[kBufsize]=0;
if(mInputStream) { if(mInputStream) {
numread = mInputStream->read(buf, kBufsize); numread = mInputStream->read(buf, kBufsize);
if (0 == numread) { if (0 == numread)
delete [] buf;
return kEOF; return kEOF;
}
} }
if((0<numread) && (0==result)) { if((0<numread) && (0==result)) {
nsDependentCString str(buf, numread); AppendToBuffer(buf, numread);
PRUnichar* unichars = ToNewUnicode(str);
AppendToBuffer(unichars, unichars+numread, unichars+kBufsize+1);
} }
delete [] buf;
mTotalRead+=numread; mTotalRead+=numread;
} }
@ -1359,11 +1398,13 @@ void nsScanner::BindSubstring(nsSlidingSubstring& aSubstring, const nsReadingIte
void nsScanner::CurrentPosition(nsReadingIterator<PRUnichar>& aPosition) void nsScanner::CurrentPosition(nsReadingIterator<PRUnichar>& aPosition)
{ {
NS_ASSERTION(mSlidingBuffer, "No data yet. CurrentPosition in invalid");
aPosition = mCurrentPosition; aPosition = mCurrentPosition;
} }
void nsScanner::EndReading(nsReadingIterator<PRUnichar>& aPosition) void nsScanner::EndReading(nsReadingIterator<PRUnichar>& aPosition)
{ {
NS_ASSERTION(mSlidingBuffer, "No data yet. EndPosition in invalid");
aPosition = mEndPosition; aPosition = mEndPosition;
} }
@ -1392,12 +1433,32 @@ void nsScanner::ReplaceCharacter(nsReadingIterator<PRUnichar>& aPosition,
} }
} }
void nsScanner::AppendToBuffer(const nsAString &aData)
{
PRUint32 len = aData.Length();
PRUnichar* buffer = (PRUnichar *) nsScannerAllocate(len * sizeof(PRUnichar));
if (buffer) {
CopyUnicodeTo(aData, 0, buffer, len);
AppendToBuffer(buffer, buffer+len, buffer+len);
}
}
void nsScanner::AppendToBuffer(const char *aData, PRUint32 aLen)
{
PRUnichar *buffer = (PRUnichar*) nsScannerAllocate((aLen+1) * sizeof(PRUnichar));
if (buffer)
{
RawToUnicode(aData, aLen, buffer, aLen+1);
AppendToBuffer(buffer, buffer+aLen, buffer+aLen);
}
}
void nsScanner::AppendToBuffer(PRUnichar* aStorageStart, void nsScanner::AppendToBuffer(PRUnichar* aStorageStart,
PRUnichar* aDataEnd, PRUnichar* aDataEnd,
PRUnichar* aStorageEnd) PRUnichar* aStorageEnd)
{ {
if (!mSlidingBuffer) { if (!mSlidingBuffer) {
mSlidingBuffer = new nsScannerString(aStorageStart, aDataEnd, aStorageEnd); mSlidingBuffer = new nsScannerString(aStorageStart, aDataEnd, aStorageEnd, nsScannerRecycle);
mSlidingBuffer->BeginReading(mCurrentPosition); mSlidingBuffer->BeginReading(mCurrentPosition);
mMarkPosition = mCurrentPosition; mMarkPosition = mCurrentPosition;
mSlidingBuffer->EndReading(mEndPosition); mSlidingBuffer->EndReading(mEndPosition);
@ -1422,6 +1483,9 @@ void nsScanner::AppendToBuffer(PRUnichar* aStorageStart,
* @return nada * @return nada
*/ */
void nsScanner::CopyUnusedData(nsString& aCopyBuffer) { void nsScanner::CopyUnusedData(nsString& aCopyBuffer) {
if (!mSlidingBuffer)
return;
nsReadingIterator<PRUnichar> start, end; nsReadingIterator<PRUnichar> start, end;
start = mCurrentPosition; start = mCurrentPosition;
end = mEndPosition; end = mEndPosition;

View File

@ -58,12 +58,17 @@
#include "nsIUnicodeDecoder.h" #include "nsIUnicodeDecoder.h"
#include "nsFileStream.h" #include "nsFileStream.h"
#include "nsSlidingString.h" #include "nsSlidingString.h"
#include "nsRecyclingAllocator.h"
// Recycling memory used by scanner
#define NS_SCANNER_BUCKETS 10
class nsScannerString : public nsSlidingString { class nsScannerString : public nsSlidingString {
public: public:
nsScannerString(PRUnichar* aStorageStart, nsScannerString(PRUnichar* aStorageStart,
PRUnichar* aDataEnd, PRUnichar* aDataEnd,
PRUnichar* aStorageEnd); PRUnichar* aStorageEnd,
nsFreeProc* aFreeProc);
virtual void UngetReadable(const nsAReadableString& aReadable, const nsReadingIterator<PRUnichar>& aCurrentPosition) { InsertReadable(aReadable,aCurrentPosition); } virtual void UngetReadable(const nsAReadableString& aReadable, const nsReadingIterator<PRUnichar>& aCurrentPosition) { InsertReadable(aReadable,aCurrentPosition); }
virtual void ReplaceCharacter(nsReadingIterator<PRUnichar>& aPosition, virtual void ReplaceCharacter(nsReadingIterator<PRUnichar>& aPosition,
@ -382,6 +387,19 @@ class nsScanner {
PRUnichar* aDataEnd, PRUnichar* aDataEnd,
PRUnichar* aStorageEnd); PRUnichar* aStorageEnd);
/**
* These versions of AppendToBuffer allocate from the recyclingallocator,
* convert to unicode if necessary and then add the buffer into the sliding
* string
*/
void AppendToBuffer(const nsAString &aData);
void AppendToBuffer(const char* aData, PRUint32 aLen);
static void InitAllocator() {
if (!gAllocator)
gAllocator = new nsRecyclingAllocator(NS_SCANNER_BUCKETS, NS_DEFAULT_RECYCLE_TIMEOUT, "parser");
}
nsInputStream* mInputStream; nsInputStream* mInputStream;
nsScannerString* mSlidingBuffer; nsScannerString* mSlidingBuffer;
nsReadingIterator<PRUnichar> mCurrentPosition; // The position we will next read from in the scanner buffer nsReadingIterator<PRUnichar> mCurrentPosition; // The position we will next read from in the scanner buffer
@ -397,6 +415,10 @@ class nsScanner {
nsString mCharset; nsString mCharset;
nsIUnicodeDecoder *mUnicodeDecoder; nsIUnicodeDecoder *mUnicodeDecoder;
PRInt32 mNewlinesSkipped; PRInt32 mNewlinesSkipped;
public:
// Allocator to recycle memory used by scanner
static nsRecyclingAllocator *gAllocator;
}; };
#endif #endif