1/*
2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
3 */
4
5/*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements.  See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License.  You may obtain a copy of the License at
12 *
13 *     http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22package com.sun.org.apache.xerces.internal.impl;
23
24import com.sun.org.apache.xerces.internal.impl.XMLScanner.NameType;
25import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
26import com.sun.org.apache.xerces.internal.util.XML11Char;
27import com.sun.org.apache.xerces.internal.util.XMLChar;
28import com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
29import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager.Limit;
30import com.sun.org.apache.xerces.internal.xni.QName;
31import com.sun.org.apache.xerces.internal.xni.XMLString;
32import java.io.IOException;
33
34/**
35 * Implements the entity scanner methods in
36 * the context of XML 1.1.
37 *
38 * @xerces.internal
39 *
40 * @author Michael Glavassevich, IBM
41 * @author Neil Graham, IBM
42 */
43
44public class XML11EntityScanner
45    extends XMLEntityScanner {
46
47    //
48    // Constructors
49    //
50
51    /** Default constructor. */
52    public XML11EntityScanner() {
53        super();
54    } // <init>()
55
56    //
57    // XMLEntityScanner methods
58    //
59
60    /**
61     * Returns the next character on the input.
62     * <p>
63     * <strong>Note:</strong> The character is <em>not</em> consumed.
64     *
65     * @throws IOException  Thrown if i/o error occurs.
66     * @throws EOFException Thrown on end of file.
67     */
68    public int peekChar() throws IOException {
69
70        // load more characters, if needed
71        if (fCurrentEntity.position == fCurrentEntity.count) {
72            load(0, true, true);
73        }
74
75        // peek at character
76        int c = fCurrentEntity.ch[fCurrentEntity.position];
77
78        // return peeked character
79        if (fCurrentEntity.isExternal()) {
80            return (c != '\r' && c != 0x85 && c != 0x2028) ? c : '\n';
81        }
82        else {
83            return c;
84        }
85
86    } // peekChar():int
87
88    /**
89     * Returns the next character on the input.
90     * <p>
91     * <strong>Note:</strong> The character is consumed.
92     *
93     * @throws IOException  Thrown if i/o error occurs.
94     * @throws EOFException Thrown on end of file.
95     */
96    protected int scanChar(NameType nt) throws IOException {
97
98        // load more characters, if needed
99        if (fCurrentEntity.position == fCurrentEntity.count) {
100            load(0, true, true);
101        }
102
103        // scan character
104        int offset = fCurrentEntity.position;
105        int c = fCurrentEntity.ch[fCurrentEntity.position++];
106        boolean external = false;
107        if (c == '\n' ||
108            ((c == '\r' || c == 0x85 || c == 0x2028) && (external = fCurrentEntity.isExternal()))) {
109            fCurrentEntity.lineNumber++;
110            fCurrentEntity.columnNumber = 1;
111            if (fCurrentEntity.position == fCurrentEntity.count) {
112                invokeListeners(1);
113                fCurrentEntity.ch[0] = (char)c;
114                load(1, false, false);
115                offset = 0;
116            }
117            if (c == '\r' && external) {
118                int cc = fCurrentEntity.ch[fCurrentEntity.position++];
119                if (cc != '\n' && cc != 0x85) {
120                    fCurrentEntity.position--;
121                }
122            }
123            c = '\n';
124        }
125
126        // return character that was scanned
127        fCurrentEntity.columnNumber++;
128        if (!detectingVersion) {
129            checkEntityLimit(nt, fCurrentEntity, offset, fCurrentEntity.position - offset);
130        }
131        return c;
132
133    } // scanChar():int
134
135    /**
136     * Returns a string matching the NMTOKEN production appearing immediately
137     * on the input as a symbol, or null if NMTOKEN Name string is present.
138     * <p>
139     * <strong>Note:</strong> The NMTOKEN characters are consumed.
140     * <p>
141     * <strong>Note:</strong> The string returned must be a symbol. The
142     * SymbolTable can be used for this purpose.
143     *
144     * @throws IOException  Thrown if i/o error occurs.
145     * @throws EOFException Thrown on end of file.
146     *
147     * @see com.sun.org.apache.xerces.internal.util.SymbolTable
148     * @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11Name
149     */
150    protected String scanNmtoken() throws IOException {
151        // load more characters, if needed
152        if (fCurrentEntity.position == fCurrentEntity.count) {
153            load(0, true, true);
154        }
155
156        // scan nmtoken
157        int offset = fCurrentEntity.position;
158
159        do {
160            char ch = fCurrentEntity.ch[fCurrentEntity.position];
161            if (XML11Char.isXML11Name(ch)) {
162                if (++fCurrentEntity.position == fCurrentEntity.count) {
163                    int length = fCurrentEntity.position - offset;
164                    invokeListeners(length);
165                    if (length == fCurrentEntity.ch.length) {
166                        // bad luck we have to resize our buffer
167                        char[] tmp = new char[fCurrentEntity.ch.length << 1];
168                        System.arraycopy(fCurrentEntity.ch, offset,
169                                         tmp, 0, length);
170                        fCurrentEntity.ch = tmp;
171                    }
172                    else {
173                        System.arraycopy(fCurrentEntity.ch, offset,
174                                         fCurrentEntity.ch, 0, length);
175                    }
176                    offset = 0;
177                    if (load(length, false, false)) {
178                        break;
179                    }
180                }
181            }
182            else if (XML11Char.isXML11NameHighSurrogate(ch)) {
183                if (++fCurrentEntity.position == fCurrentEntity.count) {
184                    int length = fCurrentEntity.position - offset;
185                    invokeListeners(length);
186                    if (length == fCurrentEntity.ch.length) {
187                        // bad luck we have to resize our buffer
188                        char[] tmp = new char[fCurrentEntity.ch.length << 1];
189                        System.arraycopy(fCurrentEntity.ch, offset,
190                                         tmp, 0, length);
191                        fCurrentEntity.ch = tmp;
192                    }
193                    else {
194                        System.arraycopy(fCurrentEntity.ch, offset,
195                                         fCurrentEntity.ch, 0, length);
196                    }
197                    offset = 0;
198                    if (load(length, false, false)) {
199                        --fCurrentEntity.startPosition;
200                        --fCurrentEntity.position;
201                        break;
202                    }
203                }
204                char ch2 = fCurrentEntity.ch[fCurrentEntity.position];
205                if ( !XMLChar.isLowSurrogate(ch2) ||
206                     !XML11Char.isXML11Name(XMLChar.supplemental(ch, ch2)) ) {
207                    --fCurrentEntity.position;
208                    break;
209                }
210                if (++fCurrentEntity.position == fCurrentEntity.count) {
211                    int length = fCurrentEntity.position - offset;
212                    invokeListeners(length);
213                    if (length == fCurrentEntity.ch.length) {
214                        // bad luck we have to resize our buffer
215                        char[] tmp = new char[fCurrentEntity.ch.length << 1];
216                        System.arraycopy(fCurrentEntity.ch, offset,
217                                         tmp, 0, length);
218                        fCurrentEntity.ch = tmp;
219                    }
220                    else {
221                        System.arraycopy(fCurrentEntity.ch, offset,
222                                         fCurrentEntity.ch, 0, length);
223                    }
224                    offset = 0;
225                    if (load(length, false, false)) {
226                        break;
227                    }
228                }
229            }
230            else {
231                break;
232            }
233        }
234        while (true);
235
236        int length = fCurrentEntity.position - offset;
237        fCurrentEntity.columnNumber += length;
238
239        // return nmtoken
240        String symbol = null;
241        if (length > 0) {
242            symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length);
243        }
244        return symbol;
245
246    } // scanNmtoken():String
247
248    /**
249     * Returns a string matching the Name production appearing immediately
250     * on the input as a symbol, or null if no Name string is present.
251     * <p>
252     * <strong>Note:</strong> The Name characters are consumed.
253     * <p>
254     * <strong>Note:</strong> The string returned must be a symbol. The
255     * SymbolTable can be used for this purpose.
256     *
257     * @param nt The type of the name (element or attribute)
258     *
259     * @throws IOException  Thrown if i/o error occurs.
260     * @throws EOFException Thrown on end of file.
261     *
262     * @see com.sun.org.apache.xerces.internal.util.SymbolTable
263     * @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11Name
264     * @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11NameStart
265     */
266    protected String scanName(NameType nt) throws IOException {
267        // load more characters, if needed
268        if (fCurrentEntity.position == fCurrentEntity.count) {
269            load(0, true, true);
270        }
271
272        // scan name
273        int offset = fCurrentEntity.position;
274        char ch = fCurrentEntity.ch[offset];
275
276        if (XML11Char.isXML11NameStart(ch)) {
277            if (++fCurrentEntity.position == fCurrentEntity.count) {
278                invokeListeners(1);
279                fCurrentEntity.ch[0] = ch;
280                offset = 0;
281                if (load(1, false, false)) {
282                    fCurrentEntity.columnNumber++;
283                    String symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 1);
284                    return symbol;
285                }
286            }
287        }
288        else if (XML11Char.isXML11NameHighSurrogate(ch)) {
289            if (++fCurrentEntity.position == fCurrentEntity.count) {
290                invokeListeners(1);
291                fCurrentEntity.ch[0] = ch;
292                offset = 0;
293                if (load(1, false, false)) {
294                    --fCurrentEntity.position;
295                    --fCurrentEntity.startPosition;
296                    return null;
297                }
298            }
299            char ch2 = fCurrentEntity.ch[fCurrentEntity.position];
300            if ( !XMLChar.isLowSurrogate(ch2) ||
301                 !XML11Char.isXML11NameStart(XMLChar.supplemental(ch, ch2)) ) {
302                --fCurrentEntity.position;
303                return null;
304            }
305            if (++fCurrentEntity.position == fCurrentEntity.count) {
306                invokeListeners(2);
307                fCurrentEntity.ch[0] = ch;
308                fCurrentEntity.ch[1] = ch2;
309                offset = 0;
310                if (load(2, false, false)) {
311                    fCurrentEntity.columnNumber += 2;
312                    String symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 2);
313                    return symbol;
314                }
315            }
316        }
317        else {
318            return null;
319        }
320
321        int length = 0;
322        do {
323            ch = fCurrentEntity.ch[fCurrentEntity.position];
324            if (XML11Char.isXML11Name(ch)) {
325                if ((length = checkBeforeLoad(fCurrentEntity, offset, offset)) > 0) {
326                    offset = 0;
327                    if (load(length, false, false)) {
328                        break;
329                    }
330                }
331            }
332            else if (XML11Char.isXML11NameHighSurrogate(ch)) {
333                if ((length = checkBeforeLoad(fCurrentEntity, offset, offset)) > 0) {
334                    offset = 0;
335                    if (load(length, false, false)) {
336                        --fCurrentEntity.position;
337                        --fCurrentEntity.startPosition;
338                        break;
339                    }
340                }
341                char ch2 = fCurrentEntity.ch[fCurrentEntity.position];
342                if ( !XMLChar.isLowSurrogate(ch2) ||
343                     !XML11Char.isXML11Name(XMLChar.supplemental(ch, ch2)) ) {
344                    --fCurrentEntity.position;
345                    break;
346                }
347                if ((length = checkBeforeLoad(fCurrentEntity, offset, offset)) > 0) {
348                    offset = 0;
349                    if (load(length, false, false)) {
350                        break;
351                    }
352                }
353            }
354            else {
355                break;
356            }
357        }
358        while (true);
359
360        length = fCurrentEntity.position - offset;
361        fCurrentEntity.columnNumber += length;
362
363        // return name
364        String symbol = null;
365        if (length > 0) {
366            checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, length);
367            checkEntityLimit(nt, fCurrentEntity, offset, length);
368            symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length);
369        }
370        return symbol;
371
372    } // scanName():String
373
374    /**
375     * Returns a string matching the NCName production appearing immediately
376     * on the input as a symbol, or null if no NCName string is present.
377     * <p>
378     * <strong>Note:</strong> The NCName characters are consumed.
379     * <p>
380     * <strong>Note:</strong> The string returned must be a symbol. The
381     * SymbolTable can be used for this purpose.
382     *
383     * @throws IOException  Thrown if i/o error occurs.
384     * @throws EOFException Thrown on end of file.
385     *
386     * @see com.sun.org.apache.xerces.internal.util.SymbolTable
387     * @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11NCName
388     * @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11NCNameStart
389     */
390    protected String scanNCName() throws IOException {
391
392        // load more characters, if needed
393        if (fCurrentEntity.position == fCurrentEntity.count) {
394            load(0, true, true);
395        }
396
397        // scan name
398        int offset = fCurrentEntity.position;
399        char ch = fCurrentEntity.ch[offset];
400
401        if (XML11Char.isXML11NCNameStart(ch)) {
402            if (++fCurrentEntity.position == fCurrentEntity.count) {
403                invokeListeners(1);
404                fCurrentEntity.ch[0] = ch;
405                offset = 0;
406                if (load(1, false, false)) {
407                    fCurrentEntity.columnNumber++;
408                    String symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 1);
409                    return symbol;
410                }
411            }
412        }
413        else if (XML11Char.isXML11NameHighSurrogate(ch)) {
414            if (++fCurrentEntity.position == fCurrentEntity.count) {
415                invokeListeners(1);
416                fCurrentEntity.ch[0] = ch;
417                offset = 0;
418                if (load(1, false, false)) {
419                    --fCurrentEntity.position;
420                    --fCurrentEntity.startPosition;
421                    return null;
422                }
423            }
424            char ch2 = fCurrentEntity.ch[fCurrentEntity.position];
425            if ( !XMLChar.isLowSurrogate(ch2) ||
426                 !XML11Char.isXML11NCNameStart(XMLChar.supplemental(ch, ch2)) ) {
427                --fCurrentEntity.position;
428                return null;
429            }
430            if (++fCurrentEntity.position == fCurrentEntity.count) {
431                invokeListeners(2);
432                fCurrentEntity.ch[0] = ch;
433                fCurrentEntity.ch[1] = ch2;
434                offset = 0;
435                if (load(2, false, false)) {
436                    fCurrentEntity.columnNumber += 2;
437                    String symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 2);
438                    return symbol;
439                }
440            }
441        }
442        else {
443            return null;
444        }
445
446        do {
447            ch = fCurrentEntity.ch[fCurrentEntity.position];
448            if (XML11Char.isXML11NCName(ch)) {
449                if (++fCurrentEntity.position == fCurrentEntity.count) {
450                    int length = fCurrentEntity.position - offset;
451                    invokeListeners(length);
452                    if (length == fCurrentEntity.ch.length) {
453                        // bad luck we have to resize our buffer
454                        char[] tmp = new char[fCurrentEntity.ch.length << 1];
455                        System.arraycopy(fCurrentEntity.ch, offset,
456                                         tmp, 0, length);
457                        fCurrentEntity.ch = tmp;
458                    }
459                    else {
460                        System.arraycopy(fCurrentEntity.ch, offset,
461                                         fCurrentEntity.ch, 0, length);
462                    }
463                    offset = 0;
464                    if (load(length, false, false)) {
465                        break;
466                    }
467                }
468            }
469            else if (XML11Char.isXML11NameHighSurrogate(ch)) {
470                if (++fCurrentEntity.position == fCurrentEntity.count) {
471                    int length = fCurrentEntity.position - offset;
472                    invokeListeners(length);
473                    if (length == fCurrentEntity.ch.length) {
474                        // bad luck we have to resize our buffer
475                        char[] tmp = new char[fCurrentEntity.ch.length << 1];
476                        System.arraycopy(fCurrentEntity.ch, offset,
477                                         tmp, 0, length);
478                        fCurrentEntity.ch = tmp;
479                    }
480                    else {
481                        System.arraycopy(fCurrentEntity.ch, offset,
482                                         fCurrentEntity.ch, 0, length);
483                    }
484                    offset = 0;
485                    if (load(length, false, false)) {
486                        --fCurrentEntity.startPosition;
487                        --fCurrentEntity.position;
488                        break;
489                    }
490                }
491                char ch2 = fCurrentEntity.ch[fCurrentEntity.position];
492                if ( !XMLChar.isLowSurrogate(ch2) ||
493                     !XML11Char.isXML11NCName(XMLChar.supplemental(ch, ch2)) ) {
494                    --fCurrentEntity.position;
495                    break;
496                }
497                if (++fCurrentEntity.position == fCurrentEntity.count) {
498                    int length = fCurrentEntity.position - offset;
499                    invokeListeners(length);
500                    if (length == fCurrentEntity.ch.length) {
501                        // bad luck we have to resize our buffer
502                        char[] tmp = new char[fCurrentEntity.ch.length << 1];
503                        System.arraycopy(fCurrentEntity.ch, offset,
504                                         tmp, 0, length);
505                        fCurrentEntity.ch = tmp;
506                    }
507                    else {
508                        System.arraycopy(fCurrentEntity.ch, offset,
509                                         fCurrentEntity.ch, 0, length);
510                    }
511                    offset = 0;
512                    if (load(length, false, false)) {
513                        break;
514                    }
515                }
516            }
517            else {
518                break;
519            }
520        }
521        while (true);
522
523        int length = fCurrentEntity.position - offset;
524        fCurrentEntity.columnNumber += length;
525
526        // return name
527        String symbol = null;
528        if (length > 0) {
529            symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length);
530        }
531        return symbol;
532
533    } // scanNCName():String
534
535    /**
536     * Scans a qualified name from the input, setting the fields of the
537     * QName structure appropriately.
538     * <p>
539     * <strong>Note:</strong> The qualified name characters are consumed.
540     * <p>
541     * <strong>Note:</strong> The strings used to set the values of the
542     * QName structure must be symbols. The SymbolTable can be used for
543     * this purpose.
544     *
545     * @param qname The qualified name structure to fill.
546     * @param nt The type of the name (element or attribute)
547     *
548     * @return Returns true if a qualified name appeared immediately on
549     *         the input and was scanned, false otherwise.
550     *
551     * @throws IOException  Thrown if i/o error occurs.
552     * @throws EOFException Thrown on end of file.
553     *
554     * @see com.sun.org.apache.xerces.internal.util.SymbolTable
555     * @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11Name
556     * @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11NameStart
557     */
558    protected boolean scanQName(QName qname, XMLScanner.NameType nt) throws IOException {
559
560        // load more characters, if needed
561        if (fCurrentEntity.position == fCurrentEntity.count) {
562            load(0, true, true);
563        }
564
565        // scan qualified name
566        int offset = fCurrentEntity.position;
567        char ch = fCurrentEntity.ch[offset];
568
569        if (XML11Char.isXML11NCNameStart(ch)) {
570            if (++fCurrentEntity.position == fCurrentEntity.count) {
571                invokeListeners(1);
572                fCurrentEntity.ch[0] = ch;
573                offset = 0;
574                if (load(1, false, false)) {
575                    fCurrentEntity.columnNumber++;
576                    String name = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 1);
577                    qname.setValues(null, name, name, null);
578                    checkEntityLimit(nt, fCurrentEntity, 0, 1);
579                    return true;
580                }
581            }
582        }
583        else if (XML11Char.isXML11NameHighSurrogate(ch)) {
584            if (++fCurrentEntity.position == fCurrentEntity.count) {
585                invokeListeners(1);
586                fCurrentEntity.ch[0] = ch;
587                offset = 0;
588                if (load(1, false, false)) {
589                    --fCurrentEntity.startPosition;
590                    --fCurrentEntity.position;
591                    return false;
592                }
593            }
594            char ch2 = fCurrentEntity.ch[fCurrentEntity.position];
595            if ( !XMLChar.isLowSurrogate(ch2) ||
596                 !XML11Char.isXML11NCNameStart(XMLChar.supplemental(ch, ch2)) ) {
597                --fCurrentEntity.position;
598                return false;
599            }
600            if (++fCurrentEntity.position == fCurrentEntity.count) {
601                invokeListeners(2);
602                fCurrentEntity.ch[0] = ch;
603                fCurrentEntity.ch[1] = ch2;
604                offset = 0;
605                if (load(2, false, false)) {
606                    fCurrentEntity.columnNumber += 2;
607                    String name = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 2);
608                    qname.setValues(null, name, name, null);
609                    checkEntityLimit(nt, fCurrentEntity, 0, 2);
610                    return true;
611                }
612            }
613        }
614        else {
615            return false;
616        }
617
618        int index = -1;
619        int length = 0;
620        boolean sawIncompleteSurrogatePair = false;
621        do {
622            ch = fCurrentEntity.ch[fCurrentEntity.position];
623            if (XML11Char.isXML11Name(ch)) {
624                if (ch == ':') {
625                    if (index != -1) {
626                        break;
627                    }
628                    index = fCurrentEntity.position;
629                    //check prefix before further read
630                    checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, index - offset);
631                }
632                if ((length = checkBeforeLoad(fCurrentEntity, offset, index)) > 0) {
633                    if (index != -1) {
634                        index = index - offset;
635                    }
636                    offset = 0;
637                    if (load(length, false, false)) {
638                        break;
639                    }
640                }
641            }
642            else if (XML11Char.isXML11NameHighSurrogate(ch)) {
643                if ((length = checkBeforeLoad(fCurrentEntity, offset, index)) > 0) {
644                    if (index != -1) {
645                        index = index - offset;
646                    }
647                    offset = 0;
648                    if (load(length, false, false)) {
649                        sawIncompleteSurrogatePair = true;
650                        --fCurrentEntity.startPosition;
651                        --fCurrentEntity.position;
652                        break;
653                    }
654                }
655                char ch2 = fCurrentEntity.ch[fCurrentEntity.position];
656                if ( !XMLChar.isLowSurrogate(ch2) ||
657                     !XML11Char.isXML11Name(XMLChar.supplemental(ch, ch2)) ) {
658                    sawIncompleteSurrogatePair = true;
659                    --fCurrentEntity.position;
660                    break;
661                }
662                if ((length = checkBeforeLoad(fCurrentEntity, offset, index)) > 0) {
663                    if (index != -1) {
664                        index = index - offset;
665                    }
666                    offset = 0;
667                    if (load(length, false, false)) {
668                        break;
669                    }
670                }
671            }
672            else {
673                break;
674            }
675        }
676        while (true);
677
678        length = fCurrentEntity.position - offset;
679        fCurrentEntity.columnNumber += length;
680
681        if (length > 0) {
682            String prefix = null;
683            String localpart = null;
684            String rawname = fSymbolTable.addSymbol(fCurrentEntity.ch,
685                                                    offset, length);
686            if (index != -1) {
687                int prefixLength = index - offset;
688                //check the result: prefix
689                checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, prefixLength);
690                prefix = fSymbolTable.addSymbol(fCurrentEntity.ch,
691                                                    offset, prefixLength);
692                int len = length - prefixLength - 1;
693                int startLocal = index +1;
694                if (!XML11Char.isXML11NCNameStart(fCurrentEntity.ch[startLocal]) &&
695                    (!XML11Char.isXML11NameHighSurrogate(fCurrentEntity.ch[startLocal]) ||
696                    sawIncompleteSurrogatePair)){
697                    fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
698                                               "IllegalQName",
699                                               null,
700                                               XMLErrorReporter.SEVERITY_FATAL_ERROR);
701                }
702                //check the result: localpart
703                checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, index + 1, len);
704                localpart = fSymbolTable.addSymbol(fCurrentEntity.ch,
705                                                   index + 1, len);
706
707            }
708            else {
709                localpart = rawname;
710                //check the result: localpart
711                checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, length);
712            }
713            qname.setValues(prefix, localpart, rawname, null);
714            checkEntityLimit(nt, fCurrentEntity, offset, length);
715            return true;
716        }
717        return false;
718
719    } // scanQName(QName):boolean
720
721    /**
722     * Scans a range of parsed character data, setting the fields of the
723     * XMLString structure, appropriately.
724     * <p>
725     * <strong>Note:</strong> The characters are consumed.
726     * <p>
727     * <strong>Note:</strong> This method does not guarantee to return
728     * the longest run of parsed character data. This method may return
729     * before markup due to reaching the end of the input buffer or any
730     * other reason.
731     * <p>
732     * <strong>Note:</strong> The fields contained in the XMLString
733     * structure are not guaranteed to remain valid upon subsequent calls
734     * to the entity scanner. Therefore, the caller is responsible for
735     * immediately using the returned character data or making a copy of
736     * the character data.
737     *
738     * @param content The content structure to fill.
739     *
740     * @return Returns the next character on the input, if known. This
741     *         value may be -1 but this does <em>note</em> designate
742     *         end of file.
743     *
744     * @throws IOException  Thrown if i/o error occurs.
745     * @throws EOFException Thrown on end of file.
746     */
747    protected int scanContent(XMLString content) throws IOException {
748
749        // load more characters, if needed
750        if (fCurrentEntity.position == fCurrentEntity.count) {
751            load(0, true, true);
752        }
753        else if (fCurrentEntity.position == fCurrentEntity.count - 1) {
754            invokeListeners(1);
755            fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1];
756            load(1, false, false);
757            fCurrentEntity.position = 0;
758            fCurrentEntity.startPosition = 0;
759        }
760
761        // normalize newlines
762        int offset = fCurrentEntity.position;
763        int c = fCurrentEntity.ch[offset];
764        int newlines = 0;
765        boolean counted = false;
766        boolean external = fCurrentEntity.isExternal();
767        if (c == '\n' || ((c == '\r' || c == 0x85 || c == 0x2028) && external)) {
768            do {
769                c = fCurrentEntity.ch[fCurrentEntity.position++];
770                if ((c == '\r' ) && external) {
771                    newlines++;
772                    fCurrentEntity.lineNumber++;
773                    fCurrentEntity.columnNumber = 1;
774                    if (fCurrentEntity.position == fCurrentEntity.count) {
775                        checkEntityLimit(null, fCurrentEntity, offset, newlines);
776                        offset = 0;
777                        fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
778                        fCurrentEntity.position = newlines;
779                        fCurrentEntity.startPosition = newlines;
780                        if (load(newlines, false, true)) {
781                            counted = true;
782                            break;
783                        }
784                    }
785                    int cc = fCurrentEntity.ch[fCurrentEntity.position];
786                    if (cc == '\n' || cc == 0x85) {
787                        fCurrentEntity.position++;
788                        offset++;
789                    }
790                    /*** NEWLINE NORMALIZATION ***/
791                    else {
792                        newlines++;
793                    }
794                }
795                else if (c == '\n' || ((c == 0x85 || c == 0x2028) && external)) {
796                    newlines++;
797                    fCurrentEntity.lineNumber++;
798                    fCurrentEntity.columnNumber = 1;
799                    if (fCurrentEntity.position == fCurrentEntity.count) {
800                        checkEntityLimit(null, fCurrentEntity, offset, newlines);
801                        offset = 0;
802                        fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
803                        fCurrentEntity.position = newlines;
804                        fCurrentEntity.startPosition = newlines;
805                        if (load(newlines, false, true)) {
806                            counted = true;
807                            break;
808                        }
809                    }
810                }
811                else {
812                    fCurrentEntity.position--;
813                    break;
814                }
815            } while (fCurrentEntity.position < fCurrentEntity.count - 1);
816            for (int i = offset; i < fCurrentEntity.position; i++) {
817                fCurrentEntity.ch[i] = '\n';
818            }
819            int length = fCurrentEntity.position - offset;
820            if (fCurrentEntity.position == fCurrentEntity.count - 1) {
821                checkEntityLimit(null, fCurrentEntity, offset, length);
822                content.setValues(fCurrentEntity.ch, offset, length);
823                return -1;
824            }
825        }
826
827        // inner loop, scanning for content
828        if (external) {
829            while (fCurrentEntity.position < fCurrentEntity.count) {
830                c = fCurrentEntity.ch[fCurrentEntity.position++];
831                if (!XML11Char.isXML11Content(c) || c == 0x85 || c == 0x2028) {
832                    fCurrentEntity.position--;
833                    break;
834                }
835            }
836        }
837        else {
838            while (fCurrentEntity.position < fCurrentEntity.count) {
839                c = fCurrentEntity.ch[fCurrentEntity.position++];
840                // In internal entities control characters are allowed to appear unescaped.
841                if (!XML11Char.isXML11InternalEntityContent(c)) {
842                    fCurrentEntity.position--;
843                    break;
844                }
845            }
846        }
847        int length = fCurrentEntity.position - offset;
848        fCurrentEntity.columnNumber += length - newlines;
849        if (!counted) {
850            checkEntityLimit(null, fCurrentEntity, offset, length);
851        }
852        content.setValues(fCurrentEntity.ch, offset, length);
853
854        // return next character
855        if (fCurrentEntity.position != fCurrentEntity.count) {
856            c = fCurrentEntity.ch[fCurrentEntity.position];
857            // REVISIT: Does this need to be updated to fix the
858            //          #x0D ^#x0A newline normalization problem? -Ac
859            if ((c == '\r' || c == 0x85 || c == 0x2028) && external) {
860                c = '\n';
861            }
862        }
863        else {
864            c = -1;
865        }
866        return c;
867
868    } // scanContent(XMLString):int
869
870    /**
871     * Scans a range of attribute value data, setting the fields of the
872     * XMLString structure, appropriately.
873     * <p>
874     * <strong>Note:</strong> The characters are consumed.
875     * <p>
876     * <strong>Note:</strong> This method does not guarantee to return
877     * the longest run of attribute value data. This method may return
878     * before the quote character due to reaching the end of the input
879     * buffer or any other reason.
880     * <p>
881     * <strong>Note:</strong> The fields contained in the XMLString
882     * structure are not guaranteed to remain valid upon subsequent calls
883     * to the entity scanner. Therefore, the caller is responsible for
884     * immediately using the returned character data or making a copy of
885     * the character data.
886     *
887     * @param quote   The quote character that signifies the end of the
888     *                attribute value data.
889     * @param content The content structure to fill.
890     * @param isNSURI a flag indicating whether the content is a Namespace URI
891     *
892     * @return Returns the next character on the input, if known. This
893     *         value may be -1 but this does <em>note</em> designate
894     *         end of file.
895     *
896     * @throws IOException  Thrown if i/o error occurs.
897     * @throws EOFException Thrown on end of file.
898     */
899    protected int scanLiteral(int quote, XMLString content, boolean isNSURI)
900        throws IOException {
901        // load more characters, if needed
902        if (fCurrentEntity.position == fCurrentEntity.count) {
903            load(0, true, true);
904        }
905        else if (fCurrentEntity.position == fCurrentEntity.count - 1) {
906            invokeListeners(1);
907            fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1];
908            load(1, false, false);
909            fCurrentEntity.startPosition = 0;
910            fCurrentEntity.position = 0;
911        }
912
913        // normalize newlines
914        int offset = fCurrentEntity.position;
915        int c = fCurrentEntity.ch[offset];
916        int newlines = 0;
917        boolean external = fCurrentEntity.isExternal();
918        if (c == '\n' || ((c == '\r' || c == 0x85 || c == 0x2028) && external)) {
919            do {
920                c = fCurrentEntity.ch[fCurrentEntity.position++];
921                if ((c == '\r' ) && external) {
922                    newlines++;
923                    fCurrentEntity.lineNumber++;
924                    fCurrentEntity.columnNumber = 1;
925                    if (fCurrentEntity.position == fCurrentEntity.count) {
926                        offset = 0;
927                        fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
928                        fCurrentEntity.position = newlines;
929                        fCurrentEntity.startPosition = newlines;
930                        if (load(newlines, false, true)) {
931                            break;
932                        }
933                    }
934                    int cc = fCurrentEntity.ch[fCurrentEntity.position];
935                    if (cc == '\n' || cc == 0x85) {
936                        fCurrentEntity.position++;
937                        offset++;
938                    }
939                    /*** NEWLINE NORMALIZATION ***/
940                    else {
941                        newlines++;
942                    }
943                }
944                else if (c == '\n' || ((c == 0x85 || c == 0x2028) && external)) {
945                    newlines++;
946                    fCurrentEntity.lineNumber++;
947                    fCurrentEntity.columnNumber = 1;
948                    if (fCurrentEntity.position == fCurrentEntity.count) {
949                        offset = 0;
950                        fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
951                        fCurrentEntity.position = newlines;
952                        fCurrentEntity.startPosition = newlines;
953                        if (load(newlines, false, true)) {
954                            break;
955                        }
956                    }
957                }
958                else {
959                    fCurrentEntity.position--;
960                    break;
961                }
962            } while (fCurrentEntity.position < fCurrentEntity.count - 1);
963            for (int i = offset; i < fCurrentEntity.position; i++) {
964                fCurrentEntity.ch[i] = '\n';
965            }
966            int length = fCurrentEntity.position - offset;
967            if (fCurrentEntity.position == fCurrentEntity.count - 1) {
968                content.setValues(fCurrentEntity.ch, offset, length);
969                return -1;
970            }
971        }
972
973        // scan literal value
974        if (external) {
975            while (fCurrentEntity.position < fCurrentEntity.count) {
976                c = fCurrentEntity.ch[fCurrentEntity.position++];
977                if (c == quote || c == '%' || !XML11Char.isXML11Content(c)
978                    || c == 0x85 || c == 0x2028) {
979                    fCurrentEntity.position--;
980                    break;
981                }
982            }
983        }
984        else {
985            while (fCurrentEntity.position < fCurrentEntity.count) {
986                c = fCurrentEntity.ch[fCurrentEntity.position++];
987                // In internal entities control characters are allowed to appear unescaped.
988                if ((c == quote && !fCurrentEntity.literal)
989                    || c == '%' || !XML11Char.isXML11InternalEntityContent(c)) {
990                    fCurrentEntity.position--;
991                    break;
992                }
993            }
994        }
995        int length = fCurrentEntity.position - offset;
996        fCurrentEntity.columnNumber += length - newlines;
997
998        checkEntityLimit(null, fCurrentEntity, offset, length);
999        if (isNSURI) {
1000            checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, length);
1001        }
1002        content.setValues(fCurrentEntity.ch, offset, length);
1003
1004        // return next character
1005        if (fCurrentEntity.position != fCurrentEntity.count) {
1006            c = fCurrentEntity.ch[fCurrentEntity.position];
1007            // NOTE: We don't want to accidentally signal the
1008            //       end of the literal if we're expanding an
1009            //       entity appearing in the literal. -Ac
1010            if (c == quote && fCurrentEntity.literal) {
1011                c = -1;
1012            }
1013        }
1014        else {
1015            c = -1;
1016        }
1017        return c;
1018
1019    } // scanLiteral(int,XMLString):int
1020
1021    /**
1022     * Scans a range of character data up to the specicied delimiter,
1023     * setting the fields of the XMLString structure, appropriately.
1024     * <p>
1025     * <strong>Note:</strong> The characters are consumed.
1026     * <p>
1027     * <strong>Note:</strong> This assumes that the internal buffer is
1028     * at least the same size, or bigger, than the length of the delimiter
1029     * and that the delimiter contains at least one character.
1030     * <p>
1031     * <strong>Note:</strong> This method does not guarantee to return
1032     * the longest run of character data. This method may return before
1033     * the delimiter due to reaching the end of the input buffer or any
1034     * other reason.
1035     * <p>
1036     * <strong>Note:</strong> The fields contained in the XMLString
1037     * structure are not guaranteed to remain valid upon subsequent calls
1038     * to the entity scanner. Therefore, the caller is responsible for
1039     * immediately using the returned character data or making a copy of
1040     * the character data.
1041     *
1042     * @param delimiter The string that signifies the end of the character
1043     *                  data to be scanned.
1044     * @param buffer      The data structure to fill.
1045     * @param chunkLimit the size limit of the data to be scanned
1046     *
1047     * @return Returns true if there is more data to scan, false otherwise.
1048     *
1049     * @throws IOException  Thrown if i/o error occurs.
1050     */
1051    protected boolean scanData(String delimiter, XMLStringBuffer buffer, int chunkLimit)
1052        throws IOException {
1053
1054        boolean done = false;
1055        int delimLen = delimiter.length();
1056        char charAt0 = delimiter.charAt(0);
1057        boolean external = fCurrentEntity.isExternal();
1058        do {
1059            // load more characters, if needed
1060            if (fCurrentEntity.position == fCurrentEntity.count) {
1061                load(0, true, false);
1062            }
1063
1064            boolean bNextEntity = false;
1065
1066            while ((fCurrentEntity.position >= fCurrentEntity.count - delimLen)
1067                && (!bNextEntity))
1068            {
1069              System.arraycopy(fCurrentEntity.ch,
1070                               fCurrentEntity.position,
1071                               fCurrentEntity.ch,
1072                               0,
1073                               fCurrentEntity.count - fCurrentEntity.position);
1074
1075              bNextEntity = load(fCurrentEntity.count - fCurrentEntity.position, false, false);
1076              fCurrentEntity.position = 0;
1077              fCurrentEntity.startPosition = 0;
1078            }
1079
1080            if (fCurrentEntity.position >= fCurrentEntity.count - delimLen) {
1081                // something must be wrong with the input:  e.g., file ends  an unterminated comment
1082                int length = fCurrentEntity.count - fCurrentEntity.position;
1083                checkEntityLimit(NameType.COMMENT, fCurrentEntity, fCurrentEntity.position, length);
1084                buffer.append (fCurrentEntity.ch, fCurrentEntity.position, length);
1085                fCurrentEntity.columnNumber += fCurrentEntity.count;
1086                fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
1087                fCurrentEntity.position = fCurrentEntity.count;
1088                fCurrentEntity.startPosition = fCurrentEntity.count;
1089                load(0,true, false);
1090                return false;
1091            }
1092
1093            // normalize newlines
1094            int offset = fCurrentEntity.position;
1095            int c = fCurrentEntity.ch[offset];
1096            int newlines = 0;
1097            if (c == '\n' || ((c == '\r' || c == 0x85 || c == 0x2028) && external)) {
1098                do {
1099                    c = fCurrentEntity.ch[fCurrentEntity.position++];
1100                    if ((c == '\r' ) && external) {
1101                        newlines++;
1102                        fCurrentEntity.lineNumber++;
1103                        fCurrentEntity.columnNumber = 1;
1104                        if (fCurrentEntity.position == fCurrentEntity.count) {
1105                            offset = 0;
1106                            fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
1107                            fCurrentEntity.position = newlines;
1108                            fCurrentEntity.startPosition = newlines;
1109                            if (load(newlines, false, true)) {
1110                                break;
1111                            }
1112                        }
1113                        int cc = fCurrentEntity.ch[fCurrentEntity.position];
1114                        if (cc == '\n' || cc == 0x85) {
1115                            fCurrentEntity.position++;
1116                            offset++;
1117                        }
1118                        /*** NEWLINE NORMALIZATION ***/
1119                        else {
1120                            newlines++;
1121                        }
1122                    }
1123                    else if (c == '\n' || ((c == 0x85 || c == 0x2028) && external)) {
1124                        newlines++;
1125                        fCurrentEntity.lineNumber++;
1126                        fCurrentEntity.columnNumber = 1;
1127                        if (fCurrentEntity.position == fCurrentEntity.count) {
1128                            offset = 0;
1129                            fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
1130                            fCurrentEntity.position = newlines;
1131                            fCurrentEntity.startPosition = newlines;
1132                            fCurrentEntity.count = newlines;
1133                            if (load(newlines, false, true)) {
1134                                break;
1135                            }
1136                        }
1137                    }
1138                    else {
1139                        fCurrentEntity.position--;
1140                        break;
1141                    }
1142                } while (fCurrentEntity.position < fCurrentEntity.count - 1);
1143                for (int i = offset; i < fCurrentEntity.position; i++) {
1144                    fCurrentEntity.ch[i] = '\n';
1145                }
1146                int length = fCurrentEntity.position - offset;
1147                if (fCurrentEntity.position == fCurrentEntity.count - 1) {
1148                    checkEntityLimit(NameType.COMMENT, fCurrentEntity, offset, length);
1149                    buffer.append(fCurrentEntity.ch, offset, length);
1150                    return true;
1151                }
1152            }
1153
1154            // iterate over buffer looking for delimiter
1155            OUTER: while (fCurrentEntity.position < fCurrentEntity.count) {
1156                c = fCurrentEntity.ch[fCurrentEntity.position++];
1157                if (c == charAt0) {
1158                    // looks like we just hit the delimiter
1159                    int delimOffset = fCurrentEntity.position - 1;
1160                    for (int i = 1; i < delimLen; i++) {
1161                        if (fCurrentEntity.position == fCurrentEntity.count) {
1162                            fCurrentEntity.position -= i;
1163                            break OUTER;
1164                        }
1165                        c = fCurrentEntity.ch[fCurrentEntity.position++];
1166                        if (delimiter.charAt(i) != c) {
1167                            fCurrentEntity.position--;
1168                            break;
1169                        }
1170                     }
1171                     if (fCurrentEntity.position == delimOffset + delimLen) {
1172                        done = true;
1173                        break;
1174                     }
1175                }
1176                else if ((external && (c == '\n' || c == '\r' || c == 0x85 || c == 0x2028))
1177                        || (!external && c == '\n')) {
1178                    fCurrentEntity.position--;
1179                    break;
1180                }
1181                // In external entities control characters cannot appear
1182                // as literals so do not skip over them.
1183                else if ((external && !XML11Char.isXML11ValidLiteral(c))
1184                        // Control characters are allowed to appear as literals in internal entities.
1185                        || (!external && !XML11Char.isXML11Valid(c))) {
1186                    fCurrentEntity.position--;
1187                    int length = fCurrentEntity.position - offset;
1188                    fCurrentEntity.columnNumber += length - newlines;
1189                    checkEntityLimit(NameType.COMMENT, fCurrentEntity, offset, length);
1190                    buffer.append(fCurrentEntity.ch, offset, length);
1191                    return true;
1192                }
1193                if (chunkLimit > 0 &&
1194                        (buffer.length + fCurrentEntity.position - offset) >= chunkLimit) {
1195                    break;
1196                }
1197            }
1198
1199            int length = fCurrentEntity.position - offset;
1200            fCurrentEntity.columnNumber += length - newlines;
1201            checkEntityLimit(NameType.COMMENT, fCurrentEntity, offset, length);
1202            if (done) {
1203                length -= delimLen;
1204            }
1205            buffer.append(fCurrentEntity.ch, offset, length);
1206
1207            if (chunkLimit > 0 && buffer.length >= chunkLimit) {
1208                break;
1209            }
1210        } while (!done && chunkLimit == 0);
1211        return !done;
1212
1213    } // scanData(String,XMLString)
1214
1215    /**
1216     * Skips a character appearing immediately on the input.
1217     * <p>
1218     * <strong>Note:</strong> The character is consumed only if it matches
1219     * the specified character.
1220     *
1221     * @param c The character to skip.
1222     *
1223     * @return Returns true if the character was skipped.
1224     *
1225     * @throws IOException  Thrown if i/o error occurs.
1226     * @throws EOFException Thrown on end of file.
1227     */
1228    protected boolean skipChar(int c, NameType nt) throws IOException {
1229
1230        // load more characters, if needed
1231        if (fCurrentEntity.position == fCurrentEntity.count) {
1232            load(0, true, true);
1233        }
1234
1235        // skip character
1236        int offset = fCurrentEntity.position;
1237        int cc = fCurrentEntity.ch[fCurrentEntity.position];
1238        if (cc == c) {
1239            fCurrentEntity.position++;
1240            if (c == '\n') {
1241                fCurrentEntity.lineNumber++;
1242                fCurrentEntity.columnNumber = 1;
1243            }
1244            else {
1245                fCurrentEntity.columnNumber++;
1246            }
1247            checkEntityLimit(nt, fCurrentEntity, offset, fCurrentEntity.position - offset);
1248            return true;
1249        }
1250        else if (c == '\n' && ((cc == 0x2028 || cc == 0x85) && fCurrentEntity.isExternal())) {
1251            fCurrentEntity.position++;
1252            fCurrentEntity.lineNumber++;
1253            fCurrentEntity.columnNumber = 1;
1254            checkEntityLimit(nt, fCurrentEntity, offset, fCurrentEntity.position - offset);
1255            return true;
1256        }
1257        else if (c == '\n' && (cc == '\r' ) && fCurrentEntity.isExternal()) {
1258            // handle newlines
1259            if (fCurrentEntity.position == fCurrentEntity.count) {
1260                invokeListeners(1);
1261                fCurrentEntity.ch[0] = (char)cc;
1262                load(1, false, false);
1263            }
1264            int ccc = fCurrentEntity.ch[++fCurrentEntity.position];
1265            if (ccc == '\n' || ccc == 0x85) {
1266                fCurrentEntity.position++;
1267            }
1268            fCurrentEntity.lineNumber++;
1269            fCurrentEntity.columnNumber = 1;
1270            checkEntityLimit(nt, fCurrentEntity, offset, fCurrentEntity.position - offset);
1271            return true;
1272        }
1273
1274        // character was not skipped
1275        return false;
1276
1277    } // skipChar(int):boolean
1278
1279    /**
1280     * Skips space characters appearing immediately on the input.
1281     * <p>
1282     * <strong>Note:</strong> The characters are consumed only if they are
1283     * space characters.
1284     *
1285     * @return Returns true if at least one space character was skipped.
1286     *
1287     * @throws IOException  Thrown if i/o error occurs.
1288     * @throws EOFException Thrown on end of file.
1289     *
1290     * @see com.sun.org.apache.xerces.internal.util.XMLChar#isSpace
1291     * @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11Space
1292     */
1293    protected boolean skipSpaces() throws IOException {
1294
1295        // load more characters, if needed
1296        if (fCurrentEntity.position == fCurrentEntity.count) {
1297            load(0, true, true);
1298        }
1299
1300
1301        //we are doing this check only in skipSpace() because it is called by
1302        //fMiscDispatcher and we want the parser to exit gracefully when document
1303        //is well-formed.
1304        //it is possible that end of document is reached and
1305        //fCurrentEntity becomes null
1306        //nothing was read so entity changed  'false' should be returned.
1307        if(fCurrentEntity == null){
1308            return false ;
1309        }
1310
1311        // skip spaces
1312        int c = fCurrentEntity.ch[fCurrentEntity.position];
1313        int offset = fCurrentEntity.position - 1;
1314        // External --  Match: S + 0x85 + 0x2028, and perform end of line normalization
1315        if (fCurrentEntity.isExternal()) {
1316            if (XML11Char.isXML11Space(c)) {
1317                do {
1318                    boolean entityChanged = false;
1319                    // handle newlines
1320                    if (c == '\n' || c == '\r' || c == 0x85 || c == 0x2028) {
1321                        fCurrentEntity.lineNumber++;
1322                        fCurrentEntity.columnNumber = 1;
1323                        if (fCurrentEntity.position == fCurrentEntity.count - 1) {
1324                            invokeListeners(1);
1325                            fCurrentEntity.ch[0] = (char)c;
1326                            entityChanged = load(1, true, false);
1327                            if (!entityChanged) {
1328                                // the load change the position to be 1,
1329                                // need to restore it when entity not changed
1330                                fCurrentEntity.startPosition = 0;
1331                                fCurrentEntity.position = 0;
1332                            } else if(fCurrentEntity == null){
1333                                return true ;
1334                            }
1335
1336                        }
1337                        if (c == '\r') {
1338                            // REVISIT: Does this need to be updated to fix the
1339                            //          #x0D ^#x0A newline normalization problem? -Ac
1340                            int cc = fCurrentEntity.ch[++fCurrentEntity.position];
1341                            if (cc != '\n' && cc != 0x85 ) {
1342                                fCurrentEntity.position--;
1343                            }
1344                        }
1345                    }
1346                    else {
1347                        fCurrentEntity.columnNumber++;
1348                    }
1349
1350                    //If this is a general entity, spaces within a start element should be counted
1351                    checkEntityLimit(null, fCurrentEntity, offset, fCurrentEntity.position - offset);
1352                    offset = fCurrentEntity.position;
1353
1354                    // load more characters, if needed
1355                    if (!entityChanged)
1356                        fCurrentEntity.position++;
1357                    if (fCurrentEntity.position == fCurrentEntity.count) {
1358                        load(0, true, true);
1359
1360                        if(fCurrentEntity == null){
1361                        return true ;
1362                        }
1363
1364                    }
1365                } while (XML11Char.isXML11Space(c = fCurrentEntity.ch[fCurrentEntity.position]));
1366                return true;
1367            }
1368        }
1369        // Internal -- Match: S (only)
1370        else if (XMLChar.isSpace(c)) {
1371            do {
1372                boolean entityChanged = false;
1373                // handle newlines
1374                if (c == '\n') {
1375                    fCurrentEntity.lineNumber++;
1376                    fCurrentEntity.columnNumber = 1;
1377                    if (fCurrentEntity.position == fCurrentEntity.count - 1) {
1378                        invokeListeners(1);
1379                        fCurrentEntity.ch[0] = (char)c;
1380                        entityChanged = load(1, true, false);
1381                        if (!entityChanged) {
1382                            // the load change the position to be 1,
1383                            // need to restore it when entity not changed
1384                            fCurrentEntity.startPosition = 0;
1385                            fCurrentEntity.position = 0;
1386                        } else if(fCurrentEntity == null){
1387                        return true ;
1388                        }
1389                    }
1390                }
1391                else {
1392                    fCurrentEntity.columnNumber++;
1393                }
1394
1395                //If this is a general entity, spaces within a start element should be counted
1396                checkEntityLimit(null, fCurrentEntity, offset, fCurrentEntity.position - offset);
1397                offset = fCurrentEntity.position;
1398
1399                // load more characters, if needed
1400                if (!entityChanged)
1401                    fCurrentEntity.position++;
1402                if (fCurrentEntity.position == fCurrentEntity.count) {
1403                    load(0, true, true);
1404
1405                    if(fCurrentEntity == null){
1406                        return true ;
1407                    }
1408
1409                }
1410            } while (XMLChar.isSpace(c = fCurrentEntity.ch[fCurrentEntity.position]));
1411            return true;
1412        }
1413
1414        // no spaces were found
1415        return false;
1416
1417    } // skipSpaces():boolean
1418
1419    /**
1420     * Skips the specified string appearing immediately on the input.
1421     * <p>
1422     * <strong>Note:</strong> The characters are consumed only if they are
1423     * space characters.
1424     *
1425     * @param s The string to skip.
1426     *
1427     * @return Returns true if the string was skipped.
1428     *
1429     * @throws IOException  Thrown if i/o error occurs.
1430     * @throws EOFException Thrown on end of file.
1431     */
1432    protected boolean skipString(String s) throws IOException {
1433
1434        // load more characters, if needed
1435        if (fCurrentEntity.position == fCurrentEntity.count) {
1436            load(0, true, true);
1437        }
1438
1439        // skip string
1440        final int length = s.length();
1441        final int beforeSkip = fCurrentEntity.position ;
1442        for (int i = 0; i < length; i++) {
1443            char c = fCurrentEntity.ch[fCurrentEntity.position++];
1444            if (c != s.charAt(i)) {
1445                fCurrentEntity.position -= i + 1;
1446                return false;
1447            }
1448            if (i < length - 1 && fCurrentEntity.position == fCurrentEntity.count) {
1449                invokeListeners(0);
1450                System.arraycopy(fCurrentEntity.ch, fCurrentEntity.count - i - 1, fCurrentEntity.ch, 0, i + 1);
1451                // REVISIT: Can a string to be skipped cross an
1452                //          entity boundary? -Ac
1453                if (load(i + 1, false, false)) {
1454                    fCurrentEntity.startPosition -= i + 1;
1455                    fCurrentEntity.position -= i + 1;
1456                    return false;
1457                }
1458            }
1459        }
1460        fCurrentEntity.columnNumber += length;
1461        if (!detectingVersion) {
1462            checkEntityLimit(null, fCurrentEntity, beforeSkip, length);
1463        }
1464        return true;
1465
1466    } // skipString(String):boolean
1467
1468} // class XML11EntityScanner
1469