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 22 package com.sun.org.apache.xerces.internal.impl; 23 24 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter; 25 import com.sun.org.apache.xerces.internal.util.XML11Char; 26 import com.sun.org.apache.xerces.internal.util.XMLChar; 27 import com.sun.org.apache.xerces.internal.util.XMLStringBuffer; 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(1); 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(1); 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(1); 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 invokeListeners(1); 1450 fCurrentEntity.ch[0] = (char)c; 1451 entityChanged = load(1, true, false); 1452 if (!entityChanged) { 1453 // the load change the position to be 1, 1454 // need to restore it when entity not changed 1455 fCurrentEntity.startPosition = 0; 1456 fCurrentEntity.position = 0; 1457 } else if(fCurrentEntity == null){ 1458 return true ; 1459 } 1460 } 1461 } 1462 else { 1463 fCurrentEntity.columnNumber++; 1464 } 1465 // load more characters, if needed 1466 if (!entityChanged) 1467 fCurrentEntity.position++; 1468 if (fCurrentEntity.position == fCurrentEntity.count) { 1469 load(0, true, true); 1470 1471 if(fCurrentEntity == null){ 1472 return true ; 1473 } 1474 1475 } 1476 } while (XMLChar.isSpace(c = fCurrentEntity.ch[fCurrentEntity.position])); 1477 return true; 1478 } 1479 1480 // no spaces were found 1481 return false; 1482 1483 } // skipSpaces():boolean 1484 1485 /** 1486 * Skips the specified string appearing immediately on the input. 1487 * <p> 1488 * <strong>Note:</strong> The characters are consumed only if they are 1489 * space characters. 1490 * 1491 * @param s The string to skip. 1492 * 1493 * @return Returns true if the string was skipped. 1494 * 1495 * @throws IOException Thrown if i/o error occurs. 1496 * @throws EOFException Thrown on end of file. 1497 */ 1498 public boolean skipString(String s) throws IOException { 1499 1500 // load more characters, if needed 1501 if (fCurrentEntity.position == fCurrentEntity.count) { 1502 load(0, true, true); 1503 } 1504 1505 // skip string 1506 final int length = s.length(); 1507 for (int i = 0; i < length; i++) { 1508 char c = fCurrentEntity.ch[fCurrentEntity.position++]; 1509 if (c != s.charAt(i)) { 1510 fCurrentEntity.position -= i + 1; 1511 return false; 1512 } 1513 if (i < length - 1 && fCurrentEntity.position == fCurrentEntity.count) { 1514 invokeListeners(0); 1515 System.arraycopy(fCurrentEntity.ch, fCurrentEntity.count - i - 1, fCurrentEntity.ch, 0, i + 1); 1516 // REVISIT: Can a string to be skipped cross an 1517 // entity boundary? -Ac 1518 if (load(i + 1, false, false)) { 1519 fCurrentEntity.startPosition -= i + 1; 1520 fCurrentEntity.position -= i + 1; 1521 return false; 1522 } 1523 } 1524 } 1525 fCurrentEntity.columnNumber += length; 1526 return true; 1527 1528 } // skipString(String):boolean 1529 1530 } // class XML11EntityScanner