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