All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sforce.ws.parser.MXParser Maven / Gradle / Ivy

There is a newer version: 62.0.0
Show newest version
/*
 * Copyright (c) 2013, salesforce.com, inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided
 * that the following conditions are met:
 *
 *    Redistributions of source code must retain the above copyright notice, this list of conditions and the
 *    following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
 *    the following disclaimer in the documentation and/or other materials provided with the distribution.
 *
 *    Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
 *    promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */


/*
 * Copyright (c) 2003 Extreme! Lab, Indiana University. All rights reserved.
 *
 * This software is open source. See the bottom of this file for the license.
 *
 * $Id: MXParser.java,v 1.48 2005/08/11 22:39:54 aslom Exp $
 */

package com.sforce.ws.parser;

import java.io.EOFException;
import java.io.IOException;
import java.io.Reader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

//import java.util.Hashtable;

//TODO best handling of interning issues
//   have isAllNewStringInterned ???

//TODO handling surrogate pairs: http://www.unicode.org/unicode/faq/utf_bom.html#6

//TODO review code for use of bufAbsoluteStart when keeping pos between next()/fillBuf()

/**
 * Absolutely minimal implementation of XMLPULL V1 API
 *
 * @author Aleksander Slominski
 */

public class MXParser
    implements XmlPullParser {
  //NOTE: no interning of those strings --> by Java lang spec they MUST be already interned
  protected final static String XML_URI = "http://www.w3.org/XML/1998/namespace";
  protected final static String XMLNS_URI = "http://www.w3.org/2000/xmlns/";
  protected final static String FEATURE_XML_ROUNDTRIP =
      //"http://xmlpull.org/v1/doc/features.html#xml-roundtrip";
      "http://xmlpull.org/v1/doc/features.html#xml-roundtrip";
  protected final static String FEATURE_NAMES_INTERNED =
      "http://xmlpull.org/v1/doc/features.html#names-interned";
  protected final static String PROPERTY_XMLDECL_VERSION =
      "http://xmlpull.org/v1/doc/properties.html#xmldecl-version";
  protected final static String PROPERTY_XMLDECL_STANDALONE =
      "http://xmlpull.org/v1/doc/properties.html#xmldecl-standalone";
  protected final static String PROPERTY_XMLDECL_CONTENT =
      "http://xmlpull.org/v1/doc/properties.html#xmldecl-content";
  protected final static String PROPERTY_LOCATION =
      "http://xmlpull.org/v1/doc/properties.html#location";

  /**
   * Implementation notice:
   * the is instance variable that controls if newString() is interning.
   * 

NOTE: newStringIntern always returns interned strings * and newString MAY return interned String depending on this variable. *

NOTE: by default in this minimal implementation it is false! */ protected boolean allStringsInterned; protected void resetStringCache() { //System.out.println("resetStringCache() minimum called"); } protected String newString(char[] cbuf, int off, int len) { return new String(cbuf, off, len); } protected String newStringIntern(char[] cbuf, int off, int len) { return (new String(cbuf, off, len)).intern(); } private static final boolean TRACE_SIZING = false; // NOTE: features are not resetable and typicaly defaults to false ... protected boolean processNamespaces; protected boolean roundtripSupported; // global parser state protected String location; protected int lineNumber; protected int columnNumber; protected boolean seenRoot; protected boolean reachedEnd; protected int eventType; protected boolean emptyElementTag; // element stack protected int depth; protected char[] elRawName[]; protected int elRawNameEnd[]; protected int elRawNameLine[]; protected String elName[]; protected String elPrefix[]; protected String elUri[]; //protected String elValue[]; protected int elNamespaceCount[]; /** * Make sure that we have enough space to keep element stack if passed size. * It will always create one additional slot then current depth */ protected void ensureElementsCapacity() { final int elStackSize = elName != null ? elName.length : 0; if ((depth + 1) >= elStackSize) { // we add at least one extra slot ... final int newSize = (depth >= 7 ? 2 * depth : 8) + 2; // = lucky 7 + 1 //25 if (TRACE_SIZING) { System.err.println("TRACE_SIZING elStackSize " + elStackSize + " ==> " + newSize); } final boolean needsCopying = elStackSize > 0; String[] arr = null; // resue arr local variable slot arr = new String[newSize]; if (needsCopying) System.arraycopy(elName, 0, arr, 0, elStackSize); elName = arr; arr = new String[newSize]; if (needsCopying) System.arraycopy(elPrefix, 0, arr, 0, elStackSize); elPrefix = arr; arr = new String[newSize]; if (needsCopying) System.arraycopy(elUri, 0, arr, 0, elStackSize); elUri = arr; int[] iarr = new int[newSize]; if (needsCopying) { System.arraycopy(elNamespaceCount, 0, iarr, 0, elStackSize); } else { // special initialization iarr[0] = 0; } elNamespaceCount = iarr; //TODO: avoid using element raw name ... iarr = new int[newSize]; if (needsCopying) { System.arraycopy(elRawNameEnd, 0, iarr, 0, elStackSize); } elRawNameEnd = iarr; iarr = new int[newSize]; if (needsCopying) { System.arraycopy(elRawNameLine, 0, iarr, 0, elStackSize); } elRawNameLine = iarr; final char[][] carr = new char[newSize][]; if (needsCopying) { System.arraycopy(elRawName, 0, carr, 0, elStackSize); } elRawName = carr; // arr = new String[newSize]; // if(needsCopying) System.arraycopy(elLocalName, 0, arr, 0, elStackSize); // elLocalName = arr; // arr = new String[newSize]; // if(needsCopying) System.arraycopy(elDefaultNs, 0, arr, 0, elStackSize); // elDefaultNs = arr; // int[] iarr = new int[newSize]; // if(needsCopying) System.arraycopy(elNsStackPos, 0, iarr, 0, elStackSize); // for (int i = elStackSize; i < iarr.length; i++) // { // iarr[i] = (i > 0) ? -1 : 0; // } // elNsStackPos = iarr; //assert depth < elName.length; } } // attribute stack protected int attributeCount; protected String attributeName[]; protected int attributeNameHash[]; //protected int attributeNameStart[]; //protected int attributeNameEnd[]; protected String attributePrefix[]; protected String attributeUri[]; protected String attributeValue[]; //protected int attributeValueStart[]; //protected int attributeValueEnd[]; /** * Make sure that in attributes temporary array is enough space. */ protected void ensureAttributesCapacity(int size) { final int attrPosSize = attributeName != null ? attributeName.length : 0; if (size >= attrPosSize) { final int newSize = size > 7 ? 2 * size : 8; // = lucky 7 + 1 //25 if (TRACE_SIZING) { System.err.println("TRACE_SIZING attrPosSize " + attrPosSize + " ==> " + newSize); } final boolean needsCopying = attrPosSize > 0; String[] arr = null; arr = new String[newSize]; if (needsCopying) System.arraycopy(attributeName, 0, arr, 0, attrPosSize); attributeName = arr; arr = new String[newSize]; if (needsCopying) System.arraycopy(attributePrefix, 0, arr, 0, attrPosSize); attributePrefix = arr; arr = new String[newSize]; if (needsCopying) System.arraycopy(attributeUri, 0, arr, 0, attrPosSize); attributeUri = arr; arr = new String[newSize]; if (needsCopying) System.arraycopy(attributeValue, 0, arr, 0, attrPosSize); attributeValue = arr; if (! allStringsInterned) { final int[] iarr = new int[newSize]; if (needsCopying) System.arraycopy(attributeNameHash, 0, iarr, 0, attrPosSize); attributeNameHash = iarr; } arr = null; // //assert attrUri.length > size } } // namespace stack protected int namespaceEnd; protected String namespacePrefix[]; protected int namespacePrefixHash[]; protected String namespaceUri[]; protected void ensureNamespacesCapacity(int size) { final int namespaceSize = namespacePrefix != null ? namespacePrefix.length : 0; if (size >= namespaceSize) { final int newSize = size > 7 ? 2 * size : 8; // = lucky 7 + 1 //25 if (TRACE_SIZING) { System.err.println("TRACE_SIZING namespaceSize " + namespaceSize + " ==> " + newSize); } final String[] newNamespacePrefix = new String[newSize]; final String[] newNamespaceUri = new String[newSize]; if (namespacePrefix != null) { System.arraycopy( namespacePrefix, 0, newNamespacePrefix, 0, namespaceEnd); System.arraycopy( namespaceUri, 0, newNamespaceUri, 0, namespaceEnd); } namespacePrefix = newNamespacePrefix; namespaceUri = newNamespaceUri; if (! allStringsInterned) { final int[] newNamespacePrefixHash = new int[newSize]; if (namespacePrefixHash != null) { System.arraycopy( namespacePrefixHash, 0, newNamespacePrefixHash, 0, namespaceEnd); } namespacePrefixHash = newNamespacePrefixHash; } //prefixesSize = newSize; // //assert nsPrefixes.length > size && nsPrefixes.length == newSize } } /** * simplistic implementation of hash function that has constant * time to compute - so it also means diminishing hash quality for long strings * but for XML parsing it should be good enough ... */ protected static int fastHash(char ch[], int off, int len) { if (len == 0) return 0; //assert len >0 int hash = ch[off]; // hash at beginnig //try { hash = (hash << 7) + ch[off + len - 1]; // hash at the end //} catch(ArrayIndexOutOfBoundsException aie) { // aie.printStackTrace(); //should never happen ... // throw new RuntimeException("this is violation of pre-condition"); //} if (len > 16) hash = (hash << 7) + ch[off + (len / 4)]; // 1/4 from beginning if (len > 8) hash = (hash << 7) + ch[off + (len / 2)]; // 1/2 of string size ... // notice that hash is at most done 3 times <<7 so shifted by 21 bits 8 bit value // so max result == 29 bits so it is quite just below 31 bits for long (2^32) ... //assert hash >= 0; return hash; } // entity replacement stack protected int entityEnd; protected String entityName[]; protected char[] entityNameBuf[]; protected String entityReplacement[]; protected char[] entityReplacementBuf[]; protected int entityNameHash[]; protected void ensureEntityCapacity() { final int entitySize = entityReplacementBuf != null ? entityReplacementBuf.length : 0; if (entityEnd >= entitySize) { final int newSize = entityEnd > 7 ? 2 * entityEnd : 8; // = lucky 7 + 1 //25 if (TRACE_SIZING) { System.err.println("TRACE_SIZING entitySize " + entitySize + " ==> " + newSize); } final String[] newEntityName = new String[newSize]; final char[] newEntityNameBuf[] = new char[newSize][]; final String[] newEntityReplacement = new String[newSize]; final char[] newEntityReplacementBuf[] = new char[newSize][]; if (entityName != null) { System.arraycopy(entityName, 0, newEntityName, 0, entityEnd); System.arraycopy(entityNameBuf, 0, newEntityNameBuf, 0, entityEnd); System.arraycopy(entityReplacement, 0, newEntityReplacement, 0, entityEnd); System.arraycopy(entityReplacementBuf, 0, newEntityReplacementBuf, 0, entityEnd); } entityName = newEntityName; entityNameBuf = newEntityNameBuf; entityReplacement = newEntityReplacement; entityReplacementBuf = newEntityReplacementBuf; if (! allStringsInterned) { final int[] newEntityNameHash = new int[newSize]; if (entityNameHash != null) { System.arraycopy(entityNameHash, 0, newEntityNameHash, 0, entityEnd); } entityNameHash = newEntityNameHash; } } } // input buffer management protected static final int READ_CHUNK_SIZE = 8 * 1024; //max data chars in one read() call protected Reader reader; protected String inputEncoding; protected int bufLoadFactor = 95; // 99% //protected int bufHardLimit; // only matters when expanding protected char buf[] = new char[ Runtime.getRuntime().freeMemory() > 1000000L ? READ_CHUNK_SIZE : 256 ]; protected int bufSoftLimit = (bufLoadFactor * buf.length) / 100; // desirable size of buffer protected boolean preventBufferCompaction; protected int bufAbsoluteStart; // this is buf protected int bufStart; protected int bufEnd; protected int pos; protected int posStart; protected int posEnd; protected char pc[] = new char[ Runtime.getRuntime().freeMemory() > 1000000L ? READ_CHUNK_SIZE : 64 ]; protected int pcStart; protected int pcEnd; // parsing state //protected boolean needsMore; //protected boolean seenMarkup; protected boolean usePC; protected boolean seenStartTag; protected boolean seenEndTag; protected boolean pastEndTag; protected boolean seenAmpersand; protected boolean seenMarkup; protected boolean seenDocdecl; // transient variable set during each call to next/Token() protected boolean tokenize; protected String text; protected String entityRefName; protected String xmlDeclVersion; protected Boolean xmlDeclStandalone; protected String xmlDeclContent; protected void reset() { //System.out.println("reset() called"); location = null; lineNumber = 1; columnNumber = 0; seenRoot = false; reachedEnd = false; eventType = START_DOCUMENT; emptyElementTag = false; depth = 0; attributeCount = 0; namespaceEnd = 0; entityEnd = 0; reader = null; inputEncoding = null; preventBufferCompaction = false; bufAbsoluteStart = 0; bufEnd = bufStart = 0; pos = posStart = posEnd = 0; pcEnd = pcStart = 0; usePC = false; seenStartTag = false; seenEndTag = false; pastEndTag = false; seenAmpersand = false; seenMarkup = false; seenDocdecl = false; xmlDeclVersion = null; xmlDeclStandalone = null; xmlDeclContent = null; resetStringCache(); } public MXParser() { } /** * Method setFeature * * @param name a String * @param state a boolean * @throws XmlPullParserException */ @Override public void setFeature(String name, boolean state) throws XmlPullParserException { if (name == null) throw new IllegalArgumentException("feature name should not be null"); if (FEATURE_PROCESS_NAMESPACES.equals(name)) { if (eventType != START_DOCUMENT) throw new XmlPullParserException( "namespace processing feature can only be changed before parsing", this, null); processNamespaces = state; // } else if(FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) { // if(type != START_DOCUMENT) throw new XmlPullParserException( // "namespace reporting feature can only be changed before parsing", this, null); // reportNsAttribs = state; } else if (FEATURE_NAMES_INTERNED.equals(name)) { if (state) { throw new XmlPullParserException( "interning names in this implementation is not supported"); } } else if (FEATURE_PROCESS_DOCDECL.equals(name)) { if (state) { throw new XmlPullParserException( "processing DOCDECL is not supported"); } //} else if(REPORT_DOCDECL.equals(name)) { // paramNotifyDoctype = state; } else if (FEATURE_XML_ROUNDTRIP.equals(name)) { //if(state == false) { // throw new XmlPullParserException( // "roundtrip feature can not be switched off"); //} roundtripSupported = state; } else { throw new XmlPullParserException("unsupporte feature " + name); } } /** * Unknown properties are always returned as false */ @Override public boolean getFeature(String name) { if (name == null) throw new IllegalArgumentException("feature name should not be nulll"); if (FEATURE_PROCESS_NAMESPACES.equals(name)) { return processNamespaces; // } else if(FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) { // return reportNsAttribs; } else if (FEATURE_NAMES_INTERNED.equals(name)) { return false; } else if (FEATURE_PROCESS_DOCDECL.equals(name)) { return false; //} else if(REPORT_DOCDECL.equals(name)) { // return paramNotifyDoctype; } else if (FEATURE_XML_ROUNDTRIP.equals(name)) { //return true; return roundtripSupported; } return false; } @Override public void setProperty(String name, Object value) throws XmlPullParserException { if (PROPERTY_LOCATION.equals(name)) { location = (String) value; } else { throw new XmlPullParserException("unsupported property: '" + name + "'"); } } @Override public Object getProperty(String name) { if (name == null) throw new IllegalArgumentException("property name should not be nulll"); if (PROPERTY_XMLDECL_VERSION.equals(name)) { return xmlDeclVersion; } else if (PROPERTY_XMLDECL_STANDALONE.equals(name)) { return xmlDeclStandalone; } else if (PROPERTY_XMLDECL_CONTENT.equals(name)) { return xmlDeclContent; } else if (PROPERTY_LOCATION.equals(name)) { return location; } return null; } @Override public void setInput(Reader in) throws XmlPullParserException { reset(); reader = in; } @Override public void setInput(java.io.InputStream inputStream, String inputEncoding) throws XmlPullParserException { if (inputStream == null) { throw new IllegalArgumentException("input stream can not be null"); } Reader reader; if (inputEncoding != null) { try { //if (inputEncoding != null) { reader = new InputStreamReader(inputStream, inputEncoding); //} else { //reader = new InputStreamReader(inputStream); //} } catch (UnsupportedEncodingException une) { throw new XmlPullParserException( "could not create reader for encoding " + inputEncoding + " : " + une, this, une); } } else { reader = new InputStreamReader(inputStream); } setInput(reader); //must be here as reest() was called in setInput() and has set this.inputEncoding to null ... this.inputEncoding = inputEncoding; } @Override public String getInputEncoding() { return inputEncoding; } @Override public void defineEntityReplacementText(String entityName, String replacementText) throws XmlPullParserException { // throw new XmlPullParserException("not allowed"); //protected char[] entityReplacement[]; ensureEntityCapacity(); // this is to make sure that if interning works we wil take advatage of it ... this.entityName[entityEnd] = newString(entityName.toCharArray(), 0, entityName.length()); entityNameBuf[entityEnd] = entityName.toCharArray(); entityReplacement[entityEnd] = replacementText; entityReplacementBuf[entityEnd] = replacementText.toCharArray(); if (!allStringsInterned) { entityNameHash[entityEnd] = fastHash(entityNameBuf[entityEnd], 0, entityNameBuf[entityEnd].length); } ++entityEnd; //TODO disallow < or & in entity replacement text (or ]]>???) // TOOD keepEntityNormalizedForAttributeValue cached as well ... } @Override public int getNamespaceCount(int depth) throws XmlPullParserException { if (!processNamespaces || depth == 0) { return 0; } //int maxDepth = eventType == END_TAG ? this.depth + 1 : this.depth; //if(depth < 0 || depth > maxDepth) throw new IllegalArgumentException( if (depth < 0 || depth > this.depth) throw new IllegalArgumentException( "allowed namespace depth 0.." + this.depth + " not " + depth); return elNamespaceCount[depth]; } @Override public String getNamespacePrefix(int pos) throws XmlPullParserException { //int end = eventType == END_TAG ? elNamespaceCount[ depth + 1 ] : namespaceEnd; //if(pos < end) { if (pos < namespaceEnd) { return namespacePrefix[pos]; } else { throw new XmlPullParserException( "position " + pos + " exceeded number of available namespaces " + namespaceEnd); } } @Override public String getNamespaceUri(int pos) throws XmlPullParserException { //int end = eventType == END_TAG ? elNamespaceCount[ depth + 1 ] : namespaceEnd; //if(pos < end) { if (pos < namespaceEnd) { return namespaceUri[pos]; } else { throw new XmlPullParserException( "position " + pos + " exceeded number of available namespaces " + namespaceEnd); } } @Override public String getNamespace(String prefix) //throws XmlPullParserException { //int count = namespaceCount[ depth ]; if (prefix != null) { for (int i = namespaceEnd - 1; i >= 0; i--) { if (prefix.equals(namespacePrefix[i])) { return namespaceUri[i]; } } if ("xml".equals(prefix)) { return XML_URI; } else if ("xmlns".equals(prefix)) { return XMLNS_URI; } } else { for (int i = namespaceEnd - 1; i >= 0; i--) { if (namespacePrefix[i] == null) { //"") { //null ) { //TODO check FIXME Alek return namespaceUri[i]; } } } return null; } @Override public int getDepth() { return depth; } private static int findFragment(int bufMinPos, char[] b, int start, int end) { //System.err.println("bufStart="+bufStart+" b="+printable(new String(b, start, end - start))+" start="+start+" end="+end); if (start < bufMinPos) { start = bufMinPos; if (start > end) start = end; return start; } if (end - start > 65) { start = end - 10; // try to find good location } int i = start + 1; while (--i > bufMinPos) { if ((end - i) > 65) break; final char c = b[i]; if (c == '<' && (start - i) > 10) break; } return i; } /** * Return string describing current position of parsers as * text 'STATE [seen %s...] @line:column'. */ @Override public String getPositionDescription() { String fragment = null; if (posStart <= pos) { final int start = findFragment(0, buf, posStart, pos); //System.err.println("start="+start); if (start < pos) { fragment = new String(buf, start, pos - start); } if (bufAbsoluteStart > 0 || start > 0) fragment = "..." + fragment; } // return " at line "+tokenizerPosRow // +" and column "+(tokenizerPosCol-1) // +(fragment != null ? " seen "+printable(fragment)+"..." : ""); return " " + TYPES[eventType] + (fragment != null ? " seen " + printable(fragment) + "..." : "") + " " + (location != null ? location : "") + "@" + getLineNumber() + ":" + getColumnNumber(); } @Override public int getLineNumber() { return lineNumber; } @Override public int getColumnNumber() { return columnNumber; } @Override public boolean isWhitespace() throws XmlPullParserException { if (eventType == TEXT || eventType == CDSECT) { if (usePC) { for (int i = pcStart; i < pcEnd; i++) { if (!isS(pc[i])) return false; } return true; } else { for (int i = posStart; i < posEnd; i++) { if (!isS(buf[i])) return false; } return true; } } else if (eventType == IGNORABLE_WHITESPACE) { return true; } throw new XmlPullParserException("no content available to check for whitespaces"); } @Override public String getText() { if (eventType == START_DOCUMENT || eventType == END_DOCUMENT) { //throw new XmlPullParserException("no content available to read"); // if(roundtripSupported) { // text = new String(buf, posStart, posEnd - posStart); // } else { return null; // } } else if (eventType == ENTITY_REF) { return text; } if (text == null) { if (!usePC || eventType == START_TAG || eventType == END_TAG) { text = new String(buf, posStart, posEnd - posStart); } else { text = new String(pc, pcStart, pcEnd - pcStart); } } return text; } @Override public char[] getTextCharacters(int [] holderForStartAndLength) { if (eventType == TEXT) { if (usePC) { holderForStartAndLength[0] = pcStart; holderForStartAndLength[1] = pcEnd - pcStart; return pc; } else { holderForStartAndLength[0] = posStart; holderForStartAndLength[1] = posEnd - posStart; return buf; } } else if (eventType == START_TAG || eventType == END_TAG || eventType == CDSECT || eventType == COMMENT || eventType == ENTITY_REF || eventType == PROCESSING_INSTRUCTION || eventType == IGNORABLE_WHITESPACE || eventType == DOCDECL) { holderForStartAndLength[0] = posStart; holderForStartAndLength[1] = posEnd - posStart; return buf; } else if (eventType == START_DOCUMENT || eventType == END_DOCUMENT) { //throw new XmlPullParserException("no content available to read"); holderForStartAndLength[0] = holderForStartAndLength[1] = -1; return null; } else { throw new IllegalArgumentException("unknown text eventType: " + eventType); } // String s = getText(); // char[] cb = null; // if(s!= null) { // cb = s.toCharArray(); // holderForStartAndLength[0] = 0; // holderForStartAndLength[1] = s.length(); // } else { // } // return cb; } @Override public String getNamespace() { if (eventType == START_TAG) { //return processNamespaces ? elUri[ depth - 1 ] : NO_NAMESPACE; return processNamespaces ? elUri[depth] : NO_NAMESPACE; } else if (eventType == END_TAG) { return processNamespaces ? elUri[depth] : NO_NAMESPACE; } return null; // String prefix = elPrefix[ maxDepth ]; // if(prefix != null) { // for( int i = namespaceEnd -1; i >= 0; i--) { // if( prefix.equals( namespacePrefix[ i ] ) ) { // return namespaceUri[ i ]; // } // } // } else { // for( int i = namespaceEnd -1; i >= 0; i--) { // if( namespacePrefix[ i ] == null ) { // return namespaceUri[ i ]; // } // } // // } // return ""; } @Override public String getName() { if (eventType == START_TAG) { //return elName[ depth - 1 ] ; return elName[depth]; } else if (eventType == END_TAG) { return elName[depth]; } else if (eventType == ENTITY_REF) { if (entityRefName == null) { entityRefName = newString(buf, posStart, posEnd - posStart); } return entityRefName; } else { return null; } } @Override public String getPrefix() { if (eventType == START_TAG) { //return elPrefix[ depth - 1 ] ; return elPrefix[depth]; } else if (eventType == END_TAG) { return elPrefix[depth]; } return null; // if(eventType != START_TAG && eventType != END_TAG) return null; // int maxDepth = eventType == END_TAG ? depth : depth - 1; // return elPrefix[ maxDepth ]; } @Override public boolean isEmptyElementTag() throws XmlPullParserException { if (eventType != START_TAG) throw new XmlPullParserException( "parser must be on START_TAG to check for empty element", this, null); return emptyElementTag; } @Override public int getAttributeCount() { if (eventType != START_TAG) return -1; return attributeCount; } @Override public String getAttributeNamespace(int index) { if (eventType != START_TAG) throw new IndexOutOfBoundsException( "only START_TAG can have attributes"); if (!processNamespaces) return NO_NAMESPACE; if (index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException( "attribute position must be 0.." + (attributeCount - 1) + " and not " + index); return attributeUri[index]; } @Override public String getAttributeName(int index) { if (eventType != START_TAG) throw new IndexOutOfBoundsException( "only START_TAG can have attributes"); if (index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException( "attribute position must be 0.." + (attributeCount - 1) + " and not " + index); return attributeName[index]; } @Override public String getAttributePrefix(int index) { if (eventType != START_TAG) throw new IndexOutOfBoundsException( "only START_TAG can have attributes"); if (!processNamespaces) return null; if (index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException( "attribute position must be 0.." + (attributeCount - 1) + " and not " + index); return attributePrefix[index]; } @Override public String getAttributeType(int index) { if (eventType != START_TAG) throw new IndexOutOfBoundsException( "only START_TAG can have attributes"); if (index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException( "attribute position must be 0.." + (attributeCount - 1) + " and not " + index); return "CDATA"; } @Override public boolean isAttributeDefault(int index) { if (eventType != START_TAG) throw new IndexOutOfBoundsException( "only START_TAG can have attributes"); if (index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException( "attribute position must be 0.." + (attributeCount - 1) + " and not " + index); return false; } @Override public String getAttributeValue(int index) { if (eventType != START_TAG) throw new IndexOutOfBoundsException( "only START_TAG can have attributes"); if (index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException( "attribute position must be 0.." + (attributeCount - 1) + " and not " + index); return attributeValue[index]; } @Override public String getAttributeValue(String namespace, String name) { if (eventType != START_TAG) throw new IndexOutOfBoundsException( "only START_TAG can have attributes" + getPositionDescription()); if (name == null) { throw new IllegalArgumentException("attribute name can not be null"); } // TODO make check if namespace is interned!!! etc. for names!!! if (processNamespaces) { if (namespace == null) { namespace = ""; } for (int i = 0; i < attributeCount; ++i) { if ((namespace == attributeUri[i] || namespace.equals(attributeUri[i])) //(namespace != null && namespace.equals(attributeUri[ i ])) // taking advantage of String.intern() && name.equals(attributeName[i])) { return attributeValue[i]; } } } else { if (namespace != null && namespace.length() == 0) { namespace = null; } if (namespace != null) throw new IllegalArgumentException( "when namespaces processing is disabled attribute namespace must be null"); for (int i = 0; i < attributeCount; ++i) { if (name.equals(attributeName[i])) { return attributeValue[i]; } } } return null; } @Override public int getEventType() throws XmlPullParserException { return eventType; } @Override public void require(int type, String namespace, String name) throws XmlPullParserException, IOException { if (!processNamespaces && namespace != null) { throw new XmlPullParserException( "processing namespaces must be enabled on parser (or factory)" + " to have possible namespaces declared on elements" + (" (postion:" + getPositionDescription()) + ")"); } if (type != getEventType() || (namespace != null && !namespace.equals(getNamespace())) || (name != null && !name.equals(getName()))) { throw new XmlPullParserException( "expected event " + TYPES[type] + (name != null ? " with name '" + name + "'" : "") + (namespace != null && name != null ? " and" : "") + (namespace != null ? " with namespace '" + namespace + "'" : "") + " but got" + (type != getEventType() ? " " + TYPES[getEventType()] : "") + (name != null && getName() != null && !name.equals(getName()) ? " name '" + getName() + "'" : "") + (namespace != null && name != null && getName() != null && !name.equals(getName()) && getNamespace() != null && !namespace.equals(getNamespace()) ? " and" : "") + (namespace != null && getNamespace() != null && !namespace.equals(getNamespace()) ? " namespace '" + getNamespace() + "'" : "") + (" (postion:" + getPositionDescription()) + ")"); } } /** * Skip sub tree that is currently porser positioned on. *
NOTE: parser must be on START_TAG and when funtion returns * parser will be positioned on corresponding END_TAG */ public void skipSubTree() throws XmlPullParserException, IOException { require(START_TAG, null, null); int level = 1; while (level > 0) { int eventType = next(); if (eventType == END_TAG) { --level; } else if (eventType == START_TAG) { ++level; } } } // public String readText() throws XmlPullParserException, IOException // { // if (getEventType() != TEXT) return ""; // String result = getText(); // next(); // return result; // } @Override public String nextText() throws XmlPullParserException, IOException { // String result = null; // boolean onStartTag = false; // if(eventType == START_TAG) { // onStartTag = true; // next(); // } // if(eventType == TEXT) { // result = getText(); // next(); // } else if(onStartTag && eventType == END_TAG) { // result = ""; // } else { // throw new XmlPullParserException( // "parser must be on START_TAG or TEXT to read text", this, null); // } // if(eventType != END_TAG) { // throw new XmlPullParserException( // "event TEXT it must be immediately followed by END_TAG", this, null); // } // return result; if (getEventType() != START_TAG) { throw new XmlPullParserException( "parser must be on START_TAG to read next text", this, null); } int eventType = next(); if (eventType == TEXT) { final String result = getText(); eventType = next(); if (eventType != END_TAG) { throw new XmlPullParserException( "TEXT must be immediately followed by END_TAG and not " + TYPES[getEventType()], this, null); } return result; } else if (eventType == END_TAG) { return ""; } else { throw new XmlPullParserException( "parser must be on START_TAG or TEXT to read text", this, null); } } @Override public int nextTag() throws XmlPullParserException, IOException { next(); if (eventType == TEXT && isWhitespace()) { // skip whitespace next(); } if (eventType != START_TAG && eventType != END_TAG) { throw new XmlPullParserException("expected START_TAG or END_TAG not " + TYPES[getEventType()], this, null); } return eventType; } @Override public int next() throws XmlPullParserException, IOException { tokenize = false; return nextImpl(); } @Override public int nextToken() throws XmlPullParserException, IOException { tokenize = true; return nextImpl(); } protected int nextImpl() throws XmlPullParserException, IOException { text = null; pcEnd = pcStart = 0; usePC = false; bufStart = posEnd; if (pastEndTag) { pastEndTag = false; --depth; namespaceEnd = elNamespaceCount[depth]; // less namespaces available } if (emptyElementTag) { emptyElementTag = false; pastEndTag = true; return eventType = END_TAG; } // [1] document ::= prolog element Misc* if (depth > 0) { if (seenStartTag) { seenStartTag = false; return eventType = parseStartTag(); } if (seenEndTag) { seenEndTag = false; return eventType = parseEndTag(); } // ASSUMPTION: we are _on_ first character of content or markup!!!! // [43] content ::= CharData? ((element | Reference | CDSect | PI | Comment) CharData?)* char ch; if (seenMarkup) { // we have read ahead ... seenMarkup = false; ch = '<'; } else if (seenAmpersand) { seenAmpersand = false; ch = '&'; } else { ch = more(); } posStart = pos - 1; // VERY IMPORTANT: this is correct start of event!!! // when true there is some potential event TEXT to return - keep gathering boolean hadCharData = false; // when true TEXT data is not continual (like ) and requires PC merging boolean needsMerging = false; MAIN_LOOP: while (true) { // work on MARKUP if (ch == '<') { if (hadCharData) { //posEnd = pos - 1; if (tokenize) { seenMarkup = true; return eventType = TEXT; } } ch = more(); if (ch == '/') { if (!tokenize && hadCharData) { seenEndTag = true; //posEnd = pos - 2; return eventType = TEXT; } return eventType = parseEndTag(); } else if (ch == '!') { ch = more(); if (ch == '-') { // note: if(tokenize == false) posStart/End is NOT changed!!!! parseComment(); if (tokenize) return eventType = COMMENT; if (!usePC && hadCharData) { needsMerging = true; } else { posStart = pos; //completely ignore comment } } else if (ch == '[') { //posEnd = pos - 3; // must remeber previous posStart/End as it merges with content of CDATA //int oldStart = posStart + bufAbsoluteStart; //int oldEnd = posEnd + bufAbsoluteStart; parseCDSect(hadCharData); if (tokenize) return eventType = CDSECT; final int cdStart = posStart; final int cdEnd = posEnd; final int cdLen = cdEnd - cdStart; if (cdLen > 0) { // was there anything inside CDATA section? hadCharData = true; if (!usePC) { needsMerging = true; } } // posStart = oldStart; // posEnd = oldEnd; // if(cdLen > 0) { // was there anything inside CDATA section? // if(hadCharData) { // // do merging if there was anything in CDSect!!!! // // if(!usePC) { // // // posEnd is correct already!!! // // if(posEnd > posStart) { // // joinPC(); // // } else { // // usePC = true; // // pcStart = pcEnd = 0; // // } // // } // // if(pcEnd + cdLen >= pc.length) ensurePC(pcEnd + cdLen); // // // copy [cdStart..cdEnd) into PC // // System.arraycopy(buf, cdStart, pc, pcEnd, cdLen); // // pcEnd += cdLen; // if(!usePC) { // needsMerging = true; // posStart = cdStart; // posEnd = cdEnd; // } // } else { // if(!usePC) { // needsMerging = true; // posStart = cdStart; // posEnd = cdEnd; // hadCharData = true; // } // } // //hadCharData = true; // } else { // if( !usePC && hadCharData ) { // needsMerging = true; // } // } } else { throw new XmlPullParserException( "unexpected character in markup " + printable(ch), this, null); } } else if (ch == '?') { parsePI(); if (tokenize) return eventType = PROCESSING_INSTRUCTION; if (!usePC && hadCharData) { needsMerging = true; } else { posStart = pos; //completely ignore PI } } else if (isNameStartChar(ch)) { if (!tokenize && hadCharData) { seenStartTag = true; //posEnd = pos - 2; return eventType = TEXT; } return eventType = parseStartTag(); } else { throw new XmlPullParserException( "unexpected character in markup " + printable(ch), this, null); } // do content compaction if it makes sense!!!! } else if (ch == '&') { // work on ENTITTY //posEnd = pos - 1; if (tokenize && hadCharData) { seenAmpersand = true; return eventType = TEXT; } final int oldStart = posStart + bufAbsoluteStart; final int oldEnd = posEnd + bufAbsoluteStart; final char[] resolvedEntity = parseEntityRef(); if (tokenize) return eventType = ENTITY_REF; // check if replacement text can be resolved !!! if (resolvedEntity == null) { if (entityRefName == null) { entityRefName = newString(buf, posStart, posEnd - posStart); } throw new XmlPullParserException( "could not resolve entity named '" + printable(entityRefName) + "'", this, null); } //int entStart = posStart; //int entEnd = posEnd; posStart = oldStart - bufAbsoluteStart; posEnd = oldEnd - bufAbsoluteStart; if (!usePC) { if (hadCharData) { joinPC(); // posEnd is already set correctly!!! needsMerging = false; } else { usePC = true; pcStart = pcEnd = 0; } } //assert usePC == true; // write into PC replacement text - do merge for replacement text!!!! for (int i = 0; i < resolvedEntity.length; i++) { if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = resolvedEntity[i]; } hadCharData = true; //assert needsMerging == false; } else { if (needsMerging) { //assert usePC == false; joinPC(); // posEnd is already set correctly!!! //posStart = pos - 1; needsMerging = false; } //no MARKUP not ENTITIES so work on character data ... // [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) hadCharData = true; boolean normalizedCR = false; final boolean normalizeInput = !tokenize || !roundtripSupported; // use loop locality here!!!! boolean seenBracket = false; boolean seenBracketBracket = false; do { // check that ]]> does not show in if (ch == ']') { if (seenBracket) { seenBracketBracket = true; } else { seenBracket = true; } } else if (seenBracketBracket && ch == '>') { throw new XmlPullParserException( "characters ]]> are not allowed in content", this, null); } else { if (seenBracket) { seenBracketBracket = seenBracket = false; } // assert seenTwoBrackets == seenBracket == false; } if (normalizeInput) { // deal with normalization issues ... if (ch == '\r') { normalizedCR = true; posEnd = pos - 1; // posEnd is already is set if (!usePC) { if (posEnd > posStart) { joinPC(); } else { usePC = true; pcStart = pcEnd = 0; } } //assert usePC == true; if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } else if (ch == '\n') { // if(!usePC) { joinPC(); } else { if(pcEnd >= pc.length) ensurePC(); } if (!normalizedCR && usePC) { if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } normalizedCR = false; } else { if (usePC) { if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = ch; } normalizedCR = false; } } ch = more(); } while (ch != '<' && ch != '&'); posEnd = pos - 1; continue MAIN_LOOP; // skip ch = more() from below - we are alreayd ahead ... } ch = more(); } // endless while(true) } else { if (seenRoot) { return parseEpilog(); } else { return parseProlog(); } } } protected int parseProlog() throws XmlPullParserException, IOException { // [2] prolog: ::= XMLDecl? Misc* (doctypedecl Misc*)? and look for [39] element char ch; if (seenMarkup) { ch = buf[pos - 1]; } else { ch = more(); } if (eventType == START_DOCUMENT) { // bootstrap parsing with getting first character input! // deal with BOM // detect BOM and frop it (Unicode int Order Mark) if (ch == '\uFFFE') { throw new XmlPullParserException( "first character in input was UNICODE noncharacter (0xFFFE)" + "- input requires int swapping", this, null); } if (ch == '\uFEFF') { // skipping UNICODE int Order Mark (so called BOM) ch = more(); } } seenMarkup = false; boolean gotS = false; posStart = pos - 1; final boolean normalizeIgnorableWS = tokenize && !roundtripSupported; boolean normalizedCR = false; while (true) { // deal with Misc // [27] Misc ::= Comment | PI | S // deal with docdecl --> mark it! // else parseStartTag seen <[^/] if (ch == '<') { if (gotS && tokenize) { posEnd = pos - 1; seenMarkup = true; return eventType = IGNORABLE_WHITESPACE; } ch = more(); if (ch == '?') { // check if it is 'xml' // deal with XMLDecl if (parsePI()) { // make sure to skip XMLDecl if (tokenize) { return eventType = PROCESSING_INSTRUCTION; } } else { // skip over - continue tokenizing posStart = pos; gotS = false; } } else if (ch == '!') { ch = more(); if (ch == 'D') { if (seenDocdecl) { throw new XmlPullParserException( "only one docdecl allowed in XML document", this, null); } seenDocdecl = true; parseDocdecl(); if (tokenize) return eventType = DOCDECL; } else if (ch == '-') { parseComment(); if (tokenize) return eventType = COMMENT; } else { throw new XmlPullParserException( "unexpected markup posStart) { joinPC(); } else { usePC = true; pcStart = pcEnd = 0; } } //assert usePC == true; if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } else if (ch == '\n') { if (!normalizedCR && usePC) { if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } normalizedCR = false; } else { if (usePC) { if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = ch; } normalizedCR = false; } } } else { throw new XmlPullParserException( "only whitespace content allowed before start tag and not " + printable(ch), this, null); } ch = more(); } } protected int parseEpilog() throws XmlPullParserException, IOException { if (eventType == END_DOCUMENT) { throw new XmlPullParserException("already reached end of XML input", this, null); } if (reachedEnd) { return eventType = END_DOCUMENT; } boolean gotS = false; final boolean normalizeIgnorableWS = tokenize && !roundtripSupported; boolean normalizedCR = false; try { // epilog: Misc* char ch; if (seenMarkup) { ch = buf[pos - 1]; } else { ch = more(); } seenMarkup = false; posStart = pos - 1; if (!reachedEnd) { while (true) { // deal with Misc // [27] Misc ::= Comment | PI | S if (ch == '<') { if (gotS && tokenize) { posEnd = pos - 1; seenMarkup = true; return eventType = IGNORABLE_WHITESPACE; } ch = more(); if (reachedEnd) { break; } if (ch == '?') { // check if it is 'xml' // deal with XMLDecl parsePI(); if (tokenize) return eventType = PROCESSING_INSTRUCTION; } else if (ch == '!') { ch = more(); if (reachedEnd) { break; } if (ch == 'D') { parseDocdecl(); //FIXME if (tokenize) return eventType = DOCDECL; } else if (ch == '-') { parseComment(); if (tokenize) return eventType = COMMENT; } else { throw new XmlPullParserException( "unexpected markup posStart) { joinPC(); } else { usePC = true; pcStart = pcEnd = 0; } } //assert usePC == true; if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } else if (ch == '\n') { if (!normalizedCR && usePC) { if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } normalizedCR = false; } else { if (usePC) { if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = ch; } normalizedCR = false; } } } else { throw new XmlPullParserException( "in epilog non whitespace content is not allowed but got " + printable(ch), this, null); } ch = more(); if (reachedEnd) { break; } } } // throw Exceptin("unexpected content in epilog // cach EOFException return END_DOCUEMENT //try { } catch (EOFException ex) { reachedEnd = true; } if (reachedEnd) { if (tokenize && gotS) { posEnd = pos; // well - this is LAST available character pos return eventType = IGNORABLE_WHITESPACE; } return eventType = END_DOCUMENT; } else { throw new XmlPullParserException("internal error in parseEpilog"); } } public int parseEndTag() throws XmlPullParserException, IOException { //ASSUMPTION ch is past "' char ch = more(); if (!isNameStartChar(ch)) { throw new XmlPullParserException( "expected name start and not " + printable(ch), this, null); } posStart = pos - 3; final int nameStart = pos - 1 + bufAbsoluteStart; do { ch = more(); } while (isNameChar(ch)); // now we go one level down -- do checks //--depth; //FIXME // check that end tag name is the same as start tag //String name = new String(buf, nameStart - bufAbsoluteStart, // (pos - 1) - (nameStart - bufAbsoluteStart)); //int last = pos - 1; int off = nameStart - bufAbsoluteStart; //final int len = last - off; final int len = (pos - 1) - off; final char[] cbuf = elRawName[depth]; if (elRawNameEnd[depth] != len) { // construct strings for exception final String startname = new String(cbuf, 0, elRawNameEnd[depth]); final String endname = new String(buf, off, len); throw new XmlPullParserException( "end tag name must match start tag name <" + startname + ">" + " from line " + elRawNameLine[depth], this, null); } for (int i = 0; i < len; i++) { if (buf[off++] != cbuf[i]) { // construct strings for exception final String startname = new String(cbuf, 0, len); final String endname = new String(buf, off - i - 1, len); throw new XmlPullParserException( "end tag name must be the same as start tag <" + startname + ">" + " from line " + elRawNameLine[depth], this, null); } } while (isS(ch)) { ch = more(); } // skip additional white spaces if (ch != '>') { throw new XmlPullParserException( "expected > to finsh end tag not " + printable(ch) + " from line " + elRawNameLine[depth], this, null); } //namespaceEnd = elNamespaceCount[ depth ]; //FIXME posEnd = pos; pastEndTag = true; return eventType = END_TAG; } public int parseStartTag() throws XmlPullParserException, IOException { //ASSUMPTION ch is past ' // [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>' ++depth; //FIXME posStart = pos - 2; emptyElementTag = false; attributeCount = 0; // retrieve name final int nameStart = pos - 1 + bufAbsoluteStart; int colonPos = -1; char ch = buf[pos - 1]; if (ch == ':' && processNamespaces) throw new XmlPullParserException( "when namespaces processing enabled colon can not be at element name start", this, null); while (true) { ch = more(); if (!isNameChar(ch)) break; if (ch == ':' && processNamespaces) { if (colonPos != -1) throw new XmlPullParserException( "only one colon is allowed in name of element when namespaces are enabled", this, null); colonPos = pos - 1 + bufAbsoluteStart; } } // retrieve name ensureElementsCapacity(); //TODO check for efficient interning and then use elRawNameInterned!!!! int elLen = (pos - 1) - (nameStart - bufAbsoluteStart); if (elRawName[depth] == null || elRawName[depth].length < elLen) { elRawName[depth] = new char[ 2 * elLen ]; } System.arraycopy(buf, nameStart - bufAbsoluteStart, elRawName[depth], 0, elLen); elRawNameEnd[depth] = elLen; elRawNameLine[depth] = lineNumber; // work on prefixes and namespace URI String prefix = null; if (processNamespaces) { if (colonPos != -1) { prefix = elPrefix[depth] = newString(buf, nameStart - bufAbsoluteStart, colonPos - nameStart); elName[depth] = newString(buf, colonPos + 1 - bufAbsoluteStart, //(pos -1) - (colonPos + 1)); pos - 2 - (colonPos - bufAbsoluteStart)); } else { prefix = elPrefix[depth] = null; elName[depth] = newString(buf, nameStart - bufAbsoluteStart, elLen); } } else { elName[depth] = newString(buf, nameStart - bufAbsoluteStart, elLen); } while (true) { while (isS(ch)) { ch = more(); } // skip additional white spaces if (ch == '>') { break; } else if (ch == '/') { if (emptyElementTag) throw new XmlPullParserException( "repeated / in tag declaration", this, null); emptyElementTag = true; ch = more(); if (ch != '>') throw new XmlPullParserException( "expected > to end empty tag not " + printable(ch), this, null); break; } else if (isNameStartChar(ch)) { ch = parseAttribute(); ch = more(); continue; } else { throw new XmlPullParserException( "start tag unexpected character " + printable(ch), this, null); } //ch = more(); // skip space } // now when namespaces were declared we can resolve them if (processNamespaces) { String uri = getNamespace(prefix); if (uri == null) { if (prefix == null) { // no prefix and no uri => use default namespace uri = NO_NAMESPACE; } else { throw new XmlPullParserException( "could not determine namespace bound to element prefix " + prefix, this, null); } } elUri[depth] = uri; //String uri = getNamespace(prefix); //if(uri == null && prefix == null) { // no prefix and no uri => use default namespace // uri = ""; //} // resolve attribute namespaces for (int i = 0; i < attributeCount; i++) { final String attrPrefix = attributePrefix[i]; if (attrPrefix != null) { final String attrUri = getNamespace(attrPrefix); if (attrUri == null) { throw new XmlPullParserException( "could not determine namespace bound to attribute prefix " + attrPrefix, this, null); } attributeUri[i] = attrUri; } else { attributeUri[i] = NO_NAMESPACE; } } //TODO //[ WFC: Unique Att Spec ] // check namespaced attribute uniqueness contraint!!! for (int i = 1; i < attributeCount; i++) { for (int j = 0; j < i; j++) { if (attributeUri[j] == attributeUri[i] && (allStringsInterned && attributeName[j].equals(attributeName[i]) || (!allStringsInterned && attributeNameHash[j] == attributeNameHash[i] && attributeName[j].equals(attributeName[i]))) ) { // prepare data for nice error messgae? String attr1 = attributeName[j]; if (attributeUri[j] != null) attr1 = attributeUri[j] + ":" + attr1; String attr2 = attributeName[i]; if (attributeUri[i] != null) attr2 = attributeUri[i] + ":" + attr2; throw new XmlPullParserException( "duplicated attributes " + attr1 + " and " + attr2, this, null); } } } } else { // ! processNamespaces //[ WFC: Unique Att Spec ] // check raw attribute uniqueness contraint!!! for (int i = 1; i < attributeCount; i++) { for (int j = 0; j < i; j++) { if ((allStringsInterned && attributeName[j].equals(attributeName[i]) || (!allStringsInterned && attributeNameHash[j] == attributeNameHash[i] && attributeName[j].equals(attributeName[i]))) ) { // prepare data for nice error message? final String attr1 = attributeName[j]; final String attr2 = attributeName[i]; throw new XmlPullParserException( "duplicated attributes " + attr1 + " and " + attr2, this, null); } } } } elNamespaceCount[depth] = namespaceEnd; posEnd = pos; return eventType = START_TAG; } protected char parseAttribute() throws XmlPullParserException, IOException { // parse attribute // [41] Attribute ::= Name Eq AttValue // [WFC: No External Entity References] // [WFC: No < in Attribute Values] final int prevPosStart = posStart + bufAbsoluteStart; final int nameStart = pos - 1 + bufAbsoluteStart; int colonPos = -1; char ch = buf[pos - 1]; if (ch == ':' && processNamespaces) throw new XmlPullParserException( "when namespaces processing enabled colon can not be at attribute name start", this, null); boolean startsWithXmlns = processNamespaces && ch == 'x'; int xmlnsPos = 0; ch = more(); while (isNameChar(ch)) { if (processNamespaces) { if (startsWithXmlns && xmlnsPos < 5) { ++xmlnsPos; if (xmlnsPos == 1) { if (ch != 'm') startsWithXmlns = false; } else if (xmlnsPos == 2) { if (ch != 'l') startsWithXmlns = false; } else if (xmlnsPos == 3) { if (ch != 'n') startsWithXmlns = false; } else if (xmlnsPos == 4) { if (ch != 's') startsWithXmlns = false; } else if (xmlnsPos == 5) { if (ch != ':') throw new XmlPullParserException( "after xmlns in attribute name must be colon" + "when namespaces are enabled", this, null); //colonPos = pos - 1 + bufAbsoluteStart; } } if (ch == ':') { if (colonPos != -1) throw new XmlPullParserException( "only one colon is allowed in attribute name" + " when namespaces are enabled", this, null); colonPos = pos - 1 + bufAbsoluteStart; } } ch = more(); } ensureAttributesCapacity(attributeCount); // --- start processing attributes String name = null; // work on prefixes and namespace URI if (processNamespaces) { if (xmlnsPos < 4) startsWithXmlns = false; if (startsWithXmlns) { if (colonPos != -1) { //prefix = attributePrefix[ attributeCount ] = null; final int nameLen = pos - 2 - (colonPos - bufAbsoluteStart); if (nameLen == 0) { throw new XmlPullParserException( "namespace prefix is required after xmlns: " + " when namespaces are enabled", this, null); } name = //attributeName[ attributeCount ] = newString(buf, colonPos - bufAbsoluteStart + 1, nameLen); //pos - 1 - (colonPos + 1 - bufAbsoluteStart) } } else { if (colonPos != -1) { int prefixLen = colonPos - nameStart; attributePrefix[attributeCount] = newString(buf, nameStart - bufAbsoluteStart, prefixLen); //colonPos - (nameStart - bufAbsoluteStart)); int nameLen = pos - 2 - (colonPos - bufAbsoluteStart); name = attributeName[attributeCount] = newString(buf, colonPos - bufAbsoluteStart + 1, nameLen); //pos - 1 - (colonPos + 1 - bufAbsoluteStart)); //name.substring(0, colonPos-nameStart); } else { attributePrefix[attributeCount] = null; name = attributeName[attributeCount] = newString(buf, nameStart - bufAbsoluteStart, pos - 1 - (nameStart - bufAbsoluteStart)); } if (!allStringsInterned) { attributeNameHash[attributeCount] = name.hashCode(); } } } else { // retrieve name name = attributeName[attributeCount] = newString(buf, nameStart - bufAbsoluteStart, pos - 1 - (nameStart - bufAbsoluteStart)); ////assert name != null; if (!allStringsInterned) { attributeNameHash[attributeCount] = name.hashCode(); } } // [25] Eq ::= S? '=' S? while (isS(ch)) { ch = more(); } // skip additional spaces if (ch != '=') throw new XmlPullParserException( "expected = after attribute name", this, null); ch = more(); while (isS(ch)) { ch = more(); } // skip additional spaces // [10] AttValue ::= '"' ([^<&"] | Reference)* '"' // | "'" ([^<&'] | Reference)* "'" final char delimit = ch; if (delimit != '"' && delimit != '\'') throw new XmlPullParserException( "attribute value must start with quotation or apostrophe not " + printable(delimit), this, null); // parse until delimit or < and resolve Reference //[67] Reference ::= EntityRef | CharRef //int valueStart = pos + bufAbsoluteStart; boolean normalizedCR = false; usePC = false; pcStart = pcEnd; posStart = pos; while (true) { ch = more(); if (ch == delimit) { break; } if (ch == '<') { throw new XmlPullParserException( "markup not allowed inside attribute value - illegal < ", this, null); } if (ch == '&') { // extractEntityRef posEnd = pos - 1; if (!usePC) { final boolean hadCharData = posEnd > posStart; if (hadCharData) { // posEnd is already set correctly!!! joinPC(); } else { usePC = true; pcStart = pcEnd = 0; } } //assert usePC == true; final char[] resolvedEntity = parseEntityRef(); // check if replacement text can be resolved !!! if (resolvedEntity == null) { if (entityRefName == null) { entityRefName = newString(buf, posStart, posEnd - posStart); } throw new XmlPullParserException( "could not resolve entity named '" + printable(entityRefName) + "'", this, null); } // write into PC replacement text - do merge for replacement text!!!! for (int i = 0; i < resolvedEntity.length; i++) { if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = resolvedEntity[i]; } } else if (ch == '\t' || ch == '\n' || ch == '\r') { // do attribute value normalization // as described in http://www.w3.org/TR/REC-xml#AVNormalize // TODO add test for it form spec ... // handle EOL normalization ... if (!usePC) { posEnd = pos - 1; if (posEnd > posStart) { joinPC(); } else { usePC = true; pcEnd = pcStart = 0; } } //assert usePC == true; if (pcEnd >= pc.length) ensurePC(pcEnd); if (ch != '\n' || !normalizedCR) { pc[pcEnd++] = ' '; //'\n'; } } else { if (usePC) { if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = ch; } } normalizedCR = ch == '\r'; } if (processNamespaces && startsWithXmlns) { String ns = null; if (!usePC) { ns = newStringIntern(buf, posStart, pos - 1 - posStart); } else { ns = newStringIntern(pc, pcStart, pcEnd - pcStart); } ensureNamespacesCapacity(namespaceEnd); int prefixHash = -1; if (colonPos != -1) { if (ns.length() == 0) { throw new XmlPullParserException( "non-default namespace can not be declared to be empty string", this, null); } // declare new namespace namespacePrefix[namespaceEnd] = name; if (!allStringsInterned) { prefixHash = namespacePrefixHash[namespaceEnd] = name.hashCode(); } } else { // declare new default namespace ... namespacePrefix[namespaceEnd] = null; //""; //null; //TODO check FIXME Alek if (!allStringsInterned) { prefixHash = namespacePrefixHash[namespaceEnd] = -1; } } namespaceUri[namespaceEnd] = ns; // detect duplicate namespace declarations!!! final int startNs = elNamespaceCount[depth - 1]; for (int i = namespaceEnd - 1; i >= startNs; --i) { if (((allStringsInterned || name == null) && namespacePrefix[i] == name) || (!allStringsInterned && name != null && namespacePrefixHash[i] == prefixHash && name.equals(namespacePrefix[i]) )) { final String s = name == null ? "default" : "'" + name + "'"; throw new XmlPullParserException( "duplicated namespace declaration for " + s + " prefix", this, null); } } ++namespaceEnd; } else { if (!usePC) { attributeValue[attributeCount] = new String(buf, posStart, pos - 1 - posStart); } else { attributeValue[attributeCount] = new String(pc, pcStart, pcEnd - pcStart); } ++attributeCount; } posStart = prevPosStart - bufAbsoluteStart; return ch; } protected char[] charRefOneCharBuf = new char[1]; protected char[] parseEntityRef() throws XmlPullParserException, IOException { // entity reference http://www.w3.org/TR/2000/REC-xml-20001006#NT-Reference // [67] Reference ::= EntityRef | CharRef // ASSUMPTION just after & entityRefName = null; posStart = pos; char ch = more(); if (ch == '#') { // parse character reference char charRef = 0; ch = more(); if (ch == 'x') { //encoded in hex while (true) { ch = more(); if (ch >= '0' && ch <= '9') { charRef = (char) (charRef * 16 + (ch - '0')); } else if (ch >= 'a' && ch <= 'f') { charRef = (char) (charRef * 16 + (ch - ('a' - 10))); } else if (ch >= 'A' && ch <= 'F') { charRef = (char) (charRef * 16 + (ch - ('A' - 10))); } else if (ch == ';') { break; } else { throw new XmlPullParserException( "character reference (with hex value) may not contain " + printable(ch), this, null); } } } else { // encoded in decimal while (true) { if (ch >= '0' && ch <= '9') { charRef = (char) (charRef * 10 + (ch - '0')); } else if (ch == ';') { break; } else { throw new XmlPullParserException( "character reference (with decimal value) may not contain " + printable(ch), this, null); } ch = more(); } } posEnd = pos - 1; charRefOneCharBuf[0] = charRef; if (tokenize) { text = newString(charRefOneCharBuf, 0, 1); } return charRefOneCharBuf; } else { // [68] EntityRef ::= '&' Name ';' // scan anem until ; if (!isNameStartChar(ch)) { throw new XmlPullParserException( "entity reference names can not start with character '" + printable(ch) + "'", this, null); } while (true) { ch = more(); if (ch == ';') { break; } if (!isNameChar(ch)) { throw new XmlPullParserException( "entity reference name can not contain character " + printable(ch) + "'", this, null); } } posEnd = pos - 1; // determine what name maps to final int len = posEnd - posStart; if (len == 2 && buf[posStart] == 'l' && buf[posStart + 1] == 't') { if (tokenize) { text = "<"; } charRefOneCharBuf[0] = '<'; return charRefOneCharBuf; //if(paramPC || isParserTokenizing) { // if(pcEnd >= pc.length) ensurePC(); // pc[pcEnd++] = '<'; //} } else if (len == 3 && buf[posStart] == 'a' && buf[posStart + 1] == 'm' && buf[posStart + 2] == 'p') { if (tokenize) { text = "&"; } charRefOneCharBuf[0] = '&'; return charRefOneCharBuf; } else if (len == 2 && buf[posStart] == 'g' && buf[posStart + 1] == 't') { if (tokenize) { text = ">"; } charRefOneCharBuf[0] = '>'; return charRefOneCharBuf; } else if (len == 4 && buf[posStart] == 'a' && buf[posStart + 1] == 'p' && buf[posStart + 2] == 'o' && buf[posStart + 3] == 's') { if (tokenize) { text = "'"; } charRefOneCharBuf[0] = '\''; return charRefOneCharBuf; } else if (len == 4 && buf[posStart] == 'q' && buf[posStart + 1] == 'u' && buf[posStart + 2] == 'o' && buf[posStart + 3] == 't') { if (tokenize) { text = "\""; } charRefOneCharBuf[0] = '"'; return charRefOneCharBuf; } else { final char[] result = lookuEntityReplacement(len); if (result != null) { return result; } } if (tokenize) text = null; return null; } } protected char[] lookuEntityReplacement(int entitNameLen) throws XmlPullParserException, IOException { if (!allStringsInterned) { final int hash = fastHash(buf, posStart, posEnd - posStart); LOOP: for (int i = entityEnd - 1; i >= 0; --i) { if (hash == entityNameHash[i] && entitNameLen == entityNameBuf[i].length) { final char[] entityBuf = entityNameBuf[i]; for (int j = 0; j < entitNameLen; j++) { if (buf[posStart + j] != entityBuf[j]) continue LOOP; } if (tokenize) text = entityReplacement[i]; return entityReplacementBuf[i]; } } } else { entityRefName = newString(buf, posStart, posEnd - posStart); for (int i = entityEnd - 1; i >= 0; --i) { // take advantage that interning for newStirng is enforced if (entityRefName == entityName[i]) { if (tokenize) text = entityReplacement[i]; return entityReplacementBuf[i]; } } } return null; } protected void parseComment() throws XmlPullParserException, IOException { // implements XML 1.0 Section 2.5 Comments //ASSUMPTION: seen ch = more(); if (seenDashDash && ch != '>') { throw new XmlPullParserException( "in comment after two dashes (--) next character must be >" + " not " + printable(ch), this, null); } if (ch == '-') { if (!seenDash) { seenDash = true; } else { seenDashDash = true; seenDash = false; } } else if (ch == '>') { if (seenDashDash) { break; // found end sequence!!!! } else { seenDashDash = false; } seenDash = false; } else { seenDash = false; } if (normalizeIgnorableWS) { if (ch == '\r') { normalizedCR = true; //posEnd = pos -1; //joinPC(); // posEnd is alreadys set if (!usePC) { posEnd = pos - 1; if (posEnd > posStart) { joinPC(); } else { usePC = true; pcStart = pcEnd = 0; } } //assert usePC == true; if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } else if (ch == '\n') { if (!normalizedCR && usePC) { if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } normalizedCR = false; } else { if (usePC) { if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = ch; } normalizedCR = false; } } } } catch (EOFException ex) { // detect EOF and create meaningful error ... throw new XmlPullParserException( "comment started on line " + curLine + " and column " + curColumn + " was not closed", this, ex); } if (tokenize) { posEnd = pos - 3; if (usePC) { pcEnd -= 2; } } } protected boolean parsePI() throws XmlPullParserException, IOException { // implements XML 1.0 Section 2.6 Processing Instructions // [16] PI ::= '' Char*)))? '?>' // [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l')) //ASSUMPTION: seen //ch = more(); if (ch == '?') { seenQ = true; } else if (ch == '>') { if (seenQ) { break; // found end sequence!!!! } seenQ = false; } else { if (piTargetEnd == -1 && isS(ch)) { piTargetEnd = pos - 1 + bufAbsoluteStart; // [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l')) if ((piTargetEnd - piTargetStart) == 3) { if ((buf[piTargetStart] == 'x' || buf[piTargetStart] == 'X') && (buf[piTargetStart + 1] == 'm' || buf[piTargetStart + 1] == 'M') && (buf[piTargetStart + 2] == 'l' || buf[piTargetStart + 2] == 'L') ) { if (piTargetStart > 3) { // posStart) { joinPC(); } else { usePC = true; pcStart = pcEnd = 0; } } //assert usePC == true; if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } else if (ch == '\n') { if (!normalizedCR && usePC) { if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } normalizedCR = false; } else { if (usePC) { if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = ch; } normalizedCR = false; } } ch = more(); } } catch (EOFException ex) { // detect EOF and create meaningful error ... throw new XmlPullParserException( "processing instruction started on line " + curLine + " and column " + curColumn + " was not closed", this, ex); } if (piTargetEnd == -1) { piTargetEnd = pos - 2 + bufAbsoluteStart; //throw new XmlPullParserException( // "processing instruction must have PITarget name", this, null); } piTargetStart -= bufAbsoluteStart; piTargetEnd -= bufAbsoluteStart; if (tokenize) { posEnd = pos - 2; if (normalizeIgnorableWS) { --pcEnd; } } return true; } // protected final static char[] VERSION = {'v','e','r','s','i','o','n'}; // protected final static char[] NCODING = {'n','c','o','d','i','n','g'}; // protected final static char[] TANDALONE = {'t','a','n','d','a','l','o','n','e'}; // protected final static char[] YES = {'y','e','s'}; // protected final static char[] NO = {'n','o'}; protected final static char[] VERSION = "version".toCharArray(); protected final static char[] NCODING = "ncoding".toCharArray(); protected final static char[] TANDALONE = "tandalone".toCharArray(); protected final static char[] YES = "yes".toCharArray(); protected final static char[] NO = "no".toCharArray(); protected void parseXmlDecl(char ch) throws XmlPullParserException, IOException { // [23] XMLDecl ::= '' // first make sure that relative positions will stay OK preventBufferCompaction = true; bufStart = 0; // necessary to keep pos unchanged during expansion! // --- parse VersionInfo // [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"') // parse is positioned just on first S past 'z') && (ch < 'A' || ch > 'Z') && (ch < '0' || ch > '9') && ch != '_' && ch != '.' && ch != ':' && ch != '-') { throw new XmlPullParserException( " 'z') && (ch < 'A' || ch > 'Z')) { throw new XmlPullParserException( " 'z') && (ch < 'A' || ch > 'Z') && (ch < '0' || ch > '9') && ch != '.' && ch != '_' && ch != '-') { throw new XmlPullParserException( " as last part of ') { throw new XmlPullParserException( "expected ?> as last part of ' int bracketLevel = 0; final boolean normalizeIgnorableWS = tokenize && !roundtripSupported; boolean normalizedCR = false; while (true) { ch = more(); if (ch == '[') ++bracketLevel; if (ch == ']') --bracketLevel; if (ch == '>' && bracketLevel == 0) break; if (normalizeIgnorableWS) { if (ch == '\r') { normalizedCR = true; //posEnd = pos -1; //joinPC(); // posEnd is alreadys set if (!usePC) { posEnd = pos - 1; if (posEnd > posStart) { joinPC(); } else { usePC = true; pcStart = pcEnd = 0; } } //assert usePC == true; if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } else if (ch == '\n') { if (!normalizedCR && usePC) { if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } normalizedCR = false; } else { if (usePC) { if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = ch; } normalizedCR = false; } } } posEnd = pos - 1; } protected void parseCDSect(boolean hadCharData) throws XmlPullParserException, IOException { // implements XML 1.0 Section 2.7 CDATA Sections // [18] CDSect ::= CDStart CData CDEnd // [19] CDStart ::= '' Char*)) // [21] CDEnd ::= ']]>' //ASSUMPTION: seen posStart) { joinPC(); } else { usePC = true; pcStart = pcEnd = 0; } } } } boolean seenBracket = false; boolean seenBracketBracket = false; boolean normalizedCR = false; while (true) { // scan until it hits "]]>" ch = more(); if (ch == ']') { if (!seenBracket) { seenBracket = true; } else { seenBracketBracket = true; //seenBracket = false; } } else if (ch == '>') { if (seenBracket && seenBracketBracket) { break; // found end sequence!!!! } else { seenBracketBracket = false; } seenBracket = false; } else { if (seenBracket) { seenBracket = false; } } if (normalizeInput) { // deal with normalization issues ... if (ch == '\r') { normalizedCR = true; posStart = cdStart - bufAbsoluteStart; posEnd = pos - 1; // posEnd is alreadys set if (!usePC) { if (posEnd > posStart) { joinPC(); } else { usePC = true; pcStart = pcEnd = 0; } } //assert usePC == true; if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } else if (ch == '\n') { if (!normalizedCR && usePC) { if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } normalizedCR = false; } else { if (usePC) { if (pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = ch; } normalizedCR = false; } } } } catch (EOFException ex) { // detect EOF and create meaningful error ... throw new XmlPullParserException( "CDATA section started on line " + curLine + " and column " + curColumn + " was not closed", this, ex); } if (normalizeInput) { if (usePC) { pcEnd = pcEnd - 2; } } posStart = cdStart - bufAbsoluteStart; posEnd = pos - 3; } protected void fillBuf() throws IOException, XmlPullParserException { if (reader == null) throw new XmlPullParserException( "reader must be set before parsing is started"); // see if we are in compaction area if (bufEnd > bufSoftLimit) { // expand buffer it makes sense!!!! boolean compact = bufStart > bufSoftLimit; boolean expand = false; if (preventBufferCompaction) { compact = false; expand = true; } else if (!compact) { //freeSpace if (bufStart < buf.length / 2) { // less then half buffer available forcompactin --> expand instead!!! expand = true; } else { // at least half of buffer can be reclaimed --> worthwhile effort!!! compact = true; } } // if buffer almost full then compact it if (compact) { //TODO: look on trashing // //assert bufStart > 0 System.arraycopy(buf, bufStart, buf, 0, bufEnd - bufStart); if (TRACE_SIZING) System.out.println( "TRACE_SIZING fillBuf() compacting " + bufStart + " bufEnd=" + bufEnd + " pos=" + pos + " posStart=" + posStart + " posEnd=" + posEnd + " buf first 100 chars:" + new String(buf, bufStart, bufEnd - bufStart < 100 ? bufEnd - bufStart : 100)); } else if (expand) { final int newSize = 2 * buf.length; final char newBuf[] = new char[ newSize ]; if (TRACE_SIZING) System.out.println("TRACE_SIZING fillBuf() " + buf.length + " => " + newSize); System.arraycopy(buf, bufStart, newBuf, 0, bufEnd - bufStart); buf = newBuf; if (bufLoadFactor > 0) { //bufSoftLimit = ( bufLoadFactor * buf.length ) /100; bufSoftLimit = (int) ((((long) bufLoadFactor) * buf.length) / 100); } } else { throw new XmlPullParserException("internal error in fillBuffer()"); } bufEnd -= bufStart; pos -= bufStart; posStart -= bufStart; posEnd -= bufStart; bufAbsoluteStart += bufStart; bufStart = 0; if (TRACE_SIZING) System.out.println( "TRACE_SIZING fillBuf() after bufEnd=" + bufEnd + " pos=" + pos + " posStart=" + posStart + " posEnd=" + posEnd + " buf first 100 chars:" + new String(buf, 0, bufEnd < 100 ? bufEnd : 100)); } // at least one charcter must be read or error final int len = buf.length - bufEnd > READ_CHUNK_SIZE ? READ_CHUNK_SIZE : buf.length - bufEnd; final int ret = reader.read(buf, bufEnd, len); if (ret > 0) { bufEnd += ret; if (TRACE_SIZING) System.out.println( "TRACE_SIZING fillBuf() after filling in buffer" + " buf first 100 chars:" + new String(buf, 0, bufEnd < 100 ? bufEnd : 100)); return; } if (ret == -1) { if (bufAbsoluteStart == 0 && pos == 0) { throw new EOFException("input contained no data"); } else { if (seenRoot && depth == 0) { // inside parsing epilog!!! reachedEnd = true; return; } else { StringBuilder expectedTagStack = new StringBuilder(); if (depth > 0) { //final char[] cbuf = elRawName[depth]; //final String startname = new String(cbuf, 0, elRawNameEnd[depth]); expectedTagStack.append(" - expected end tag"); if (depth > 1) { expectedTagStack.append("s"); //more than one end tag } expectedTagStack.append(" "); for (int i = depth; i > 0; i--) { String tagName = new String(elRawName[i], 0, elRawNameEnd[i]); expectedTagStack.append("'); } expectedTagStack.append(" to close"); for (int i = depth; i > 0; i--) { if (i != depth) { expectedTagStack.append(" and"); //more than one end tag } String tagName = new String(elRawName[i], 0, elRawNameEnd[i]); expectedTagStack.append(" start tag <" + tagName + ">"); expectedTagStack.append(" from line " + elRawNameLine[i]); } expectedTagStack.append(", parser stopped on"); } throw new EOFException("no more data available" + expectedTagStack.toString() + getPositionDescription()); } } } else { throw new IOException("error reading input, returned " + ret); } } protected char more() throws IOException, XmlPullParserException { if (pos >= bufEnd) { fillBuf(); // this return value should be ignonored as it is used in epilog parsing ... if (reachedEnd) return (char) -1; } final char ch = buf[pos++]; //line/columnNumber if (ch == '\n') { ++lineNumber; columnNumber = 1; } else { ++columnNumber; } //System.out.print(ch); return ch; } // /** // * This function returns position of parser in XML input stream // * (how many characters were processed. // *

NOTE: this logical position and not byte offset as encodings // * such as UTF8 may use more than one byte to encode one character. // */ // public int getCurrentInputPosition() { // return pos + bufAbsoluteStart; // } protected void ensurePC(int end) { //assert end >= pc.length; final int newSize = end > READ_CHUNK_SIZE ? 2 * end : 2 * READ_CHUNK_SIZE; final char[] newPC = new char[ newSize ]; if (TRACE_SIZING) System.out.println("TRACE_SIZING ensurePC() " + pc.length + " ==> " + newSize + " end=" + end); System.arraycopy(pc, 0, newPC, 0, pcEnd); pc = newPC; //assert end < pc.length; } protected void joinPC() { //assert usePC == false; //assert posEnd > posStart; final int len = posEnd - posStart; final int newEnd = pcEnd + len + 1; if (newEnd >= pc.length) ensurePC(newEnd); // add 1 for extra space for one char //assert newEnd < pc.length; System.arraycopy(buf, posStart, pc, pcEnd, len); pcEnd += len; usePC = true; } protected char requireInput(char ch, char[] input) throws XmlPullParserException, IOException { for (int i = 0; i < input.length; i++) { if (ch != input[i]) { throw new XmlPullParserException( "expected " + printable(input[i]) + " in " + new String(input) + " and not " + printable(ch), this, null); } ch = more(); } return ch; } protected char requireNextS() throws XmlPullParserException, IOException { final char ch = more(); if (!isS(ch)) { throw new XmlPullParserException( "white space is required and not " + printable(ch), this, null); } return skipS(ch); } protected char skipS(char ch) throws XmlPullParserException, IOException { while (isS(ch)) { ch = more(); } // skip additional spaces return ch; } // nameStart / name lookup tables based on XML 1.1 http://www.w3.org/TR/2001/WD-xml11-20011213/ protected static final int LOOKUP_MAX = 0x400; protected static final char LOOKUP_MAX_CHAR = (char) LOOKUP_MAX; // protected static int lookupNameStartChar[] = new int[ LOOKUP_MAX_CHAR / 32 ]; // protected static int lookupNameChar[] = new int[ LOOKUP_MAX_CHAR / 32 ]; private final static boolean lookupNameStartChar[] = new boolean[ LOOKUP_MAX ]; protected final static boolean lookupNameChar[] = new boolean[ LOOKUP_MAX ]; private static void setName(char ch) //{ lookupNameChar[ (int)ch / 32 ] |= (1 << (ch % 32)); } { lookupNameChar[ch] = true; } private static void setNameStart(char ch) //{ lookupNameStartChar[ (int)ch / 32 ] |= (1 << (ch % 32)); setName(ch); } { lookupNameStartChar[ch] = true; setName(ch); } static { setNameStart(':'); for (char ch = 'A'; ch <= 'Z'; ++ch) setNameStart(ch); setNameStart('_'); for (char ch = 'a'; ch <= 'z'; ++ch) setNameStart(ch); for (char ch = '\u00c0'; ch <= '\u02FF'; ++ch) setNameStart(ch); for (char ch = '\u0370'; ch <= '\u037d'; ++ch) setNameStart(ch); for (char ch = '\u037f'; ch < '\u0400'; ++ch) setNameStart(ch); setName('-'); setName('.'); for (char ch = '0'; ch <= '9'; ++ch) setName(ch); setName('\u00b7'); for (char ch = '\u0300'; ch <= '\u036f'; ++ch) setName(ch); } //private final static boolean isNameStartChar(char ch) { protected boolean isNameStartChar(char ch) { return (ch < LOOKUP_MAX_CHAR && lookupNameStartChar[ch]) || (ch >= LOOKUP_MAX_CHAR && ch <= '\u2027') || (ch >= '\u202A' && ch <= '\u218F') || (ch >= '\u2800' && ch <= '\uFFEF') ; // if(ch < LOOKUP_MAX_CHAR) return lookupNameStartChar[ ch ]; // else return ch <= '\u2027' // || (ch >= '\u202A' && ch <= '\u218F') // || (ch >= '\u2800' && ch <= '\uFFEF') // ; //return false; // return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == ':' // || (ch >= '0' && ch <= '9'); // if(ch < LOOKUP_MAX_CHAR) return (lookupNameStartChar[ (int)ch / 32 ] & (1 << (ch % 32))) != 0; // if(ch <= '\u2027') return true; // //[#x202A-#x218F] // if(ch < '\u202A') return false; // if(ch <= '\u218F') return true; // // added pairts [#x2800-#xD7FF] | [#xE000-#xFDCF] | [#xFDE0-#xFFEF] | [#x10000-#x10FFFF] // if(ch < '\u2800') return false; // if(ch <= '\uFFEF') return true; // return false; // else return (supportXml11 && ( (ch < '\u2027') || (ch > '\u2029' && ch < '\u2200') ... } //private final static boolean isNameChar(char ch) { protected boolean isNameChar(char ch) { //return isNameStartChar(ch); // if(ch < LOOKUP_MAX_CHAR) return (lookupNameChar[ (int)ch / 32 ] & (1 << (ch % 32))) != 0; return (ch < LOOKUP_MAX_CHAR && lookupNameChar[ch]) || (ch >= LOOKUP_MAX_CHAR && ch <= '\u2027') || (ch >= '\u202A' && ch <= '\u218F') || (ch >= '\u2800' && ch <= '\uFFEF') ; //return false; // return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == ':' // || (ch >= '0' && ch <= '9'); // if(ch < LOOKUP_MAX_CHAR) return (lookupNameStartChar[ (int)ch / 32 ] & (1 << (ch % 32))) != 0; //else return // else if(ch <= '\u2027') return true; // //[#x202A-#x218F] // else if(ch < '\u202A') return false; // else if(ch <= '\u218F') return true; // // added pairts [#x2800-#xD7FF] | [#xE000-#xFDCF] | [#xFDE0-#xFFEF] | [#x10000-#x10FFFF] // else if(ch < '\u2800') return false; // else if(ch <= '\uFFEF') return true; //else return false; } protected boolean isS(char ch) { return (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'); // || (supportXml11 && (ch == '\u0085' || ch == '\u2028'); } //protected boolean isChar(char ch) { return (ch < '\uD800' || ch > '\uDFFF') // ch != '\u0000' ch < '\uFFFE' //protected char printable(char ch) { return ch; } protected String printable(char ch) { if (ch == '\n') { return "\\n"; } else if (ch == '\r') { return "\\r"; } else if (ch == '\t') { return "\\t"; } else if (ch == '\'') { return "\\'"; } if (ch > 127 || ch < 32) { return "\\u" + Integer.toHexString(ch); } return "" + ch; } protected String printable(String s) { if (s == null) return null; final int sLen = s.length(); StringBuilder buf = new StringBuilder(sLen + 10); for (int i = 0; i < sLen; ++i) { buf.append(printable(s.charAt(i))); } s = buf.toString(); return s; } } /* * Indiana University Extreme! Lab Software License, Version 1.2 * * Copyright (C) 2003 The Trustees of Indiana University. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1) All redistributions of source code must retain the above * copyright notice, the list of authors in the original source * code, this list of conditions and the disclaimer listed in this * license; * * 2) All redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the disclaimer * listed in this license in the documentation and/or other * materials provided with the distribution; * * 3) Any documentation included with all redistributions must include * the following acknowledgement: * * "This product includes software developed by the Indiana * University Extreme! Lab. For further information please visit * http://www.extreme.indiana.edu/" * * Alternatively, this acknowledgment may appear in the software * itself, and wherever such third-party acknowledgments normally * appear. * * 4) The name "Indiana University" or "Indiana University * Extreme! Lab" shall not be used to endorse or promote * products derived from this software without prior written * permission from Indiana University. For written permission, * please contact http://www.extreme.indiana.edu/. * * 5) Products derived from this software may not use "Indiana * University" name nor may "Indiana University" appear in their name, * without prior written permission of the Indiana University. * * Indiana University provides no reassurances that the source code * provided does not infringe the patent or any other intellectual * property rights of any other entity. Indiana University disclaims any * liability to any recipient for claims brought by any other entity * based on infringement of intellectual property rights or otherwise. * * LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH * NO WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA * UNIVERSITY GIVES NO WARRANTIES AND MAKES NO REPRESENTATION THAT * SOFTWARE IS FREE OF INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR * OTHER PROPRIETARY RIGHTS. INDIANA UNIVERSITY MAKES NO WARRANTIES THAT * SOFTWARE IS FREE FROM "BUGS", "VIRUSES", "TROJAN HORSES", "TRAP * DOORS", "WORMS", OR OTHER HARMFUL CODE. LICENSEE ASSUMES THE ENTIRE * RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR ASSOCIATED MATERIALS, * AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION GENERATED USING * SOFTWARE. */





© 2015 - 2024 Weber Informatics LLC | Privacy Policy