1 2 9 10 package org.xmlpull.mxp1; 11 12 import java.io.EOFException ; 13 import java.io.IOException ; 14 import java.io.Reader ; 15 import java.io.InputStreamReader ; 16 import java.io.UnsupportedEncodingException ; 17 18 20 import org.xmlpull.v1.XmlPullParser; 21 import org.xmlpull.v1.XmlPullParserException; 22 23 26 28 30 35 36 public class MXParser 37 implements XmlPullParser 38 { 39 protected final static String XML_URI = "http://www.w3.org/XML/1998/namespace"; 41 protected final static String XMLNS_URI = "http://www.w3.org/2000/xmlns/"; 42 protected final static String FEATURE_XML_ROUNDTRIP= 43 "http://xmlpull.org/v1/doc/features.html#xml-roundtrip"; 45 protected final static String FEATURE_NAMES_INTERNED = 46 "http://xmlpull.org/v1/doc/features.html#names-interned"; 47 protected final static String PROPERTY_XMLDECL_VERSION = 48 "http://xmlpull.org/v1/doc/properties.html#xmldecl-version"; 49 protected final static String PROPERTY_XMLDECL_STANDALONE = 50 "http://xmlpull.org/v1/doc/properties.html#xmldecl-standalone"; 51 protected final static String PROPERTY_XMLDECL_CONTENT = 52 "http://xmlpull.org/v1/doc/properties.html#xmldecl-content"; 53 54 55 62 protected boolean allStringsInterned; 63 64 protected void resetStringCache() { 65 } 67 68 protected String newString(char[] cbuf, int off, int len) { 69 return new String (cbuf, off, len); 70 } 71 72 protected String newStringIntern(char[] cbuf, int off, int len) { 73 return (new String (cbuf, off, len)).intern(); 74 } 75 76 77 private static final boolean TRACE_SIZING = false; 78 79 protected boolean processNamespaces; 81 protected boolean roundtripSupported; 82 83 protected int lineNumber; 85 protected int columnNumber; 86 protected boolean seenRoot; 87 protected boolean reachedEnd; 88 protected int eventType; 89 protected boolean emptyElementTag; 90 protected int depth; 92 protected char[] elRawName[]; 93 protected int elRawNameEnd[]; 94 protected String elName[]; 96 protected String elPrefix[]; 97 protected String elUri[]; 98 protected int elNamespaceCount[]; 100 101 102 103 107 protected void ensureElementsCapacity() { 108 int elStackSize = elName != null ? elName.length : 0; 109 if( (depth + 1) >= elStackSize) { 110 int newSize = (depth >= 7 ? 2 * depth : 8) + 2; if(TRACE_SIZING) { 113 System.err.println("TRACE_SIZING elStackSize "+elStackSize+" ==> "+newSize); 114 } 115 boolean needsCopying = elStackSize > 0; 116 String [] arr = null; 117 arr = new String [newSize]; 118 if(needsCopying) System.arraycopy(elName, 0, arr, 0, elStackSize); 119 elName = arr; 120 arr = new String [newSize]; 121 if(needsCopying) System.arraycopy(elPrefix, 0, arr, 0, elStackSize); 122 elPrefix = arr; 123 arr = new String [newSize]; 124 if(needsCopying) System.arraycopy(elUri, 0, arr, 0, elStackSize); 125 elUri = arr; 126 127 int[] iarr = new int[newSize]; 128 if(needsCopying) { 129 System.arraycopy(elNamespaceCount, 0, iarr, 0, elStackSize); 130 } else { 131 iarr[0] = 0; 133 } 134 elNamespaceCount = iarr; 135 136 iarr = new int[newSize]; 138 if(needsCopying) { 139 System.arraycopy(elRawNameEnd, 0, iarr, 0, elStackSize); 140 } 141 elRawNameEnd = iarr; 142 143 char[][] carr = new char[newSize][]; 144 if(needsCopying) { 145 System.arraycopy(elRawName, 0, carr, 0, elStackSize); 146 } 147 elRawName = carr; 148 } 163 } 164 165 166 protected static final int LOOKUP_MAX = 0x400; 168 protected static final char LOOKUP_MAX_CHAR = (char)LOOKUP_MAX; 169 protected static boolean lookupNameStartChar[] = new boolean[ LOOKUP_MAX ]; 172 protected static boolean lookupNameChar[] = new boolean[ LOOKUP_MAX ]; 173 174 private static final void setName(char ch) 175 { lookupNameChar[ ch ] = true; } 177 private static final void setNameStart(char ch) 178 { lookupNameStartChar[ ch ] = true; setName(ch); } 180 181 static { 182 setNameStart(':'); 183 for (char ch = 'A'; ch <= 'Z'; ++ch) setNameStart(ch); 184 setNameStart('_'); 185 for (char ch = 'a'; ch <= 'z'; ++ch) setNameStart(ch); 186 for (char ch = '\u00c0'; ch <= '\u02FF'; ++ch) setNameStart(ch); 187 for (char ch = '\u0370'; ch <= '\u037d'; ++ch) setNameStart(ch); 188 for (char ch = '\u037f'; ch < '\u0400'; ++ch) setNameStart(ch); 189 190 setName('-'); 191 setName('.'); 192 for (char ch = '0'; ch <= '9'; ++ch) setName(ch); 193 setName('\u00b7'); 194 for (char ch = '\u0300'; ch <= '\u036f'; ++ch) setName(ch); 195 } 196 197 protected boolean isNameStartChar(char ch) { 199 return (ch < LOOKUP_MAX_CHAR && lookupNameStartChar[ ch ]) 200 || (ch >= LOOKUP_MAX_CHAR && ch <= '\u2027') 201 || (ch >= '\u202A' && ch <= '\u218F') 202 || (ch >= '\u2800' && ch <= '\uFFEF') 203 ; 204 205 223 224 } 226 227 protected boolean isNameChar(char ch) { 229 231 233 return (ch < LOOKUP_MAX_CHAR && lookupNameChar[ ch ]) 234 || (ch >= LOOKUP_MAX_CHAR && ch <= '\u2027') 235 || (ch >= '\u202A' && ch <= '\u218F') 236 || (ch >= '\u2800' && ch <= '\uFFEF') 237 ; 238 243 } 253 254 protected boolean isS(char ch) { 255 return (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'); 256 } 258 259 262 263 protected int attributeCount; 265 protected String attributeName[]; 266 protected int attributeNameHash[]; 267 protected String attributePrefix[]; 270 protected String attributeUri[]; 271 protected String attributeValue[]; 272 275 276 279 protected void ensureAttributesCapacity(int size) { 280 int attrPosSize = attributeName != null ? attributeName.length : 0; 281 if(size >= attrPosSize) { 282 int newSize = size > 7 ? 2 * size : 8; if(TRACE_SIZING) { 284 System.err.println("TRACE_SIZING attrPosSize "+attrPosSize+" ==> "+newSize); 285 } 286 boolean needsCopying = attrPosSize > 0; 287 String [] arr = null; 288 289 arr = new String [newSize]; 290 if(needsCopying) System.arraycopy(attributeName, 0, arr, 0, attrPosSize); 291 attributeName = arr; 292 293 arr = new String [newSize]; 294 if(needsCopying) System.arraycopy(attributePrefix, 0, arr, 0, attrPosSize); 295 attributePrefix = arr; 296 297 arr = new String [newSize]; 298 if(needsCopying) System.arraycopy(attributeUri, 0, arr, 0, attrPosSize); 299 attributeUri = arr; 300 301 arr = new String [newSize]; 302 if(needsCopying) System.arraycopy(attributeValue, 0, arr, 0, attrPosSize); 303 attributeValue = arr; 304 305 if( ! allStringsInterned ) { 306 int[] iarr = new int[newSize]; 307 if(needsCopying) System.arraycopy(attributeNameHash, 0, iarr, 0, attrPosSize); 308 attributeNameHash = iarr; 309 } 310 311 arr = null; 312 } 314 } 315 316 protected int namespaceEnd; 318 protected String namespacePrefix[]; 319 protected int namespacePrefixHash[]; 320 protected String namespaceUri[]; 321 322 protected void ensureNamespacesCapacity(int size) { 323 int namespaceSize = namespacePrefix != null ? namespacePrefix.length : 0; 324 if(size >= namespaceSize) { 325 int newSize = size > 7 ? 2 * size : 8; if(TRACE_SIZING) { 327 System.err.println("TRACE_SIZING namespaceSize "+namespaceSize+" ==> "+newSize); 328 } 329 String [] newNamespacePrefix = new String [newSize]; 330 String [] newNamespaceUri = new String [newSize]; 331 if(namespacePrefix != null) { 332 System.arraycopy( 333 namespacePrefix, 0, newNamespacePrefix, 0, namespaceEnd); 334 System.arraycopy( 335 namespaceUri, 0, newNamespaceUri, 0, namespaceEnd); 336 } 337 namespacePrefix = newNamespacePrefix; 338 namespaceUri = newNamespaceUri; 339 340 341 if( ! allStringsInterned ) { 342 int[] newNamespacePrefixHash = new int[newSize]; 343 if(namespacePrefixHash != null) { 344 System.arraycopy( 345 namespacePrefixHash, 0, newNamespacePrefixHash, 0, namespaceEnd); 346 } 347 namespacePrefixHash = newNamespacePrefixHash; 348 } 349 } 352 } 353 354 359 protected static final int fastHash( char ch[], int off, int len ) { 360 if(len == 0) return 0; 361 int hash = ch[off]; hash = (hash << 7) + ch[ off + len - 1 ]; if(len > 16) hash = (hash << 7) + ch[ off + (len / 4)]; if(len > 8) hash = (hash << 7) + ch[ off + (len / 2)]; return hash; 375 } 376 377 protected int entityEnd; 379 protected String entityName[]; 380 protected char[] entityNameBuf[]; 381 protected int entityNameHash[]; 382 protected char[] entityReplacementBuf[]; 383 protected String entityReplacement[]; 384 385 386 protected void ensureEntityCapacity() { 387 int entitySize = entityReplacementBuf != null ? entityReplacementBuf.length : 0; 388 if(entityEnd >= entitySize) { 389 int newSize = entityEnd > 7 ? 2 * entityEnd : 8; if(TRACE_SIZING) { 391 System.err.println("TRACE_SIZING entitySize "+entitySize+" ==> "+newSize); 392 } 393 String [] newEntityName = new String [newSize]; 394 char[] newEntityNameBuf[] = new char[newSize][]; 395 String [] newEntityReplacement = new String [newSize]; 396 char[] newEntityReplacementBuf[] = new char[newSize][]; 397 if(entityName != null) { 398 System.arraycopy(entityName, 0, newEntityName, 0, entityEnd); 399 System.arraycopy(entityReplacementBuf, 0, newEntityReplacement, 0, entityEnd); 400 System.arraycopy(entityReplacement, 0, newEntityReplacement, 0, entityEnd); 401 System.arraycopy(entityReplacementBuf, 0, newEntityReplacementBuf, 0, entityEnd); 402 } 403 entityName = newEntityName; 404 entityNameBuf = newEntityNameBuf; 405 entityReplacement = newEntityReplacement; 406 entityReplacementBuf = newEntityReplacementBuf; 407 408 if( ! allStringsInterned ) { 409 int[] newEntityNameHash = new int[newSize]; 410 if(entityNameHash != null) { 411 System.arraycopy(entityNameHash, 0, newEntityNameHash, 0, entityEnd); 412 } 413 entityNameHash = newEntityNameHash; 414 } 415 } 416 } 417 418 protected static final int READ_CHUNK_SIZE = 8*1024; protected Reader reader; 421 protected String inputEncoding; 422 423 424 protected int bufLoadFactor = 95; 427 protected char buf[] = new char[ 428 Runtime.getRuntime().freeMemory() > 1000000L ? READ_CHUNK_SIZE : 256 ]; 429 protected int bufSoftLimit = ( bufLoadFactor * buf.length ) /100; protected boolean preventBufferCompaction; 431 432 protected int bufAbsoluteStart; protected int bufStart; 434 protected int bufEnd; 435 protected int pos; 436 protected int posStart; 437 protected int posEnd; 438 439 protected char pc[] = new char[ 440 Runtime.getRuntime().freeMemory() > 1000000L ? READ_CHUNK_SIZE : 64 ]; 441 protected int pcStart; 442 protected int pcEnd; 443 444 445 protected boolean usePC; 449 450 451 protected boolean seenStartTag; 452 protected boolean seenEndTag; 453 protected boolean pastEndTag; 454 protected boolean seenAmpersand; 455 protected boolean seenMarkup; 456 protected boolean seenDocdecl; 457 458 protected boolean tokenize; 460 protected String text; 461 protected String entityRefName; 462 463 protected String xmlDeclVersion; 464 protected Boolean xmlDeclStandalone; 465 protected String xmlDeclContent; 466 467 protected void reset() { 468 lineNumber = 1; 470 columnNumber = 0; 471 seenRoot = false; 472 reachedEnd = false; 473 eventType = START_DOCUMENT; 474 emptyElementTag = false; 475 476 depth = 0; 477 478 attributeCount = 0; 479 480 namespaceEnd = 0; 481 482 entityEnd = 0; 483 484 reader = null; 485 inputEncoding = null; 486 487 preventBufferCompaction = false; 488 bufAbsoluteStart = 0; 489 bufEnd = bufStart = 0; 490 pos = posStart = posEnd = 0; 491 492 pcEnd = pcStart = 0; 493 494 usePC = false; 495 496 seenStartTag = false; 497 seenEndTag = false; 498 pastEndTag = false; 499 seenAmpersand = false; 500 seenMarkup = false; 501 seenDocdecl = false; 502 503 xmlDeclVersion = null; 504 xmlDeclStandalone = null; 505 xmlDeclContent = null; 506 507 resetStringCache(); 508 } 509 510 public MXParser() { 511 } 512 513 514 523 public void setFeature(String name, 524 boolean state) throws XmlPullParserException 525 { 526 if(name == null) throw new IllegalArgumentException ("feature name should not be nulll"); 527 if(FEATURE_PROCESS_NAMESPACES.equals(name)) { 528 if(eventType != START_DOCUMENT) throw new XmlPullParserException( 529 "namespace processing feature can only be changed before parsing", this, null); 530 processNamespaces = state; 531 } else if(FEATURE_NAMES_INTERNED.equals(name)) { 536 if(state != false) { 537 throw new XmlPullParserException( 538 "interning names in this implementation is not supported"); 539 } 540 } else if(FEATURE_PROCESS_DOCDECL.equals(name)) { 541 if(state != false) { 542 throw new XmlPullParserException( 543 "processing DOCDECL is not supported"); 544 } 545 } else if(FEATURE_XML_ROUNDTRIP.equals(name)) { 548 roundtripSupported = state; 553 } else { 554 throw new XmlPullParserException("unknown feature "+name); 555 } 556 } 557 558 559 public boolean getFeature(String name) 560 { 561 if(name == null) throw new IllegalArgumentException ("feature name should not be nulll"); 562 if(FEATURE_PROCESS_NAMESPACES.equals(name)) { 563 return processNamespaces; 564 } else if(FEATURE_NAMES_INTERNED.equals(name)) { 567 return false; 568 } else if(FEATURE_PROCESS_DOCDECL.equals(name)) { 569 return false; 570 } else if(FEATURE_XML_ROUNDTRIP.equals(name)) { 573 return roundtripSupported; 575 } 576 return false; 577 } 578 579 public void setProperty(String name, 580 Object value) 581 throws XmlPullParserException 582 { 583 throw new XmlPullParserException("unsupported property: '"+name+"'"); 584 } 585 586 587 public Object getProperty(String name) 588 { 589 if(name == null) throw new IllegalArgumentException ("property name should not be nulll"); 590 if(PROPERTY_XMLDECL_VERSION.equals(name)) { 591 return xmlDeclVersion; 592 } else if(PROPERTY_XMLDECL_STANDALONE.equals(name)) { 593 return xmlDeclStandalone; 594 } else if(PROPERTY_XMLDECL_CONTENT.equals(name)) { 595 return xmlDeclContent; 596 } 597 return null; 598 } 599 600 601 public void setInput(Reader in) throws XmlPullParserException 602 { 603 reset(); 604 reader = in; 605 } 606 607 608 public void setInput(java.io.InputStream inputStream, String inputEncoding) 609 throws XmlPullParserException 610 { 611 if(inputStream == null) { 612 throw new IllegalArgumentException ("input stream can not be null"); 613 } 614 Reader reader; 615 if(inputEncoding != null) { 616 try { 617 if(inputEncoding != null) { 618 reader = new InputStreamReader (inputStream, inputEncoding); 619 } else { 620 reader = new InputStreamReader (inputStream); 621 } 622 } catch (UnsupportedEncodingException une) { 623 throw new XmlPullParserException( 624 "could not create reader for encoding "+inputEncoding+" : "+une, this, une); 625 } 626 } else { 627 reader = new InputStreamReader (inputStream); 628 } 629 setInput(reader); 630 this.inputEncoding = inputEncoding; 632 } 633 634 public String getInputEncoding() { 635 return inputEncoding; 636 } 637 638 public void defineEntityReplacementText(String entityName, 639 String replacementText) 640 throws XmlPullParserException 641 { 642 644 ensureEntityCapacity(); 646 647 this.entityName[entityEnd] = newString(entityName.toCharArray(), 0, entityName.length()); 649 entityNameBuf[entityEnd] = entityName.toCharArray(); 650 651 entityReplacement[entityEnd] = replacementText; 652 entityReplacementBuf[entityEnd] = replacementText.toCharArray(); 653 if(!allStringsInterned) { 654 entityNameHash[ entityEnd ] = 655 fastHash(entityNameBuf[entityEnd], 0, entityNameBuf[entityEnd].length); 656 } 657 ++entityEnd; 658 } 661 662 public int getNamespaceCount(int depth) 663 throws XmlPullParserException 664 { 665 if(processNamespaces == false || depth == 0) { 666 return 0; 667 } 668 if(depth < 0 || depth > this.depth) throw new IllegalArgumentException ( 671 "napespace count mayt be for depth 0.."+this.depth+" not "+depth); 672 return elNamespaceCount[ depth ]; 673 } 674 675 public String getNamespacePrefix(int pos) 676 throws XmlPullParserException 677 { 678 679 if(pos < namespaceEnd) { 682 return namespacePrefix[ pos ]; 683 } else { 684 throw new XmlPullParserException( 685 "position "+pos+" exceeded number of available namespaces "+namespaceEnd); 686 } 687 } 688 689 public String getNamespaceUri(int pos) throws XmlPullParserException 690 { 691 if(pos < namespaceEnd) { 694 return namespaceUri[ pos ]; 695 } else { 696 throw new XmlPullParserException( 697 "position "+pos+" exceedded number of available namespaces "+namespaceEnd); 698 } 699 } 700 701 public String getNamespace( String prefix ) 702 { 704 if(prefix != null) { 706 for( int i = namespaceEnd -1; i >= 0; i--) { 707 if( prefix.equals( namespacePrefix[ i ] ) ) { 708 return namespaceUri[ i ]; 709 } 710 } 711 if("xml".equals( prefix )) { 712 return XML_URI; 713 } else if("xmlns".equals( prefix )) { 714 return XMLNS_URI; 715 } 716 } else { 717 for( int i = namespaceEnd -1; i >= 0; i--) { 718 if( namespacePrefix[ i ] == null ) { 719 return namespaceUri[ i ]; 720 } 721 } 722 723 } 724 return null; 725 } 726 727 728 public int getDepth() 729 { 730 return depth; 731 } 732 733 734 private static int findFragment(int bufMinPos, char[] b, int start, int end) { 735 if(start < bufMinPos) { 737 start = bufMinPos; 738 if(start > end) start = end; 739 return start; 740 } 741 if(end - start > 65) { 742 start = end - 10; } 744 int i = start + 1; 745 while(--i > bufMinPos) { 746 if((end - i) > 65) break; 747 char c = b[i]; 748 if(c == '<' && (start - i) > 10) break; 749 } 750 return i; 751 } 752 753 754 758 public String getPositionDescription () 759 { 760 String fragment = null; 761 if(posStart <= pos) { 762 int start = findFragment(0, buf, posStart, pos); 763 if(start < pos) { 765 fragment = new String (buf, start, pos - start); 766 } 767 if(bufAbsoluteStart > 0 || start > 0) fragment = "..." + fragment; 768 } 769 return " "+TYPES[ eventType ] + 773 (fragment != null ? " seen "+printable(fragment)+"..." : "")+ 774 " @"+getLineNumber()+":"+getColumnNumber(); 775 } 776 777 public int getLineNumber() 778 { 779 return lineNumber; 780 } 781 782 public int getColumnNumber() 783 { 784 return columnNumber; 785 } 786 787 788 public boolean isWhitespace() throws XmlPullParserException 789 { 790 if(eventType == TEXT || eventType == CDSECT) { 791 if(usePC) { 792 for (int i = pcStart; i <pcEnd; i++) 793 { 794 if(!isS(pc[ i ])) return false; 795 } 796 return true; 797 } else { 798 for (int i = posStart; i <posEnd; i++) 799 { 800 if(!isS(buf[ i ])) return false; 801 } 802 return true; 803 } 804 } else if(eventType == IGNORABLE_WHITESPACE) { 805 return true; 806 } 807 throw new XmlPullParserException("no content available to check for whitespaces"); 808 } 809 810 public String getText() 811 { 812 if(eventType == START_DOCUMENT || eventType == END_DOCUMENT) { 813 return null; 818 } else if(eventType == ENTITY_REF) { 820 return text; 821 } 822 if(text == null) { 823 if(!usePC || eventType == START_TAG || eventType == END_TAG) { 824 text = new String (buf, posStart, posEnd - posStart); 825 } else { 826 text = new String (pc, pcStart, pcEnd - pcStart); 827 } 828 } 829 return text; 830 } 831 832 public char[] getTextCharacters(int [] holderForStartAndLength) 833 { 834 if( eventType == TEXT ) { 835 if(usePC) { 836 holderForStartAndLength[0] = pcStart; 837 holderForStartAndLength[1] = pcEnd - pcStart; 838 return pc; 839 } else { 840 holderForStartAndLength[0] = posStart; 841 holderForStartAndLength[1] = posEnd - posStart; 842 return buf; 843 844 } 845 } else if( eventType == START_TAG 846 || eventType == END_TAG 847 || eventType == CDSECT 848 || eventType == COMMENT 849 || eventType == ENTITY_REF 850 || eventType == PROCESSING_INSTRUCTION 851 || eventType == IGNORABLE_WHITESPACE 852 || eventType == DOCDECL) 853 { 854 holderForStartAndLength[0] = posStart; 855 holderForStartAndLength[1] = posEnd - posStart; 856 return buf; 857 } else if(eventType == START_DOCUMENT 858 || eventType == END_DOCUMENT) { 859 holderForStartAndLength[0] = holderForStartAndLength[1] = -1; 861 return null; 862 } else { 863 throw new IllegalArgumentException ("unknown text eventType: "+eventType); 864 } 865 } 875 876 public String getNamespace() 877 { 878 if(eventType == START_TAG) { 879 return processNamespaces ? elUri[ depth ] : NO_NAMESPACE; 881 } else if(eventType == END_TAG) { 882 return processNamespaces ? elUri[ depth ] : NO_NAMESPACE; 883 } 884 return null; 885 } 902 903 public String getName() 904 { 905 if(eventType == START_TAG) { 906 return elName[ depth ] ; 908 } else if(eventType == END_TAG) { 909 return elName[ depth ] ; 910 } else if(eventType == ENTITY_REF) { 911 if(entityRefName == null) { 912 entityRefName = newString(buf, posStart, posEnd - posStart); 913 } 914 return entityRefName; 915 } else { 916 return null; 917 } 918 } 919 920 public String getPrefix() 921 { 922 if(eventType == START_TAG) { 923 return elPrefix[ depth ] ; 925 } else if(eventType == END_TAG) { 926 return elPrefix[ depth ] ; 927 } 928 return null; 929 } 933 934 935 public boolean isEmptyElementTag() throws XmlPullParserException 936 { 937 if(eventType != START_TAG) throw new XmlPullParserException( 938 "parser must be on START_TAG to check for empty element", this, null); 939 return emptyElementTag; 940 } 941 942 public int getAttributeCount() 943 { 944 if(eventType != START_TAG) return -1; 945 return attributeCount; 946 } 947 948 public String getAttributeNamespace(int index) 949 { 950 if(eventType != START_TAG) throw new IndexOutOfBoundsException ( 951 "only START_TAG can have attributes"); 952 if(processNamespaces == false) return NO_NAMESPACE; 953 if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException ( 954 "attribute position must be 0.."+(attributeCount-1)+" and not "+index); 955 return attributeUri[ index ]; 956 } 957 958 public String getAttributeName(int index) 959 { 960 if(eventType != START_TAG) throw new IndexOutOfBoundsException ( 961 "only START_TAG can have attributes"); 962 if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException ( 963 "attribute position must be 0.."+(attributeCount-1)+" and not "+index); 964 return attributeName[ index ]; 965 } 966 967 public String getAttributePrefix(int index) 968 { 969 if(eventType != START_TAG) throw new IndexOutOfBoundsException ( 970 "only START_TAG can have attributes"); 971 if(processNamespaces == false) return null; 972 if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException ( 973 "attribute position must be 0.."+(attributeCount-1)+" and not "+index); 974 return attributePrefix[ index ]; 975 } 976 977 public String getAttributeType(int index) { 978 if(eventType != START_TAG) throw new IndexOutOfBoundsException ( 979 "only START_TAG can have attributes"); 980 if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException ( 981 "attribute position must be 0.."+(attributeCount-1)+" and not "+index); 982 return "CDATA"; 983 } 984 985 public boolean isAttributeDefault(int index) { 986 if(eventType != START_TAG) throw new IndexOutOfBoundsException ( 987 "only START_TAG can have attributes"); 988 if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException ( 989 "attribute position must be 0.."+(attributeCount-1)+" and not "+index); 990 return false; 991 } 992 993 public String getAttributeValue(int index) 994 { 995 if(eventType != START_TAG) throw new IndexOutOfBoundsException ( 996 "only START_TAG can have attributes"); 997 if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException ( 998 "attribute position must be 0.."+(attributeCount-1)+" and not "+index); 999 return attributeValue[ index ]; 1000 } 1001 1002 public String getAttributeValue(String namespace, 1003 String name) 1004 { 1005 if(eventType != START_TAG) throw new IndexOutOfBoundsException ( 1006 "only START_TAG can have attributes"); 1007 if(name == null) { 1008 throw new IllegalArgumentException ("attribute name can not be null"); 1009 } 1010 if(processNamespaces) { 1012 for(int i = 0; i < attributeCount; ++i) { 1013 if(namespace == attributeUri[ i ] && name.equals(attributeName[i])) 1015 { 1016 return attributeValue[i]; 1017 } 1018 } 1019 } else { 1020 if(namespace != null && namespace.length() == 0) { 1021 namespace = null; 1022 } 1023 if(namespace != null) throw new IllegalArgumentException ( 1024 "when namespaces processing is disabled attribute namespace must be null"); 1025 for(int i = 0; i < attributeCount; ++i) { 1026 if(name.equals(attributeName[i])) 1027 { 1028 return attributeValue[i]; 1029 } 1030 } 1031 } 1032 return null; 1033 } 1034 1035 1036 public int getEventType() 1037 throws XmlPullParserException 1038 { 1039 return eventType; 1040 } 1041 1042 public void require(int type, String namespace, String name) 1043 throws XmlPullParserException, IOException 1044 { 1045 if (type != getEventType() 1046 || (namespace != null && !namespace.equals (getNamespace())) 1047 || (name != null && !name.equals (getName ())) ) 1048 { 1049 throw new XmlPullParserException ( 1050 "expected event "+TYPES[ type ] 1051 +(name != null ? " with name '"+name+"'" : "") 1052 +(namespace != null && name != null ? " and" : "") 1053 +(namespace != null ? " with namespace '"+namespace+"'" : "") 1054 +" but got" 1055 +(type != getEventType() ? " "+TYPES[ getEventType() ] : "") 1056 +(name != null && getName() != null && !name.equals (getName ()) 1057 ? " name '"+getName()+"'" : "") 1058 +(namespace != null && name != null 1059 && getName() != null && !name.equals (getName ()) 1060 && getNamespace() != null && !namespace.equals (getNamespace()) 1061 ? " and" : "") 1062 +(namespace != null && getNamespace() != null && !namespace.equals (getNamespace()) 1063 ? " namespace '"+getNamespace()+"'" : "") 1064 +(" (postion:"+ getPositionDescription())+")"); 1065 } 1066 } 1067 1068 1076 public String nextText() throws XmlPullParserException, IOException 1077 { 1078 if(getEventType() != START_TAG) { 1099 throw new XmlPullParserException( 1100 "parser must be on START_TAG to read next text", this, null); 1101 } 1102 int eventType = next(); 1103 if(eventType == TEXT) { 1104 String result = getText(); 1105 eventType = next(); 1106 if(eventType != END_TAG) { 1107 throw new XmlPullParserException( 1108 "TEXT must be immediately followed by END_TAG and not " 1109 +TYPES[ getEventType() ], this, null); 1110 } 1111 return result; 1112 } else if(eventType == END_TAG) { 1113 return ""; 1114 } else { 1115 throw new XmlPullParserException( 1116 "parser must be on START_TAG or TEXT to read text", this, null); 1117 } 1118 } 1119 1120 public int nextTag() throws XmlPullParserException, IOException 1121 { 1122 next(); 1123 if(eventType == TEXT && isWhitespace()) { next(); 1125 } 1126 if (eventType != START_TAG && eventType != END_TAG) { 1127 throw new XmlPullParserException("expected START_TAG or END_TAG not " 1128 +TYPES[ getEventType() ], this, null); 1129 } 1130 return eventType; 1131 } 1132 1133 public int next() 1134 throws XmlPullParserException, IOException 1135 { 1136 tokenize = false; 1137 return nextImpl(); 1138 } 1139 1140 public int nextToken() 1141 throws XmlPullParserException, IOException 1142 { 1143 tokenize = true; 1144 return nextImpl(); 1145 } 1146 1147 1148 protected int nextImpl() 1149 throws XmlPullParserException, IOException 1150 { 1151 text = null; 1152 pcEnd = pcStart = 0; 1153 usePC = false; 1154 bufStart = posEnd; 1155 if(pastEndTag) { 1156 pastEndTag = false; 1157 --depth; 1158 namespaceEnd = elNamespaceCount[ depth ]; } 1160 if(emptyElementTag) { 1161 emptyElementTag = false; 1162 pastEndTag = true; 1163 return eventType = END_TAG; 1164 } 1165 1166 if(depth > 0) { 1168 1169 if(seenStartTag) { 1170 seenStartTag = false; 1171 return eventType = parseStartTag(); 1172 } 1173 if(seenEndTag) { 1174 seenEndTag = false; 1175 return eventType = parseEndTag(); 1176 } 1177 1178 char ch; 1181 if(seenMarkup) { seenMarkup = false; 1183 ch = '<'; 1184 } else if(seenAmpersand) { 1185 seenAmpersand = false; 1186 ch = '&'; 1187 } else { 1188 ch = more(); 1189 } 1190 posStart = pos - 1; 1192 boolean hadCharData = false; 1194 1195 boolean needsMerging = false; 1197 1198 MAIN_LOOP: 1199 while(true) { 1200 if(ch == '<') { 1202 if(hadCharData) { 1203 if(tokenize) { 1205 seenMarkup = true; 1206 return eventType = TEXT; 1207 } 1208 } 1209 ch = more(); 1210 if(ch == '/') { 1211 if(!tokenize && hadCharData) { 1212 seenEndTag = true; 1213 return eventType = TEXT; 1215 } 1216 return eventType = parseEndTag(); 1217 } else if(ch == '!') { 1218 ch = more(); 1219 if(ch == '-') { 1220 parseComment(); 1222 if(tokenize) return eventType = COMMENT; 1223 if( !usePC && hadCharData ) needsMerging = true; 1224 } else if(ch == '[') { 1225 parseCDSect(hadCharData); 1230 if(tokenize) return eventType = CDSECT; 1231 int cdStart = posStart; 1232 int cdEnd = posEnd; 1233 int cdLen = cdEnd - cdStart; 1234 1235 1236 if(cdLen > 0) { if(!usePC) { 1238 hadCharData = true; 1239 needsMerging = true; 1240 } 1241 } 1242 1243 } else { 1281 throw new XmlPullParserException( 1282 "unexpected character in markup "+printable(ch), this, null); 1283 } 1284 } else if(ch == '?') { 1285 parsePI(); 1286 if(tokenize) return eventType = PROCESSING_INSTRUCTION; 1287 if( !usePC && hadCharData ) needsMerging = true; 1288 } else if( isNameStartChar(ch) ) { 1289 if(!tokenize && hadCharData) { 1290 seenStartTag = true; 1291 return eventType = TEXT; 1293 } 1294 return eventType = parseStartTag(); 1295 } else { 1296 throw new XmlPullParserException( 1297 "unexpected character in markup "+printable(ch), this, null); 1298 } 1299 1301 } else if(ch == '&') { 1302 if(tokenize && hadCharData) { 1305 seenAmpersand = true; 1306 return eventType = TEXT; 1307 } 1308 int oldStart = posStart + bufAbsoluteStart; 1309 int oldEnd = posEnd + + bufAbsoluteStart; 1310 char[] resolvedEntity = parseEntityRef(); 1311 if(tokenize) return eventType = ENTITY_REF; 1312 if(resolvedEntity == null) { 1314 if(entityRefName == null) { 1315 entityRefName = newString(buf, posStart, posEnd - posStart); 1316 } 1317 throw new XmlPullParserException( 1318 "could not resolve entity named '"+printable(entityRefName)+"'", 1319 this, null); 1320 } 1321 posStart = oldStart - bufAbsoluteStart; 1324 posEnd = oldEnd - bufAbsoluteStart; 1325 if(!usePC) { 1326 if(hadCharData) { 1327 joinPC(); needsMerging = false; 1329 } else { 1330 usePC = true; 1331 pcStart = pcEnd = 0; 1332 } 1333 } 1334 for (int i = 0; i < resolvedEntity.length; i++) 1337 { 1338 if(pcEnd >= pc.length) ensurePC(pcEnd); 1339 pc[pcEnd++] = resolvedEntity[ i ]; 1340 1341 } 1342 } else { 1344 1345 if(needsMerging) { 1346 joinPC(); needsMerging = false; 1350 } 1351 1352 1353 1355 1356 1357 1359 1360 hadCharData = true; 1361 1362 boolean normalizedCR = false; 1363 boolean normalizeInput = tokenize == false || roundtripSupported == false; 1364 do { 1366 1367 if(normalizeInput) { 1376 if(ch == '\r') { 1378 normalizedCR = true; 1379 posEnd = pos -1; 1380 if(!usePC) { 1382 if(posEnd > posStart) { 1383 joinPC(); 1384 } else { 1385 usePC = true; 1386 pcStart = pcEnd = 0; 1387 } 1388 } 1389 if(pcEnd >= pc.length) ensurePC(pcEnd); 1391 pc[pcEnd++] = '\n'; 1392 } else if(ch == '\n') { 1393 if(!normalizedCR && usePC) { 1395 if(pcEnd >= pc.length) ensurePC(pcEnd); 1396 pc[pcEnd++] = '\n'; 1397 } 1398 normalizedCR = false; 1399 } else { 1400 if(usePC) { 1401 if(pcEnd >= pc.length) ensurePC(pcEnd); 1402 pc[pcEnd++] = ch; 1403 } 1404 normalizedCR = false; 1405 } 1406 } 1407 ch = more(); 1408 } while(ch != '<' && ch != '&'); 1409 posEnd = pos - 1; 1410 continue MAIN_LOOP; } 1412 ch = more(); 1413 } } else { 1415 if(seenRoot) { 1416 return parseEpilog(); 1417 } else { 1418 return parseProlog(); 1419 } 1420 } 1421 } 1422 1423 1424 protected int parseProlog() 1425 throws XmlPullParserException, IOException 1426 { 1427 1429 char ch; 1430 if(seenMarkup) { 1431 ch = buf[ pos - 1 ]; 1432 } else { 1433 ch = more(); 1434 } 1435 1436 if(eventType == START_DOCUMENT) { 1437 if(ch == '\uFFFE') { 1441 throw new XmlPullParserException( 1442 "first character in input was UNICODE noncharacter (0xFFFE)"+ 1443 "- input requires int swapping", this, null); 1444 } 1445 if(ch == '\uFEFF') { 1446 ch = more(); 1448 } 1449 } 1450 seenMarkup = false; 1451 boolean gotS = false; 1452 posStart = pos - 1; 1453 boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false; 1454 boolean normalizedCR = false; 1455 while(true) { 1456 if(ch == '<') { 1461 if(gotS && tokenize) { 1462 posEnd = pos - 1; 1463 seenMarkup = true; 1464 return eventType = IGNORABLE_WHITESPACE; 1465 } 1466 ch = more(); 1467 if(ch == '?') { 1468 if(parsePI()) { if(tokenize) { 1472 return eventType = PROCESSING_INSTRUCTION; 1473 } 1474 } else { 1475 posStart = pos; 1477 gotS = false; 1478 } 1479 1480 } else if(ch == '!') { 1481 ch = more(); 1482 if(ch == 'D') { 1483 if(seenDocdecl) { 1484 throw new XmlPullParserException( 1485 "only one docdecl allowed in XML document", this, null); 1486 } 1487 seenDocdecl = true; 1488 parseDocdecl(); 1489 if(tokenize) return eventType = DOCDECL; 1490 } else if(ch == '-') { 1491 parseComment(); 1492 if(tokenize) return eventType = COMMENT; 1493 } else { 1494 throw new XmlPullParserException( 1495 "unexpected markup <!"+printable(ch), this, null); 1496 } 1497 } else if(ch == '/') { 1498 throw new XmlPullParserException( 1499 "expected start tag name and not "+printable(ch), this, null); 1500 } else if(isNameStartChar(ch)) { 1501 seenRoot = true; 1502 return parseStartTag(); 1503 } else { 1504 throw new XmlPullParserException( 1505 "expected start tag name and not "+printable(ch), this, null); 1506 } 1507 } else if(isS(ch)) { 1508 gotS = true; 1509 if(normalizeIgnorableWS) { 1510 if(ch == '\r') { 1511 normalizedCR = true; 1512 if(!usePC) { 1516 posEnd = pos -1; 1517 if(posEnd > posStart) { 1518 joinPC(); 1519 } else { 1520 usePC = true; 1521 pcStart = pcEnd = 0; 1522 } 1523 } 1524 if(pcEnd >= pc.length) ensurePC(pcEnd); 1526 pc[pcEnd++] = '\n'; 1527 } else if(ch == '\n') { 1528 if(!normalizedCR && usePC) { 1529 if(pcEnd >= pc.length) ensurePC(pcEnd); 1530 pc[pcEnd++] = '\n'; 1531 } 1532 normalizedCR = false; 1533 } else { 1534 if(usePC) { 1535 if(pcEnd >= pc.length) ensurePC(pcEnd); 1536 pc[pcEnd++] = ch; 1537 } 1538 normalizedCR = false; 1539 } 1540 } 1541 } else { 1542 throw new XmlPullParserException( 1543 "only whitespace content allowed before start tag and not "+printable(ch), 1544 this, null); 1545 } 1546 ch = more(); 1547 } 1548 } 1549 1550 protected int parseEpilog() 1551 throws XmlPullParserException, IOException 1552 { 1553 if(eventType == END_DOCUMENT) { 1554 throw new XmlPullParserException("already reached end document", this, null); 1555 } 1556 if(reachedEnd) { 1557 return eventType = END_DOCUMENT; 1558 } 1559 boolean gotS = false; 1560 boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false; 1561 boolean normalizedCR = false; 1562 try { 1563 char ch; 1565 if(seenMarkup) { 1566 ch = buf[ pos - 1 ]; 1567 } else { 1568 ch = more(); 1569 } 1570 seenMarkup = false; 1571 posStart = pos - 1; 1572 while(true) { 1573 if(ch == '<') { 1576 if(gotS && tokenize) { 1577 posEnd = pos - 1; 1578 seenMarkup = true; 1579 return eventType = IGNORABLE_WHITESPACE; 1580 } 1581 ch = more(); 1582 if(ch == '?') { 1583 parsePI(); 1586 if(tokenize) return eventType = PROCESSING_INSTRUCTION; 1587 1588 } else if(ch == '!') { 1589 ch = more(); 1590 if(ch == 'D') { 1591 parseDocdecl(); if(tokenize) return eventType = DOCDECL; 1593 } else if(ch == '-') { 1594 parseComment(); 1595 if(tokenize) return eventType = COMMENT; 1596 } else { 1597 throw new XmlPullParserException( 1598 "unexpected markup <!"+printable(ch), this, null); 1599 } 1600 } else if(ch == '/') { 1601 throw new XmlPullParserException( 1602 "end tag not allowed in epilog but got "+printable(ch), this, null); 1603 } else if(isNameStartChar(ch)) { 1604 throw new XmlPullParserException( 1605 "start tag not allowed in epilog but got "+printable(ch), this, null); 1606 } else { 1607 throw new XmlPullParserException( 1608 "in epilog expected ignorable content and not "+printable(ch), 1609 this, null); 1610 } 1611 } else if(isS(ch)) { 1612 gotS = true; 1613 if(normalizeIgnorableWS) { 1614 if(ch == '\r') { 1615 normalizedCR = true; 1616 if(!usePC) { 1620 posEnd = pos -1; 1621 if(posEnd > posStart) { 1622 joinPC(); 1623 } else { 1624 usePC = true; 1625 pcStart = pcEnd = 0; 1626 } 1627 } 1628 if(pcEnd >= pc.length) ensurePC(pcEnd); 1630 pc[pcEnd++] = '\n'; 1631 } else if(ch == '\n') { 1632 if(!normalizedCR && usePC) { 1633 if(pcEnd >= pc.length) ensurePC(pcEnd); 1634 pc[pcEnd++] = '\n'; 1635 } 1636 normalizedCR = false; 1637 } else { 1638 if(usePC) { 1639 if(pcEnd >= pc.length) ensurePC(pcEnd); 1640 pc[pcEnd++] = ch; 1641 } 1642 normalizedCR = false; 1643 } 1644 } 1645 } else { 1646 throw new XmlPullParserException( 1647 "in epilog non whitespace content is not allowed but got "+printable(ch), 1648 this, null); 1649 } 1650 ch = more(); 1651 } 1652 1653 } catch(EOFException ex) { 1657 reachedEnd = true; 1658 if(tokenize && gotS) { 1659 posEnd = pos; return eventType = IGNORABLE_WHITESPACE; 1661 } 1662 return eventType = END_DOCUMENT; 1663 } 1664 } 1665 1666 1667 public int parseEndTag() throws XmlPullParserException, IOException { 1668 char ch = more(); 1671 if(!isNameStartChar(ch)) { 1672 throw new XmlPullParserException( 1673 "expected name start and not "+printable(ch), this, null); 1674 } 1675 posStart = pos - 3; 1676 int nameStart = pos - 1 + bufAbsoluteStart; 1677 do { 1678 ch = more(); 1679 } while(isNameChar(ch)); 1680 1681 1684 int last = pos - 1; 1688 int off = nameStart - bufAbsoluteStart; 1689 int len = last - off; 1690 char[] cbuf = elRawName[depth]; 1691 if(elRawNameEnd[depth] != len) { 1692 String startname = new String (cbuf, 0, elRawNameEnd[depth]); 1694 String endname = new String (buf, off, len); 1695 throw new XmlPullParserException( 1696 "end tag name '"+endname+"' must match start tag name '"+startname+"'", 1697 this, null); 1698 } 1699 for (int i = 0; i < len; i++) 1700 { 1701 if(buf[off++] != cbuf[i]) { 1702 String startname = new String (cbuf, 0, len); 1704 String endname = new String (buf, off - i - 1, len); 1705 throw new XmlPullParserException( 1706 "end tag name '"+endname+"' must be the same as start tag '"+startname+"'", 1707 this, null); 1708 } 1709 } 1710 1711 while(isS(ch)) { ch = more(); } if(ch != '>') throw new XmlPullParserException( 1713 "expected > to finsh end tag not "+printable(ch), this, null); 1714 1715 1716 1717 1719 posEnd = pos; 1720 pastEndTag = true; 1721 return eventType = END_TAG; 1722 } 1723 1724 public int parseStartTag() throws XmlPullParserException, IOException { 1725 ++depth; 1730 posStart = pos - 2; 1731 1732 emptyElementTag = false; 1733 attributeCount = 0; 1734 int nameStart = pos - 1 + bufAbsoluteStart; 1736 int colonPos = -1; 1737 char ch = buf[ pos - 1]; 1738 if(ch == ':' && processNamespaces) throw new XmlPullParserException( 1739 "when namespaces processing enabled colon can not be at element name start", 1740 this, null); 1741 while(true) { 1742 ch = more(); 1743 if(!isNameChar(ch)) break; 1744 if(ch == ':' && processNamespaces) { 1745 if(colonPos != -1) throw new XmlPullParserException( 1746 "only one colon is allowed in name of element when namespaces are enabled", 1747 this, null); 1748 colonPos = pos - 1 + bufAbsoluteStart; 1749 } 1750 } 1751 1752 ensureElementsCapacity(); 1754 1755 1756 1758 int elLen = (pos - 1) - (nameStart - bufAbsoluteStart); 1759 if(elRawName[ depth ] == null || elRawName[ depth ].length < elLen) { 1760 elRawName[ depth ] = new char[ 2 * elLen ]; 1761 } 1762 System.arraycopy(buf, nameStart - bufAbsoluteStart, elRawName[ depth ], 0, elLen); 1763 elRawNameEnd[ depth ] = elLen; 1764 1765 String name = null; 1766 1767 String prefix = null; 1769 if(processNamespaces) { 1770 if(colonPos != -1) { 1771 prefix = elPrefix[ depth ] = newString(buf, nameStart - bufAbsoluteStart, 1772 colonPos - nameStart); 1773 name = elName[ depth ] = newString(buf, colonPos + 1 - bufAbsoluteStart, 1774 pos - 2 - (colonPos - bufAbsoluteStart)); 1776 } else { 1777 prefix = elPrefix[ depth ] = null; 1778 name = elName[ depth ] = newString(buf, nameStart - bufAbsoluteStart, elLen); 1779 } 1780 } else { 1781 1782 name = elName[ depth ] = newString(buf, nameStart - bufAbsoluteStart, elLen); 1783 1784 } 1785 1786 1787 while(true) { 1788 1789 while(isS(ch)) { ch = more(); } 1791 if(ch == '>') { 1792 break; 1793 } else if(ch == '/') { 1794 if(emptyElementTag) throw new XmlPullParserException( 1795 "repeated / in tag declaration", this, null); 1796 emptyElementTag = true; 1797 ch = more(); 1798 if(ch != '>') throw new XmlPullParserException( 1799 "expected > to end empty tag not "+printable(ch), this, null); 1800 break; 1801 } else if(isNameStartChar(ch)) { 1802 ch = parseAttribute(); 1803 ch = more(); 1804 continue; 1805 } else { 1806 throw new XmlPullParserException( 1807 "start tag unexpected character "+printable(ch), this, null); 1808 } 1809 } 1811 1812 if(processNamespaces) { 1814 String uri = getNamespace(prefix); 1815 if(uri == null) { 1816 if(prefix == null) { uri = NO_NAMESPACE; 1818 } else { 1819 throw new XmlPullParserException( 1820 "could not determine namespace bound to element prefix "+prefix, 1821 this, null); 1822 } 1823 1824 } 1825 elUri[ depth ] = uri; 1826 1827 1828 for (int i = 0; i < attributeCount; i++) 1834 { 1835 String attrPrefix = attributePrefix[ i ]; 1836 if(attrPrefix != null) { 1837 String attrUri = getNamespace(attrPrefix); 1838 if(attrUri == null) { 1839 throw new XmlPullParserException( 1840 "could not determine namespace bound to attribute prefix "+attrPrefix, 1841 this, null); 1842 1843 } 1844 attributeUri[ i ] = attrUri; 1845 } else { 1846 attributeUri[ i ] = NO_NAMESPACE; 1847 } 1848 } 1849 1850 1854 for (int i = 1; i < attributeCount; i++) 1855 { 1856 for (int j = 0; j < i; j++) 1857 { 1858 if( attributeUri[j] == attributeUri[i] 1859 && (allStringsInterned && attributeName[j].equals(attributeName[i]) 1860 || (!allStringsInterned 1861 && attributeNameHash[ j ] == attributeNameHash[ i ] 1862 && attributeName[j].equals(attributeName[i])) ) 1863 1864 ) { 1865 String attr1 = attributeName[j]; 1867 if(attributeUri[j] != null) attr1 = attributeUri[j]+":"+attr1; 1868 String attr2 = attributeName[i]; 1869 if(attributeUri[i] != null) attr2 = attributeUri[i]+":"+attr2; 1870 throw new XmlPullParserException( 1871 "duplicated attributes "+attr1+" and "+attr2, this, null); 1872 } 1873 } 1874 } 1875 1876 1877 } else { 1879 for (int i = 1; i < attributeCount; i++) 1882 { 1883 for (int j = 0; j < i; j++) 1884 { 1885 if((allStringsInterned && attributeName[j].equals(attributeName[i]) 1886 || (!allStringsInterned 1887 && attributeNameHash[ j ] == attributeNameHash[ i ] 1888 && attributeName[j].equals(attributeName[i])) ) 1889 1890 ) { 1891 String attr1 = attributeName[j]; 1893 String attr2 = attributeName[i]; 1894 throw new XmlPullParserException( 1895 "duplicated attributes "+attr1+" and "+attr2, this, null); 1896 } 1897 } 1898 } 1899 } 1900 1901 elNamespaceCount[ depth ] = namespaceEnd; 1902 posEnd = pos; 1903 return eventType = START_TAG; 1904 } 1905 1906 protected char parseAttribute() throws XmlPullParserException, IOException 1907 { 1908 int prevPosStart = posStart + bufAbsoluteStart; 1913 int nameStart = pos - 1 + bufAbsoluteStart; 1914 int colonPos = -1; 1915 char ch = buf[ pos - 1 ]; 1916 if(ch == ':' && processNamespaces) throw new XmlPullParserException( 1917 "when namespaces processing enabled colon can not be at attribute name start", 1918 this, null); 1919 1920 1921 boolean startsWithXmlns = processNamespaces && ch == 'x'; 1922 int xmlnsPos = 0; 1923 1924 ch = more(); 1925 while(isNameChar(ch)) { 1926 if(processNamespaces) { 1927 if(startsWithXmlns && xmlnsPos < 5) { 1928 ++xmlnsPos; 1929 if(xmlnsPos == 1) { if(ch != 'm') startsWithXmlns = false; } 1930 else if(xmlnsPos == 2) { if(ch != 'l') startsWithXmlns = false; } 1931 else if(xmlnsPos == 3) { if(ch != 'n') startsWithXmlns = false; } 1932 else if(xmlnsPos == 4) { if(ch != 's') startsWithXmlns = false; } 1933 else if(xmlnsPos == 5) { 1934 if(ch != ':') throw new XmlPullParserException( 1935 "after xmlns in attribute name must be colon" 1936 +"when namespaces are enabled", this, null); 1937 } 1939 } 1940 if(ch == ':') { 1941 if(colonPos != -1) throw new XmlPullParserException( 1942 "only one colon is allowed in attribute name" 1943 +" when namespaces are enabled", this, null); 1944 colonPos = pos - 1 + bufAbsoluteStart; 1945 } 1946 } 1947 ch = more(); 1948 } 1949 1950 ensureAttributesCapacity(attributeCount); 1951 1952 String name = null; 1954 String prefix = null; 1955 if(processNamespaces) { 1957 if(xmlnsPos < 4) startsWithXmlns = false; 1958 if(startsWithXmlns) { 1959 if(colonPos != -1) { 1960 name = newString(buf, colonPos - bufAbsoluteStart + 1, 1963 pos - 2 - (colonPos - bufAbsoluteStart) 1965 ); 1966 } 1967 } else { 1968 if(colonPos != -1) { 1969 prefix = attributePrefix[ attributeCount ] = 1970 newString(buf, nameStart - bufAbsoluteStart, 1971 colonPos - nameStart); 1973 name = attributeName[ attributeCount ] = 1974 newString(buf, colonPos - bufAbsoluteStart + 1, 1975 pos - 2 - (colonPos - bufAbsoluteStart)); 1977 } else { 1979 prefix = attributePrefix[ attributeCount ] = null; 1980 name = attributeName[ attributeCount ] = 1981 newString(buf, nameStart - bufAbsoluteStart, 1982 pos - 1 - (nameStart - bufAbsoluteStart)); 1983 } 1984 if(!allStringsInterned) { 1985 attributeNameHash[ attributeCount ] = name.hashCode(); 1986 } 1987 } 1988 1989 } else { 1990 name = attributeName[ attributeCount ] = 1992 newString(buf, nameStart - bufAbsoluteStart, 1993 pos - 1 - (nameStart - bufAbsoluteStart)); 1994 if(!allStringsInterned) { 1996 attributeNameHash[ attributeCount ] = name.hashCode(); 1997 } 1998 } 1999 2000 while(isS(ch)) { ch = more(); } if(ch != '=') throw new XmlPullParserException( 2003 "expected = after attribute name", this, null); 2004 ch = more(); 2005 while(isS(ch)) { ch = more(); } 2007 char delimit = ch; 2010 if(delimit != '"' && delimit != '\'') throw new XmlPullParserException( 2011 "attribute value must start with quotation or apostrophe not " 2012 +printable(delimit), this, null); 2013 2017 2018 boolean normalizedCR = false; 2019 usePC = false; 2020 pcStart = pcEnd; 2021 posStart = pos; 2022 2023 while(true) { 2024 ch = more(); 2025 if(ch == delimit) { 2026 break; 2027 } if(ch == '<') { 2028 throw new XmlPullParserException( 2029 "markup not allowed inside attribute value - illegal < ", this, null); 2030 } if(ch == '&') { 2031 posEnd = pos - 1; 2033 if(!usePC) { 2034 boolean hadCharData = posEnd > posStart; 2035 if(hadCharData) { 2036 joinPC(); 2038 } else { 2039 usePC = true; 2040 pcStart = pcEnd = 0; 2041 } 2042 } 2043 2045 char[] resolvedEntity = parseEntityRef(); 2046 if(resolvedEntity == null) { 2048 if(entityRefName == null) { 2049 entityRefName = newString(buf, posStart, posEnd - posStart); 2050 } 2051 throw new XmlPullParserException( 2052 "could not resolve entity named '"+printable(entityRefName)+"'", 2053 this, null); 2054 } 2055 for (int i = 0; i < resolvedEntity.length; i++) 2057 { 2058 if(pcEnd >= pc.length) ensurePC(pcEnd); 2059 pc[pcEnd++] = resolvedEntity[ i ]; 2060 } 2061 } else if(ch == '\t' || ch == '\n' || ch == '\r') { 2062 if(!usePC) { 2067 posEnd = pos - 1; 2068 if(posEnd > posStart) { 2069 joinPC(); 2070 } else { 2071 usePC = true; 2072 pcEnd = pcStart = 0; 2073 } 2074 } 2075 if(pcEnd >= pc.length) ensurePC(pcEnd); 2077 if(ch != '\n' || !normalizedCR) { 2078 pc[pcEnd++] = ' '; } 2080 2081 } else { 2082 if(usePC) { 2083 if(pcEnd >= pc.length) ensurePC(pcEnd); 2084 pc[pcEnd++] = ch; 2085 } 2086 } 2087 normalizedCR = ch == '\r'; 2088 } 2089 2090 2091 if(processNamespaces && startsWithXmlns) { 2092 String ns = null; 2093 if(!usePC) { 2094 ns = newStringIntern(buf, posStart, pos - 1 - posStart); 2095 } else { 2096 ns = newStringIntern(pc, pcStart, pcEnd - pcStart); 2097 } 2098 ensureNamespacesCapacity(namespaceEnd); 2099 int prefixHash = -1; 2100 if(colonPos != -1) { 2101 if(ns.length() == 0) { 2102 throw new XmlPullParserException( 2103 "non-default namespace can not be declared to be empty string", this, null); 2104 } 2105 namespacePrefix[ namespaceEnd ] = name; 2107 if(!allStringsInterned) { 2108 prefixHash = namespacePrefixHash[ namespaceEnd ] = name.hashCode(); 2109 } 2110 } else { 2111 namespacePrefix[ namespaceEnd ] = null; 2113 if(!allStringsInterned) { 2114 prefixHash = namespacePrefixHash[ namespaceEnd ] = -1; 2115 } 2116 } 2117 namespaceUri[ namespaceEnd ] = ns; 2118 2119 int startNs = elNamespaceCount[ depth - 1 ]; 2121 for (int i = namespaceEnd - 1; i >= startNs; --i) 2122 { 2123 if(((allStringsInterned || name == null) && namespacePrefix[ i ] == name) 2124 || (!allStringsInterned && name != null && 2125 namespacePrefixHash[ i ] == prefixHash 2126 && name.equals(namespacePrefix[ i ]) 2127 )) 2128 { 2129 String s = name == null ? "default" : "'"+name+"'"; 2130 throw new XmlPullParserException( 2131 "duplicated namespace declaration for "+s+" prefix", this, null); 2132 } 2133 } 2134 2135 ++namespaceEnd; 2136 2137 } else { 2138 if(!usePC) { 2139 attributeValue[ attributeCount ] = 2140 new String (buf, posStart, pos - 1 - posStart); 2141 } else { 2142 attributeValue[ attributeCount ] = 2143 new String (pc, pcStart, pcEnd - pcStart); 2144 } 2145 ++attributeCount; 2146 } 2147 posStart = prevPosStart - bufAbsoluteStart; 2148 return ch; 2149 } 2150 2151 protected char[] charRefOneCharBuf = new char[1]; 2152 2153 protected char[] parseEntityRef() 2154 throws XmlPullParserException, IOException 2155 { 2156 entityRefName = null; 2158 posStart = pos; 2159 char ch = more(); 2160 if(ch == '#') { 2161 char charRef = 0; 2163 ch = more(); 2164 if(ch == 'x') { 2165 while(true) { 2167 ch = more(); 2168 if(ch >= '0' && ch <= '9') { 2169 charRef = (char)(charRef * 16 + (ch - '0')); 2170 } else if(ch >= 'a' && ch <= 'f') { 2171 charRef = (char)(charRef * 16 + (ch - ('a' - 10))); 2172 } else if(ch >= 'A' && ch <= 'F') { 2173 charRef = (char)(charRef * 16 + (ch - ('A' - 10))); 2174 } else if(ch == ';') { 2175 break; 2176 } else { 2177 throw new XmlPullParserException( 2178 "character reference (with hex value) may not contain " 2179 +printable(ch), this, null); 2180 } 2181 } 2182 } else { 2183 while(true) { 2185 if(ch >= '0' && ch <= '9') { 2186 charRef = (char)(charRef * 10 + (ch - '0')); 2187 } else if(ch == ';') { 2188 break; 2189 } else { 2190 throw new XmlPullParserException( 2191 "character reference (with decimal value) may not contain " 2192 +printable(ch), this, null); 2193 } 2194 ch = more(); 2195 } 2196 } 2197 posEnd = pos - 1; 2198 charRefOneCharBuf[0] = charRef; 2199 if(tokenize) { 2200 text = newString(charRefOneCharBuf, 0, 1); 2201 } 2202 return charRefOneCharBuf; 2203 } else { 2204 2206 do{ ch = more(); } while(ch != ';'); 2208 posEnd = pos - 1; 2209 int len = posEnd - posStart; 2211 if(len == 2 && buf[posStart] == 'l' && buf[posStart+1] == 't') { 2212 if(tokenize) { 2213 text = "<"; 2214 } 2215 charRefOneCharBuf[0] = '<'; 2216 return charRefOneCharBuf; 2217 } else if(len == 3 && buf[posStart] == 'a' 2222 && buf[posStart+1] == 'm' && buf[posStart+2] == 'p') { 2223 if(tokenize) { 2224 text = "&"; 2225 } 2226 charRefOneCharBuf[0] = '&'; 2227 return charRefOneCharBuf; 2228 } else if(len == 2 && buf[posStart] == 'g' && buf[posStart+1] == 't') { 2229 if(tokenize) { 2230 text = ">"; 2231 } 2232 charRefOneCharBuf[0] = '>'; 2233 return charRefOneCharBuf; 2234 } else if(len == 4 && buf[posStart] == 'a' && buf[posStart+1] == 'p' 2235 && buf[posStart+2] == 'o' && buf[posStart+3] == 's') 2236 { 2237 if(tokenize) { 2238 text = "'"; 2239 } 2240 charRefOneCharBuf[0] = '\''; 2241 return charRefOneCharBuf; 2242 } else if(len == 4 && buf[posStart] == 'q' && buf[posStart+1] == 'u' 2243 && buf[posStart+2] == 'o' && buf[posStart+3] == 't') 2244 { 2245 if(tokenize) { 2246 text = "\""; 2247 } 2248 charRefOneCharBuf[0] = '"'; 2249 return charRefOneCharBuf; 2250 } else { 2251 char[] result = lookuEntityReplacement(len); 2252 if(result != null) { 2253 return result; 2254 } 2255 } 2256 if(tokenize) text = null; 2257 return null; 2258 } 2259 } 2260 2261 protected char[] lookuEntityReplacement(int entitNameLen) 2262 throws XmlPullParserException, IOException 2263 2264 { 2265 if(!allStringsInterned) { 2266 int hash = fastHash(buf, posStart, posEnd - posStart); 2267 LOOP: 2268 for (int i = entityEnd - 1; i >= 0; --i) 2269 { 2270 if(hash == entityNameHash[ i ] && entitNameLen == entityNameBuf[ i ].length) { 2271 char[] entityBuf = entityNameBuf[ i ]; 2272 for (int j = 0; j < entitNameLen; j++) 2273 { 2274 if(buf[posStart + j] != entityBuf[j]) continue LOOP; 2275 } 2276 if(tokenize) text = entityReplacement[ i ]; 2277 return entityReplacementBuf[ i ]; 2278 } 2279 } 2280 } else { 2281 entityRefName = newString(buf, posStart, posEnd - posStart); 2282 for (int i = entityEnd - 1; i >= 0; --i) 2283 { 2284 if(entityRefName == entityName[ i ]) { 2286 if(tokenize) text = entityReplacement[ i ]; 2287 return entityReplacementBuf[ i ]; 2288 } 2289 } 2290 } 2291 return null; 2292 } 2293 2294 2295 protected void parseComment() 2296 throws XmlPullParserException, IOException 2297 { 2298 2300 char ch = more(); 2302 if(ch != '-') throw new XmlPullParserException( 2303 "expected <!-- for comment start", this, null); 2304 if(tokenize) posStart = pos; 2305 2306 int curLine = lineNumber; 2307 int curColumn = columnNumber; 2308 try { 2309 boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false; 2310 boolean normalizedCR = false; 2311 2312 boolean seenDash = false; 2313 boolean seenDashDash = false; 2314 while(true) { 2315 ch = more(); 2317 if(seenDashDash && ch != '>') { 2318 throw new XmlPullParserException( 2319 "in comment after two dashes (--) next character must be >" 2320 +" not "+printable(ch), this, null); 2321 } 2322 if(ch == '-') { 2323 if(!seenDash) { 2324 seenDash = true; 2325 } else { 2326 seenDashDash = true; 2327 seenDash = false; 2328 } 2329 } else if(ch == '>') { 2330 if(seenDashDash) { 2331 break; } else { 2333 seenDashDash = false; 2334 } 2335 seenDash = false; 2336 } else { 2337 seenDash = false; 2338 if(normalizeIgnorableWS) { 2339 if(ch == '\r') { 2340 normalizedCR = true; 2341 if(!usePC) { 2345 posEnd = pos -1; 2346 if(posEnd > posStart) { 2347 joinPC(); 2348 } else { 2349 usePC = true; 2350 pcStart = pcEnd = 0; 2351 } 2352 } 2353 if(pcEnd >= pc.length) ensurePC(pcEnd); 2355 pc[pcEnd++] = '\n'; 2356 } else if(ch == '\n') { 2357 if(!normalizedCR && usePC) { 2358 if(pcEnd >= pc.length) ensurePC(pcEnd); 2359 pc[pcEnd++] = '\n'; 2360 } 2361 normalizedCR = false; 2362 } else { 2363 if(usePC) { 2364 if(pcEnd >= pc.length) ensurePC(pcEnd); 2365 pc[pcEnd++] = ch; 2366 } 2367 normalizedCR = false; 2368 } 2369 } 2370 } 2371 } 2372 } catch(EOFException ex) { 2373 throw new XmlPullParserException( 2375 "comment started on line "+curLine+" and column "+curColumn+" was not closed", 2376 this, ex); 2377 } 2378 if(tokenize) posEnd = pos - 3; 2379 } 2380 2381 protected boolean parsePI() 2382 throws XmlPullParserException, IOException 2383 { 2384 2386 2388 if(tokenize) posStart = pos; 2390 int curLine = lineNumber; 2391 int curColumn = columnNumber; 2392 int piTargetStart = pos + bufAbsoluteStart; 2393 int piTargetEnd = -1; 2394 boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false; 2395 boolean normalizedCR = false; 2396 2397 try { 2398 boolean seenQ = false; 2399 char ch; 2400 while(true) { 2401 ch = more(); 2403 if(ch == '?') { 2404 seenQ = true; 2405 } else if(ch == '>') { 2406 if(seenQ) { 2407 break; } 2409 seenQ = false; 2410 } else { 2411 if(piTargetEnd == -1 && isS(ch)) { 2412 piTargetEnd = pos - 1 + bufAbsoluteStart; 2413 2414 if((piTargetEnd - piTargetStart) == 3) { 2416 if((buf[piTargetStart] == 'x' || buf[piTargetStart] == 'X') 2417 && (buf[piTargetStart+1] == 'm' || buf[piTargetStart+1] == 'M') 2418 && (buf[piTargetStart+2] == 'l' || buf[piTargetStart+2] == 'L') 2419 ) 2420 { 2421 if(piTargetStart > 3) { throw new XmlPullParserException( 2423 "processing instruction can not have PITarget with reserveld xml name", 2424 this, null); 2425 } else { 2426 if(buf[piTargetStart] != 'x' 2427 && buf[piTargetStart+1] != 'm' 2428 && buf[piTargetStart+2] != 'l') 2429 { 2430 throw new XmlPullParserException( 2431 "XMLDecl must have xml name in lowercase", 2432 this, null); 2433 } 2434 } 2435 parseXmlDecl(ch); 2436 if(tokenize) posEnd = pos - 2; 2437 int off = piTargetStart - bufAbsoluteStart + 3; 2438 int len = pos - 2 - off; 2439 xmlDeclContent = newString(buf, off, len); 2440 return false; 2441 } 2442 } 2443 } 2444 seenQ = false; 2445 if(normalizeIgnorableWS) { 2446 if(ch == '\r') { 2447 normalizedCR = true; 2448 if(!usePC) { 2452 posEnd = pos -1; 2453 if(posEnd > posStart) { 2454 joinPC(); 2455 } else { 2456 usePC = true; 2457 pcStart = pcEnd = 0; 2458 } 2459 } 2460 if(pcEnd >= pc.length) ensurePC(pcEnd); 2462 pc[pcEnd++] = '\n'; 2463 } else if(ch == '\n') { 2464 if(!normalizedCR && usePC) { 2465 if(pcEnd >= pc.length) ensurePC(pcEnd); 2466 pc[pcEnd++] = '\n'; 2467 } 2468 normalizedCR = false; 2469 } else { 2470 if(usePC) { 2471 if(pcEnd >= pc.length) ensurePC(pcEnd); 2472 pc[pcEnd++] = ch; 2473 } 2474 normalizedCR = false; 2475 } 2476 } 2477 } 2478 } 2479 } catch(EOFException ex) { 2480 throw new XmlPullParserException( 2482 "processing instruction started on line "+curLine+" and column "+curColumn 2483 +" was not closed", 2484 this, ex); 2485 } 2486 if(piTargetEnd == -1) { 2487 throw new XmlPullParserException( 2488 "processing instruction must have PITarget name", this, null); 2489 } 2490 piTargetStart -= bufAbsoluteStart; 2491 piTargetEnd -= bufAbsoluteStart; 2492 if(tokenize) posEnd = pos - 2; 2493 return true; 2494 } 2495 2496 protected final static char[] VERSION = {'v','e','r','s','i','o','n'}; 2497 protected final static char[] NCODING = {'n','c','o','d','i','n','g'}; 2498 protected final static char[] TANDALONE = {'t','a','n','d','a','l','o','n','e'}; 2499 protected final static char[] YES = {'y','e','s'}; 2500 protected final static char[] NO = {'n','o'}; 2501 2502 protected char requireInput(char ch, char[] input) 2503 throws XmlPullParserException, IOException 2504 { 2505 for (int i = 0; i < input.length; i++) 2506 { 2507 if(ch != input[i]) { 2508 throw new XmlPullParserException( 2509 "expected "+printable(input[i])+" in "+new String (input) 2510 +" and not "+printable(ch), this, null); 2511 } 2512 ch = more(); 2513 } 2514 return ch; 2515 } 2516 2517 2518 protected char requireNextS() 2519 throws XmlPullParserException, IOException 2520 { 2521 char ch = more(); 2522 if(!isS(ch)) { 2523 throw new XmlPullParserException( 2524 "white space is required and not "+printable(ch), this, null); 2525 } 2526 return skipS(ch); 2527 } 2528 2529 protected char skipS(char ch) 2530 throws XmlPullParserException, IOException 2531 { 2532 while(isS(ch)) { ch = more(); } return ch; 2534 } 2535 2536 protected void parseXmlDecl(char ch) 2537 throws XmlPullParserException, IOException 2538 { 2539 2541 preventBufferCompaction = true; 2543 bufStart = 0; 2545 2547 ch = skipS(ch); 2550 ch = requireInput(ch, VERSION); 2551 ch = skipS(ch); 2553 if(ch != '=') { 2554 throw new XmlPullParserException( 2555 "expected equals sign (=) after version and not "+printable(ch), this, null); 2556 } 2557 ch = more(); 2558 ch = skipS(ch); 2559 if(ch != '\'' && ch != '"') { 2560 throw new XmlPullParserException( 2561 "expected apostrophe (') or quotation mark (\") after version and not " 2562 +printable(ch), this, null); 2563 } 2564 char quotChar = ch; 2565 int versionStart = pos; 2567 ch = more(); 2568 while(ch != quotChar) { 2570 if((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z') && (ch < '0' || ch > '9') 2571 && ch != '_' && ch != '.' && ch != ':' && ch != '-') 2572 { 2573 throw new XmlPullParserException( 2574 "<?xml version value expected to be in ([a-zA-Z0-9_.:] | '-')" 2575 +" not "+printable(ch), this, null); 2576 } 2577 ch = more(); 2578 } 2579 int versionEnd = pos - 1; 2580 parseXmlDeclWithVersion(versionStart, versionEnd); 2581 preventBufferCompaction = false; } 2583 2585 protected void parseXmlDeclWithVersion(int versionStart, int versionEnd) 2586 throws XmlPullParserException, IOException 2587 { 2588 if((versionEnd - versionStart != 3) 2590 || buf[versionStart] != '1' 2591 || buf[versionStart+1] != '.' 2592 || buf[versionStart+2] != '0') 2593 { 2594 throw new XmlPullParserException( 2595 "only 1.0 is supported as <?xml version not '" 2596 +printable(new String (buf, versionStart, versionEnd - versionStart))+"'", this, null); 2597 } 2598 xmlDeclVersion = newString(buf, versionStart, versionEnd - versionStart); 2599 2600 char ch = more(); 2602 ch = skipS(ch); 2603 if(ch == 'e') { 2604 ch = more(); 2605 ch = requireInput(ch, NCODING); 2606 ch = skipS(ch); 2607 if(ch != '=') { 2608 throw new XmlPullParserException( 2609 "expected equals sign (=) after encoding and not "+printable(ch), this, null); 2610 } 2611 ch = more(); 2612 ch = skipS(ch); 2613 if(ch != '\'' && ch != '"') { 2614 throw new XmlPullParserException( 2615 "expected apostrophe (') or quotation mark (\") after encoding and not " 2616 +printable(ch), this, null); 2617 } 2618 char quotChar = ch; 2619 int encodingStart = pos; 2620 ch = more(); 2621 if((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z')) 2623 { 2624 throw new XmlPullParserException( 2625 "<?xml encoding name expected to start with [A-Za-z]" 2626 +" not "+printable(ch), this, null); 2627 } 2628 ch = more(); 2629 while(ch != quotChar) { 2630 if((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z') && (ch < '0' || ch > '9') 2631 && ch != '.' && ch != '_' && ch != '-') 2632 { 2633 throw new XmlPullParserException( 2634 "<?xml encoding value expected to be in ([A-Za-z0-9._] | '-')" 2635 +" not "+printable(ch), this, null); 2636 } 2637 ch = more(); 2638 } 2639 int encodingEnd = pos - 1; 2640 2641 2642 inputEncoding = newString(buf, encodingStart, encodingEnd - encodingStart); 2644 ch = more(); 2645 } 2646 2647 ch = skipS(ch); 2648 if(ch == 's') { 2650 ch = more(); 2651 ch = requireInput(ch, TANDALONE); 2652 ch = skipS(ch); 2653 if(ch != '=') { 2654 throw new XmlPullParserException( 2655 "expected equals sign (=) after standalone and not "+printable(ch), 2656 this, null); 2657 } 2658 ch = more(); 2659 ch = skipS(ch); 2660 if(ch != '\'' && ch != '"') { 2661 throw new XmlPullParserException( 2662 "expected apostrophe (') or quotation mark (\") after encoding and not " 2663 +printable(ch), this, null); 2664 } 2665 char quotChar = ch; 2666 int standaloneStart = pos; 2667 ch = more(); 2668 if(ch == 'y') { 2669 ch = requireInput(ch, YES); 2670 xmlDeclStandalone = new Boolean (true); 2672 } else if(ch == 'n') { 2673 ch = requireInput(ch, NO); 2674 xmlDeclStandalone = new Boolean (false); 2676 } else { 2677 throw new XmlPullParserException( 2678 "expected 'yes' or 'no' after standalone and not " 2679 +printable(ch), this, null); 2680 } 2681 if(ch != quotChar) { 2682 throw new XmlPullParserException( 2683 "expected "+quotChar+" after standalone value not " 2684 +printable(ch), this, null); 2685 } 2686 ch = more(); 2687 } 2688 2689 2690 ch = skipS(ch); 2691 if(ch != '?') { 2692 throw new XmlPullParserException( 2693 "expected ?> as last part of <?xml not " 2694 +printable(ch), this, null); 2695 } 2696 ch = more(); 2697 if(ch != '>') { 2698 throw new XmlPullParserException( 2699 "expected ?> as last part of <?xml not " 2700 +printable(ch), this, null); 2701 } 2702 2703 } 2704 protected void parseDocdecl() 2705 throws XmlPullParserException, IOException 2706 { 2707 char ch = more(); 2709 if(ch != 'O') throw new XmlPullParserException( 2710 "expected <!DOCTYPE", this, null); 2711 ch = more(); 2712 if(ch != 'C') throw new XmlPullParserException( 2713 "expected <!DOCTYPE", this, null); 2714 ch = more(); 2715 if(ch != 'T') throw new XmlPullParserException( 2716 "expected <!DOCTYPE", this, null); 2717 ch = more(); 2718 if(ch != 'Y') throw new XmlPullParserException( 2719 "expected <!DOCTYPE", this, null); 2720 ch = more(); 2721 if(ch != 'P') throw new XmlPullParserException( 2722 "expected <!DOCTYPE", this, null); 2723 ch = more(); 2724 if(ch != 'E') throw new XmlPullParserException( 2725 "expected <!DOCTYPE", this, null); 2726 posStart = pos; 2727 2729 int bracketLevel = 0; 2732 boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false; 2733 boolean normalizedCR = false; 2734 while(true) { 2735 ch = more(); 2736 if(ch == '[') ++bracketLevel; 2737 if(ch == ']') --bracketLevel; 2738 if(ch == '>' && bracketLevel == 0) break; 2739 if(normalizeIgnorableWS) { 2740 if(ch == '\r') { 2741 normalizedCR = true; 2742 if(!usePC) { 2746 posEnd = pos -1; 2747 if(posEnd > posStart) { 2748 joinPC(); 2749 } else { 2750 usePC = true; 2751 pcStart = pcEnd = 0; 2752 } 2753 } 2754 if(pcEnd >= pc.length) ensurePC(pcEnd); 2756 pc[pcEnd++] = '\n'; 2757 } else if(ch == '\n') { 2758 if(!normalizedCR && usePC) { 2759 if(pcEnd >= pc.length) ensurePC(pcEnd); 2760 pc[pcEnd++] = '\n'; 2761 } 2762 normalizedCR = false; 2763 } else { 2764 if(usePC) { 2765 if(pcEnd >= pc.length) ensurePC(pcEnd); 2766 pc[pcEnd++] = ch; 2767 } 2768 normalizedCR = false; 2769 } 2770 } 2771 2772 } 2773 posEnd = pos - 1; 2774 } 2775 2776 protected void parseCDSect(boolean hadCharData) 2777 throws XmlPullParserException, IOException 2778 { 2779 2781 2786 char ch = more(); 2788 if(ch != 'C') throw new XmlPullParserException( 2789 "expected <[CDATA[ for comment start", this, null); 2790 ch = more(); 2791 if(ch != 'D') throw new XmlPullParserException( 2792 "expected <[CDATA[ for comment start", this, null); 2793 ch = more(); 2794 if(ch != 'A') throw new XmlPullParserException( 2795 "expected <[CDATA[ for comment start", this, null); 2796 ch = more(); 2797 if(ch != 'T') throw new XmlPullParserException( 2798 "expected <[CDATA[ for comment start", this, null); 2799 ch = more(); 2800 if(ch != 'A') throw new XmlPullParserException( 2801 "expected <[CDATA[ for comment start", this, null); 2802 ch = more(); 2803 if(ch != '[') throw new XmlPullParserException( 2804 "expected <[CDATA[ for comment start", this, null); 2805 2806 int cdStart = pos + bufAbsoluteStart; 2808 int curLine = lineNumber; 2809 int curColumn = columnNumber; 2810 boolean normalizeInput = tokenize == false || roundtripSupported == false; 2811 try { 2812 boolean seenBracket = false; 2813 boolean seenBracketBracket = false; 2814 boolean normalizedCR = false; 2815 if(normalizeInput) { 2816 if(hadCharData) { 2817 if(!usePC) { 2818 if(posEnd > posStart) { 2820 joinPC(); 2821 } else { 2822 usePC = true; 2823 pcStart = pcEnd = 0; 2824 } 2825 } 2826 } 2827 } 2828 while(true) { 2829 ch = more(); 2831 if(ch == ']') { 2832 if(!seenBracket) { 2833 seenBracket = true; 2834 } else { 2835 seenBracketBracket = true; 2836 } 2838 } else if(ch == '>') { 2839 if(seenBracketBracket) { 2840 break; } else { 2842 seenBracketBracket = false; 2843 } 2844 seenBracket = false; 2845 } else { 2846 seenBracket = false; 2847 } 2848 if(normalizeInput) { 2849 if(ch == '\r') { 2851 normalizedCR = true; 2852 posStart = cdStart - bufAbsoluteStart; 2854 posEnd = pos; 2855 if(!usePC) { 2856 if(posEnd > posStart) { 2857 joinPC(); 2858 } else { 2859 usePC = true; 2860 pcStart = pcEnd = 0; 2861 } 2862 } 2863 if(pcEnd >= pc.length) ensurePC(pcEnd); 2865 pc[pcEnd++] = '\n'; 2866 } else if(ch == '\n') { 2867 if(!normalizedCR && usePC) { 2868 if(pcEnd >= pc.length) ensurePC(pcEnd); 2869 pc[pcEnd++] = '\n'; 2870 } 2871 normalizedCR = false; 2872 } else { 2873 if(usePC) { 2874 if(pcEnd >= pc.length) ensurePC(pcEnd); 2875 pc[pcEnd++] = ch; 2876 } 2877 normalizedCR = false; 2878 } 2879 } 2880 } 2881 } catch(EOFException ex) { 2882 throw new XmlPullParserException( 2884 "CDATA section started on line "+curLine+" and column "+curColumn+" was not closed", 2885 this, ex); 2886 } 2887 if(normalizeInput) { 2888 if(usePC) { 2889 pcEnd = pcEnd - 2; 2890 } 2891 } 2892 posStart = cdStart - bufAbsoluteStart; 2893 posEnd = pos - 3; 2894 } 2895 2896 protected void fillBuf() throws IOException , XmlPullParserException { 2897 if(reader == null) throw new XmlPullParserException( 2898 "reader must be set before parsing is started"); 2899 2900 if(bufEnd > bufSoftLimit) { 2902 2903 boolean compact = bufStart > bufSoftLimit; 2905 boolean expand = false; 2906 if(preventBufferCompaction) { 2907 compact = false; 2908 expand = true; 2909 } else if(!compact) { 2910 if(bufStart < buf.length / 2) { 2912 expand = true; 2914 } else { 2915 compact = true; 2917 } 2918 } 2919 2920 if(compact) { 2922 System.arraycopy(buf, bufStart, buf, 0, bufEnd - bufStart); 2925 if(TRACE_SIZING) System.out.println( 2926 "TRACE_SIZING fillBuf() compacting "+bufStart 2927 +" bufEnd="+bufEnd 2928 +" pos="+pos+" posStart="+posStart+" posEnd="+posEnd 2929 +" buf first 100 chars:"+new String (buf, bufStart, 2930 bufEnd - bufStart < 100 ? bufEnd - bufStart : 100 )); 2931 2932 } else if(expand) { 2933 int newSize = 2 * buf.length; 2934 char newBuf[] = new char[ newSize ]; 2935 if(TRACE_SIZING) System.out.println("TRACE_SIZING fillBuf() "+buf.length+" => "+newSize); 2936 System.arraycopy(buf, bufStart, newBuf, 0, bufEnd - bufStart); 2937 buf = newBuf; 2938 if(bufLoadFactor > 0) { 2939 bufSoftLimit = ( bufLoadFactor * buf.length ) /100; 2940 } 2941 2942 } else { 2943 throw new XmlPullParserException("internal error in fillBuffer()"); 2944 } 2945 bufEnd -= bufStart; 2946 pos -= bufStart; 2947 posStart -= bufStart; 2948 posEnd -= bufStart; 2949 bufAbsoluteStart += bufStart; 2950 bufStart = 0; 2951 if(TRACE_SIZING) System.out.println( 2952 "TRACE_SIZING fillBuf() after bufEnd="+bufEnd 2953 +" pos="+pos+" posStart="+posStart+" posEnd="+posEnd 2954 +" buf first 100 chars:"+new String (buf, 0, bufEnd < 100 ? bufEnd : 100)); 2955 } 2956 int len = buf.length - bufEnd > READ_CHUNK_SIZE ? READ_CHUNK_SIZE : buf.length - bufEnd; 2958 int ret = reader.read(buf, bufEnd, len); 2959 if(ret > 0) { 2960 bufEnd += ret; 2961 if(TRACE_SIZING) System.out.println( 2962 "TRACE_SIZING fillBuf() after filling in buffer" 2963 +" buf first 100 chars:"+new String (buf, 0, bufEnd < 100 ? bufEnd : 100)); 2964 2965 return; 2966 } 2967 if(ret == -1) { 2968 throw new EOFException ("no more data available"); 2969 } else { 2970 throw new IOException ("error reading input, returned "+ret); 2971 } 2972 } 2973 2974 protected char more() throws IOException , XmlPullParserException { 2975 if(pos >= bufEnd) fillBuf(); 2976 char ch = buf[pos++]; 2977 if(ch == '\n') { ++lineNumber; columnNumber = 1; } 2979 else { ++columnNumber; } 2980 return ch; 2982 } 2983 2984 protected String printable(char ch) { 2986 if(ch == '\n') { 2987 return "\\n"; 2988 } else if(ch == '\r') { 2989 return "\\r"; 2990 } else if(ch == '\t') { 2991 return "\\t"; 2992 } else if(ch == '\'') { 2993 return "\\'"; 2994 } if(ch > 127 || ch < 32) { 2995 return "\\u"+Integer.toHexString((int)ch); 2996 } 2997 return ""+ch; 2998 } 2999 3000 protected String printable(String s) { 3001 if(s == null) return null; 3002 StringBuffer buf = new StringBuffer (); 3003 for(int i = 0; i < s.length(); ++i) { 3004 buf.append(printable(s.charAt(i))); 3005 } 3006 s = buf.toString(); 3007 return s; 3008 } 3009 3010 protected void ensurePC(int end) { 3011 int newSize = end > READ_CHUNK_SIZE ? 2 * end : 2 * READ_CHUNK_SIZE; 3013 char[] newPC = new char[ newSize ]; 3014 if(TRACE_SIZING) System.out.println("TRACE_SIZING ensurePC() "+pc.length+" ==> "+newSize+" end="+end); 3015 System.arraycopy(pc, 0, newPC, 0, pcEnd); 3016 pc = newPC; 3017 } 3019 3020 protected void joinPC() { 3021 int len = posEnd - posStart; 3024 int newEnd = pcEnd + len + 1; 3025 if(newEnd >= pc.length) ensurePC(newEnd); System.arraycopy(buf, posStart, pc, pcEnd, len); 3028 pcEnd += len; 3029 usePC = true; 3030 3031 } 3032 3033} 3034 3035 3036 3085 3086 3087 3088 | Popular Tags |