~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/htmlparser/src/nsScanner.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
2
/* ***** BEGIN LICENSE BLOCK *****
 
3
 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
 
4
 *
 
5
 * The contents of this file are subject to the Netscape Public License
 
6
 * Version 1.1 (the "License"); you may not use this file except in
 
7
 * compliance with the License. You may obtain a copy of the License at
 
8
 * http://www.mozilla.org/NPL/
 
9
 *
 
10
 * Software distributed under the License is distributed on an "AS IS" basis,
 
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
12
 * for the specific language governing rights and limitations under the
 
13
 * License.
 
14
 *
 
15
 * The Original Code is mozilla.org code.
 
16
 *
 
17
 * The Initial Developer of the Original Code is 
 
18
 * Netscape Communications Corporation.
 
19
 * Portions created by the Initial Developer are Copyright (C) 1998
 
20
 * the Initial Developer. All Rights Reserved.
 
21
 *
 
22
 * Contributor(s):
 
23
 *
 
24
 *
 
25
 * Alternatively, the contents of this file may be used under the terms of
 
26
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
27
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
28
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
29
 * of those above. If you wish to allow use of your version of this file only
 
30
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
31
 * use your version of this file under the terms of the NPL, indicate your
 
32
 * decision by deleting the provisions above and replace them with the notice
 
33
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
34
 * the provisions above, a recipient may use your version of this file under
 
35
 * the terms of any one of the NPL, the GPL or the LGPL.
 
36
 *
 
37
 * ***** END LICENSE BLOCK ***** */
 
38
 
 
39
//#define __INCREMENTAL 1
 
40
 
 
41
#include "nsScanner.h"
 
42
#include "nsDebug.h"
 
43
#include "nsIServiceManager.h"
 
44
#include "nsICharsetConverterManager.h"
 
45
#include "nsICharsetAlias.h"
 
46
#include "nsReadableUtils.h"
 
47
#include "nsIInputStream.h"
 
48
#include "nsILocalFile.h"
 
49
#include "nsNetUtil.h"
 
50
#include "nsUTF8Utils.h" // for LossyConvertEncoding
 
51
#include "nsCRT.h"
 
52
#include "nsParser.h"
 
53
 
 
54
static NS_DEFINE_CID(kCharsetAliasCID, NS_CHARSETALIAS_CID);
 
55
 
 
56
nsReadEndCondition::nsReadEndCondition(const PRUnichar* aTerminateChars) :
 
57
  mChars(aTerminateChars), mFilter(PRUnichar(~0)) // All bits set
 
58
{
 
59
  // Build filter that will be used to filter out characters with
 
60
  // bits that none of the terminal chars have. This works very well
 
61
  // because terminal chars often have only the last 4-6 bits set and
 
62
  // normal ascii letters have bit 7 set. Other letters have even higher
 
63
  // bits set.
 
64
  
 
65
  // Calculate filter
 
66
  const PRUnichar *current = aTerminateChars;
 
67
  PRUnichar terminalChar = *current;
 
68
  while (terminalChar) {
 
69
    mFilter &= ~terminalChar;
 
70
    ++current;
 
71
    terminalChar = *current;
 
72
  }
 
73
}
 
74
 
 
75
static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
 
76
 
 
77
static const char kBadHTMLText[] ="<H3>Oops...</H3>You just tried to read a non-existent document: <BR>";
 
78
static const char kUnorderedStringError[] = "String argument must be ordered. Don't you read API's?";
 
79
 
 
80
#ifdef __INCREMENTAL
 
81
const int   kBufsize=1;
 
82
#else
 
83
const int   kBufsize=64;
 
84
#endif
 
85
 
 
86
MOZ_DECL_CTOR_COUNTER(nsScanner)
 
87
 
 
88
/**
 
89
 *  Use this constructor if you want i/o to be based on 
 
90
 *  a single string you hand in during construction.
 
91
 *  This short cut was added for Javascript.
 
92
 *
 
93
 *  @update  gess 5/12/98
 
94
 *  @param   aMode represents the parser mode (nav, other)
 
95
 *  @return  
 
96
 */
 
97
nsScanner::nsScanner(const nsAString& anHTMLString, const nsACString& aCharset,
 
98
                     PRInt32 aSource)
 
99
  : mParser(nsnull)
 
100
{
 
101
  MOZ_COUNT_CTOR(nsScanner);
 
102
 
 
103
  mTotalRead = anHTMLString.Length();
 
104
  mSlidingBuffer = nsnull;
 
105
  mCountRemaining = 0;
 
106
  mFirstNonWhitespacePosition = -1;
 
107
  AppendToBuffer(anHTMLString);
 
108
  mSlidingBuffer->BeginReading(mCurrentPosition);
 
109
  mMarkPosition = mCurrentPosition;
 
110
  mIncremental = PR_FALSE;
 
111
  mUnicodeDecoder = 0;
 
112
  mCharsetSource = kCharsetUninitialized;
 
113
  SetDocumentCharset(aCharset, aSource);
 
114
}
 
115
 
 
116
/**
 
117
 *  Use this constructor if you want i/o to be based on strings 
 
118
 *  the scanner receives. If you pass a null filename, you
 
119
 *  can still provide data to the scanner via append.
 
120
 *
 
121
 *  @update  gess 5/12/98
 
122
 *  @param   aFilename --
 
123
 *  @return  
 
124
 */
 
125
nsScanner::nsScanner(nsString& aFilename,PRBool aCreateStream,
 
126
                     const nsACString& aCharset, PRInt32 aSource)
 
127
  : mFilename(aFilename), mParser(nsnull)
 
128
{
 
129
  MOZ_COUNT_CTOR(nsScanner);
 
130
 
 
131
  mSlidingBuffer = nsnull;
 
132
 
 
133
  // XXX This is a big hack.  We need to initialize the iterators to something.
 
134
  // What matters is that mCurrentPosition == mEndPosition, so that our methods
 
135
  // believe that we are at EOF (see bug 182067).  We null out mCurrentPosition
 
136
  // so that we have some hope of catching null pointer dereferences associated
 
137
  // with this hack. --darin
 
138
  memset(&mCurrentPosition, 0, sizeof(mCurrentPosition));
 
139
  mMarkPosition = mCurrentPosition;
 
140
  mEndPosition = mCurrentPosition;
 
141
 
 
142
  mIncremental = PR_TRUE;
 
143
  mFirstNonWhitespacePosition = -1;
 
144
  mCountRemaining = 0;
 
145
  mTotalRead=0;
 
146
 
 
147
  if(aCreateStream) {
 
148
    nsCOMPtr<nsILocalFile> file;
 
149
    nsCOMPtr<nsIInputStream> fileStream;
 
150
    
 
151
    NS_NewLocalFile(aFilename, PR_TRUE, getter_AddRefs(file));
 
152
    if (file)
 
153
      NS_NewLocalFileInputStream(getter_AddRefs(mInputStream), file);
 
154
 
 
155
  } //if
 
156
  mUnicodeDecoder = 0;
 
157
  mCharsetSource = kCharsetUninitialized;
 
158
  SetDocumentCharset(aCharset, aSource);
 
159
}
 
160
 
 
161
/**
 
162
 *  Use this constructor if you want i/o to be stream based.
 
163
 *
 
164
 *  @update  gess 5/12/98
 
165
 *  @param   aStream --
 
166
 *  @param   assumeOwnership --
 
167
 *  @param   aFilename --
 
168
 *  @return  
 
169
 */
 
170
nsScanner::nsScanner(const nsAString& aFilename, nsIInputStream* aStream,
 
171
                     const nsACString& aCharset, PRInt32 aSource)
 
172
  : mFilename(aFilename), mParser(nsnull)
 
173
{  
 
174
  MOZ_COUNT_CTOR(nsScanner);
 
175
 
 
176
  mSlidingBuffer = nsnull;
 
177
 
 
178
  // XXX This is a big hack.  We need to initialize the iterators to something.
 
179
  // What matters is that mCurrentPosition == mEndPosition, so that our methods
 
180
  // believe that we are at EOF (see bug 182067).  We null out mCurrentPosition
 
181
  // so that we have some hope of catching null pointer dereferences associated
 
182
  // with this hack. --darin
 
183
  memset(&mCurrentPosition, 0, sizeof(mCurrentPosition));
 
184
  mMarkPosition = mCurrentPosition;
 
185
  mEndPosition = mCurrentPosition;
 
186
 
 
187
  mIncremental = PR_FALSE;
 
188
  mFirstNonWhitespacePosition = -1;
 
189
  mCountRemaining = 0;
 
190
  mTotalRead=0;
 
191
  mInputStream=aStream;
 
192
  mUnicodeDecoder = 0;
 
193
  mCharsetSource = kCharsetUninitialized;
 
194
  SetDocumentCharset(aCharset, aSource);
 
195
}
 
196
 
 
197
 
 
198
nsresult nsScanner::SetDocumentCharset(const nsACString& aCharset , PRInt32 aSource) {
 
199
 
 
200
  nsresult res = NS_OK;
 
201
 
 
202
  if( aSource < mCharsetSource) // priority is lower the the current one , just
 
203
    return res;
 
204
 
 
205
  nsCOMPtr<nsICharsetAlias> calias(do_GetService(kCharsetAliasCID, &res));
 
206
  NS_ASSERTION( nsnull != calias, "cannot find charset alias");
 
207
  if( NS_SUCCEEDED(res) && (nsnull != calias))
 
208
  {
 
209
    PRBool same = PR_FALSE;
 
210
    res = calias->Equals(aCharset, mCharset, &same);
 
211
    if(NS_SUCCEEDED(res) && same)
 
212
    {
 
213
      return NS_OK; // no difference, don't change it
 
214
    }
 
215
    // different, need to change it
 
216
    nsCAutoString charsetName;
 
217
    res = calias->GetPreferred(aCharset, charsetName);
 
218
 
 
219
    if(NS_FAILED(res) && (kCharsetUninitialized == mCharsetSource) )
 
220
    {
 
221
       // failed - unknown alias , fallback to ISO-8859-1
 
222
      charsetName.Assign(NS_LITERAL_CSTRING("ISO-8859-1"));
 
223
    }
 
224
    mCharset = charsetName;
 
225
    mCharsetSource = aSource;
 
226
 
 
227
    nsCOMPtr<nsICharsetConverterManager> ccm = 
 
228
             do_GetService(kCharsetConverterManagerCID, &res);
 
229
    if(NS_SUCCEEDED(res) && (nsnull != ccm))
 
230
    {
 
231
      nsIUnicodeDecoder * decoder = nsnull;
 
232
      res = ccm->GetUnicodeDecoderRaw(mCharset.get(), &decoder);
 
233
      if(NS_SUCCEEDED(res) && (nsnull != decoder))
 
234
      {
 
235
         NS_IF_RELEASE(mUnicodeDecoder);
 
236
 
 
237
         mUnicodeDecoder = decoder;
 
238
      }    
 
239
    }
 
240
  }
 
241
  return res;
 
242
}
 
243
 
 
244
 
 
245
/**
 
246
 *  default destructor
 
247
 *  
 
248
 *  @update  gess 3/25/98
 
249
 *  @param   
 
250
 *  @return  
 
251
 */
 
252
nsScanner::~nsScanner() {
 
253
 
 
254
  if (mSlidingBuffer) {
 
255
    delete mSlidingBuffer;
 
256
  }
 
257
 
 
258
  MOZ_COUNT_DTOR(nsScanner);
 
259
 
 
260
  if(mInputStream) {
 
261
    mInputStream->Close();
 
262
    mInputStream = 0;
 
263
  }
 
264
 
 
265
  NS_IF_RELEASE(mUnicodeDecoder);
 
266
}
 
267
 
 
268
/**
 
269
 *  Resets current offset position of input stream to marked position. 
 
270
 *  This allows us to back up to this point if the need should arise, 
 
271
 *  such as when tokenization gets interrupted.
 
272
 *  NOTE: IT IS REALLY BAD FORM TO CALL RELEASE WITHOUT CALLING MARK FIRST!
 
273
 *
 
274
 *  @update  gess 5/12/98
 
275
 *  @param   
 
276
 *  @return  
 
277
 */
 
278
void nsScanner::RewindToMark(void){
 
279
  mCountRemaining += (Distance(mMarkPosition, mCurrentPosition));
 
280
  mCurrentPosition = mMarkPosition;
 
281
}
 
282
 
 
283
 
 
284
/**
 
285
 *  Records current offset position in input stream. This allows us
 
286
 *  to back up to this point if the need should arise, such as when
 
287
 *  tokenization gets interrupted.
 
288
 *
 
289
 *  @update  gess 7/29/98
 
290
 *  @param   
 
291
 *  @return  
 
292
 */
 
293
void nsScanner::Mark() {
 
294
  if (mSlidingBuffer) {
 
295
    mSlidingBuffer->DiscardPrefix(mCurrentPosition);
 
296
    mSlidingBuffer->BeginReading(mCurrentPosition);
 
297
    mMarkPosition = mCurrentPosition;
 
298
  }
 
299
}
 
300
 
 
301
 
 
302
/** 
 
303
 * Insert data to our underlying input buffer as
 
304
 * if it were read from an input stream.
 
305
 *
 
306
 * @update  harishd 01/12/99
 
307
 * @return  error code 
 
308
 */
 
309
PRBool nsScanner::UngetReadable(const nsAString& aBuffer) {
 
310
 
 
311
  mSlidingBuffer->UngetReadable(aBuffer,mCurrentPosition);
 
312
  mSlidingBuffer->BeginReading(mCurrentPosition); // Insertion invalidated our iterators
 
313
  mSlidingBuffer->EndReading(mEndPosition);
 
314
 
 
315
  PRUint32 length = aBuffer.Length();
 
316
  mCountRemaining += length; // Ref. bug 117441
 
317
  mTotalRead += length;
 
318
  return PR_TRUE;
 
319
}
 
320
 
 
321
/** 
 
322
 * Append data to our underlying input buffer as
 
323
 * if it were read from an input stream.
 
324
 *
 
325
 * @update  gess4/3/98
 
326
 * @return  error code 
 
327
 */
 
328
nsresult nsScanner::Append(const nsAString& aBuffer) {
 
329
  
 
330
  mTotalRead += aBuffer.Length();
 
331
  AppendToBuffer(aBuffer);
 
332
  return NS_OK;
 
333
}
 
334
 
 
335
/**
 
336
 *  
 
337
 *  
 
338
 *  @update  gess 5/21/98
 
339
 *  @param   
 
340
 *  @return  
 
341
 */
 
342
nsresult nsScanner::Append(const char* aBuffer, PRUint32 aLen,
 
343
                           nsIRequest *aRequest)
 
344
{
 
345
  nsresult res=NS_OK;
 
346
  PRUnichar *unichars, *start;
 
347
  if(mUnicodeDecoder) {
 
348
    PRInt32 unicharBufLen = 0;
 
349
    mUnicodeDecoder->GetMaxLength(aBuffer, aLen, &unicharBufLen);
 
350
    nsScannerString::Buffer* buffer = nsScannerString::AllocBuffer(unicharBufLen + 1);
 
351
    NS_ENSURE_TRUE(buffer,NS_ERROR_OUT_OF_MEMORY);
 
352
    start = unichars = buffer->DataStart();
 
353
          
 
354
    PRInt32 totalChars = 0;
 
355
    PRInt32 unicharLength = unicharBufLen;
 
356
    do {
 
357
      PRInt32 srcLength = aLen;
 
358
                  res = mUnicodeDecoder->Convert(aBuffer, &srcLength, unichars, &unicharLength);
 
359
 
 
360
      totalChars += unicharLength;
 
361
      // Continuation of failure case
 
362
                  if(NS_FAILED(res)) {
 
363
        // if we failed, we consume one byte, replace it with U+FFFD
 
364
        // and try the conversion again.
 
365
        unichars[unicharLength++] = (PRUnichar)0xFFFD;
 
366
        unichars = unichars + unicharLength;
 
367
        unicharLength = unicharBufLen - (++totalChars);
 
368
 
 
369
                          mUnicodeDecoder->Reset();
 
370
 
 
371
        if(((PRUint32) (srcLength + 1)) > aLen) {
 
372
          srcLength = aLen;
 
373
        }
 
374
        else {
 
375
          ++srcLength;
 
376
        }
 
377
 
 
378
        aBuffer += srcLength;
 
379
        aLen -= srcLength;
 
380
                  }
 
381
          } while (NS_FAILED(res) && (aLen > 0));
 
382
 
 
383
    buffer->SetDataLength(totalChars);
 
384
    AppendToBuffer(buffer, aRequest);
 
385
    mTotalRead += totalChars;
 
386
 
 
387
    // Don't propagate return code of unicode decoder
 
388
    // since it doesn't reflect on our success or failure
 
389
    // - Ref. bug 87110
 
390
    res = NS_OK; 
 
391
  }
 
392
  else {
 
393
    AppendASCIItoBuffer(aBuffer, aLen, aRequest);
 
394
    mTotalRead+=aLen;
 
395
  }
 
396
 
 
397
  return res;
 
398
}
 
399
 
 
400
 
 
401
/** 
 
402
 * Grab data from underlying stream.
 
403
 *
 
404
 * @update  gess4/3/98
 
405
 * @return  error code
 
406
 */
 
407
nsresult nsScanner::FillBuffer(void) {
 
408
  nsresult result=NS_OK;
 
409
 
 
410
  if(!mInputStream) {
 
411
#if 0
 
412
    //This is DEBUG code!!!!!!  XXX DEBUG XXX
 
413
    //If you're here, it means someone tried to load a
 
414
    //non-existent document. So as a favor, we emit a
 
415
    //little bit of HTML explaining the error.
 
416
    if(0==mTotalRead) {
 
417
      mBuffer.Append((const char*)kBadHTMLText);
 
418
      mBuffer.Append(mFilename);
 
419
      mTotalRead+=mBuffer.Length();
 
420
    }
 
421
    else 
 
422
#endif
 
423
    result=kEOF;
 
424
  }
 
425
  else {
 
426
    PRUint32 numread=0;
 
427
    char buf[kBufsize+1];
 
428
    buf[kBufsize]=0;
 
429
 
 
430
    // XXX use ReadSegments to avoid extra buffer copy? --darin
 
431
 
 
432
    result = mInputStream->Read(buf, kBufsize, &numread);
 
433
    if (0 == numread) {
 
434
      return kEOF;
 
435
    }
 
436
 
 
437
    if((0<numread) && (0==result)) {
 
438
      AppendASCIItoBuffer(buf, numread, nsnull);
 
439
    }
 
440
    mTotalRead+=numread;
 
441
  }
 
442
 
 
443
  return result;
 
444
}
 
445
 
 
446
/**
 
447
 *  determine if the scanner has reached EOF
 
448
 *  
 
449
 *  @update  gess 5/12/98
 
450
 *  @param   
 
451
 *  @return  0=!eof 1=eof 
 
452
 */
 
453
nsresult nsScanner::Eof() {
 
454
  nsresult theError=NS_OK;
 
455
  
 
456
  if (!mSlidingBuffer) {
 
457
    return kEOF;
 
458
  }
 
459
 
 
460
  theError=FillBuffer();  
 
461
 
 
462
  if(NS_OK==theError) {
 
463
    if (0==(PRUint32)mSlidingBuffer->Length()) {
 
464
      return kEOF;
 
465
    }
 
466
  }
 
467
 
 
468
  return theError;
 
469
}
 
470
 
 
471
/**
 
472
 *  retrieve next char from scanners internal input stream
 
473
 *  
 
474
 *  @update  gess 3/25/98
 
475
 *  @param   
 
476
 *  @return  error code reflecting read status
 
477
 */
 
478
nsresult nsScanner::GetChar(PRUnichar& aChar) {
 
479
  nsresult result=NS_OK;
 
480
  aChar=0;  
 
481
 
 
482
  if (!mSlidingBuffer) {
 
483
    return kEOF;
 
484
  }
 
485
 
 
486
  if (mCurrentPosition == mEndPosition) {
 
487
    result=Eof();
 
488
  }
 
489
 
 
490
  if(NS_OK == result){
 
491
    aChar=*mCurrentPosition++;
 
492
    --mCountRemaining;
 
493
  }
 
494
  return result;
 
495
}
 
496
 
 
497
 
 
498
/**
 
499
 *  peek ahead to consume next char from scanner's internal
 
500
 *  input buffer
 
501
 *  
 
502
 *  @update  gess 3/25/98
 
503
 *  @param   
 
504
 *  @return  
 
505
 */
 
506
nsresult nsScanner::Peek(PRUnichar& aChar, PRUint32 aOffset) {
 
507
  nsresult result=NS_OK;
 
508
  aChar=0;  
 
509
  
 
510
  if (!mSlidingBuffer) {
 
511
    return kEOF;
 
512
  }
 
513
 
 
514
  if (mCurrentPosition == mEndPosition) {
 
515
    result=Eof();
 
516
  }
 
517
 
 
518
  if(NS_OK == result){
 
519
    if (aOffset) {
 
520
      while ((NS_OK == result) && (mCountRemaining <= aOffset)) {
 
521
        result = Eof();
 
522
      }
 
523
 
 
524
      if (NS_OK == result) {
 
525
        nsScannerIterator pos = mCurrentPosition;
 
526
        pos.advance(aOffset);
 
527
        aChar=*pos;
 
528
      }
 
529
    }
 
530
    else {
 
531
      aChar=*mCurrentPosition;
 
532
    }
 
533
  }
 
534
 
 
535
  return result;
 
536
}
 
537
 
 
538
nsresult nsScanner::Peek(nsAString& aStr, PRInt32 aNumChars, PRInt32 aOffset)
 
539
{
 
540
  if (!mSlidingBuffer) {
 
541
    return kEOF;
 
542
  }
 
543
 
 
544
  if (mCurrentPosition == mEndPosition) {
 
545
    return Eof();
 
546
  }    
 
547
  
 
548
  nsScannerIterator start, end;
 
549
 
 
550
  start = mCurrentPosition;
 
551
 
 
552
  if (mCountRemaining <= aOffset) {
 
553
    return kEOF;
 
554
  }
 
555
 
 
556
  if (aOffset > 0) {
 
557
    start.advance(aOffset);
 
558
  }
 
559
 
 
560
  if (mCountRemaining < PRUint32(aNumChars + aOffset)) {
 
561
    end = mEndPosition;
 
562
  }
 
563
  else {
 
564
    end = start;
 
565
    end.advance(aNumChars);
 
566
  }
 
567
 
 
568
  CopyUnicodeTo(start, end, aStr);
 
569
 
 
570
  return NS_OK;
 
571
}
 
572
 
 
573
 
 
574
/**
 
575
 *  Skip whitespace on scanner input stream
 
576
 *  
 
577
 *  @update  gess 3/25/98
 
578
 *  @param   
 
579
 *  @return  error status
 
580
 */
 
581
nsresult nsScanner::SkipWhitespace(PRInt32& aNewlinesSkipped) {
 
582
 
 
583
  if (!mSlidingBuffer) {
 
584
    return kEOF;
 
585
  }
 
586
 
 
587
  PRUnichar theChar = 0;
 
588
  nsresult  result = Peek(theChar);
 
589
  
 
590
  if (result == kEOF) {
 
591
    // XXX why wouldn't Eof() return kEOF?? --darin
 
592
    return Eof();
 
593
  }
 
594
  
 
595
  nsScannerIterator current = mCurrentPosition;
 
596
  PRBool    done = PR_FALSE;
 
597
  PRBool    skipped = PR_FALSE;
 
598
  
 
599
  while (!done && current != mEndPosition) {
 
600
    switch(theChar) {
 
601
      case '\n':
 
602
      case '\r': ++aNewlinesSkipped;
 
603
      case ' ' :
 
604
      case '\b':
 
605
      case '\t':
 
606
        {
 
607
          skipped = PR_TRUE;
 
608
          PRUnichar thePrevChar = theChar;
 
609
          theChar = (++current != mEndPosition) ? *current : '\0';
 
610
          if ((thePrevChar == '\r' && theChar == '\n') ||
 
611
              (thePrevChar == '\n' && theChar == '\r')) {
 
612
            theChar = (++current != mEndPosition) ? *current : '\0'; // CRLF == LFCR => LF
 
613
          }
 
614
        }
 
615
        break;
 
616
      default:
 
617
        done = PR_TRUE;
 
618
        break;
 
619
    }
 
620
  }
 
621
 
 
622
  if (skipped) {
 
623
    SetPosition(current);
 
624
    if (current == mEndPosition) {
 
625
      result = Eof();
 
626
    }
 
627
  }
 
628
 
 
629
  return result;
 
630
}
 
631
 
 
632
/**
 
633
 *  Skip over chars as long as they equal given char
 
634
 *  
 
635
 *  @update  gess 3/25/98
 
636
 *  @param   
 
637
 *  @return  error code
 
638
 */
 
639
nsresult nsScanner::SkipOver(PRUnichar aSkipChar){
 
640
 
 
641
  if (!mSlidingBuffer) {
 
642
    return kEOF;
 
643
  }
 
644
 
 
645
  PRUnichar ch=0;
 
646
  nsresult   result=NS_OK;
 
647
 
 
648
  while(NS_OK==result) {
 
649
    result=Peek(ch);
 
650
    if(NS_OK == result) {
 
651
      if(ch!=aSkipChar) {
 
652
        break;
 
653
      }
 
654
      GetChar(ch);
 
655
    } 
 
656
    else break;
 
657
  } //while
 
658
  return result;
 
659
 
 
660
}
 
661
 
 
662
/**
 
663
 *  Skip over chars as long as they're in aSkipSet
 
664
 *  
 
665
 *  @update  gess 3/25/98
 
666
 *  @param   aSkipSet is an ordered string.
 
667
 *  @return  error code
 
668
 */
 
669
nsresult nsScanner::SkipOver(nsString& aSkipSet){
 
670
 
 
671
  if (!mSlidingBuffer) {
 
672
    return kEOF;
 
673
  }
 
674
 
 
675
  PRUnichar theChar=0;
 
676
  nsresult  result=NS_OK;
 
677
 
 
678
  while(NS_OK==result) {
 
679
    result=Peek(theChar);
 
680
    if(NS_OK == result) {
 
681
      PRInt32 pos=aSkipSet.FindChar(theChar);
 
682
      if(kNotFound==pos) {
 
683
        break;
 
684
      }
 
685
      GetChar(theChar);
 
686
    } 
 
687
    else break;
 
688
  } //while
 
689
  return result;
 
690
 
 
691
}
 
692
 
 
693
 
 
694
/**
 
695
 *  Skip over chars until they're in aValidSet
 
696
 *  
 
697
 *  @update  gess 3/25/98
 
698
 *  @param   aValid set is an ordered string that 
 
699
 *           contains chars you're looking for
 
700
 *  @return  error code
 
701
 */
 
702
nsresult nsScanner::SkipTo(nsString& aValidSet){
 
703
  if (!mSlidingBuffer) {
 
704
    return kEOF;
 
705
  }
 
706
 
 
707
  PRUnichar ch=0;
 
708
  nsresult  result=NS_OK;
 
709
 
 
710
  while(NS_OK==result) {
 
711
    result=Peek(ch);
 
712
    if(NS_OK == result) {
 
713
      PRInt32 pos=aValidSet.FindChar(ch);
 
714
      if(kNotFound!=pos) {
 
715
        break;
 
716
      }
 
717
      GetChar(ch);
 
718
    } 
 
719
    else break;
 
720
  } //while
 
721
  return result;
 
722
}
 
723
 
 
724
#if 0
 
725
void DoErrTest(nsString& aString) {
 
726
  PRInt32 pos=aString.FindChar(0);
 
727
  if(kNotFound<pos) {
 
728
    if(aString.Length()-1!=pos) {
 
729
    }
 
730
  }
 
731
}
 
732
 
 
733
void DoErrTest(nsCString& aString) {
 
734
  PRInt32 pos=aString.FindChar(0);
 
735
  if(kNotFound<pos) {
 
736
    if(aString.Length()-1!=pos) {
 
737
    }
 
738
  }
 
739
}
 
740
#endif
 
741
 
 
742
/**
 
743
 *  Skip over chars as long as they're in aValidSet
 
744
 *  
 
745
 *  @update  gess 3/25/98
 
746
 *  @param   aValidSet is an ordered string containing the 
 
747
 *           characters you want to skip
 
748
 *  @return  error code
 
749
 */
 
750
nsresult nsScanner::SkipPast(nsString& aValidSet){
 
751
  NS_NOTYETIMPLEMENTED("Error: SkipPast not yet implemented.");
 
752
  return NS_OK;
 
753
}
 
754
 
 
755
/**
 
756
 *  Consume characters until you did not find the terminal char
 
757
 *  
 
758
 *  @update  gess 3/25/98
 
759
 *  @param   aString - receives new data from stream
 
760
 *  @param   aIgnore - If set ignores ':','-','_','.'
 
761
 *  @return  error code
 
762
 */
 
763
nsresult nsScanner::GetIdentifier(nsString& aString,PRBool allowPunct) {
 
764
 
 
765
  if (!mSlidingBuffer) {
 
766
    return kEOF;
 
767
  }
 
768
 
 
769
  PRUnichar         theChar=0;
 
770
  nsresult          result=Peek(theChar);
 
771
  nsScannerIterator current, end;
 
772
  PRBool            found=PR_FALSE;  
 
773
  
 
774
  current = mCurrentPosition;
 
775
  end = mEndPosition;
 
776
 
 
777
  while(current != end) {
 
778
 
 
779
    theChar=*current;
 
780
    found=PR_FALSE;
 
781
    switch(theChar) {
 
782
      case ':':
 
783
      case '_':
 
784
      case '-':
 
785
      case '.':
 
786
        found=allowPunct;
 
787
        break;
 
788
      default:
 
789
        found = ('a'<=theChar && theChar<='z') ||
 
790
                ('A'<=theChar && theChar<='Z') ||
 
791
                ('0'<=theChar && theChar<='9');
 
792
        break;
 
793
    }
 
794
 
 
795
    if(!found) {
 
796
      // If the current character isn't a valid character for
 
797
      // the identifier, we're done. Copy the results into
 
798
      // the string passed in.
 
799
      CopyUnicodeTo(mCurrentPosition, current, aString);
 
800
      break;
 
801
    }
 
802
    ++current;
 
803
  }
 
804
 
 
805
  // Drop NULs on the floor since nobody really likes them.
 
806
  while (current != end && !*current) {
 
807
    ++current;
 
808
  }
 
809
 
 
810
  SetPosition(current);  
 
811
  if (current == end) {
 
812
    result = Eof();
 
813
  }
 
814
 
 
815
  //DoErrTest(aString);
 
816
 
 
817
  return result;
 
818
}
 
819
 
 
820
/**
 
821
 *  Consume characters until you did not find the terminal char
 
822
 *  
 
823
 *  @update  gess 3/25/98
 
824
 *  @param   aString - receives new data from stream
 
825
 *  @param   allowPunct - If set ignores ':','-','_','.'
 
826
 *  @return  error code
 
827
 */
 
828
nsresult nsScanner::ReadIdentifier(nsString& aString,PRBool allowPunct) {
 
829
 
 
830
  if (!mSlidingBuffer) {
 
831
    return kEOF;
 
832
  }
 
833
 
 
834
  PRUnichar         theChar=0;
 
835
  nsresult          result=Peek(theChar);
 
836
  nsScannerIterator origin, current, end;
 
837
  PRBool            found=PR_FALSE;  
 
838
 
 
839
  origin = mCurrentPosition;
 
840
  current = mCurrentPosition;
 
841
  end = mEndPosition;
 
842
 
 
843
  while(current != end) {
 
844
 
 
845
    theChar=*current;
 
846
    found=PR_FALSE;
 
847
    switch(theChar) {
 
848
      case ':':
 
849
      case '_':
 
850
      case '-':
 
851
      case '.':
 
852
        found=allowPunct;
 
853
        break;
 
854
      default:
 
855
        found = ('a'<=theChar && theChar<='z') ||
 
856
                ('A'<=theChar && theChar<='Z') ||
 
857
                ('0'<=theChar && theChar<='9');
 
858
        break;
 
859
    }
 
860
 
 
861
    if(!found) {
 
862
      AppendUnicodeTo(mCurrentPosition, current, aString);
 
863
      break;
 
864
    }
 
865
    
 
866
    ++current;
 
867
  }
 
868
  
 
869
  // Drop NULs on the floor since nobody really likes them
 
870
  while (current != end && !*current) {
 
871
    ++current;
 
872
  }
 
873
 
 
874
  SetPosition(current);
 
875
  if (current == end) {
 
876
    AppendUnicodeTo(origin, current, aString);
 
877
    return Eof();
 
878
  }
 
879
 
 
880
  //DoErrTest(aString);
 
881
 
 
882
  return result;
 
883
}
 
884
 
 
885
nsresult nsScanner::ReadIdentifier(nsScannerIterator& aStart,
 
886
                                   nsScannerIterator& aEnd,
 
887
                                   PRBool allowPunct) {
 
888
 
 
889
  if (!mSlidingBuffer) {
 
890
    return kEOF;
 
891
  }
 
892
 
 
893
  PRUnichar         theChar=0;
 
894
  nsresult          result=Peek(theChar);
 
895
  nsScannerIterator origin, current, end;
 
896
  PRBool            found=PR_FALSE;  
 
897
 
 
898
  origin = mCurrentPosition;
 
899
  current = mCurrentPosition;
 
900
  end = mEndPosition;
 
901
 
 
902
  while(current != end) {
 
903
 
 
904
    theChar=*current;
 
905
    if(theChar) {
 
906
      found=PR_FALSE;
 
907
      switch(theChar) {
 
908
        case ':':
 
909
        case '_':
 
910
        case '-':
 
911
          found=allowPunct;
 
912
          break;
 
913
        default:
 
914
          if(('a'<=theChar) && (theChar<='z'))
 
915
            found=PR_TRUE;
 
916
          else if(('A'<=theChar) && (theChar<='Z'))
 
917
            found=PR_TRUE;
 
918
          else if(('0'<=theChar) && (theChar<='9'))
 
919
            found=PR_TRUE;
 
920
          break;
 
921
      }
 
922
 
 
923
      if(!found) {
 
924
        aStart = mCurrentPosition;
 
925
        aEnd = current;
 
926
        break;
 
927
      }
 
928
    }
 
929
    ++current;
 
930
  }
 
931
  
 
932
  SetPosition(current);
 
933
  if (current == end) {
 
934
    aStart = origin;
 
935
    aEnd = current;
 
936
    return Eof();
 
937
  }
 
938
 
 
939
  //DoErrTest(aString);
 
940
 
 
941
  return result;
 
942
}
 
943
 
 
944
/**
 
945
 *  Consume digits 
 
946
 *  
 
947
 *  @param   aString - should contain digits
 
948
 *  @return  error code
 
949
 */
 
950
nsresult nsScanner::ReadNumber(nsString& aString,PRInt32 aBase) {
 
951
 
 
952
  if (!mSlidingBuffer) {
 
953
    return kEOF;
 
954
  }
 
955
 
 
956
  NS_ASSERTION(aBase == 10 || aBase == 16,"base value not supported");
 
957
 
 
958
  PRUnichar         theChar=0;
 
959
  nsresult          result=Peek(theChar);
 
960
  nsScannerIterator origin, current, end;
 
961
 
 
962
  origin = mCurrentPosition;
 
963
  current = origin;
 
964
  end = mEndPosition;
 
965
 
 
966
  PRBool done = PR_FALSE;
 
967
  while(current != end) {
 
968
    theChar=*current;
 
969
    if(theChar) {
 
970
      done = (theChar < '0' || theChar > '9') && 
 
971
             ((aBase == 16)? (theChar < 'A' || theChar > 'F') &&
 
972
                             (theChar < 'a' || theChar > 'f')
 
973
                             :PR_TRUE);
 
974
      if(done) {
 
975
        AppendUnicodeTo(origin, current, aString);
 
976
        break;
 
977
      }
 
978
    }
 
979
    ++current;
 
980
  }
 
981
 
 
982
  SetPosition(current);
 
983
  if (current == end) {
 
984
    AppendUnicodeTo(origin, current, aString);
 
985
    return Eof();
 
986
  }
 
987
 
 
988
  //DoErrTest(aString);
 
989
 
 
990
  return result;
 
991
}
 
992
 
 
993
/**
 
994
 *  Consume characters until you find the terminal char
 
995
 *  
 
996
 *  @update  gess 3/25/98
 
997
 *  @param   aString receives new data from stream
 
998
 *  @param   addTerminal tells us whether to append terminal to aString
 
999
 *  @return  error code
 
1000
 */
 
1001
nsresult nsScanner::ReadWhitespace(nsString& aString,
 
1002
                                   PRInt32& aNewlinesSkipped) {
 
1003
 
 
1004
  if (!mSlidingBuffer) {
 
1005
    return kEOF;
 
1006
  }
 
1007
 
 
1008
  PRUnichar theChar = 0;
 
1009
  nsresult  result = Peek(theChar);
 
1010
  
 
1011
  if (result == kEOF) {
 
1012
    return Eof();
 
1013
  }
 
1014
  
 
1015
  nsScannerIterator origin, current, end;
 
1016
  PRBool done = PR_FALSE;  
 
1017
 
 
1018
  origin = mCurrentPosition;
 
1019
  current = origin;
 
1020
  end = mEndPosition;
 
1021
 
 
1022
  while(!done && current != end) {
 
1023
    switch(theChar) {
 
1024
      case '\n':
 
1025
      case '\r': ++aNewlinesSkipped;
 
1026
      case ' ' :
 
1027
      case '\b':
 
1028
      case '\t':
 
1029
        {
 
1030
          PRUnichar thePrevChar = theChar;
 
1031
          theChar = (++current != end) ? *current : '\0';
 
1032
          if ((thePrevChar == '\r' && theChar == '\n') ||
 
1033
              (thePrevChar == '\n' && theChar == '\r')) {
 
1034
            theChar = (++current != end) ? *current : '\0'; // CRLF == LFCR => LF
 
1035
          }
 
1036
        }
 
1037
        break;
 
1038
      default:
 
1039
        done = PR_TRUE;
 
1040
        AppendUnicodeTo(origin, current, aString);
 
1041
        break;
 
1042
    }
 
1043
  }
 
1044
 
 
1045
  SetPosition(current);
 
1046
  if (current == end) {
 
1047
    AppendUnicodeTo(origin, current, aString);
 
1048
    result = Eof();
 
1049
  }
 
1050
 
 
1051
  return result;
 
1052
}
 
1053
 
 
1054
nsresult nsScanner::ReadWhitespace(nsScannerIterator& aStart, 
 
1055
                                   nsScannerIterator& aEnd,
 
1056
                                   PRInt32& aNewlinesSkipped) {
 
1057
 
 
1058
  if (!mSlidingBuffer) {
 
1059
    return kEOF;
 
1060
  }
 
1061
 
 
1062
  PRUnichar theChar = 0;
 
1063
  nsresult  result = Peek(theChar);
 
1064
  
 
1065
  if (result == kEOF) {
 
1066
    return Eof();
 
1067
  }
 
1068
  
 
1069
  nsScannerIterator origin, current, end;
 
1070
  PRBool done = PR_FALSE;  
 
1071
 
 
1072
  origin = mCurrentPosition;
 
1073
  current = origin;
 
1074
  end = mEndPosition;
 
1075
 
 
1076
  while(!done && current != end) {
 
1077
    switch(theChar) {
 
1078
      case '\n':
 
1079
      case '\r': ++aNewlinesSkipped;
 
1080
      case ' ' :
 
1081
      case '\b':
 
1082
      case '\t':
 
1083
        {
 
1084
          PRUnichar thePrevChar = theChar;
 
1085
          theChar = (++current != end) ? *current : '\0';
 
1086
          if ((thePrevChar == '\r' && theChar == '\n') ||
 
1087
              (thePrevChar == '\n' && theChar == '\r')) {
 
1088
            theChar = (++current != end) ? *current : '\0'; // CRLF == LFCR => LF
 
1089
          }
 
1090
        }
 
1091
        break;
 
1092
      default:
 
1093
        done = PR_TRUE;
 
1094
        aStart = origin;
 
1095
        aEnd = current;
 
1096
        break;
 
1097
    }
 
1098
  }
 
1099
 
 
1100
  SetPosition(current);
 
1101
  if (current == end) {
 
1102
    aStart = origin;
 
1103
    aEnd = current;
 
1104
    result = Eof();
 
1105
  }
 
1106
 
 
1107
  return result;
 
1108
}
 
1109
 
 
1110
/**
 
1111
 *  Consume chars as long as they are <i>in</i> the 
 
1112
 *  given validSet of input chars.
 
1113
 *  
 
1114
 *  @update  gess 3/25/98
 
1115
 *  @param   aString will contain the result of this method
 
1116
 *  @param   aValidSet is an ordered string that contains the
 
1117
 *           valid characters
 
1118
 *  @return  error code
 
1119
 */
 
1120
nsresult nsScanner::ReadWhile(nsString& aString,
 
1121
                             nsString& aValidSet,
 
1122
                             PRBool addTerminal){
 
1123
 
 
1124
  if (!mSlidingBuffer) {
 
1125
    return kEOF;
 
1126
  }
 
1127
 
 
1128
  PRUnichar         theChar=0;
 
1129
  nsresult          result=Peek(theChar);
 
1130
  nsScannerIterator origin, current, end;
 
1131
 
 
1132
  origin = mCurrentPosition;
 
1133
  current = origin;
 
1134
  end = mEndPosition;
 
1135
 
 
1136
  while(current != end) {
 
1137
 
 
1138
    theChar=*current;
 
1139
    if(theChar) {
 
1140
      PRInt32 pos=aValidSet.FindChar(theChar);
 
1141
      if(kNotFound==pos) {
 
1142
        if(addTerminal)
 
1143
          ++current;
 
1144
        AppendUnicodeTo(origin, current, aString);
 
1145
        break;
 
1146
      }
 
1147
    }
 
1148
    ++current;
 
1149
  }
 
1150
 
 
1151
  SetPosition(current);
 
1152
  if (current == end) {
 
1153
    AppendUnicodeTo(origin, current, aString);
 
1154
    return Eof();
 
1155
  }
 
1156
 
 
1157
  //DoErrTest(aString);
 
1158
 
 
1159
  return result;
 
1160
 
 
1161
}
 
1162
 
 
1163
#ifdef MOZ_STANDALONE_COMPOSER
 
1164
nsresult nsScanner::Checks(const nsReadEndCondition& aEndCondition)
 
1165
{
 
1166
  if (!mSlidingBuffer) {
 
1167
    return kEOF;
 
1168
  }
 
1169
 
 
1170
  nsScannerIterator origin, current;
 
1171
  const PRUnichar* setstart = aEndCondition.mChars;
 
1172
  const PRUnichar* setcurrent = setstart;
 
1173
 
 
1174
  origin = mCurrentPosition;
 
1175
  current = origin;
 
1176
 
 
1177
  PRUnichar         theChar = 0;
 
1178
  nsresult          result  = Peek(theChar);
 
1179
 
 
1180
  if (result == kEOF) {
 
1181
    return Eof();
 
1182
  }
 
1183
  
 
1184
  while (current != mEndPosition) {
 
1185
    // Filter out completely wrong characters
 
1186
    // Check if all bits are in the required area
 
1187
    if(!(theChar & aEndCondition.mFilter)) {
 
1188
      // They were. Do a thorough check.
 
1189
      if (*setcurrent == theChar)
 
1190
        ++setcurrent;
 
1191
      else
 
1192
        break;
 
1193
 
 
1194
      if (!*setcurrent)
 
1195
        goto found;
 
1196
    }
 
1197
    ++current;
 
1198
    theChar = *current;
 
1199
  }
 
1200
 
 
1201
  return Eof();
 
1202
 
 
1203
found:
 
1204
  return NS_OK;
 
1205
}
 
1206
#endif
 
1207
 
 
1208
/**
 
1209
 *  Consume characters until you encounter one contained in given
 
1210
 *  input set.
 
1211
 *  
 
1212
 *  @update  gess 3/25/98
 
1213
 *  @param   aString will contain the result of this method
 
1214
 *  @param   aTerminalSet is an ordered string that contains
 
1215
 *           the set of INVALID characters
 
1216
 *  @return  error code
 
1217
 */
 
1218
nsresult nsScanner::ReadUntil(nsAString& aString,
 
1219
                              const nsReadEndCondition& aEndCondition,
 
1220
                              PRBool addTerminal,
 
1221
                              PRBool aAllTerminators)
 
1222
{  
 
1223
  if (!mSlidingBuffer) {
 
1224
    return kEOF;
 
1225
  }
 
1226
 
 
1227
  nsScannerIterator origin, current;
 
1228
  const PRUnichar* setstart = aEndCondition.mChars;
 
1229
  const PRUnichar* setcurrent = setstart;
 
1230
 
 
1231
  origin = mCurrentPosition;
 
1232
  current = origin;
 
1233
 
 
1234
  PRUnichar         theChar=0;
 
1235
  nsresult          result=Peek(theChar);
 
1236
 
 
1237
  if (result == kEOF) {
 
1238
    return Eof();
 
1239
  }
 
1240
  
 
1241
  while (current != mEndPosition) {
 
1242
    // Filter out completely wrong characters
 
1243
    // Check if all bits are in the required area
 
1244
    if(!(theChar & aEndCondition.mFilter)) {
 
1245
      // They were. Do a thorough check.
 
1246
 
 
1247
      if (aAllTerminators) {
 
1248
        if (*setcurrent && *setcurrent == theChar)
 
1249
          ++setcurrent;
 
1250
        else {
 
1251
          setcurrent = setstart;
 
1252
          if (*setcurrent && *setcurrent == theChar)
 
1253
            ++setcurrent;
 
1254
        }
 
1255
        if (!*setcurrent)
 
1256
          goto found;
 
1257
      }
 
1258
      else {
 
1259
        setcurrent = setstart;
 
1260
        while (*setcurrent) {
 
1261
          if (*setcurrent == theChar) {
 
1262
            goto found;
 
1263
          }
 
1264
          ++setcurrent;
 
1265
        }
 
1266
      }
 
1267
    }
 
1268
    
 
1269
    ++current;
 
1270
    theChar = *current;
 
1271
  }
 
1272
 
 
1273
  // If we are here, we didn't find any terminator in the string and
 
1274
  // current = mEndPosition
 
1275
  SetPosition(current);
 
1276
  AppendUnicodeTo(origin, current, aString);
 
1277
  return Eof();
 
1278
 
 
1279
found:
 
1280
  if(addTerminal)
 
1281
    ++current;
 
1282
  AppendUnicodeTo(origin, current, aString);
 
1283
  SetPosition(current);
 
1284
 
 
1285
  //DoErrTest(aString);
 
1286
 
 
1287
  return NS_OK;
 
1288
}
 
1289
 
 
1290
nsresult nsScanner::ReadUntil(nsScannerIterator& aStart, 
 
1291
                              nsScannerIterator& aEnd,
 
1292
                              const nsReadEndCondition &aEndCondition,
 
1293
                              PRBool addTerminal)
 
1294
{
 
1295
  if (!mSlidingBuffer) {
 
1296
    return kEOF;
 
1297
  }
 
1298
 
 
1299
  nsScannerIterator origin, current;
 
1300
  const PRUnichar* setstart = aEndCondition.mChars;
 
1301
  const PRUnichar* setcurrent;
 
1302
 
 
1303
  origin = mCurrentPosition;
 
1304
  current = origin;
 
1305
 
 
1306
  PRUnichar         theChar=0;
 
1307
  nsresult          result=Peek(theChar);
 
1308
  
 
1309
  if (result == kEOF) {
 
1310
    aStart = aEnd = current;
 
1311
    return Eof();
 
1312
  }
 
1313
  
 
1314
  while (current != mEndPosition) {
 
1315
    // Filter out completely wrong characters
 
1316
    // Check if all bits are in the required area
 
1317
    if(!(theChar & aEndCondition.mFilter)) {
 
1318
      // They were. Do a thorough check.
 
1319
      setcurrent = setstart;
 
1320
      while (*setcurrent) {
 
1321
        if (*setcurrent == theChar) {
 
1322
          goto found;
 
1323
        }
 
1324
      ++setcurrent;
 
1325
      }
 
1326
    }
 
1327
    
 
1328
    ++current;
 
1329
    theChar = *current;
 
1330
  }
 
1331
 
 
1332
  // If we are here, we didn't find any terminator in the string and
 
1333
  // current = mEndPosition
 
1334
  SetPosition(current);
 
1335
  aStart = origin;
 
1336
  aEnd = current;
 
1337
  return Eof();
 
1338
 
 
1339
 found:
 
1340
  if(addTerminal)
 
1341
    ++current;
 
1342
  aStart = origin;
 
1343
  aEnd = current;
 
1344
  SetPosition(current);
 
1345
 
 
1346
  return NS_OK; 
 
1347
}
 
1348
 
 
1349
/**
 
1350
 *  Consumes chars until you see the given terminalChar
 
1351
 *  
 
1352
 *  @update  gess 3/25/98
 
1353
 *  @param   
 
1354
 *  @return  error code
 
1355
 */
 
1356
nsresult nsScanner::ReadUntil(nsAString& aString,
 
1357
                              PRUnichar aTerminalChar,
 
1358
                              PRBool addTerminal)
 
1359
{
 
1360
  if (!mSlidingBuffer) {
 
1361
    return kEOF;
 
1362
  }
 
1363
 
 
1364
  nsScannerIterator origin, current;
 
1365
 
 
1366
  origin = mCurrentPosition;
 
1367
  current = origin;
 
1368
 
 
1369
  PRUnichar theChar;
 
1370
  Peek(theChar);
 
1371
  
 
1372
  while (current != mEndPosition) {
 
1373
    if (aTerminalChar == theChar) {
 
1374
      if(addTerminal)
 
1375
        ++current;
 
1376
      AppendUnicodeTo(origin, current, aString);
 
1377
      SetPosition(current);
 
1378
      return NS_OK;
 
1379
    }
 
1380
    ++current;
 
1381
    theChar = *current;
 
1382
  }
 
1383
 
 
1384
  // If we are here, we didn't find any terminator in the string and
 
1385
  // current = mEndPosition
 
1386
  AppendUnicodeTo(origin, current, aString);
 
1387
  SetPosition(current);
 
1388
  return Eof();
 
1389
 
 
1390
}
 
1391
 
 
1392
void nsScanner::BindSubstring(nsScannerSubstring& aSubstring, const nsScannerIterator& aStart, const nsScannerIterator& aEnd)
 
1393
{
 
1394
  aSubstring.Rebind(*mSlidingBuffer, aStart, aEnd);
 
1395
}
 
1396
 
 
1397
void nsScanner::CurrentPosition(nsScannerIterator& aPosition)
 
1398
{
 
1399
  aPosition = mCurrentPosition;
 
1400
}
 
1401
 
 
1402
void nsScanner::EndReading(nsScannerIterator& aPosition)
 
1403
{
 
1404
  aPosition = mEndPosition;
 
1405
}
 
1406
 
 
1407
void nsScanner::SetPosition(nsScannerIterator& aPosition, PRBool aTerminate, PRBool aReverse)
 
1408
{
 
1409
  if (mSlidingBuffer) {
 
1410
    if (aReverse) {
 
1411
      mCountRemaining += (Distance(aPosition, mCurrentPosition));
 
1412
    }
 
1413
    else {
 
1414
      mCountRemaining -= (Distance(mCurrentPosition, aPosition));
 
1415
    }
 
1416
    mCurrentPosition = aPosition;
 
1417
    if (aTerminate && (mCurrentPosition == mEndPosition)) {
 
1418
      mMarkPosition = mCurrentPosition;
 
1419
      mSlidingBuffer->DiscardPrefix(mCurrentPosition);
 
1420
    }
 
1421
  }
 
1422
}
 
1423
 
 
1424
void nsScanner::ReplaceCharacter(nsScannerIterator& aPosition,
 
1425
                                 PRUnichar aChar)
 
1426
{
 
1427
  if (mSlidingBuffer) {
 
1428
    mSlidingBuffer->ReplaceCharacter(aPosition, aChar);
 
1429
  }
 
1430
}
 
1431
 
 
1432
void nsScanner::AppendToBuffer(nsScannerString::Buffer* aBuf,
 
1433
                               nsIRequest *aRequest)
 
1434
{
 
1435
  if (nsParser::sParserDataListeners && mParser &&
 
1436
      NS_FAILED(mParser->DataAdded(Substring(aBuf->DataStart(),
 
1437
                                             aBuf->DataEnd()), aRequest))) {
 
1438
    // Don't actually append on failure.
 
1439
 
 
1440
    return;
 
1441
  }
 
1442
 
 
1443
  if (!mSlidingBuffer) {
 
1444
    mSlidingBuffer = new nsScannerString(aBuf);
 
1445
    mSlidingBuffer->BeginReading(mCurrentPosition);
 
1446
    mMarkPosition = mCurrentPosition;
 
1447
    mSlidingBuffer->EndReading(mEndPosition);
 
1448
    mCountRemaining = aBuf->DataLength();
 
1449
  }
 
1450
  else {
 
1451
    mSlidingBuffer->AppendBuffer(aBuf);
 
1452
    if (mCurrentPosition == mEndPosition) {
 
1453
      mSlidingBuffer->BeginReading(mCurrentPosition);
 
1454
    }
 
1455
    mSlidingBuffer->EndReading(mEndPosition);
 
1456
    mCountRemaining += aBuf->DataLength();
 
1457
  }
 
1458
 
 
1459
  if (mFirstNonWhitespacePosition == -1) {
 
1460
    nsScannerIterator iter(mCurrentPosition);
 
1461
    nsScannerIterator end(mEndPosition);
 
1462
 
 
1463
    while (iter != end) {
 
1464
      if (!nsCRT::IsAsciiSpace(*iter)) {
 
1465
        mFirstNonWhitespacePosition = Distance(mCurrentPosition, iter);
 
1466
 
 
1467
        break;
 
1468
      }
 
1469
 
 
1470
      ++iter;
 
1471
    }
 
1472
  }
 
1473
}
 
1474
 
 
1475
void nsScanner::AppendASCIItoBuffer(const char* aData, PRUint32 aLen,
 
1476
                                    nsIRequest *aRequest)
 
1477
{
 
1478
  nsScannerString::Buffer* buf = nsScannerString::AllocBuffer(aLen);
 
1479
  if (buf)
 
1480
  {
 
1481
    LossyConvertEncoding<char, PRUnichar> converter(buf->DataStart());
 
1482
    converter.write(aData, aLen);
 
1483
    converter.write_terminator();
 
1484
    AppendToBuffer(buf, aRequest);
 
1485
  }
 
1486
}
 
1487
 
 
1488
/**
 
1489
 *  call this to copy bytes out of the scanner that have not yet been consumed
 
1490
 *  by the tokenization process.
 
1491
 *  
 
1492
 *  @update  gess 5/12/98
 
1493
 *  @param   aCopyBuffer is where the scanner buffer will be copied to
 
1494
 *  @return  nada
 
1495
 */
 
1496
void nsScanner::CopyUnusedData(nsString& aCopyBuffer) {
 
1497
  nsScannerIterator start, end;
 
1498
  start = mCurrentPosition;
 
1499
  end = mEndPosition;
 
1500
 
 
1501
  CopyUnicodeTo(start, end, aCopyBuffer);
 
1502
}
 
1503
 
 
1504
/**
 
1505
 *  Retrieve the name of the file that the scanner is reading from.
 
1506
 *  In some cases, it's just a given name, because the scanner isn't
 
1507
 *  really reading from a file.
 
1508
 *  
 
1509
 *  @update  gess 5/12/98
 
1510
 *  @return  
 
1511
 */
 
1512
nsString& nsScanner::GetFilename(void) {
 
1513
  return mFilename;
 
1514
}
 
1515
 
 
1516
/**
 
1517
 *  Conduct self test. Actually, selftesting for this class
 
1518
 *  occurs in the parser selftest.
 
1519
 *  
 
1520
 *  @update  gess 3/25/98
 
1521
 *  @param   
 
1522
 *  @return  
 
1523
 */
 
1524
 
 
1525
void nsScanner::SelfTest(void) {
 
1526
#ifdef _DEBUG
 
1527
#endif
 
1528
}
 
1529
 
 
1530
 
 
1531