nsresult nsScanner::ReadUntil(nsScannerSharedSubstring& aString, const nsReadEndCondition& aEndCondition, PRBool addTerminal) { if (!mSlidingBuffer) { return kEOF; } nsScannerIterator origin, current; const PRUnichar* setstart = aEndCondition.mChars; const PRUnichar* setcurrent; origin = mCurrentPosition; current = origin; PRUnichar theChar=0; nsresult result=Peek(theChar); if (NS_FAILED(result)) { return result; } while (current != mEndPosition) { theChar = *current; if (theChar == '\0') { ReplaceCharacter(current, sInvalid); theChar = sInvalid; } // Filter out completely wrong characters // Check if all bits are in the required area if(!(theChar & aEndCondition.mFilter)) { // They were. Do a thorough check. setcurrent = setstart; while (*setcurrent) { if (*setcurrent == theChar) { if(addTerminal) ++current; AppendUnicodeTo(origin, current, aString); SetPosition(current); //DoErrTest(aString); return NS_OK; } ++setcurrent; } } ++current; } // If we are here, we didn't find any terminator in the string and // current = mEndPosition SetPosition(current); AppendUnicodeTo(origin, current, aString); return FillBuffer(); }
/** * Consume characters until you run into a char that's not valid in an * entity name * * @param aString - receives new data from stream * @return error code */ nsresult nsScanner::ReadEntityIdentifier(nsString& aString) { if (!mSlidingBuffer) { return kEOF; } PRUnichar theChar=0; nsresult result=Peek(theChar); nsScannerIterator origin, current, end; PRBool found=PR_FALSE; origin = mCurrentPosition; current = mCurrentPosition; end = mEndPosition; while(current != end) { theChar=*current; if(theChar) { found=PR_FALSE; switch(theChar) { case '_': case '-': case '.': // Don't allow ':' in entity names. See bug 23791 found = PR_TRUE; break; default: found = ('a'<=theChar && theChar<='z') || ('A'<=theChar && theChar<='Z') || ('0'<=theChar && theChar<='9'); break; } if(!found) { AppendUnicodeTo(mCurrentPosition, current, aString); break; } } ++current; } SetPosition(current); if (current == end) { AppendUnicodeTo(origin, current, aString); return FillBuffer(); } //DoErrTest(aString); return result; }
/** * Consume characters until you run into space, a '<', a '>', or a '/'. * * @param aString - receives new data from stream * @return error code */ nsresult nsScanner::ReadTagIdentifier(nsScannerSharedSubstring& aString) { if (!mSlidingBuffer) { return kEOF; } PRUnichar theChar=0; nsresult result=Peek(theChar); nsScannerIterator current, end; PRBool found=PR_FALSE; current = mCurrentPosition; end = mEndPosition; // Loop until we find an illegal character. Everything is then appended // later. while(current != end && !found) { theChar=*current; switch(theChar) { case '\n': case '\r': case ' ' : case '\b': case '\t': case '\v': case '\f': case '<': case '>': case '/': found = PR_TRUE; break; case '\0': ReplaceCharacter(current, sInvalid); break; default: break; } if (!found) { ++current; } } // Don't bother appending nothing. if (current != mCurrentPosition) { AppendUnicodeTo(mCurrentPosition, current, aString); } SetPosition(current); if (current == end) { result = FillBuffer(); } //DoErrTest(aString); return result; }
/** * Consume chars as long as they are <i>in</i> the * given validSet of input chars. * * @update gess 3/25/98 * @param aString will contain the result of this method * @param aValidSet is an ordered string that contains the * valid characters * @return error code */ nsresult nsScanner::ReadWhile(nsString& aString, nsString& aValidSet, PRBool addTerminal){ if (!mSlidingBuffer) { return kEOF; } PRUnichar theChar=0; nsresult result=Peek(theChar); nsScannerIterator origin, current, end; origin = mCurrentPosition; current = origin; end = mEndPosition; while(current != end) { theChar=*current; if (theChar == '\0') { ReplaceCharacter(current, sInvalid); theChar = sInvalid; } if(theChar) { PRInt32 pos=aValidSet.FindChar(theChar); if(kNotFound==pos) { if(addTerminal) ++current; AppendUnicodeTo(origin, current, aString); break; } } ++current; } SetPosition(current); if (current == end) { AppendUnicodeTo(origin, current, aString); return FillBuffer(); } //DoErrTest(aString); return result; }
/** * Consumes chars until you see the given terminalChar * * @update gess 3/25/98 * @param * @return error code */ nsresult nsScanner::ReadUntil(nsAString& aString, PRUnichar aTerminalChar, PRBool addTerminal) { if (!mSlidingBuffer) { return kEOF; } nsScannerIterator origin, current; origin = mCurrentPosition; current = origin; PRUnichar theChar; nsresult result = Peek(theChar); if (NS_FAILED(result)) { return result; } while (current != mEndPosition) { if (theChar == '\0') { ReplaceCharacter(current, sInvalid); theChar = sInvalid; } if (aTerminalChar == theChar) { if(addTerminal) ++current; AppendUnicodeTo(origin, current, aString); SetPosition(current); return NS_OK; } ++current; theChar = *current; } // If we are here, we didn't find any terminator in the string and // current = mEndPosition AppendUnicodeTo(origin, current, aString); SetPosition(current); return FillBuffer(); }
/** * Consume digits * * @param aString - should contain digits * @return error code */ nsresult nsScanner::ReadNumber(nsString& aString,PRInt32 aBase) { if (!mSlidingBuffer) { return kEOF; } NS_ASSERTION(aBase == 10 || aBase == 16,"base value not supported"); PRUnichar theChar=0; nsresult result=Peek(theChar); nsScannerIterator origin, current, end; origin = mCurrentPosition; current = origin; end = mEndPosition; PRBool done = PR_FALSE; while(current != end) { theChar=*current; if(theChar) { done = (theChar < '0' || theChar > '9') && ((aBase == 16)? (theChar < 'A' || theChar > 'F') && (theChar < 'a' || theChar > 'f') :PR_TRUE); if(done) { AppendUnicodeTo(origin, current, aString); break; } } ++current; } SetPosition(current); if (current == end) { AppendUnicodeTo(origin, current, aString); return FillBuffer(); } //DoErrTest(aString); return result; }
NS_IMETHODIMP nsAOLCiter::StripCites(const nsAString& aInString, nsAString& aOutString) { // Remove the beginning cites, if any: nsAutoString tOutputString; nsReadingIterator <PRUnichar> iter, enditer; aInString.BeginReading(iter); aInString.EndReading(enditer); if (StringBeginsWith(aInString, NS_LITERAL_STRING(">>"))) { iter.advance(2); while (nsCRT::IsAsciiSpace(*iter)) ++iter; AppendUnicodeTo(iter, enditer, tOutputString); } else CopyUnicodeTo(iter, enditer, tOutputString); // Remove the end cites, if any: tOutputString.Trim("<", PR_FALSE, PR_TRUE, PR_FALSE); aOutString.Assign(tOutputString); return NS_OK; }
/** * Consume characters until you find the terminal char * * @update gess 3/25/98 * @param aString receives new data from stream * @param addTerminal tells us whether to append terminal to aString * @return error code */ nsresult nsScanner::ReadWhitespace(nsScannerSharedSubstring& aString, PRInt32& aNewlinesSkipped, PRBool& aHaveCR) { aHaveCR = PR_FALSE; if (!mSlidingBuffer) { return kEOF; } PRUnichar theChar = 0; nsresult result = Peek(theChar); if (NS_FAILED(result)) { return result; } nsScannerIterator origin, current, end; PRBool done = PR_FALSE; origin = mCurrentPosition; current = origin; end = mEndPosition; PRBool haveCR = PR_FALSE; while(!done && current != end) { switch(theChar) { case '\n': case '\r': { ++aNewlinesSkipped; PRUnichar thePrevChar = theChar; theChar = (++current != end) ? *current : '\0'; if ((thePrevChar == '\r' && theChar == '\n') || (thePrevChar == '\n' && theChar == '\r')) { theChar = (++current != end) ? *current : '\0'; // CRLF == LFCR => LF haveCR = PR_TRUE; } else if (thePrevChar == '\r') { // Lone CR becomes CRLF; callers should know to remove extra CRs AppendUnicodeTo(origin, current, aString); aString.writable().Append(PRUnichar('\n')); origin = current; haveCR = PR_TRUE; } } break; case ' ' : case '\t': theChar = (++current != end) ? *current : '\0'; break; default: done = PR_TRUE; AppendUnicodeTo(origin, current, aString); break; } } SetPosition(current); if (current == end) { AppendUnicodeTo(origin, current, aString); result = FillBuffer(); } aHaveCR = haveCR; return result; }
NS_IMETHODIMP nsExpatDriver::ConsumeToken(nsScanner& aScanner, PRBool& aFlushTokens) { // We keep the scanner pointing to the position where Expat will start // parsing. nsScannerIterator currentExpatPosition; aScanner.CurrentPosition(currentExpatPosition); // This is the start of the first buffer that we need to pass to Expat. nsScannerIterator start = currentExpatPosition; start.advance(mExpatBuffered); // This is the end of the last buffer (at this point, more data could come in // later). nsScannerIterator end; aScanner.EndReading(end); PR_LOG(gExpatDriverLog, PR_LOG_DEBUG, ("Remaining in expat's buffer: %i, remaining in scanner: %i.", mExpatBuffered, Distance(start, end))); // We want to call Expat if we have more buffers, or if we know there won't // be more buffers (and so we want to flush the remaining data), or if we're // currently blocked and there's data in Expat's buffer. while (start != end || (mIsFinalChunk && !mMadeFinalCallToExpat) || (BlockedOrInterrupted() && mExpatBuffered > 0)) { PRBool noMoreBuffers = start == end && mIsFinalChunk; PRBool blocked = BlockedOrInterrupted(); const PRUnichar *buffer; PRUint32 length; if (blocked || noMoreBuffers) { // If we're blocked we just resume Expat so we don't need a buffer, if // there aren't any more buffers we pass a null buffer to Expat. buffer = nsnull; length = 0; #if defined(PR_LOGGING) || defined (DEBUG) if (blocked) { PR_LOG(gExpatDriverLog, PR_LOG_DEBUG, ("Resuming Expat, will parse data remaining in Expat's " "buffer.\nContent of Expat's buffer:\n-----\n%s\n-----\n", NS_ConvertUTF16toUTF8(currentExpatPosition.get(), mExpatBuffered).get())); } else { NS_ASSERTION(mExpatBuffered == Distance(currentExpatPosition, end), "Didn't pass all the data to Expat?"); PR_LOG(gExpatDriverLog, PR_LOG_DEBUG, ("Last call to Expat, will parse data remaining in Expat's " "buffer.\nContent of Expat's buffer:\n-----\n%s\n-----\n", NS_ConvertUTF16toUTF8(currentExpatPosition.get(), mExpatBuffered).get())); } #endif } else { buffer = start.get(); length = PRUint32(start.size_forward()); PR_LOG(gExpatDriverLog, PR_LOG_DEBUG, ("Calling Expat, will parse data remaining in Expat's buffer and " "new data.\nContent of Expat's buffer:\n-----\n%s\n-----\nNew " "data:\n-----\n%s\n-----\n", NS_ConvertUTF16toUTF8(currentExpatPosition.get(), mExpatBuffered).get(), NS_ConvertUTF16toUTF8(start.get(), length).get())); } PRUint32 consumed; ParseBuffer(buffer, length, noMoreBuffers, &consumed); if (consumed > 0) { nsScannerIterator oldExpatPosition = currentExpatPosition; currentExpatPosition.advance(consumed); // We consumed some data, we want to store the last line of data that // was consumed in case we run into an error (to show the line in which // the error occurred). // The length of the last line that Expat has parsed. XML_Size lastLineLength = XML_GetCurrentColumnNumber(mExpatParser); if (lastLineLength <= consumed) { // The length of the last line was less than what expat consumed, so // there was at least one line break in the consumed data. Store the // last line until the point where we stopped parsing. nsScannerIterator startLastLine = currentExpatPosition; startLastLine.advance(-((ptrdiff_t)lastLineLength)); CopyUnicodeTo(startLastLine, currentExpatPosition, mLastLine); } else { // There was no line break in the consumed data, append the consumed // data. AppendUnicodeTo(oldExpatPosition, currentExpatPosition, mLastLine); } } mExpatBuffered += length - consumed; if (BlockedOrInterrupted()) { PR_LOG(gExpatDriverLog, PR_LOG_DEBUG, ("Blocked or interrupted parser (probably for loading linked " "stylesheets or scripts).")); aScanner.SetPosition(currentExpatPosition, PR_TRUE); aScanner.Mark(); return mInternalState; } if (noMoreBuffers && mExpatBuffered == 0) { mMadeFinalCallToExpat = PR_TRUE; } if (NS_FAILED(mInternalState)) { if (XML_GetErrorCode(mExpatParser) != XML_ERROR_NONE) { NS_ASSERTION(mInternalState == NS_ERROR_HTMLPARSER_STOPPARSING, "Unexpected error"); // Look for the next newline after the last one we consumed nsScannerIterator lastLine = currentExpatPosition; while (lastLine != end) { length = PRUint32(lastLine.size_forward()); PRUint32 endOffset = 0; const PRUnichar *buffer = lastLine.get(); while (endOffset < length && buffer[endOffset] != '\n' && buffer[endOffset] != '\r') { ++endOffset; } mLastLine.Append(Substring(buffer, buffer + endOffset)); if (endOffset < length) { // We found a newline. break; } lastLine.advance(length); } HandleError(); } return mInternalState; } // Either we have more buffers, or we were blocked (and we'll flush in the // next iteration), or we should have emptied Expat's buffer. NS_ASSERTION(!noMoreBuffers || blocked || (mExpatBuffered == 0 && currentExpatPosition == end), "Unreachable data left in Expat's buffer"); start.advance(length); // It's possible for start to have passed end if we received more data // (e.g. if we spun the event loop in an inline script). Reload end now // to compensate. aScanner.EndReading(end); } aScanner.SetPosition(currentExpatPosition, PR_TRUE); aScanner.Mark(); PR_LOG(gExpatDriverLog, PR_LOG_DEBUG, ("Remaining in expat's buffer: %i, remaining in scanner: %i.", mExpatBuffered, Distance(currentExpatPosition, end))); return NS_SUCCEEDED(mInternalState) ? kEOF : NS_OK; }