home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 March / Chip_2002-03_cd1.bin / internet / kosek / xml / xt-czech / Encoding.java next >
Text File  |  2000-10-30  |  91KB  |  2,989 lines

  1. package com.jclark.xml.tok;
  2.  
  3. /**
  4.  * An <code>Encoding</code> object corresponds to a possible
  5.  * encoding (a mapping from characters to sequences of bytes).
  6.  * It provides operations on byte arrays
  7.  * that represent all or part of a parsed XML entity in that encoding.
  8.  * <p>
  9.  * The set of ASCII characters excluding <code>$@\^`{}~</code>
  10.  * have a special status; these are called <i>XML significant</i>
  11.  * characters.
  12.  * <p>
  13.  * This class imposes certain restrictions on an encoding:
  14.  * <ul>
  15.  * <li>the encoding must be stateless;
  16.  * <li>a single byte must not encode more than one character;
  17.  * <li>all XML significant characters must be encoded by the same number
  18.  * of bytes, and no character may be encoded by fewer bytes.
  19.  * </ul>
  20.  * <p>
  21.  * Several methods operate on byte subarrays. The subarray is specified
  22.  * by a byte array <code>buf</code> and two integers,
  23.  * <code>off</code> and <code>end</code>; <code>off</code>
  24.  * gives the index in <code>buf</code> of the first byte of the subarray
  25.  * and <code>end</code> gives the
  26.  * index in <code>buf</code> of the byte immediately after the last byte.
  27.  * <p>
  28.  * Use the <code>getInitialEncoding</code> method to get an
  29.  * <code>Encoding</code> object to use to start parsing an entity.
  30.  * <p>
  31.  * The main operations provided by <code>Encoding</code> are
  32.  * <code>tokenizeProlog</code>, <code>tokenizeContent</code> and
  33.  * <code>tokenizeCdataSection</code>;
  34.  * these are used to divide up an XML entity into tokens.
  35.  * <code>tokenizeProlog</code> is used for the prolog of an XML document
  36.  * as well as for the external subset and parameter entities (except
  37.  * when referenced in an <code>EntityValue</code>);
  38.  * it can also be used for parsing the <code>Misc</code>* that follows
  39.  * the document element.
  40.  * <code>tokenizeContent</code> is used for the document element and for
  41.  * parsed general entities that are referenced in <code>content</code>
  42.  * except for CDATA sections.
  43.  * <code>tokenizeCdataSection</code> is used for CDATA sections, following
  44.  * the <code><![CDATA[</code> up to and including the <code>]]></code>.
  45.  * <p>
  46.  * <code>tokenizeAttributeValue</code> and <code>tokenizeEntityValue</code>
  47.  * are used to further divide up tokens returned by <code>tokenizeProlog</code>
  48.  * and <code>tokenizeContent</code>; they are also used to divide up entities
  49.  * referenced in attribute values or entity values.
  50.  * @version $Revision: 1.1 $ $Date: 2000/01/18 13:06:33 $
  51.  */
  52.  
  53. public abstract class Encoding {
  54.   /**
  55.    * Represents one or more characters of data.
  56.    */
  57.   public static final int TOK_DATA_CHARS = 0;
  58.  
  59.   /**
  60.    * Represents a newline (CR, LF or CR followed by LF) in data.
  61.    */
  62.   public static final int TOK_DATA_NEWLINE = TOK_DATA_CHARS + 1;
  63.  
  64.   /**
  65.    * Represents a complete start-tag <code><name></code>,
  66.    * that doesn't have any attribute specifications.
  67.    */
  68.   public static final int TOK_START_TAG_NO_ATTS = TOK_DATA_NEWLINE + 1;
  69.  
  70.   /**
  71.    * Represents a complete start-tag <code><name att="val"></code>,
  72.    * that contains one or more attribute specifications.
  73.    */
  74.   public static final int TOK_START_TAG_WITH_ATTS = TOK_START_TAG_NO_ATTS + 1;
  75.  
  76.   /**
  77.    * Represents an empty element tag <code><name/></code>,
  78.    * that doesn't have any attribute specifications.
  79.    */
  80.   public static final int TOK_EMPTY_ELEMENT_NO_ATTS = TOK_START_TAG_WITH_ATTS + 1;
  81.  
  82.   /**
  83.    * Represents an empty element tag <code><name att="val"/></code>,
  84.    * that contains one or more attribute specifications.
  85.    */
  86.   public static final int TOK_EMPTY_ELEMENT_WITH_ATTS = TOK_EMPTY_ELEMENT_NO_ATTS + 1;
  87.  
  88.   /**
  89.    * Represents a complete end-tag <code></name></code>.
  90.    */
  91.   public static final int TOK_END_TAG = TOK_EMPTY_ELEMENT_WITH_ATTS + 1;
  92.  
  93.   /**
  94.    * Represents the start of a CDATA section <code><![CDATA[</code>.
  95.    */
  96.   public static final int TOK_CDATA_SECT_OPEN = TOK_END_TAG + 1;
  97.  
  98.   /**
  99.    * Represents the end of a CDATA section <code>]]></code>.
  100.    */
  101.   public static final int TOK_CDATA_SECT_CLOSE = TOK_CDATA_SECT_OPEN + 1;
  102.  
  103.   /**
  104.    * Represents a general entity reference.
  105.    */
  106.   public static final int TOK_ENTITY_REF = TOK_CDATA_SECT_CLOSE + 1;
  107.  
  108.   /**
  109.    * Represents a general entity reference to a one of the 5 predefined
  110.    * entities <code>amp</code>, <code>lt</code>, <code>gt</code>,
  111.    * <code>quot</code>, <code>apos</code>.
  112.    */
  113.   public static final int TOK_MAGIC_ENTITY_REF = TOK_ENTITY_REF + 1;
  114.  
  115.   /**
  116.    * Represents a numeric character reference (decimal or hexadecimal),
  117.    * when the referenced character is less than or equal to 0xFFFF
  118.    * and so is represented by a single char.
  119.    */
  120.   public static final int TOK_CHAR_REF = TOK_MAGIC_ENTITY_REF + 1;
  121.  
  122.   /**
  123.    * Represents a numeric character reference (decimal or hexadecimal),
  124.    * when the referenced character is greater than 0xFFFF and so is
  125.    * represented by a pair of chars.
  126.    */
  127.   public static final int TOK_CHAR_PAIR_REF = TOK_CHAR_REF + 1;
  128.  
  129.   /**
  130.    * Represents a processing instruction.
  131.    */
  132.   public static final int TOK_PI = TOK_CHAR_PAIR_REF + 1;
  133.  
  134.   /**
  135.    * Represents an XML declaration or text declaration (a processing
  136.    * instruction whose target is <code>xml</code>).
  137.    */
  138.   public static final int TOK_XML_DECL = TOK_PI + 1;
  139.  
  140.   /**
  141.    * Represents a comment <code><!-- comment --></code>.
  142.    * This can occur both in the prolog and in content.
  143.    */
  144.   public static final int TOK_COMMENT = TOK_XML_DECL + 1;
  145.  
  146.   /**
  147.    * Represents a white space character in an attribute value,
  148.    * excluding white space characters that are part of line boundaries.
  149.    */
  150.   public static final int TOK_ATTRIBUTE_VALUE_S = TOK_COMMENT + 1;
  151.  
  152.   /**
  153.    * Represents a parameter entity reference in the prolog.
  154.    */
  155.   public static final int TOK_PARAM_ENTITY_REF = TOK_ATTRIBUTE_VALUE_S + 1;
  156.  
  157.   /**
  158.    * Represents whitespace in the prolog.
  159.    * The token contains one or more whitespace characters.
  160.    */
  161.   public static final int TOK_PROLOG_S = TOK_PARAM_ENTITY_REF + 1;
  162.  
  163.   /**
  164.    * Represents <code><!NAME</code> in the prolog.
  165.    */
  166.   public static final int TOK_DECL_OPEN = TOK_PROLOG_S + 1;
  167.  
  168.   /**
  169.    * Represents <code>></code> in the prolog.
  170.    */
  171.   public static final int TOK_DECL_CLOSE = TOK_DECL_OPEN + 1;
  172.  
  173.   /**
  174.    * Represents a name in the prolog.
  175.    */
  176.   public static final int TOK_NAME = TOK_DECL_CLOSE + 1;
  177.  
  178.   /**
  179.    * Represents a name token in the prolog that is not a name.
  180.    */
  181.   public static final int TOK_NMTOKEN = TOK_NAME + 1;
  182.  
  183.   /**
  184.    * Represents <code>#NAME</code> in the prolog.
  185.    */
  186.   public static final int TOK_POUND_NAME = TOK_NMTOKEN + 1;
  187.  
  188.   /**
  189.    * Represents <code>|</code> in the prolog.
  190.    */
  191.   public static final int TOK_OR = TOK_POUND_NAME + 1;
  192.  
  193.   /**
  194.    * Represents a <code>%</code> in the prolog that does not start
  195.    * a parameter entity reference.
  196.    * This can occur in an entity declaration.
  197.    */
  198.   public static final int TOK_PERCENT = TOK_OR + 1;
  199.  
  200.   /**
  201.    * Represents a <code>(</code> in the prolog.
  202.    */
  203.   public static final int TOK_OPEN_PAREN = TOK_PERCENT + 1;
  204.  
  205.   /**
  206.    * Represents a <code>)</code> in the prolog that is not
  207.    * followed immediately by any of
  208.    *  <code>*</code>, <code>+</code> or <code>?</code>.
  209.    */
  210.   public static final int TOK_CLOSE_PAREN = TOK_OPEN_PAREN + 1;
  211.  
  212.   /**
  213.    * Represents <code>[</code> in the prolog.
  214.    */
  215.   public static final int TOK_OPEN_BRACKET = TOK_CLOSE_PAREN + 1;
  216.  
  217.   /**
  218.    * Represents <code>]</code> in the prolog.
  219.    */
  220.   public static final int TOK_CLOSE_BRACKET = TOK_OPEN_BRACKET + 1;
  221.  
  222.   /**
  223.    * Represents a literal (EntityValue, AttValue, SystemLiteral or
  224.    * PubidLiteral).
  225.    */
  226.   public static final int TOK_LITERAL = TOK_CLOSE_BRACKET + 1;
  227.  
  228.   /**
  229.    * Represents a name followed immediately by <code>?</code>.
  230.    */
  231.   public static final int TOK_NAME_QUESTION = TOK_LITERAL + 1;
  232.  
  233.   /**
  234.    * Represents a name followed immediately by <code>*</code>.
  235.    */
  236.   public static final int TOK_NAME_ASTERISK = TOK_NAME_QUESTION + 1;
  237.  
  238.   /**
  239.    * Represents a name followed immediately by <code>+</code>.
  240.    */
  241.   public static final int TOK_NAME_PLUS = TOK_NAME_ASTERISK + 1;
  242.  
  243.   /**
  244.    * Represents <code><![</code> in the prolog.
  245.    */
  246.   public static final int TOK_COND_SECT_OPEN = TOK_NAME_PLUS + 1;
  247.  
  248.   /**
  249.    * Represents <code>]]></code> in the prolog.
  250.    */
  251.   public static final int TOK_COND_SECT_CLOSE = TOK_COND_SECT_OPEN + 1;
  252.  
  253.   /**
  254.    * Represents <code>)?</code> in the prolog.
  255.    */
  256.   public static final int TOK_CLOSE_PAREN_QUESTION = TOK_COND_SECT_CLOSE + 1;
  257.  
  258.   /**
  259.    * Represents <code>)*</code> in the prolog.
  260.    */
  261.   public static final int TOK_CLOSE_PAREN_ASTERISK = TOK_CLOSE_PAREN_QUESTION + 1;
  262.  
  263.   /**
  264.    * Represents <code>)+</code> in the prolog.
  265.    */
  266.   public static final int TOK_CLOSE_PAREN_PLUS = TOK_CLOSE_PAREN_ASTERISK + 1;
  267.  
  268.   /**
  269.    * Represents <code>,</code> in the prolog.
  270.    */
  271.   public static final int TOK_COMMA = TOK_CLOSE_PAREN_PLUS + 1;
  272.  
  273.   /**
  274.    * Convert bytes to characters.
  275.    * The bytes on <code>sourceBuf</code> between <code>sourceStart</code>
  276.    * and <code>sourceEnd</code> are converted to characters and stored
  277.    * in <code>targetBuf</code> starting at <code>targetStart</code>.
  278.    * <code>(targetBuf.length - targetStart) * getMinBytesPerChar()</code>
  279.    * must be at greater than or equal to
  280.    * <code>sourceEnd - sourceStart</code>.
  281.    * If <code>getFixedBytesPerChar</code> returns a value greater than 0,
  282.    * then the return value will be equal to
  283.    * <code>(sourceEnd - sourceStart)/getFixedBytesPerChar()</code>.
  284.    * @return the number of characters stored into <code>targetBuf</code>
  285.    * @see #getFixedBytesPerChar
  286.    */
  287.   public abstract int convert(byte[] sourceBuf, int sourceStart, int sourceEnd,
  288.                   char[] targetBuf, int targetStart);
  289.  
  290.   /**
  291.    * Returns the number of bytes required to represent each <code>char</code>,
  292.    * or zero if different <code>char</code>s are represented by different
  293.    * numbers of bytes.  The value returned will 0, 1, 2, or 4.
  294.    */
  295.   public abstract int getFixedBytesPerChar();
  296.  
  297.   private static Encoding utf8Encoding;
  298.   private static Encoding utf16LittleEndianEncoding;
  299.   private static Encoding utf16BigEndianEncoding;
  300.   private static Encoding internalEncoding;
  301.   private static Encoding iso8859_1Encoding;
  302.   private static Encoding asciiEncoding;
  303.   private static Encoding windows1250Encoding;
  304.   private static Encoding iso8859_2Encoding;
  305.  
  306.   private static final byte UTF8_ENCODING = 0;
  307.   private static final byte UTF16_LITTLE_ENDIAN_ENCODING = 1;
  308.   private static final byte UTF16_BIG_ENDIAN_ENCODING = 2;
  309.   private static final byte INTERNAL_ENCODING = 3;
  310.   private static final byte ISO8859_1_ENCODING = 4;
  311.   private static final byte ASCII_ENCODING = 5;
  312.   private static final byte WINDOWS1250_ENCODING = 6;
  313.   private static final byte ISO8859_2_ENCODING = 7;
  314.  
  315.   // Encoding vector for windows-1250 encoding
  316.   // This encoding is used by Windows for Central European languages
  317.   private static final String windows1250MapString =
  318.     "\0\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f" +
  319.     "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f" +
  320.     "\u0020\u0021\"\u0023\u0024\u0025\u0026\'\u0028\u0029\u002a\u002b\u002c\u002d\u002e\u002f" +
  321.     "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u003a\u003b\u003c\u003d\u003e\u003f" +
  322.     "\u0040\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u004a\u004b\u004c\u004d\u004e\u004f" +
  323.     "\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005a\u005b\\\u005d\u005e\u005f" +
  324.     "\u0060\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u006a\u006b\u006c\u006d\u006e\u006f" +
  325.     "\u0070\u0071\u0072\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007a\u007b\u007c\u007d\u007e\u007f" +
  326.     "\u20ac\ufffd\u201a\ufffd\u201e\u2026\u2020\u2021\ufffd\u2030\u0160\u2039\u015a\u0164\u017d\u0179" +
  327.     "\ufffd\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffd\u2122\u0161\u203a\u015b\u0165\u017e\u017a" +
  328.     "\u00a0\u02c7\u02d8\u0141\u00a4\u0104\u00a6\u00a7\u00a8\u00a9\u015e\u00ab\ufffd\u00ad\u00ae\u017b" +
  329.     "\u00b0\u00b1\u02db\u0142\u00b4\u00b5\u00b6\u00b7\u00b8\u0105\u015f\u00bb\u013d\u02dd\u013e\u017c" +
  330.     "\u0154\u00c1\u00c2\u0102\u00c4\u0139\u0106\u00c7\u010c\u00c9\u0118\u00cb\u011a\u00cd\u00ce\u010e" +
  331.     "\u0110\u0143\u0147\u00d3\u00d4\u0150\u00d6\u00d7\u0158\u016e\u00da\u0170\u00dc\u00dd\u0162\u00df" +
  332.     "\u0155\u00e1\u00e2\u0103\u00e4\u013a\u0107\u00e7\u010d\u00e9\u0119\u00eb\u011b\u00ed\u00ee\u010f" +
  333.     "\u0111\u0144\u0148\u00f3\u00f4\u0151\u00f6\u00f7\u0159\u016f\u00fa\u0171\u00fc\u00fd\u0163\u02d9";
  334.  
  335.   // Encoding vector for ISO 8859-2 encoding
  336.   // This encoding is ISO standard for Central European languages
  337.   private static final String iso8859_2MapString =
  338.     "\0\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f" +
  339.     "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f" +
  340.     "\u0020\u0021\"\u0023\u0024\u0025\u0026\'\u0028\u0029\u002a\u002b\u002c\u002d\u002e\u002f" +
  341.     "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u003a\u003b\u003c\u003d\u003e\u003f" +
  342.     "\u0040\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u004a\u004b\u004c\u004d\u004e\u004f" +
  343.     "\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005a\u005b\\\u005d\u005e\u005f" +
  344.     "\u0060\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u006a\u006b\u006c\u006d\u006e\u006f" +
  345.     "\u0070\u0071\u0072\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007a\u007b\u007c\u007d\u007e\u007f" +
  346.     "\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f" +
  347.     "\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f" +
  348.     "\u00a0\u0104\u02d8\u0141\u00a4\u013d\u015a\u00a7\u00a8\u0160\u015e\u0164\u0179\u00ad\u017d\u017b" +
  349.     "\u00b0\u0105\u02db\u0142\u00b4\u013e\u015b\u02c7\u00b8\u0161\u015f\u0165\u017a\u02dd\u017e\u017c" +
  350.     "\u0154\u00c1\u00c2\u0102\u00c4\u0139\u0106\u00c7\u010c\u00c9\u0118\u00cb\u011a\u00cd\u00ce\u010e" +
  351.     "\u0110\u0143\u0147\u00d3\u00d4\u0150\u00d6\u00d7\u0158\u016e\u00da\u0170\u00dc\u00dd\u0162\u00df" +
  352.     "\u0155\u00e1\u00e2\u0103\u00e4\u013a\u0107\u00e7\u010d\u00e9\u0119\u00eb\u011b\u00ed\u00ee\u010f" +
  353.     "\u0111\u0144\u0148\u00f3\u00f4\u0151\u00f6\u00f7\u0159\u016f\u00fa\u0171\u00fc\u00fd\u0163\u02d9";
  354.  
  355.   private static synchronized Encoding getEncoding(byte enc) {
  356.     switch (enc) {
  357.     case UTF8_ENCODING:
  358.       if (utf8Encoding == null)
  359.     utf8Encoding = new UTF8Encoding();
  360.       return utf8Encoding;
  361.     case UTF16_LITTLE_ENDIAN_ENCODING:
  362.       if (utf16LittleEndianEncoding == null)
  363.     utf16LittleEndianEncoding = new UTF16LittleEndianEncoding();
  364.       return utf16LittleEndianEncoding;
  365.     case UTF16_BIG_ENDIAN_ENCODING:
  366.       if (utf16BigEndianEncoding == null)
  367.     utf16BigEndianEncoding = new UTF16BigEndianEncoding();
  368.       return utf16BigEndianEncoding;
  369.     case INTERNAL_ENCODING:
  370.       if (internalEncoding == null)
  371.     internalEncoding = new InternalEncoding();
  372.       return internalEncoding;
  373.     case ISO8859_1_ENCODING:
  374.       if (iso8859_1Encoding == null)
  375.     iso8859_1Encoding = new ISO8859_1Encoding();
  376.       return iso8859_1Encoding;
  377.     case ASCII_ENCODING:
  378.       if (asciiEncoding == null)
  379.     asciiEncoding = new ASCIIEncoding();
  380.       return asciiEncoding;
  381.     case WINDOWS1250_ENCODING:
  382.       if (windows1250Encoding == null)
  383.     windows1250Encoding = new SingleByteEncoding(windows1250MapString);
  384.       return windows1250Encoding;
  385.     case ISO8859_2_ENCODING:
  386.       if (iso8859_2Encoding == null)
  387.     iso8859_2Encoding = new SingleByteEncoding(iso8859_2MapString);
  388.       return iso8859_2Encoding;
  389.     }
  390.     return null;
  391.   }
  392.  
  393.   Encoding getUTF16Encoding() {
  394.     return getEncoding(UTF16_BIG_ENDIAN_ENCODING);
  395.   }
  396.  
  397.   // Bytes with type < 0 may not be data in content.
  398.   // The negation of the lead byte type gives the total number of bytes.
  399.   static final int BT_LEAD2 = -2;
  400.   static final int BT_LEAD3 = BT_LEAD2 - 1;
  401.   static final int BT_LEAD4 = BT_LEAD3 - 1;
  402.   static final int BT_NONXML = BT_LEAD4 - 1;
  403.   static final int BT_MALFORM = BT_NONXML - 1;
  404.   static final int BT_LT = BT_MALFORM - 1;
  405.   static final int BT_AMP = BT_LT - 1;
  406.   static final int BT_RSQB = BT_AMP - 1;
  407.   static final int BT_CR = BT_RSQB - 1;
  408.   static final int BT_LF = BT_CR - 1;
  409.   // Bytes with type >= 0 are treated as data in content.
  410.   static final int BT_GT = 0;
  411.   static final int BT_QUOT = BT_GT + 1;
  412.   static final int BT_APOS = BT_QUOT + 1;
  413.   static final int BT_EQUALS = BT_APOS + 1;
  414.   static final int BT_QUEST = BT_EQUALS + 1;
  415.   static final int BT_EXCL = BT_QUEST + 1;
  416.   static final int BT_SOL = BT_EXCL + 1;
  417.   static final int BT_SEMI = BT_SOL + 1;
  418.   static final int BT_NUM = BT_SEMI + 1;
  419.   static final int BT_LSQB = BT_NUM + 1;
  420.   static final int BT_S = BT_LSQB + 1;
  421.   static final int BT_NMSTRT = BT_S + 1;
  422.   static final int BT_NAME = BT_NMSTRT + 1;
  423.   static final int BT_MINUS = BT_NAME + 1;
  424.   static final int BT_OTHER = BT_MINUS + 1;
  425.   static final int BT_PERCNT = BT_OTHER + 1;
  426.   static final int BT_LPAR = BT_PERCNT + 1;
  427.   static final int BT_RPAR = BT_LPAR + 1;
  428.   static final int BT_AST = BT_RPAR + 1;
  429.   static final int BT_PLUS = BT_AST + 1;
  430.   static final int BT_COMMA = BT_PLUS + 1;
  431.   static final int BT_VERBAR = BT_COMMA + 1;
  432.  
  433.   final static byte[] asciiTypeTable = {
  434.     /* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
  435.     /* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
  436.     /* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
  437.     /* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML,
  438.     /* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
  439.     /* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
  440.     /* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
  441.     /* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
  442.     /* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
  443.     /* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
  444.     /* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
  445.     /* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
  446.     /* 0x30 */ BT_NAME, BT_NAME, BT_NAME, BT_NAME,
  447.     /* 0x34 */ BT_NAME, BT_NAME, BT_NAME, BT_NAME,
  448.     /* 0x38 */ BT_NAME, BT_NAME, BT_NMSTRT, BT_SEMI,
  449.     /* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
  450.     /* 0x40 */ BT_OTHER, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
  451.     /* 0x44 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
  452.     /* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
  453.     /* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
  454.     /* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
  455.     /* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
  456.     /* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
  457.     /* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
  458.     /* 0x60 */ BT_OTHER, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
  459.     /* 0x64 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
  460.     /* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
  461.     /* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
  462.     /* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
  463.     /* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
  464.     /* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
  465.     /* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER
  466.   };
  467.  
  468.   // The minimum number of bytes per character.
  469.   private /* final */ int minBPC;
  470.  
  471.   Encoding(int minBPC) {
  472.     this.minBPC = minBPC;
  473.   }
  474.  
  475.   // There are guaranteed to be minBPC available bytes starting at off.
  476.   abstract int byteType(byte[] buf, int off);
  477.  
  478.   abstract int byteToAscii(byte[] buf, int off);
  479.  
  480.   // This must only be called when c is an (XML significant) ASCII character.
  481.   abstract boolean charMatches(byte[] buf, int off, char c);
  482.  
  483.   // Called only when byteType(buf, off) == BT_LEAD2
  484.   int byteType2(byte[] buf, int off) {
  485.     return BT_OTHER;
  486.   }
  487.   // Called only when byteType(buf, off) == BT_LEAD3
  488.   int byteType3(byte[] buf, int off) {
  489.     return BT_OTHER;
  490.   }
  491.   // Called only when byteType(buf, off) == BT_LEAD4
  492.   int byteType4(byte[] buf, int off) {
  493.     return BT_OTHER;
  494.   }
  495.  
  496.   void check2(byte[] buf, int off) throws InvalidTokenException { }
  497.   void check3(byte[] buf, int off) throws InvalidTokenException { }
  498.   void check4(byte[] buf, int off) throws InvalidTokenException { }
  499.  
  500.   /**
  501.    * Moves a position forward.
  502.    * On entry, <code>pos</code> gives the position of the byte at index
  503.    * <code>off</code> in <code>buf</code>.
  504.    * On exit, it <code>pos</code> will give the position of the byte at index
  505.    * <code>end</code>, which must be greater than or equal to <code>off</code>.
  506.    * The bytes between <code>off</code> and <code>end</code> must encode
  507.    * one or more complete characters.
  508.    * A carriage return followed by a line feed will be treated as a single
  509.    * line delimiter provided that they are given to <code>movePosition</code>
  510.    * together.
  511.    */
  512.   public abstract void movePosition(byte[] buf, int off, int end, Position pos);
  513.  
  514.   // end encoding specific part
  515.  
  516.   private final
  517.   void checkCharMatches(byte[] buf, int off, char c) throws InvalidTokenException {
  518.     if (!charMatches(buf, off, c))
  519.       throw new InvalidTokenException(off);
  520.   }
  521.  
  522.   /* off points to character following "<!-" */
  523.  
  524.   private final
  525.   int scanComment(byte[] buf, int off, int end, Token token)
  526.        throws InvalidTokenException, PartialTokenException {
  527.     if (off != end) {
  528.       checkCharMatches(buf, off, '-');
  529.       off += minBPC;
  530.       while (off != end) {
  531.     switch (byteType(buf, off)) {
  532.     case BT_LEAD2:
  533.       if (end - off < 2)
  534.         throw new PartialCharException(off);
  535.       check2(buf, off);
  536.       off += 2;
  537.       break;
  538.     case BT_LEAD3:
  539.       if (end - off < 3)
  540.         throw new PartialCharException(off);
  541.       check3(buf, off);
  542.       off += 3;
  543.       break;
  544.     case BT_LEAD4:
  545.       if (end - off < 4)
  546.         throw new PartialCharException(off);
  547.       check4(buf, off);
  548.       off += 4;
  549.       break;
  550.     case BT_NONXML:
  551.     case BT_MALFORM:
  552.       throw new InvalidTokenException(off);
  553.     case BT_MINUS:
  554.       if ((off += minBPC) == end)
  555.         throw new PartialTokenException();
  556.       if (charMatches(buf, off, '-')) {
  557.         if ((off += minBPC) == end)
  558.           throw new PartialTokenException();
  559.         checkCharMatches(buf, off, '>');
  560.         token.tokenEnd = off + minBPC;
  561.         return TOK_COMMENT;
  562.       }
  563.       break;
  564.     default:
  565.       off += minBPC;
  566.       break;
  567.     }
  568.       }
  569.     }
  570.     throw new PartialTokenException();
  571.   }
  572.  
  573.   /* off points to character following "<!" */
  574.  
  575.   private final
  576.   int scanDecl(byte[] buf, int off, int end, Token token)
  577.        throws InvalidTokenException, PartialTokenException {
  578.     if (off == end)
  579.       throw new PartialTokenException();
  580.     switch (byteType(buf, off)) {
  581.     case BT_MINUS:
  582.       return scanComment(buf, off + minBPC, end, token);
  583.     case BT_LSQB:
  584.       token.tokenEnd = off + minBPC;
  585.       return TOK_COND_SECT_OPEN;
  586.     case BT_NMSTRT:
  587.       off += minBPC;
  588.       break;
  589.     default:
  590.       throw new InvalidTokenException(off);
  591.     }
  592.     while (off != end) {
  593.       switch (byteType(buf, off)) {
  594.       case BT_PERCNT:
  595.     if (off + minBPC == end)
  596.       throw new PartialTokenException();
  597.     /* don't allow <!ENTITY% foo "whatever"> */
  598.     switch (byteType(buf, off + minBPC)) {
  599.     case BT_S:
  600.     case BT_CR:
  601.     case BT_LF:
  602.     case BT_PERCNT:
  603.       throw new InvalidTokenException(off);
  604.     }
  605.     /* fall through */
  606.       case BT_S:
  607.       case BT_CR:
  608.       case BT_LF:
  609.     token.tokenEnd = off;
  610.     return TOK_DECL_OPEN;
  611.       case BT_NMSTRT:
  612.     off += minBPC;
  613.     break;
  614.       default:
  615.     throw new InvalidTokenException(off);
  616.       }
  617.     }
  618.     throw new PartialTokenException();
  619.   }
  620.  
  621.   private final
  622.   boolean targetIsXml(byte[] buf, int off, int end) throws InvalidTokenException {
  623.     boolean upper = false;
  624.     if (end - off != minBPC*3)
  625.       return false;
  626.     switch (byteToAscii(buf, off)) {
  627.     case 'x':
  628.       break;
  629.     case 'X':
  630.       upper = true;
  631.       break;
  632.     default:
  633.       return false;
  634.     }
  635.     off += minBPC;
  636.     switch (byteToAscii(buf, off)) {
  637.     case 'm':
  638.       break;
  639.     case 'M':
  640.       upper = true;
  641.       break;
  642.     default:
  643.       return false;
  644.     }
  645.     off += minBPC;
  646.     switch (byteToAscii(buf, off)) {
  647.     case 'l':
  648.       break;
  649.     case 'L':
  650.       upper = true;
  651.       break;
  652.     default:
  653.       return false;
  654.     }
  655.     if (upper)
  656.       throw new InvalidTokenException(off, InvalidTokenException.XML_TARGET);
  657.     return true;
  658.   }
  659.  
  660.   /* off points to character following "<?" */
  661.  
  662.   private final
  663.   int scanPi(byte[] buf, int off, int end, Token token)
  664.        throws PartialTokenException, InvalidTokenException {
  665.     int target = off;
  666.     if (off == end)
  667.       throw new PartialTokenException();
  668.     switch (byteType(buf, off)) {
  669.     case BT_NMSTRT:
  670.       off += minBPC;
  671.       break;
  672.     case BT_LEAD2:
  673.       if (end - off < 2)
  674.     throw new PartialCharException(off);
  675.       if (byteType2(buf, off) != BT_NMSTRT)
  676.     throw new InvalidTokenException(off);
  677.       off += 2;
  678.       break;
  679.     case BT_LEAD3:
  680.       if (end - off < 3)
  681.     throw new PartialCharException(off);
  682.       if (byteType3(buf, off) != BT_NMSTRT)
  683.     throw new InvalidTokenException(off);
  684.       off += 3;
  685.       break;
  686.     case BT_LEAD4:
  687.       if (end - off < 4)
  688.     throw new PartialCharException(off);
  689.       if (byteType4(buf, off) != BT_NMSTRT)
  690.     throw new InvalidTokenException(off);
  691.       off += 4;
  692.       break;
  693.     default:
  694.       throw new InvalidTokenException(off);
  695.     }
  696.     while (off != end) {
  697.       switch (byteType(buf, off)) {
  698.       case BT_NMSTRT:
  699.       case BT_NAME:
  700.       case BT_MINUS:
  701.     off += minBPC;
  702.     break;
  703.       case BT_LEAD2:
  704.     if (end - off < 2)
  705.       throw new PartialCharException(off);
  706.     if (!isNameChar2(buf, off))
  707.       throw new InvalidTokenException(off);
  708.     off += 2;
  709.     break;
  710.       case BT_LEAD3:
  711.     if (end - off < 3)
  712.       throw new PartialCharException(off);
  713.     if (!isNameChar3(buf, off))
  714.       throw new InvalidTokenException(off);
  715.     off += 3;
  716.     break;
  717.       case BT_LEAD4:
  718.     if (end - off < 4)
  719.       throw new PartialCharException(off);
  720.     if (!isNameChar4(buf, off))
  721.       throw new InvalidTokenException(off);
  722.     off += 4;
  723.     break;
  724.       case BT_S:
  725.       case BT_CR:
  726.       case BT_LF:
  727.     boolean isXml = targetIsXml(buf, target, off);
  728.     token.nameEnd = off;
  729.     off += minBPC;
  730.     while (off != end) {
  731.       switch (byteType(buf, off)) {
  732.       case BT_LEAD2:
  733.         if (end - off < 2)
  734.           throw new PartialCharException(off);
  735.         check2(buf, off);
  736.         off += 2;
  737.         break;
  738.       case BT_LEAD3:
  739.         if (end - off < 3)
  740.           throw new PartialCharException(off);
  741.         check3(buf, off);
  742.         off += 3;
  743.         break;
  744.       case BT_LEAD4:
  745.         if (end - off < 4)
  746.           throw new PartialCharException(off);
  747.         check4(buf, off);
  748.         off += 4;
  749.         break;
  750.       case BT_NONXML:
  751.       case BT_MALFORM:
  752.         throw new InvalidTokenException(off);
  753.       case BT_QUEST:
  754.         off += minBPC;
  755.         if (off == end)
  756.           throw new PartialTokenException();
  757.         if (charMatches(buf, off, '>')) {
  758.           token.tokenEnd = off + minBPC;
  759.           if (isXml)
  760.         return TOK_XML_DECL;
  761.           else
  762.         return TOK_PI;
  763.         }
  764.         break;
  765.       default:
  766.         off += minBPC;
  767.         break;
  768.       }
  769.     }
  770.     throw new PartialTokenException();
  771.       case BT_QUEST:
  772.     token.nameEnd = off;
  773.     off += minBPC;
  774.     if (off == end)
  775.       throw new PartialTokenException();
  776.     checkCharMatches(buf, off, '>');
  777.     token.tokenEnd = off + minBPC;
  778.     return (targetIsXml(buf, target, token.nameEnd)
  779.         ? TOK_XML_DECL
  780.         : TOK_PI);
  781.       default:
  782.     throw new InvalidTokenException(off);
  783.       }
  784.     }
  785.     throw new PartialTokenException();
  786.   }
  787.  
  788.   /* off points to character following "<![" */
  789.  
  790.   private static final String CDATA = "CDATA[";
  791.  
  792.   private final
  793.   int scanCdataSection(byte[] buf, int off, int end, Token token)
  794.        throws PartialTokenException, InvalidTokenException {
  795.     /* "CDATA[".length() == 6 */
  796.     if (end - off < 6 * minBPC)
  797.       throw new PartialTokenException();
  798.     for (int i = 0; i < CDATA.length(); i++, off += minBPC)
  799.       checkCharMatches(buf, off, CDATA.charAt(i));
  800.     token.tokenEnd = off;
  801.     return TOK_CDATA_SECT_OPEN;
  802.   }
  803.  
  804.   /**
  805.    * Scans the first token of a byte subarrary that starts with the
  806.    * content of a CDATA section.
  807.    * Returns one of the following integers according to the type of token
  808.    * that the subarray starts with:
  809.    * <ul>
  810.    * <li><code>TOK_DATA_CHARS</code>
  811.    * <li><code>TOK_DATA_NEWLINE</code>
  812.    * <li><code>TOK_CDATA_SECT_CLOSE</code>
  813.    * </ul>
  814.    * <p>
  815.    * Information about the token is stored in <code>token</code>.
  816.    * <p>
  817.    * After <code>TOK_CDATA_SECT_CLOSE</code> is returned, the application
  818.    * should use <code>tokenizeContent</code>.
  819.    *
  820.    * @exception EmptyTokenException if the subarray is empty
  821.    * @exception PartialTokenException if the subarray contains only part of
  822.    * a legal token
  823.    * @exception InvalidTokenException if the subarrary does not start
  824.    * with a legal token or part of one
  825.    * @exception ExtensibleTokenException if the subarray encodes just a carriage
  826.    * return ('\r')
  827.    *
  828.    * @see #TOK_DATA_CHARS
  829.    * @see #TOK_DATA_NEWLINE
  830.    * @see #TOK_CDATA_SECT_CLOSE
  831.    * @see Token
  832.    * @see EmptyTokenException
  833.    * @see PartialTokenException
  834.    * @see InvalidTokenException
  835.    * @see ExtensibleTokenException
  836.    * @see #tokenizeContent
  837.    */
  838.   public final int tokenizeCdataSection(byte[] buf, int off, int end, Token token) throws EmptyTokenException, PartialTokenException, InvalidTokenException, ExtensibleTokenException {
  839.     if (minBPC > 1)
  840.       end = adjustEnd(off, end);
  841.     if (off == end)
  842.       throw new EmptyTokenException();
  843.     switch (byteType(buf, off)) {
  844.     case BT_RSQB:
  845.       off += minBPC;
  846.       if (off == end)
  847.     throw new PartialTokenException();
  848.       if (!charMatches(buf, off, ']'))
  849.     break;
  850.       off += minBPC;
  851.       if (off == end)
  852.     throw new PartialTokenException();
  853.       if (!charMatches(buf, off, '>')) {
  854.     off -= minBPC;
  855.     break;
  856.       }
  857.       token.tokenEnd = off + minBPC;
  858.       return TOK_CDATA_SECT_CLOSE;
  859.     case BT_CR:
  860.       off += minBPC;
  861.       if (off == end)
  862.     throw new ExtensibleTokenException(TOK_DATA_NEWLINE);
  863.       if (byteType(buf, off) == BT_LF)
  864.     off += minBPC;
  865.       token.tokenEnd = off;
  866.       return TOK_DATA_NEWLINE;
  867.     case BT_LF:
  868.       token.tokenEnd = off + minBPC;
  869.       return TOK_DATA_NEWLINE;
  870.     case BT_NONXML:
  871.     case BT_MALFORM:
  872.       throw new InvalidTokenException(off);
  873.     case BT_LEAD2:
  874.       if (end - off < 2)
  875.     throw new PartialCharException(off);
  876.       check2(buf, off);
  877.       off += 2;
  878.       break;
  879.     case BT_LEAD3:
  880.       if (end - off < 3)
  881.     throw new PartialCharException(off);
  882.       check3(buf, off);
  883.       off += 3;
  884.       break;
  885.     case BT_LEAD4:
  886.       if (end - off < 4)
  887.     throw new PartialCharException(off);
  888.       check4(buf, off);
  889.       off += 4;
  890.       break;
  891.     default:
  892.       off += minBPC;
  893.       break;
  894.     }
  895.     token.tokenEnd = extendCdata(buf, off, end);
  896.     return TOK_DATA_CHARS;
  897.   }
  898.  
  899.   int extendCdata(final byte[] buf, int off, final int end) throws InvalidTokenException {
  900.     while (off != end) {
  901.       switch (byteType(buf, off)) {
  902.       case BT_LEAD2:
  903.     if (end - off < 2)
  904.       return off;
  905.     check2(buf, off);
  906.     off += 2;
  907.     break;
  908.       case BT_LEAD3:
  909.     if (end - off < 3)
  910.       return off;
  911.     check3(buf, off);
  912.     off += 3;
  913.     break;
  914.       case BT_LEAD4:
  915.     if (end - off < 4)
  916.       return off;
  917.     check4(buf, off);
  918.     off += 4;
  919.     break;
  920.       case BT_RSQB:
  921.       case BT_NONXML:
  922.       case BT_MALFORM:
  923.       case BT_CR:
  924.       case BT_LF:
  925.     return off;
  926.       default:
  927.     off += minBPC;
  928.     break;
  929.       }
  930.     }
  931.     return off;
  932.   }
  933.  
  934.  
  935.   /* off points to character following "</" */
  936.  
  937.   private final
  938.   int scanEndTag(byte[] buf, int off, int end, Token token)
  939.        throws PartialTokenException, InvalidTokenException {
  940.     if (off == end)
  941.       throw new PartialTokenException();
  942.     switch (byteType(buf, off)) {
  943.     case BT_NMSTRT:
  944.       off += minBPC;
  945.       break;
  946.     case BT_LEAD2:
  947.       if (end - off < 2)
  948.     throw new PartialCharException(off);
  949.       if (byteType2(buf, off) != BT_NMSTRT)
  950.     throw new InvalidTokenException(off);
  951.       off += 2;
  952.       break;
  953.     case BT_LEAD3:
  954.       if (end - off < 3)
  955.     throw new PartialCharException(off);
  956.       if (byteType3(buf, off) != BT_NMSTRT)
  957.     throw new InvalidTokenException(off);
  958.       off += 3;
  959.       break;
  960.     case BT_LEAD4:
  961.       if (end - off < 4)
  962.     throw new PartialCharException(off);
  963.       if (byteType4(buf, off) != BT_NMSTRT)
  964.     throw new InvalidTokenException(off);
  965.       off += 4;
  966.       break;
  967.     default:
  968.       throw new InvalidTokenException(off);
  969.     }
  970.     while (off != end) {
  971.       switch (byteType(buf, off)) {
  972.       case BT_NMSTRT:
  973.       case BT_NAME:
  974.       case BT_MINUS:
  975.     off += minBPC;
  976.     break;
  977.       case BT_LEAD2:
  978.     if (end - off < 2)
  979.       throw new PartialCharException(off);
  980.     if (!isNameChar2(buf, off))
  981.       throw new InvalidTokenException(off);
  982.     off += 2;
  983.     break;
  984.       case BT_LEAD3:
  985.     if (end - off < 3)
  986.       throw new PartialCharException(off);
  987.     if (!isNameChar3(buf, off))
  988.       throw new InvalidTokenException(off);
  989.     off += 3;
  990.     break;
  991.       case BT_LEAD4:
  992.     if (end - off < 4)
  993.       throw new PartialCharException(off);
  994.     if (!isNameChar4(buf, off))
  995.       throw new InvalidTokenException(off);
  996.     off += 4;
  997.     break;
  998.       case BT_S:
  999.       case BT_CR:
  1000.       case BT_LF:
  1001.     token.nameEnd = off;
  1002.     for (off += minBPC; off != end; off += minBPC) {
  1003.       switch (byteType(buf, off)) {
  1004.       case BT_S:
  1005.       case BT_CR:
  1006.       case BT_LF:
  1007.         break;
  1008.       case BT_GT:
  1009.         token.tokenEnd = off + minBPC;
  1010.         return TOK_END_TAG;
  1011.       default:
  1012.         throw new InvalidTokenException(off);
  1013.       }
  1014.     }
  1015.     throw new PartialTokenException();
  1016.       case BT_GT:
  1017.     token.nameEnd = off;
  1018.     token.tokenEnd = off + minBPC;
  1019.     return TOK_END_TAG;
  1020.       default:
  1021.     throw new InvalidTokenException(off);
  1022.       }
  1023.     }
  1024.     throw new PartialTokenException();
  1025.   }
  1026.  
  1027.   /* off points to character following "&#X" */
  1028.  
  1029.   private final
  1030.   int scanHexCharRef(byte[] buf, int off, int end, Token token)
  1031.        throws PartialTokenException, InvalidTokenException {
  1032.     if (off != end) {
  1033.       int c = byteToAscii(buf, off);
  1034.       int num;
  1035.       switch (c) {
  1036.       case '0': case '1': case '2': case '3': case '4':
  1037.       case '5': case '6': case '7': case '8': case '9':
  1038.     num = c - '0';
  1039.     break;
  1040.       case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  1041.     num = c - ('A' - 10);
  1042.     break;
  1043.       case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  1044.     num = c - ('a' - 10);
  1045.     break;
  1046.       default:
  1047.     throw new InvalidTokenException(off);
  1048.       }
  1049.       for (off += minBPC; off != end; off += minBPC) {
  1050.     c = byteToAscii(buf, off);
  1051.     switch (c) {
  1052.     case '0': case '1': case '2': case '3': case '4':
  1053.     case '5': case '6': case '7': case '8': case '9':
  1054.       num = (num << 4) + c - '0';
  1055.       break;
  1056.     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  1057.       num = (num << 4) + c - ('A' - 10);
  1058.       break;
  1059.     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  1060.       num = (num << 4) + c - ('a' - 10);
  1061.       break;
  1062.     case ';':
  1063.       token.tokenEnd = off + minBPC;
  1064.       return setRefChar(num, token);
  1065.     default:
  1066.       throw new InvalidTokenException(off);
  1067.     }
  1068.     if (num >= 0x110000)
  1069.       throw new InvalidTokenException(off);
  1070.       }
  1071.     }
  1072.     throw new PartialTokenException();
  1073.   }
  1074.  
  1075.   /* off points to character following "&#" */
  1076.  
  1077.   private final
  1078.   int scanCharRef(byte[] buf, int off, int end, Token token)
  1079.        throws PartialTokenException, InvalidTokenException {
  1080.     if (off != end) {
  1081.       int c = byteToAscii(buf, off);
  1082.       switch (c) {
  1083.       case 'x':
  1084.     return scanHexCharRef(buf, off + minBPC, end, token);
  1085.       case '0':
  1086.       case '1':
  1087.       case '2':
  1088.       case '3':
  1089.       case '4':
  1090.       case '5':
  1091.       case '6':
  1092.       case '7':
  1093.       case '8':
  1094.       case '9':
  1095.     break;
  1096.       default:
  1097.     throw new InvalidTokenException(off);
  1098.       }
  1099.       int num = c - '0';
  1100.       for (off += minBPC; off != end; off += minBPC) {
  1101.     c = byteToAscii(buf, off);
  1102.     switch (c) {
  1103.     case '0':
  1104.     case '1':
  1105.     case '2':
  1106.     case '3':
  1107.     case '4':
  1108.     case '5':
  1109.     case '6':
  1110.     case '7':
  1111.     case '8':
  1112.     case '9':
  1113.       num = num * 10 + (c - '0');
  1114.       if (num < 0x110000)
  1115.         break;
  1116.       /* fall through */
  1117.     default:
  1118.       throw new InvalidTokenException(off);
  1119.     case ';':
  1120.       token.tokenEnd = off + minBPC;
  1121.       return setRefChar(num, token);
  1122.     }
  1123.       }
  1124.     }
  1125.     throw new PartialTokenException();
  1126.   }
  1127.  
  1128.   /* num is known to be < 0x110000; return the token code */
  1129.   private final int setRefChar(int num, Token token)
  1130.      throws InvalidTokenException {
  1131.     if (num < 0x10000) {
  1132.       switch (charTypeTable[num >> 8][num & 0xFF]) {
  1133.       case BT_NONXML:
  1134.       case BT_LEAD4:
  1135.       case BT_MALFORM:
  1136.     throw new InvalidTokenException(token.tokenEnd - minBPC);
  1137.       }
  1138.       token.refChar1 = (char)num;
  1139.       return TOK_CHAR_REF;
  1140.     }
  1141.     else {
  1142.       num -= 0x10000;
  1143.       token.refChar1 = (char)((num >> 10) + 0xD800);
  1144.       token.refChar2 = (char)((num & ((1 << 10) - 1)) + 0xDC00);
  1145.       return TOK_CHAR_PAIR_REF;
  1146.     }
  1147.   }
  1148.  
  1149.   private final
  1150.   boolean isMagicEntityRef(byte[] buf, int off, int end, Token token) {
  1151.     switch (byteToAscii(buf, off)) {
  1152.     case 'a':
  1153.       if (end - off < minBPC*4)
  1154.     break;
  1155.       switch (byteToAscii(buf, off + minBPC)) {
  1156.       case 'm':
  1157.     if (charMatches(buf, off + minBPC*2, 'p')
  1158.         && charMatches(buf, off + minBPC*3, ';')) {
  1159.       token.tokenEnd = off + minBPC*4;
  1160.       token.refChar1 = '&';
  1161.       return true;
  1162.     }
  1163.     break;
  1164.       case 'p':
  1165.     if (end - off >= minBPC*5
  1166.         && charMatches(buf, off + minBPC*2, 'o')
  1167.         && charMatches(buf, off + minBPC*3, 's')
  1168.         && charMatches(buf, off + minBPC*4, ';')) {
  1169.       token.tokenEnd = off + minBPC*5;
  1170.       token.refChar1 = '\'';
  1171.       return true;
  1172.     }
  1173.     break;
  1174.       }
  1175.       break;
  1176.     case 'l':
  1177.       if (end - off >= minBPC*3
  1178.       && charMatches(buf, off + minBPC, 't')
  1179.       && charMatches(buf, off + minBPC*2, ';')) {
  1180.     token.tokenEnd = off + minBPC*3;
  1181.     token.refChar1 = '<';
  1182.     return true;
  1183.       }
  1184.       break;
  1185.     case 'g':
  1186.       if (end - off >= minBPC*3
  1187.       && charMatches(buf, off + minBPC, 't')
  1188.       && charMatches(buf, off + minBPC*2, ';')) {
  1189.     token.tokenEnd = off + minBPC*3;
  1190.     token.refChar1 = '>';
  1191.     return true;
  1192.       }
  1193.       break;
  1194.     case 'q':
  1195.       if (end - off >= minBPC*5
  1196.       && charMatches(buf, off + minBPC, 'u')
  1197.       && charMatches(buf, off + minBPC*2, 'o')
  1198.       && charMatches(buf, off + minBPC*3, 't')
  1199.       && charMatches(buf, off + minBPC*4, ';')) {
  1200.     token.tokenEnd = off + minBPC*5;
  1201.     token.refChar1 = '"';
  1202.     return true;
  1203.       }
  1204.       break;
  1205.     }
  1206.     return false;
  1207.   }
  1208.   /* off points to character following "&" */
  1209.  
  1210.   private final
  1211.   int scanRef(byte[] buf, int off, int end, Token token)
  1212.        throws PartialTokenException, InvalidTokenException {
  1213.     if (off == end)
  1214.       throw new PartialTokenException();
  1215.     if (isMagicEntityRef(buf, off, end, token))
  1216.       return TOK_MAGIC_ENTITY_REF;
  1217.     switch (byteType(buf, off)) {
  1218.     case BT_NMSTRT:
  1219.       off += minBPC;
  1220.       break;
  1221.     case BT_LEAD2:
  1222.       if (end - off < 2)
  1223.     throw new PartialCharException(off);
  1224.       if (byteType2(buf, off) != BT_NMSTRT)
  1225.     throw new InvalidTokenException(off);
  1226.       off += 2;
  1227.       break;
  1228.     case BT_LEAD3:
  1229.       if (end - off < 3)
  1230.     throw new PartialCharException(off);
  1231.       if (byteType3(buf, off) != BT_NMSTRT)
  1232.     throw new InvalidTokenException(off);
  1233.       off += 3;
  1234.       break;
  1235.     case BT_LEAD4:
  1236.       if (end - off < 4)
  1237.     throw new PartialCharException(off);
  1238.       if (byteType4(buf, off) != BT_NMSTRT)
  1239.     throw new InvalidTokenException(off);
  1240.       off += 4;
  1241.       break;
  1242.     case BT_NUM:
  1243.       return scanCharRef(buf, off + minBPC, end, token);
  1244.     default:
  1245.       throw new InvalidTokenException(off);
  1246.     }
  1247.     while (off != end) {
  1248.       switch (byteType(buf, off)) {
  1249.       case BT_NMSTRT:
  1250.       case BT_NAME:
  1251.       case BT_MINUS:
  1252.     off += minBPC;
  1253.     break;
  1254.       case BT_LEAD2:
  1255.     if (end - off < 2)
  1256.       throw new PartialCharException(off);
  1257.     if (!isNameChar2(buf, off))
  1258.       throw new InvalidTokenException(off);
  1259.     off += 2;
  1260.     break;
  1261.       case BT_LEAD3:
  1262.     if (end - off < 3)
  1263.       throw new PartialCharException(off);
  1264.     if (!isNameChar3(buf, off))
  1265.       throw new InvalidTokenException(off);
  1266.     off += 3;
  1267.     break;
  1268.       case BT_LEAD4:
  1269.     if (end - off < 4)
  1270.       throw new PartialCharException(off);
  1271.     if (!isNameChar4(buf, off))
  1272.       throw new InvalidTokenException(off);
  1273.     off += 4;
  1274.     break;
  1275.       case BT_SEMI:
  1276.     token.nameEnd = off;
  1277.     token.tokenEnd = off + minBPC;
  1278.     return TOK_ENTITY_REF;
  1279.       default:
  1280.     throw new InvalidTokenException(off);
  1281.       }
  1282.     }
  1283.     throw new PartialTokenException();
  1284.   }
  1285.  
  1286.   /* off points to character following first character of attribute name */
  1287.  
  1288.   private final
  1289.   int scanAtts(int nameStart, byte[] buf, int off, int end, ContentToken token)
  1290.        throws PartialTokenException, InvalidTokenException {
  1291.     int nameEnd = -1;
  1292.     while (off != end) {
  1293.       switch (byteType(buf, off)) {
  1294.       case BT_NMSTRT:
  1295.       case BT_NAME:
  1296.       case BT_MINUS:
  1297.     off += minBPC;
  1298.     break;
  1299.       case BT_LEAD2:
  1300.     if (end - off < 2)
  1301.       throw new PartialCharException(off);
  1302.     if (!isNameChar2(buf, off))
  1303.       throw new InvalidTokenException(off);
  1304.     off += 2;
  1305.     break;
  1306.       case BT_LEAD3:
  1307.     if (end - off < 3)
  1308.       throw new PartialCharException(off);
  1309.     if (!isNameChar3(buf, off))
  1310.       throw new InvalidTokenException(off);
  1311.     off += 3;
  1312.     break;
  1313.       case BT_LEAD4:
  1314.     if (end - off < 4)
  1315.       throw new PartialCharException(off);
  1316.     if (!isNameChar4(buf, off))
  1317.       throw new InvalidTokenException(off);
  1318.     off += 4;
  1319.     break;
  1320.       case BT_S:
  1321.       case BT_CR:
  1322.       case BT_LF:
  1323.     nameEnd = off;
  1324.       loop:
  1325.     for (;;) {
  1326.       off += minBPC;
  1327.       if (off == end)
  1328.         throw new PartialTokenException();
  1329.       switch (byteType(buf, off)) {
  1330.       case BT_EQUALS:
  1331.         break loop;
  1332.       case BT_S:
  1333.       case BT_LF:
  1334.       case BT_CR:
  1335.         break;
  1336.       default:
  1337.         throw new InvalidTokenException(off);
  1338.       }
  1339.     }
  1340.     /* fall through */
  1341.       case BT_EQUALS:
  1342.     {
  1343.       if (nameEnd < 0)
  1344.         nameEnd = off;
  1345.       int open;
  1346.       for (;;) {
  1347.  
  1348.         off += minBPC;
  1349.         if (off == end)
  1350.           throw new PartialTokenException();
  1351.         open = byteType(buf, off);
  1352.         if (open == BT_QUOT || open == BT_APOS)
  1353.           break;
  1354.         switch (open) {
  1355.         case BT_S:
  1356.         case BT_LF:
  1357.         case BT_CR:
  1358.           break;
  1359.         default:
  1360.           throw new InvalidTokenException(off);
  1361.         }
  1362.       }
  1363.       off += minBPC;
  1364.       int valueStart = off;
  1365.       boolean normalized = true;
  1366.       /* in attribute value */
  1367.       for (;;) {
  1368.         int t;
  1369.         if (off == end)
  1370.           throw new PartialTokenException();
  1371.         t = byteType(buf, off);
  1372.         if (t == open)
  1373.           break;
  1374.         switch (t) {
  1375.         case BT_NONXML:
  1376.         case BT_MALFORM:
  1377.           throw new InvalidTokenException(off);
  1378.         case BT_LEAD2:
  1379.           if (end - off < 2)
  1380.         throw new PartialCharException(off);
  1381.           check2(buf, off);
  1382.           off += 2;
  1383.           break;
  1384.         case BT_LEAD3:
  1385.           if (end - off < 3)
  1386.         throw new PartialCharException(off);
  1387.           check3(buf, off);
  1388.           off += 3;
  1389.           break;
  1390.         case BT_LEAD4:
  1391.           if (end - off < 4)
  1392.         throw new PartialCharException(off);
  1393.           check4(buf, off);
  1394.           off += 4;
  1395.           break;
  1396.         case BT_AMP:
  1397.           {
  1398.         normalized = false;
  1399.         int saveNameEnd = token.nameEnd;
  1400.         scanRef(buf, off + minBPC, end, token);
  1401.         token.nameEnd = saveNameEnd;
  1402.         off = token.tokenEnd;
  1403.         break;
  1404.           }
  1405.         case BT_S:
  1406.           if (normalized
  1407.           && (off == valueStart
  1408.               || byteToAscii(buf, off) != ' '
  1409.               || (off + minBPC != end
  1410.               && (byteToAscii(buf, off + minBPC) == ' '
  1411.                   || byteType(buf, off + minBPC) == open))))
  1412.         normalized = false;
  1413.           off += minBPC;
  1414.           break;
  1415.         case BT_LT:
  1416.           throw new InvalidTokenException(off);
  1417.         case BT_LF:
  1418.         case BT_CR:
  1419.           normalized = false;
  1420.           /* fall through */
  1421.         default:
  1422.           off += minBPC;
  1423.           break;
  1424.         }
  1425.       }
  1426.       token.appendAttribute(nameStart, nameEnd, valueStart, off,
  1427.                 normalized);
  1428.       off += minBPC;
  1429.       if (off == end)
  1430.         throw new PartialTokenException();
  1431.       int t = byteType(buf, off);
  1432.       switch (t) {
  1433.       case BT_S:
  1434.       case BT_CR:
  1435.       case BT_LF:
  1436.         off += minBPC;
  1437.         if (off == end)
  1438.           throw new PartialTokenException();
  1439.         t = byteType(buf, off);
  1440.         break;
  1441.       case BT_GT:
  1442.       case BT_SOL:
  1443.         break;
  1444.       default:
  1445.         throw new InvalidTokenException(off);
  1446.       }
  1447.       /* off points to closing quote */
  1448.     skipToName:
  1449.       for (;;) {
  1450.         switch (t) {
  1451.         case BT_NMSTRT:
  1452.           nameStart = off;
  1453.           off += minBPC;
  1454.           break skipToName;
  1455.         case BT_LEAD2:
  1456.           if (end - off < 2)
  1457.         throw new PartialCharException(off);
  1458.           if (byteType2(buf, off) != BT_NMSTRT)
  1459.         throw new InvalidTokenException(off);
  1460.           nameStart = off;
  1461.           off += 2;
  1462.           break skipToName;
  1463.         case BT_LEAD3:
  1464.           if (end - off < 3)
  1465.         throw new PartialCharException(off);
  1466.           if (byteType3(buf, off) != BT_NMSTRT)
  1467.         throw new InvalidTokenException(off);
  1468.           nameStart = off;
  1469.           off += 3;
  1470.           break skipToName;
  1471.         case BT_LEAD4:
  1472.           if (end - off < 4)
  1473.         throw new PartialCharException(off);
  1474.           if (byteType4(buf, off) != BT_NMSTRT)
  1475.         throw new InvalidTokenException(off);
  1476.           nameStart = off;
  1477.           off += 4;
  1478.           break skipToName;
  1479.         case BT_S:
  1480.         case BT_CR:
  1481.         case BT_LF:
  1482.           break;
  1483.         case BT_GT:
  1484.           token.checkAttributeUniqueness(buf);
  1485.           token.tokenEnd = off + minBPC;
  1486.           return TOK_START_TAG_WITH_ATTS;
  1487.         case BT_SOL:
  1488.           off += minBPC;
  1489.           if (off == end)
  1490.         throw new PartialTokenException();
  1491.           checkCharMatches(buf, off, '>');
  1492.           token.checkAttributeUniqueness(buf);
  1493.           token.tokenEnd = off + minBPC;
  1494.           return TOK_EMPTY_ELEMENT_WITH_ATTS;
  1495.         default:
  1496.           throw new InvalidTokenException(off);
  1497.         }
  1498.         off += minBPC;
  1499.         if (off == end)
  1500.           throw new PartialTokenException();
  1501.         t = byteType(buf, off);
  1502.       }
  1503.       nameEnd = -1;
  1504.       break;
  1505.     }
  1506.       default:
  1507.     throw new InvalidTokenException(off);
  1508.       }
  1509.     }
  1510.     throw new PartialTokenException();
  1511.   }
  1512.  
  1513.   /* off points to character following "<" */
  1514.  
  1515.   private final
  1516.   int scanLt(byte[] buf, int off, int end, ContentToken token)
  1517.        throws PartialTokenException, InvalidTokenException {
  1518.     if (off == end)
  1519.       throw new PartialTokenException();
  1520.     switch (byteType(buf, off)) {
  1521.     case BT_NMSTRT:
  1522.       off += minBPC;
  1523.       break;
  1524.     case BT_LEAD2:
  1525.       if (end - off < 2)
  1526.     throw new PartialCharException(off);
  1527.       if (byteType2(buf, off) != BT_NMSTRT)
  1528.     throw new InvalidTokenException(off);
  1529.       off += 2;
  1530.       break;
  1531.     case BT_LEAD3:
  1532.       if (end - off < 3)
  1533.     throw new PartialCharException(off);
  1534.       if (byteType3(buf, off) != BT_NMSTRT)
  1535.     throw new InvalidTokenException(off);
  1536.       off += 3;
  1537.       break;
  1538.     case BT_LEAD4:
  1539.       if (end - off < 4)
  1540.     throw new PartialCharException(off);
  1541.       if (byteType4(buf, off) != BT_NMSTRT)
  1542.     throw new InvalidTokenException(off);
  1543.       off += 4;
  1544.       break;
  1545.     case BT_EXCL:
  1546.       if ((off += minBPC) == end)
  1547.     throw new PartialTokenException();
  1548.       switch (byteType(buf, off)) {
  1549.       case BT_MINUS:
  1550.     return scanComment(buf, off + minBPC, end, token);
  1551.       case BT_LSQB:
  1552.     return scanCdataSection(buf, off + minBPC, end, token);
  1553.       }
  1554.       throw new InvalidTokenException(off);
  1555.     case BT_QUEST:
  1556.       return scanPi(buf, off + minBPC, end, token);
  1557.     case BT_SOL:
  1558.       return scanEndTag(buf, off + minBPC, end, token);
  1559.     default:
  1560.       throw new InvalidTokenException(off);
  1561.     }
  1562.     /* we have a start-tag */
  1563.     token.nameEnd = -1;
  1564.     token.clearAttributes();
  1565.     while (off != end) {
  1566.       switch (byteType(buf, off)) {
  1567.       case BT_NMSTRT:
  1568.       case BT_NAME:
  1569.       case BT_MINUS:
  1570.     off += minBPC;
  1571.     break;
  1572.       case BT_LEAD2:
  1573.     if (end - off < 2)
  1574.       throw new PartialCharException(off);
  1575.     if (!isNameChar2(buf, off))
  1576.       throw new InvalidTokenException(off);
  1577.     off += 2;
  1578.     break;
  1579.       case BT_LEAD3:
  1580.     if (end - off < 3)
  1581.       throw new PartialCharException(off);
  1582.     if (!isNameChar3(buf, off))
  1583.       throw new InvalidTokenException(off);
  1584.     off += 3;
  1585.     break;
  1586.       case BT_LEAD4:
  1587.     if (end - off < 4)
  1588.       throw new PartialCharException(off);
  1589.     if (!isNameChar4(buf, off))
  1590.       throw new InvalidTokenException(off);
  1591.     off += 4;
  1592.     break;
  1593.       case BT_S:
  1594.       case BT_CR:
  1595.       case BT_LF:
  1596.     token.nameEnd = off;
  1597.     off += minBPC;
  1598.       loop:
  1599.     for (;;) {
  1600.       if (off == end)
  1601.         throw new PartialTokenException();
  1602.       switch (byteType(buf, off)) {
  1603.       case BT_NMSTRT:
  1604.         return scanAtts(off, buf, off + minBPC, end, token);
  1605.       case BT_LEAD2:
  1606.         if (end - off < 2)
  1607.           throw new PartialCharException(off);
  1608.         if (byteType2(buf, off) != BT_NMSTRT)
  1609.           throw new InvalidTokenException(off);
  1610.         return scanAtts(off, buf, off + 2, end, token);
  1611.       case BT_LEAD3:
  1612.         if (end - off < 3)
  1613.           throw new PartialCharException(off);
  1614.         if (byteType3(buf, off) != BT_NMSTRT)
  1615.           throw new InvalidTokenException(off);
  1616.         return scanAtts(off, buf, off + 3, end, token);
  1617.       case BT_LEAD4:
  1618.         if (end - off < 4)
  1619.           throw new PartialCharException(off);
  1620.         if (byteType4(buf, off) != BT_NMSTRT)
  1621.           throw new InvalidTokenException(off);
  1622.         return scanAtts(off, buf, off + 4, end, token);
  1623.       case BT_GT:
  1624.       case BT_SOL:
  1625.         break loop;
  1626.       case BT_S:
  1627.       case BT_CR:
  1628.       case BT_LF:
  1629.         off += minBPC;
  1630.         break;
  1631.       default:
  1632.         throw new InvalidTokenException(off);
  1633.       }
  1634.     }
  1635.     break;
  1636.       case BT_GT:
  1637.     if (token.nameEnd < 0)
  1638.       token.nameEnd = off;
  1639.     token.tokenEnd = off + minBPC;
  1640.     return TOK_START_TAG_NO_ATTS;
  1641.       case BT_SOL:
  1642.     if (token.nameEnd < 0)
  1643.       token.nameEnd = off;
  1644.     off += minBPC;
  1645.     if (off == end)
  1646.       throw new PartialTokenException();
  1647.     checkCharMatches(buf, off, '>');
  1648.     token.tokenEnd = off + minBPC;
  1649.     return TOK_EMPTY_ELEMENT_NO_ATTS;
  1650.       default:
  1651.     throw new InvalidTokenException(off);
  1652.       }
  1653.     }
  1654.     throw new PartialTokenException();
  1655.   }
  1656.  
  1657.   // Ensure that we always scan a multiple of minBPC bytes.
  1658.  
  1659.   private final int adjustEnd(int off, int end) throws PartialCharException {
  1660.     int n = end - off;
  1661.     if ((n & (minBPC - 1)) != 0) {
  1662.       n &= ~(minBPC - 1);
  1663.       if (n == 0)
  1664.     throw new PartialCharException(off);
  1665.       return off + n;
  1666.     }
  1667.     else
  1668.       return end;
  1669.   }
  1670.  
  1671.   /**
  1672.    * Scans the first token of a byte subarrary that contains content.
  1673.    * Returns one of the following integers according to the type of token
  1674.    * that the subarray starts with:
  1675.    * <ul>
  1676.    * <li><code>TOK_START_TAG_NO_ATTS</code>
  1677.    * <li><code>TOK_START_TAG_WITH_ATTS</code>
  1678.    * <li><code>TOK_EMPTY_ELEMENT_NO_ATTS</code>
  1679.    * <li><code>TOK_EMPTY_ELEMENT_WITH_ATTS</code>
  1680.    * <li><code>TOK_END_TAG</code>
  1681.    * <li><code>TOK_DATA_CHARS</code>
  1682.    * <li><code>TOK_DATA_NEWLINE</code>
  1683.    * <li><code>TOK_CDATA_SECT_OPEN</code>
  1684.    * <li><code>TOK_ENTITY_REF</code>
  1685.    * <li><code>TOK_MAGIC_ENTITY_REF</code>
  1686.    * <li><code>TOK_CHAR_REF</code>
  1687.    * <li><code>TOK_CHAR_PAIR_REF</code>
  1688.    * <li><code>TOK_PI</code>
  1689.    * <li><code>TOK_XML_DECL</code>
  1690.    * <li><code>TOK_COMMENT</code>
  1691.    * </ul>
  1692.    * <p>
  1693.    * Information about the token is stored in <code>token</code>.
  1694.    * <p>
  1695.    * When <code>TOK_CDATA_SECT_OPEN</code> is returned,
  1696.    * <code>tokenizeCdataSection</code> should be called until
  1697.    * it returns <code>TOK_CDATA_SECT</code>.
  1698.    *
  1699.    * @exception EmptyTokenException if the subarray is empty
  1700.    * @exception PartialTokenException if the subarray contains only part of
  1701.    * a legal token
  1702.    * @exception InvalidTokenException if the subarrary does not start
  1703.    * with a legal token or part of one
  1704.    * @exception ExtensibleTokenException if the subarray encodes just a carriage
  1705.    * return ('\r')
  1706.    *
  1707.    * @see #TOK_START_TAG_NO_ATTS
  1708.    * @see #TOK_START_TAG_WITH_ATTS
  1709.    * @see #TOK_EMPTY_ELEMENT_NO_ATTS
  1710.    * @see #TOK_EMPTY_ELEMENT_WITH_ATTS
  1711.    * @see #TOK_END_TAG
  1712.    * @see #TOK_DATA_CHARS
  1713.    * @see #TOK_DATA_NEWLINE
  1714.    * @see #TOK_CDATA_SECT_OPEN
  1715.    * @see #TOK_ENTITY_REF
  1716.    * @see #TOK_MAGIC_ENTITY_REF
  1717.    * @see #TOK_CHAR_REF
  1718.    * @see #TOK_CHAR_PAIR_REF
  1719.    * @see #TOK_PI
  1720.    * @see #TOK_XML_DECL
  1721.    * @see #TOK_COMMENT
  1722.    * @see ContentToken
  1723.    * @see EmptyTokenException
  1724.    * @see PartialTokenException
  1725.    * @see InvalidTokenException
  1726.    * @see ExtensibleTokenException
  1727.    * @see #tokenizeCdataSection
  1728.    */
  1729.   public final int tokenizeContent(byte[] buf, int off, int end, ContentToken token)
  1730.        throws PartialTokenException, InvalidTokenException, EmptyTokenException, ExtensibleTokenException {
  1731.  
  1732.     if (minBPC > 1)
  1733.       end = adjustEnd(off, end);
  1734.     if (off == end)
  1735.       throw new EmptyTokenException();
  1736.     switch (byteType(buf, off)) {
  1737.     case BT_LT:
  1738.       return scanLt(buf, off + minBPC, end, token);
  1739.     case BT_AMP:
  1740.       return scanRef(buf, off + minBPC, end, token);
  1741.     case BT_CR:
  1742.       off += minBPC;
  1743.       if (off == end)
  1744.     throw new ExtensibleTokenException(TOK_DATA_NEWLINE);
  1745.       if (byteType(buf, off) == BT_LF)
  1746.     off += minBPC;
  1747.       token.tokenEnd = off;
  1748.       return TOK_DATA_NEWLINE;
  1749.     case BT_LF:
  1750.       token.tokenEnd = off + minBPC;
  1751.       return TOK_DATA_NEWLINE;
  1752.     case BT_RSQB:
  1753.       off += minBPC;
  1754.       if (off == end)
  1755.     throw new ExtensibleTokenException(TOK_DATA_CHARS);
  1756.       if (!charMatches(buf, off, ']'))
  1757.     break;
  1758.       off += minBPC;
  1759.       if (off == end)
  1760.     throw new ExtensibleTokenException(TOK_DATA_CHARS);
  1761.       if (!charMatches(buf, off, '>')) {
  1762.     off -= minBPC;
  1763.     break;
  1764.       }
  1765.       throw new InvalidTokenException(off);
  1766.     case BT_NONXML:
  1767.     case BT_MALFORM:
  1768.       throw new InvalidTokenException(off);
  1769.     case BT_LEAD2:
  1770.       if (end - off < 2)
  1771.     throw new PartialCharException(off);
  1772.       check2(buf, off);
  1773.       off += 2;
  1774.       break;
  1775.     case BT_LEAD3:
  1776.       if (end - off < 3)
  1777.     throw new PartialCharException(off);
  1778.       check3(buf, off);
  1779.       off += 3;
  1780.       break;
  1781.     case BT_LEAD4:
  1782.       if (end - off < 4)
  1783.     throw new PartialCharException(off);
  1784.       check4(buf, off);
  1785.       off += 4;
  1786.       break;
  1787.     default:
  1788.       off += minBPC;
  1789.       break;
  1790.     }
  1791.     token.tokenEnd = extendData(buf, off, end);
  1792.     return TOK_DATA_CHARS;
  1793.   }
  1794.  
  1795.   int extendData(final byte[] buf, int off, final int end) throws InvalidTokenException {
  1796.     while (off != end) {
  1797.       switch (byteType(buf, off)) {
  1798.       case BT_LEAD2:
  1799.     if (end - off < 2)
  1800.       return off;
  1801.     check2(buf, off);
  1802.     off += 2;
  1803.     break;
  1804.       case BT_LEAD3:
  1805.     if (end - off < 3)
  1806.       return off;
  1807.     check3(buf, off);
  1808.     off += 3;
  1809.     break;
  1810.       case BT_LEAD4:
  1811.     if (end - off < 4)
  1812.       return off;
  1813.     check4(buf, off);
  1814.     off += 4;
  1815.     break;
  1816.       case BT_RSQB:
  1817.       case BT_AMP:
  1818.       case BT_LT:
  1819.       case BT_NONXML:
  1820.       case BT_MALFORM:
  1821.       case BT_CR:
  1822.       case BT_LF:
  1823.     return off;
  1824.       default:
  1825.     off += minBPC;
  1826.     break;
  1827.       }
  1828.     }
  1829.     return off;
  1830.   }
  1831.  
  1832.   /* off points to character following "%" */
  1833.  
  1834.   private final
  1835.   int scanPercent(byte[] buf, int off, int end, Token token)
  1836.        throws PartialTokenException, InvalidTokenException {
  1837.     if (off == end)
  1838.       throw new PartialTokenException();
  1839.     switch (byteType(buf, off)) {
  1840.     case BT_NMSTRT:
  1841.       off += minBPC;
  1842.       break;
  1843.     case BT_LEAD2:
  1844.       if (end - off < 2)
  1845.     throw new PartialCharException(off);
  1846.       if (byteType2(buf, off) != BT_NMSTRT)
  1847.     throw new InvalidTokenException(off);
  1848.       off += 2;
  1849.       break;
  1850.     case BT_LEAD3:
  1851.       if (end - off < 3)
  1852.     throw new PartialCharException(off);
  1853.       if (byteType3(buf, off) != BT_NMSTRT)
  1854.     throw new InvalidTokenException(off);
  1855.       off += 3;
  1856.       break;
  1857.     case BT_LEAD4:
  1858.       if (end - off < 4)
  1859.     throw new PartialCharException(off);
  1860.       if (byteType4(buf, off) != BT_NMSTRT)
  1861.     throw new InvalidTokenException(off);
  1862.       off += 4;
  1863.       break;
  1864.     case BT_S:
  1865.     case BT_LF:
  1866.     case BT_CR:
  1867.     case BT_PERCNT:
  1868.       token.tokenEnd = off;
  1869.       return TOK_PERCENT;
  1870.     default:
  1871.       throw new InvalidTokenException(off);
  1872.     }
  1873.     while (off != end) {
  1874.       switch (byteType(buf, off)) {
  1875.       case BT_NMSTRT:
  1876.       case BT_NAME:
  1877.       case BT_MINUS:
  1878.     off += minBPC;
  1879.     break;
  1880.       case BT_LEAD2:
  1881.     if (end - off < 2)
  1882.       throw new PartialCharException(off);
  1883.     if (!isNameChar2(buf, off))
  1884.       throw new InvalidTokenException(off);
  1885.     off += 2;
  1886.     break;
  1887.       case BT_LEAD3:
  1888.     if (end - off < 3)
  1889.       throw new PartialCharException(off);
  1890.     if (!isNameChar3(buf, off))
  1891.       throw new InvalidTokenException(off);
  1892.     off += 3;
  1893.     break;
  1894.       case BT_LEAD4:
  1895.     if (end - off < 4)
  1896.       throw new PartialCharException(off);
  1897.     if (!isNameChar4(buf, off))
  1898.       throw new InvalidTokenException(off);
  1899.     off += 4;
  1900.     break;
  1901.       case BT_SEMI:
  1902.     token.nameEnd = off;
  1903.     token.tokenEnd = off + minBPC;
  1904.     return TOK_PARAM_ENTITY_REF;
  1905.       default:
  1906.     throw new InvalidTokenException(off);
  1907.       }
  1908.     }
  1909.     throw new PartialTokenException();
  1910.   }
  1911.  
  1912.  
  1913.   private final
  1914.   int scanPoundName(byte[] buf, int off, int end, Token token)
  1915.        throws PartialTokenException, InvalidTokenException, ExtensibleTokenException {
  1916.     if (off == end)
  1917.       throw new PartialTokenException();
  1918.     switch (byteType(buf, off)) {
  1919.     case BT_NMSTRT:
  1920.       off += minBPC;
  1921.       break;
  1922.     case BT_LEAD2:
  1923.       if (end - off < 2)
  1924.     throw new PartialCharException(off);
  1925.       if (byteType2(buf, off) != BT_NMSTRT)
  1926.     throw new InvalidTokenException(off);
  1927.       off += 2;
  1928.       break;
  1929.     case BT_LEAD3:
  1930.       if (end - off < 3)
  1931.     throw new PartialCharException(off);
  1932.       if (byteType3(buf, off) != BT_NMSTRT)
  1933.     throw new InvalidTokenException(off);
  1934.       off += 3;
  1935.       break;
  1936.     case BT_LEAD4:
  1937.       if (end - off < 4)
  1938.     throw new PartialCharException(off);
  1939.       if (byteType4(buf, off) != BT_NMSTRT)
  1940.     throw new InvalidTokenException(off);
  1941.       off += 4;
  1942.       break;
  1943.     default:
  1944.       throw new InvalidTokenException(off);
  1945.     }
  1946.     while (off != end) {
  1947.       switch (byteType(buf, off)) {
  1948.       case BT_NMSTRT:
  1949.       case BT_NAME:
  1950.       case BT_MINUS:
  1951.     off += minBPC;
  1952.     break;
  1953.       case BT_LEAD2:
  1954.     if (end - off < 2)
  1955.       throw new PartialCharException(off);
  1956.     if (!isNameChar2(buf, off))
  1957.       throw new InvalidTokenException(off);
  1958.     off += 2;
  1959.     break;
  1960.       case BT_LEAD3:
  1961.     if (end - off < 3)
  1962.       throw new PartialCharException(off);
  1963.     if (!isNameChar3(buf, off))
  1964.       throw new InvalidTokenException(off);
  1965.     off += 3;
  1966.     break;
  1967.       case BT_LEAD4:
  1968.     if (end - off < 4)
  1969.       throw new PartialCharException(off);
  1970.     if (!isNameChar4(buf, off))
  1971.       throw new InvalidTokenException(off);
  1972.     off += 4;
  1973.     break;
  1974.       case BT_CR:
  1975.       case BT_LF:
  1976.       case BT_S:
  1977.       case BT_RPAR:
  1978.       case BT_GT:
  1979.       case BT_PERCNT:
  1980.       case BT_VERBAR:
  1981.     token.tokenEnd = off;
  1982.     return TOK_POUND_NAME;
  1983.       default:
  1984.     throw new InvalidTokenException(off);
  1985.       }
  1986.     }
  1987.     throw new ExtensibleTokenException(TOK_POUND_NAME);
  1988.   }
  1989.  
  1990.   private final
  1991.   int scanLit(int open, byte[] buf, int off, int end, Token token)
  1992.        throws PartialTokenException, InvalidTokenException, ExtensibleTokenException {
  1993.     while (off != end) {
  1994.       int t = byteType(buf, off);
  1995.       switch (t) {
  1996.       case BT_LEAD2:
  1997.     if (end - off < 2)
  1998.       throw new PartialTokenException();
  1999.     check2(buf, off);
  2000.     off += 2;
  2001.     break;
  2002.       case BT_LEAD3:
  2003.     if (end - off < 3)
  2004.       throw new PartialTokenException();
  2005.     check3(buf, off);
  2006.     off += 3;
  2007.     break;
  2008.       case BT_LEAD4:
  2009.     if (end - off < 4)
  2010.       throw new PartialTokenException();
  2011.     check4(buf, off);
  2012.     off += 4;
  2013.     break;
  2014.       case BT_NONXML:
  2015.       case BT_MALFORM:
  2016.     throw new InvalidTokenException(off);
  2017.       case BT_QUOT:
  2018.       case BT_APOS:
  2019.     off += minBPC;
  2020.     if (t != open)
  2021.       break;
  2022.     if (off == end)
  2023.       throw new ExtensibleTokenException(TOK_LITERAL);
  2024.     switch (byteType(buf, off)) {
  2025.     case BT_S:
  2026.     case BT_CR:
  2027.     case BT_LF:
  2028.     case BT_GT:
  2029.     case BT_PERCNT:
  2030.     case BT_LSQB:
  2031.       token.tokenEnd = off;
  2032.       return TOK_LITERAL;
  2033.     default:
  2034.       throw new InvalidTokenException(off);
  2035.     }
  2036.       default:
  2037.     off += minBPC;
  2038.     break;
  2039.       }
  2040.     }
  2041.     throw new PartialTokenException();
  2042.   }
  2043.  
  2044.   /**
  2045.    * Returns an encoding object to be used to start parsing an external entity.
  2046.    * The encoding is chosen based on the initial 4 bytes of the entity.
  2047.    *
  2048.    * @param buf the byte array containing the initial bytes of the entity
  2049.    * @param off the index in <code>buf</code> of the first byte of the entity
  2050.    * @param end the index in <code>buf</code> following the last available
  2051.    * byte of the entity; <code>end - off</code> must be greater than or equal
  2052.    * to 4 unless the entity has fewer that 4 bytes, in which case it must
  2053.    * be equal to the length of the entity
  2054.    * @param token receives information about the presence of a byte order
  2055.    * mark; if the entity starts with a byte order mark
  2056.    * then <code>token.getTokenEnd()</code>
  2057.    * will return <code>off + 2</code>, otherwise it will return
  2058.    * <code>off</code>
  2059.    *
  2060.    * @see TextDecl
  2061.    * @see XmlDecl
  2062.    * @see #TOK_XML_DECL
  2063.    * @see #getEncoding
  2064.    * @see #getInternalEncoding
  2065.    */
  2066.   public static final
  2067.   Encoding getInitialEncoding(byte[] buf, int off, int end, Token token) {
  2068.     token.tokenEnd = off;
  2069.     switch (end - off) {
  2070.     case 0:
  2071.       break;
  2072.     case 1:
  2073.       if (buf[off] < 0)
  2074.     return null;
  2075.       break;
  2076.     default:
  2077.       int b0 = buf[off] & 0xFF;
  2078.       int b1 = buf[off + 1] & 0xFF;
  2079.       switch ((b0 << 8) | b1) {
  2080.       case 0xFEFF:
  2081.     token.tokenEnd = off + 2;
  2082.     /* fall through */
  2083.       case '<': /* not legal; but not a fatal error */
  2084.     return getEncoding(UTF16_BIG_ENDIAN_ENCODING);
  2085.       case 0xFFFE:
  2086.     token.tokenEnd = off + 2;
  2087.     /* fall through */
  2088.       case '<' << 8:  /* not legal; but not a fatal error */
  2089.     return getEncoding(UTF16_LITTLE_ENDIAN_ENCODING);
  2090.       }
  2091.     }
  2092.     return getEncoding(UTF8_ENCODING);
  2093.   }
  2094.  
  2095.   /**
  2096.    * Returns an <code>Encoding</code> corresponding to
  2097.    * the specified IANA character set name.
  2098.    * Returns this <code>Encoding</code> if the name is null.
  2099.    * Returns null if the specified encoding is not supported.
  2100.    * Note that there are two distinct <code>Encoding</code> objects
  2101.    * associated with the name <code>UTF-16</code>, one for
  2102.    * each possible byte order; if this <code>Encoding</code>
  2103.    * is UTF-16 with little-endian byte ordering, then
  2104.    * <code>getEncoding("UTF-16")</code> will return this,
  2105.    * otherwise it will return an <code>Encoding</code> for
  2106.    * UTF-16 with big-endian byte ordering.
  2107.    * @param name a string specifying the IANA name of the encoding; this is
  2108.    * case insensitive
  2109.    */
  2110.   public final
  2111.   Encoding getEncoding(String name) {
  2112.     if (name == null)
  2113.       return this;
  2114.     if (name.equalsIgnoreCase("UTF-8"))
  2115.       return getEncoding(UTF8_ENCODING);
  2116.     if (name.equalsIgnoreCase("UTF-16"))
  2117.       return getUTF16Encoding();
  2118.     if (name.equalsIgnoreCase("ISO-8859-1"))
  2119.       return getEncoding(ISO8859_1_ENCODING);
  2120.     if (name.equalsIgnoreCase("US-ASCII"))
  2121.       return getEncoding(ASCII_ENCODING);
  2122.     if (name.equalsIgnoreCase("windows-1250"))
  2123.       return getEncoding(WINDOWS1250_ENCODING);
  2124.     if (name.equalsIgnoreCase("ISO-8859-2"))
  2125.       return getEncoding(ISO8859_2_ENCODING);
  2126.     return null;
  2127.   }
  2128.  
  2129.   /**
  2130.    * Returns an <code>Encoding</code> for entities encoded with
  2131.    * a single-byte encoding (an encoding in which each byte represents
  2132.    * exactly one character).
  2133.    * @param map a string specifying the character represented by each byte;
  2134.    * the string must have a length of 256; <code>map.charAt(b)</code>
  2135.    * specifies the character encoded by byte <code>b</code>; bytes that do
  2136.    * not represent any character should be mapped to <code>\uFFFD</code>
  2137.    */
  2138.   public final
  2139.   Encoding getSingleByteEncoding(String map) {
  2140.     return new SingleByteEncoding(map);
  2141.   }
  2142.  
  2143.   /**
  2144.    * Returns an <code>Encoding</code> object for use with internal entities.
  2145.    * This is a UTF-16 big endian encoding, except that newlines
  2146.    * are assumed to have been normalized into line feed,
  2147.    * so carriage return is treated like a space.
  2148.    */
  2149.   public final static
  2150.   Encoding getInternalEncoding() {
  2151.     return getEncoding(INTERNAL_ENCODING);
  2152.   }
  2153.  
  2154.   /**
  2155.    * Scans the first token of a byte subarray that contains part of a
  2156.    * prolog.
  2157.    * Returns one of the following integers according to the type of token
  2158.    * that the subarray starts with:
  2159.    * <ul>
  2160.    * <li><code>TOK_PI</code>
  2161.    * <li><code>TOK_XML_DECL</code>
  2162.    * <li><code>TOK_COMMENT</code>
  2163.    * <li><code>TOK_PARAM_ENTITY_REF</code>
  2164.    * <li><code>TOK_PROLOG_S</code>
  2165.    * <li><code>TOK_DECL_OPEN</code>
  2166.    * <li><code>TOK_DECL_CLOSE</code>
  2167.    * <li><code>TOK_NAME</code>
  2168.    * <li><code>TOK_NMTOKEN</code>
  2169.    * <li><code>TOK_POUND_NAME</code>
  2170.    * <li><code>TOK_OR</code>
  2171.    * <li><code>TOK_PERCENT</code>
  2172.    * <li><code>TOK_OPEN_PAREN</code>
  2173.    * <li><code>TOK_CLOSE_PAREN</code>
  2174.    * <li><code>TOK_OPEN_BRACKET</code>
  2175.    * <li><code>TOK_CLOSE_BRACKET</code>
  2176.    * <li><code>TOK_LITERAL</code>
  2177.    * <li><code>TOK_NAME_QUESTION</code>
  2178.    * <li><code>TOK_NAME_ASTERISK</code>
  2179.    * <li><code>TOK_NAME_PLUS</code>
  2180.    * <li><code>TOK_COND_SECT_OPEN</code>
  2181.    * <li><code>TOK_COND_SECT_CLOSE</code>
  2182.    * <li><code>TOK_CLOSE_PAREN_QUESTION</code>
  2183.    * <li><code>TOK_CLOSE_PAREN_ASTERISK</code>
  2184.    * <li><code>TOK_CLOSE_PAREN_PLUS</code>
  2185.    * <li><code>TOK_COMMA</code>
  2186.    * </ul>
  2187.    * @exception EmptyTokenException if the subarray is empty
  2188.    * @exception PartialTokenException if the subarray contains only part of
  2189.    * a legal token
  2190.    * @exception InvalidTokenException if the subarrary does not start
  2191.    * with a legal token or part of one
  2192.    * @exception EndOfPrologException if the subarray starts with the document
  2193.    * element; <code>tokenizeContent</code> should be used on the remainder
  2194.    * of the entity
  2195.    * @exception ExtensibleTokenException if the subarray is a legal token
  2196.    * but subsequent bytes in the same entity could be part of the token
  2197.    * @see #TOK_PI
  2198.    * @see #TOK_XML_DECL
  2199.    * @see #TOK_COMMENT
  2200.    * @see #TOK_PARAM_ENTITY_REF
  2201.    * @see #TOK_PROLOG_S
  2202.    * @see #TOK_DECL_OPEN
  2203.    * @see #TOK_DECL_CLOSE
  2204.    * @see #TOK_NAME
  2205.    * @see #TOK_NMTOKEN
  2206.    * @see #TOK_POUND_NAME
  2207.    * @see #TOK_OR
  2208.    * @see #TOK_PERCENT
  2209.    * @see #TOK_OPEN_PAREN
  2210.    * @see #TOK_CLOSE_PAREN
  2211.    * @see #TOK_OPEN_BRACKET
  2212.    * @see #TOK_CLOSE_BRACKET
  2213.    * @see #TOK_LITERAL
  2214.    * @see #TOK_NAME_QUESTION
  2215.    * @see #TOK_NAME_ASTERISK
  2216.    * @see #TOK_NAME_PLUS
  2217.    * @see #TOK_COND_SECT_OPEN
  2218.    * @see #TOK_COND_SECT_CLOSE
  2219.    * @see #TOK_CLOSE_PAREN_QUESTION
  2220.    * @see #TOK_CLOSE_PAREN_ASTERISK
  2221.    * @see #TOK_CLOSE_PAREN_PLUS
  2222.    * @see #TOK_COMMA
  2223.    * @see ContentToken
  2224.    * @see EmptyTokenException
  2225.    * @see PartialTokenException
  2226.    * @see InvalidTokenException
  2227.    * @see ExtensibleTokenException
  2228.    * @see EndOfPrologException
  2229.    */
  2230.  
  2231.   public final
  2232.   int tokenizeProlog(byte[] buf, int off, int end, Token token)
  2233.        throws PartialTokenException,
  2234.               InvalidTokenException,
  2235.               EmptyTokenException,
  2236.               ExtensibleTokenException,
  2237.               EndOfPrologException {
  2238.     int tok;
  2239.     if (minBPC > 1)
  2240.       end = adjustEnd(off, end);
  2241.     if (off == end)
  2242.       throw new EmptyTokenException();
  2243.     switch (byteType(buf, off)) {
  2244.     case BT_QUOT:
  2245.       return scanLit(BT_QUOT, buf, off + minBPC, end, token);
  2246.     case BT_APOS:
  2247.       return scanLit(BT_APOS, buf, off + minBPC, end, token);
  2248.     case BT_LT:
  2249.       {
  2250.     off += minBPC;
  2251.     if (off == end)
  2252.       throw new PartialTokenException();
  2253.     switch (byteType(buf, off)) {
  2254.     case BT_EXCL:
  2255.       return scanDecl(buf, off + minBPC, end, token);
  2256.     case BT_QUEST:
  2257.       return scanPi(buf, off + minBPC, end, token);
  2258.     case BT_NMSTRT:
  2259.     case BT_LEAD2:
  2260.     case BT_LEAD3:
  2261.     case BT_LEAD4:
  2262.       token.tokenEnd = off - minBPC;
  2263.       throw new EndOfPrologException();
  2264.     }
  2265.     throw new InvalidTokenException(off);
  2266.       }
  2267.     case BT_CR:
  2268.       if (off + minBPC == end)
  2269.     throw new ExtensibleTokenException(TOK_PROLOG_S);
  2270.       /* fall through */
  2271.     case BT_S:
  2272.     case BT_LF:
  2273.       for (;;) {
  2274.     off += minBPC;
  2275.     if (off == end)
  2276.       break;
  2277.     switch (byteType(buf, off)) {
  2278.     case BT_S:
  2279.     case BT_LF:
  2280.       break;
  2281.     case BT_CR:
  2282.       /* don't split CR/LF pair */
  2283.       if (off + minBPC != end)
  2284.         break;
  2285.       /* fall through */
  2286.     default:
  2287.       token.tokenEnd = off;
  2288.       return TOK_PROLOG_S;
  2289.     }
  2290.       }
  2291.       token.tokenEnd = off;
  2292.       return TOK_PROLOG_S;
  2293.     case BT_PERCNT:
  2294.       return scanPercent(buf, off + minBPC, end, token);
  2295.     case BT_COMMA:
  2296.       token.tokenEnd = off + minBPC;
  2297.       return TOK_COMMA;
  2298.     case BT_LSQB:
  2299.       token.tokenEnd = off + minBPC;
  2300.       return TOK_OPEN_BRACKET;
  2301.     case BT_RSQB:
  2302.       off += minBPC;
  2303.       if (off == end)
  2304.     throw new ExtensibleTokenException(TOK_CLOSE_BRACKET);
  2305.       if (charMatches(buf, off, ']')) {
  2306.     if (off + minBPC == end)
  2307.       throw new PartialTokenException();
  2308.     if (charMatches(buf, off + minBPC, '>')) {
  2309.       token.tokenEnd = off + 2*minBPC;
  2310.       return TOK_COND_SECT_CLOSE;
  2311.     }
  2312.       }
  2313.       token.tokenEnd = off;
  2314.       return TOK_CLOSE_BRACKET;
  2315.     case BT_LPAR:
  2316.       token.tokenEnd = off + minBPC;
  2317.       return TOK_OPEN_PAREN;
  2318.     case BT_RPAR:
  2319.       off += minBPC;
  2320.       if (off == end)
  2321.     throw new ExtensibleTokenException(TOK_CLOSE_PAREN);
  2322.       switch (byteType(buf, off)) {
  2323.       case BT_AST:
  2324.     token.tokenEnd = off + minBPC;
  2325.     return TOK_CLOSE_PAREN_ASTERISK;
  2326.       case BT_QUEST:
  2327.     token.tokenEnd = off + minBPC;
  2328.     return TOK_CLOSE_PAREN_QUESTION;
  2329.       case BT_PLUS:
  2330.     token.tokenEnd = off + minBPC;
  2331.     return TOK_CLOSE_PAREN_PLUS;
  2332.       case BT_CR:
  2333.       case BT_LF:
  2334.       case BT_S:
  2335.       case BT_GT:
  2336.       case BT_COMMA:
  2337.       case BT_VERBAR:
  2338.       case BT_RPAR:
  2339.     token.tokenEnd = off;
  2340.     return TOK_CLOSE_PAREN;
  2341.       }
  2342.       throw new InvalidTokenException(off);
  2343.     case BT_VERBAR:
  2344.       token.tokenEnd = off + minBPC;
  2345.       return TOK_OR;
  2346.     case BT_GT:
  2347.       token.tokenEnd = off + minBPC;
  2348.       return TOK_DECL_CLOSE;
  2349.     case BT_NUM:
  2350.       return scanPoundName(buf, off + minBPC, end, token);
  2351.     case BT_LEAD2:
  2352.       if (end - off < 2)
  2353.     throw new PartialCharException(off);
  2354.       switch (byteType2(buf, off)) {
  2355.       case BT_NMSTRT:
  2356.     off += 2;
  2357.     tok = TOK_NAME;
  2358.     break;
  2359.       case BT_NAME:
  2360.     off += 2;
  2361.     tok = TOK_NMTOKEN;
  2362.     break;
  2363.       default:
  2364.     throw new InvalidTokenException(off);
  2365.       }
  2366.       break;
  2367.     case BT_LEAD3:
  2368.       if (end - off < 3)
  2369.     throw new PartialCharException(off);
  2370.       switch (byteType3(buf, off)) {
  2371.       case BT_NMSTRT:
  2372.     off += 3;
  2373.     tok = TOK_NAME;
  2374.     break;
  2375.       case BT_NAME:
  2376.     off += 3;
  2377.     tok = TOK_NMTOKEN;
  2378.     break;
  2379.       default:
  2380.     throw new InvalidTokenException(off);
  2381.       }
  2382.       break;
  2383.     case BT_LEAD4:
  2384.       if (end - off < 4)
  2385.     throw new PartialCharException(off);
  2386.       switch (byteType4(buf, off)) {
  2387.       case BT_NMSTRT:
  2388.     off += 4;
  2389.     tok = TOK_NAME;
  2390.     break;
  2391.       case BT_NAME:
  2392.     off += 4;
  2393.     tok = TOK_NMTOKEN;
  2394.     break;
  2395.       default:
  2396.     throw new InvalidTokenException(off);
  2397.       }
  2398.       break;
  2399.     case BT_NMSTRT:
  2400.       tok = TOK_NAME;
  2401.       off += minBPC;
  2402.       break;
  2403.     case BT_NAME:
  2404.     case BT_MINUS:
  2405.       tok = TOK_NMTOKEN;
  2406.       off += minBPC;
  2407.       break;
  2408.     default:
  2409.       throw new InvalidTokenException(off);
  2410.     }
  2411.     while (off != end) {
  2412.       switch (byteType(buf, off)) {
  2413.       case BT_NMSTRT:
  2414.       case BT_NAME:
  2415.       case BT_MINUS:
  2416.     off += minBPC;
  2417.     break;
  2418.       case BT_LEAD2:
  2419.     if (end - off < 2)
  2420.       throw new PartialCharException(off);
  2421.     if (!isNameChar2(buf, off))
  2422.       throw new InvalidTokenException(off);
  2423.     off += 2;
  2424.     break;
  2425.       case BT_LEAD3:
  2426.     if (end - off < 3)
  2427.       throw new PartialCharException(off);
  2428.     if (!isNameChar3(buf, off))
  2429.       throw new InvalidTokenException(off);
  2430.     off += 3;
  2431.     break;
  2432.       case BT_LEAD4:
  2433.     if (end - off < 4)
  2434.       throw new PartialCharException(off);
  2435.     if (!isNameChar4(buf, off))
  2436.       throw new InvalidTokenException(off);
  2437.     off += 4;
  2438.     break;
  2439.       case BT_GT:
  2440.       case BT_RPAR:
  2441.       case BT_COMMA:
  2442.       case BT_VERBAR:
  2443.       case BT_LSQB:
  2444.       case BT_PERCNT:
  2445.       case BT_S:
  2446.       case BT_CR:
  2447.       case BT_LF:
  2448.     token.tokenEnd = off;
  2449.     return tok;
  2450.       case BT_PLUS:
  2451.     if (tok != TOK_NAME)
  2452.       throw new InvalidTokenException(off);
  2453.     token.tokenEnd = off + minBPC;
  2454.     return TOK_NAME_PLUS;
  2455.       case BT_AST:
  2456.     if (tok != TOK_NAME)
  2457.       throw new InvalidTokenException(off);
  2458.     token.tokenEnd = off + minBPC;
  2459.     return TOK_NAME_ASTERISK;
  2460.       case BT_QUEST:
  2461.     if (tok != TOK_NAME)
  2462.       throw new InvalidTokenException(off);
  2463.     token.tokenEnd = off + minBPC;
  2464.     return TOK_NAME_QUESTION;
  2465.       default:
  2466.     throw new InvalidTokenException(off);
  2467.       }
  2468.     }
  2469.     throw new ExtensibleTokenException(tok);
  2470.   }
  2471.  
  2472.   /**
  2473.    * Scans the first token of a byte subarrary that contains part of
  2474.    * literal attribute value.  The opening and closing delimiters
  2475.    * are not included in the subarrary.
  2476.    * Returns one of the following integers according to the type of
  2477.    * token that the subarray starts with:
  2478.    * <ul>
  2479.    * <li><code>TOK_DATA_CHARS</code>
  2480.    * <li><code>TOK_DATA_NEWLINE</code>
  2481.    * <li><code>TOK_ATTRIBUTE_VALUE_S</code>
  2482.    * <li><code>TOK_MAGIC_ENTITY_REF</code>
  2483.    * <li><code>TOK_ENTITY_REF</code>
  2484.    * <li><code>TOK_CHAR_REF</code>
  2485.    * <li><code>TOK_CHAR_PAIR_REF</code>
  2486.    * </ul>
  2487.    * @exception EmptyTokenException if the subarray is empty
  2488.    * @exception PartialTokenException if the subarray contains only part of
  2489.    * a legal token
  2490.    * @exception InvalidTokenException if the subarrary does not start
  2491.    * with a legal token or part of one
  2492.    * @exception ExtensibleTokenException if the subarray encodes just a carriage
  2493.    * return ('\r')
  2494.    * @see #TOK_DATA_CHARS
  2495.    * @see #TOK_DATA_NEWLINE
  2496.    * @see #TOK_ATTRIBUTE_VALUE_S
  2497.    * @see #TOK_MAGIC_ENTITY_REF
  2498.    * @see #TOK_ENTITY_REF
  2499.    * @see #TOK_CHAR_REF
  2500.    * @see #TOK_CHAR_PAIR_REF
  2501.    * @see Token
  2502.    * @see EmptyTokenException
  2503.    * @see PartialTokenException
  2504.    * @see InvalidTokenException
  2505.    * @see ExtensibleTokenException
  2506.    */
  2507.   public final
  2508.   int tokenizeAttributeValue(byte[] buf, int off, int end, Token token)
  2509.        throws PartialTokenException, InvalidTokenException,
  2510.               EmptyTokenException, ExtensibleTokenException {
  2511.     if (minBPC > 1)
  2512.       end = adjustEnd(off, end);
  2513.     if (off == end)
  2514.       throw new EmptyTokenException();
  2515.     int start = off;
  2516.     while (off != end) {
  2517.       switch (byteType(buf, off)) {
  2518.       case BT_LEAD2:
  2519.     if (end - off < 2)
  2520.       throw new PartialCharException(off);
  2521.     off += 2;
  2522.     break;
  2523.       case BT_LEAD3:
  2524.     if (end - off < 3)
  2525.       throw new PartialCharException(off);
  2526.     off += 3;
  2527.     break;
  2528.       case BT_LEAD4:
  2529.     if (end - off < 4)
  2530.       throw new PartialCharException(off);
  2531.     off += 4;
  2532.     break;
  2533.       case BT_AMP:
  2534.     if (off == start)
  2535.       return scanRef(buf, off + minBPC, end, token);
  2536.     token.tokenEnd = off;
  2537.     return TOK_DATA_CHARS;
  2538.       case BT_LT:
  2539.     /* this is for inside entity references */
  2540.     throw new InvalidTokenException(off);
  2541.       case BT_S:
  2542.     if (off == start) {
  2543.       token.tokenEnd = off + minBPC;
  2544.       return TOK_ATTRIBUTE_VALUE_S;
  2545.     }
  2546.     token.tokenEnd = off;
  2547.     return TOK_DATA_CHARS;
  2548.       case BT_LF:
  2549.     if (off == start) {
  2550.       token.tokenEnd = off + minBPC;
  2551.       return TOK_DATA_NEWLINE;
  2552.     }
  2553.     token.tokenEnd = off;
  2554.     return TOK_DATA_CHARS;
  2555.       case BT_CR:
  2556.     if (off == start) {
  2557.       off += minBPC;
  2558.       if (off == end)
  2559.         throw new ExtensibleTokenException(TOK_DATA_NEWLINE);
  2560.       if (byteType(buf, off) == BT_LF)
  2561.         off += minBPC;
  2562.       token.tokenEnd = off;
  2563.       return TOK_DATA_NEWLINE;
  2564.     }
  2565.     token.tokenEnd = off;
  2566.     return TOK_DATA_CHARS;
  2567.       default:
  2568.     off += minBPC;
  2569.     break;
  2570.       }
  2571.     }
  2572.     token.tokenEnd = off;
  2573.     return TOK_DATA_CHARS;
  2574.   }
  2575.  
  2576.   /**
  2577.    * Scans the first token of a byte subarrary that contains part of
  2578.    * literal entity value.  The opening and closing delimiters
  2579.    * are not included in the subarrary.
  2580.    * Returns one of the following integers according to the type of
  2581.    * token that the subarray starts with:
  2582.    * <ul>
  2583.    * <li><code>TOK_DATA_CHARS</code>
  2584.    * <li><code>TOK_DATA_NEWLINE</code>
  2585.    * <li><code>TOK_PARAM_ENTITY_REF</code>
  2586.    * <li><code>TOK_MAGIC_ENTITY_REF</code>
  2587.    * <li><code>TOK_ENTITY_REF</code>
  2588.    * <li><code>TOK_CHAR_REF</code>
  2589.    * <li><code>TOK_CHAR_PAIR_REF</code>
  2590.    * </ul>
  2591.    * @exception EmptyTokenException if the subarray is empty
  2592.    * @exception PartialTokenException if the subarray contains only part of
  2593.    * a legal token
  2594.    * @exception InvalidTokenException if the subarrary does not start
  2595.    * with a legal token or part of one
  2596.    * @exception ExtensibleTokenException if the subarray encodes just a carriage
  2597.    * return ('\r')
  2598.    * @see #TOK_DATA_CHARS
  2599.    * @see #TOK_DATA_NEWLINE
  2600.    * @see #TOK_MAGIC_ENTITY_REF
  2601.    * @see #TOK_ENTITY_REF
  2602.    * @see #TOK_PARAM_ENTITY_REF
  2603.    * @see #TOK_CHAR_REF
  2604.    * @see #TOK_CHAR_PAIR_REF
  2605.    * @see Token
  2606.    * @see EmptyTokenException
  2607.    * @see PartialTokenException
  2608.    * @see InvalidTokenException
  2609.    * @see ExtensibleTokenException
  2610.    */
  2611.   public final
  2612.   int tokenizeEntityValue(byte[] buf, int off, int end, Token token)
  2613.        throws PartialTokenException, InvalidTokenException,
  2614.               EmptyTokenException, ExtensibleTokenException {
  2615.     if (minBPC > 1)
  2616.       end = adjustEnd(off, end);
  2617.     if (off == end)
  2618.       throw new EmptyTokenException();
  2619.     int start = off;
  2620.     while (off != end) {
  2621.       switch (byteType(buf, off)) {
  2622.       case BT_LEAD2:
  2623.     if (end - off < 2)
  2624.       throw new PartialCharException(off);
  2625.     off += 2;
  2626.     break;
  2627.       case BT_LEAD3:
  2628.     if (end - off < 3)
  2629.       throw new PartialCharException(off);
  2630.     off += 3;
  2631.     break;
  2632.       case BT_LEAD4:
  2633.     if (end - off < 4)
  2634.       throw new PartialCharException(off);
  2635.     off += 4;
  2636.     break;
  2637.       case BT_AMP:
  2638.     if (off == start)
  2639.       return scanRef(buf, off + minBPC, end, token);
  2640.     token.tokenEnd = off;
  2641.     return TOK_DATA_CHARS;
  2642.       case BT_PERCNT:
  2643.     if (off == start)
  2644.       return scanPercent(buf, off + minBPC, end, token);
  2645.     token.tokenEnd = off;
  2646.     return TOK_DATA_CHARS;
  2647.       case BT_LF:
  2648.     if (off == start) {
  2649.       token.tokenEnd = off + minBPC;
  2650.       return TOK_DATA_NEWLINE;
  2651.     }
  2652.     token.tokenEnd = off;
  2653.     return TOK_DATA_CHARS;
  2654.       case BT_CR:
  2655.     if (off == start) {
  2656.       off += minBPC;
  2657.       if (off == end)
  2658.         throw new ExtensibleTokenException(TOK_DATA_NEWLINE);
  2659.       if (byteType(buf, off) == BT_LF)
  2660.         off += minBPC;
  2661.       token.tokenEnd = off;
  2662.       return TOK_DATA_NEWLINE;
  2663.     }
  2664.     token.tokenEnd = off;
  2665.     return TOK_DATA_CHARS;
  2666.       default:
  2667.     off += minBPC;
  2668.     break;
  2669.       }
  2670.     }
  2671.     token.tokenEnd = off;
  2672.     return TOK_DATA_CHARS;
  2673.   }
  2674.  
  2675.   /**
  2676.    * Skips over an ignored conditional section.
  2677.    * The subarray starts following the <code><![ IGNORE [</code>.
  2678.    *
  2679.    * @return the index of the character following the closing
  2680.    * <code>]]></code>
  2681.    *
  2682.    * @exception PartialTokenException if the subarray does not contain the
  2683.    * complete ignored conditional section
  2684.    * @exception InvalidTokenException if the ignored conditional section
  2685.    * contains illegal characters
  2686.    */
  2687.   public final
  2688.   int skipIgnoreSect(byte[] buf, int off, int end) throws PartialTokenException, InvalidTokenException {
  2689.     if (minBPC > 1)
  2690.       end = adjustEnd(off, end);
  2691.     int level = 0;
  2692.   loop:
  2693.     while (off != end) {
  2694.       switch (byteType(buf, off)) {
  2695.       case BT_LEAD2:
  2696.     if (end - off < 2)
  2697.       throw new PartialCharException(off);
  2698.     check2(buf, off);
  2699.     off += 2;
  2700.     break;
  2701.       case BT_LEAD3:
  2702.     if (end - off < 3)
  2703.       throw new PartialCharException(off);
  2704.     check3(buf, off);
  2705.     off += 3;
  2706.     break;
  2707.       case BT_LEAD4:
  2708.     if (end - off < 4)
  2709.       throw new PartialCharException(off);
  2710.     check4(buf, off);
  2711.     off += 4;
  2712.     break;
  2713.       case BT_NONXML:
  2714.       case BT_MALFORM:
  2715.     throw new InvalidTokenException(off);
  2716.       case BT_LT:
  2717.     off += minBPC;
  2718.     if (off == end)
  2719.       break loop;
  2720.     if (!charMatches(buf, off, '!'))
  2721.       break;
  2722.     off += minBPC;
  2723.     if (off == end)
  2724.       break loop;
  2725.     if (!charMatches(buf, off, '['))
  2726.       break;
  2727.     level++;
  2728.     off += minBPC;
  2729.     break;
  2730.       case BT_RSQB:
  2731.     off += minBPC;
  2732.     if (off == end)
  2733.       break loop;
  2734.     if (!charMatches(buf, off, ']'))
  2735.       break;
  2736.     off += minBPC;
  2737.     if (off == end)
  2738.       break loop;
  2739.     if (charMatches(buf, off, '>')) {
  2740.       if (level == 0)
  2741.         return off + minBPC;
  2742.       level--;
  2743.     }
  2744.     else if (charMatches(buf, off, ']'))
  2745.       break;
  2746.     off += minBPC;
  2747.     break;
  2748.       default:
  2749.     off += minBPC;
  2750.     break;
  2751.       }
  2752.     }
  2753.     throw new PartialTokenException();
  2754.   }
  2755.  
  2756.   /**
  2757.    * Checks that a literal contained in the specified byte subarray
  2758.    * is a legal public identifier and returns a string with
  2759.    * the normalized content of the public id.
  2760.    * The subarray includes the opening and closing quotes.
  2761.    * @exception InvalidTokenException if it is not a legal public identifier
  2762.    */
  2763.   public final
  2764.   String getPublicId(byte[] buf, int off, int end) throws InvalidTokenException {
  2765.     StringBuffer sbuf = new StringBuffer();
  2766.     off += minBPC;
  2767.     end -= minBPC;
  2768.     for (; off != end; off += minBPC) {
  2769.       char c = (char)byteToAscii(buf, off);
  2770.       switch (byteType(buf, off)) {
  2771.       case BT_MINUS:
  2772.       case BT_APOS:
  2773.       case BT_LPAR:
  2774.       case BT_RPAR:
  2775.       case BT_PLUS:
  2776.       case BT_COMMA:
  2777.       case BT_SOL:
  2778.       case BT_EQUALS:
  2779.       case BT_QUEST:
  2780.       case BT_SEMI:
  2781.       case BT_EXCL:
  2782.       case BT_AST:
  2783.       case BT_PERCNT:
  2784.       case BT_NUM:
  2785.     sbuf.append(c);
  2786.     break;
  2787.       case BT_S:
  2788.     if (charMatches(buf, off, '\t'))
  2789.       throw new InvalidTokenException(off);
  2790.     /* fall through */
  2791.       case BT_CR:
  2792.       case BT_LF:
  2793.     if (sbuf.length() > 0 && sbuf.charAt(sbuf.length() - 1) != ' ')
  2794.       sbuf.append(' ');
  2795.     break;
  2796.       case BT_NAME:
  2797.       case BT_NMSTRT:
  2798.     if ((c & ~0x7f) == 0) {
  2799.       sbuf.append(c);
  2800.       break;
  2801.     }
  2802.     // fall through
  2803.       default:
  2804.     switch (c) {
  2805.     case '$':
  2806.     case '@':
  2807.       break;
  2808.     default:
  2809.       throw new InvalidTokenException(off);
  2810.     }
  2811.     break;
  2812.       }
  2813.     }
  2814.     if (sbuf.length() > 0 && sbuf.charAt(sbuf.length() - 1) == ' ')
  2815.       sbuf.setLength(sbuf.length() - 1);
  2816.     return sbuf.toString();
  2817.   }
  2818.  
  2819.   /**
  2820.    * Returns true if the specified byte subarray is equal to the string.
  2821.    * The string must contain only XML significant characters.
  2822.    */
  2823.   public final
  2824.   boolean matchesXMLString(byte[] buf, int off, int end, String str) {
  2825.     int len = str.length();
  2826.     if (len*minBPC != end - off)
  2827.       return false;
  2828.     for (int i = 0; i < len; off += minBPC, i++) {
  2829.       if (!charMatches(buf, off, str.charAt(i)))
  2830.     return false;
  2831.     }
  2832.     return true;
  2833.   }
  2834.  
  2835.   /**
  2836.    * Skips over XML whitespace characters at the start of the specified
  2837.    * subarray.
  2838.    *
  2839.    * @return the index of the first non-whitespace character,
  2840.    * <code>end</code> if there is the subarray is all whitespace
  2841.    */
  2842.   public final
  2843.   int skipS(byte[] buf, int off, int end) {
  2844.   loop:
  2845.     while (off < end) {
  2846.       switch (byteType(buf, off)) {
  2847.       case BT_S:
  2848.       case BT_CR:
  2849.       case BT_LF:
  2850.     off += minBPC;
  2851.     break;
  2852.       default:
  2853.     break loop;
  2854.       }
  2855.     }
  2856.     return off;
  2857.   }
  2858.  
  2859.   private final boolean isNameChar2(byte[] buf, int off) {
  2860.     int bt = byteType2(buf, off);
  2861.     return bt == BT_NAME || bt == BT_NMSTRT;
  2862.   }
  2863.   private final boolean isNameChar3(byte[] buf, int off) {
  2864.     int bt = byteType3(buf, off);
  2865.     return bt == BT_NAME || bt == BT_NMSTRT;
  2866.   }
  2867.   private final boolean isNameChar4(byte[] buf, int off) {
  2868.     int bt = byteType4(buf, off);
  2869.     return bt == BT_NAME || bt == BT_NMSTRT;
  2870.   }
  2871.  
  2872.   private static final String nameStartSingles =
  2873.   "\u003a\u005f\u0386\u038c\u03da\u03dc\u03de\u03e0\u0559\u06d5\u093d\u09b2" +
  2874.   "\u0a5e\u0a8d\u0abd\u0ae0\u0b3d\u0b9c\u0cde\u0e30\u0e84\u0e8a\u0e8d\u0ea5" +
  2875.   "\u0ea7\u0eb0\u0ebd\u1100\u1109\u113c\u113e\u1140\u114c\u114e\u1150\u1159" +
  2876.   "\u1163\u1165\u1167\u1169\u1175\u119e\u11a8\u11ab\u11ba\u11eb\u11f0\u11f9" +
  2877.   "\u1f59\u1f5b\u1f5d\u1fbe\u2126\u212e\u3007";
  2878.   private static final String nameStartRanges =
  2879.   "\u0041\u005a\u0061\u007a\u00c0\u00d6\u00d8\u00f6\u00f8\u00ff\u0100\u0131" +
  2880.   "\u0134\u013e\u0141\u0148\u014a\u017e\u0180\u01c3\u01cd\u01f0\u01f4\u01f5" +
  2881.   "\u01fa\u0217\u0250\u02a8\u02bb\u02c1\u0388\u038a\u038e\u03a1\u03a3\u03ce" +
  2882.   "\u03d0\u03d6\u03e2\u03f3\u0401\u040c\u040e\u044f\u0451\u045c\u045e\u0481" +
  2883.   "\u0490\u04c4\u04c7\u04c8\u04cb\u04cc\u04d0\u04eb\u04ee\u04f5\u04f8\u04f9" +
  2884.   "\u0531\u0556\u0561\u0586\u05d0\u05ea\u05f0\u05f2\u0621\u063a\u0641\u064a" +
  2885.   "\u0671\u06b7\u06ba\u06be\u06c0\u06ce\u06d0\u06d3\u06e5\u06e6\u0905\u0939" +
  2886.   "\u0958\u0961\u0985\u098c\u098f\u0990\u0993\u09a8\u09aa\u09b0\u09b6\u09b9" +
  2887.   "\u09dc\u09dd\u09df\u09e1\u09f0\u09f1\u0a05\u0a0a\u0a0f\u0a10\u0a13\u0a28" +
  2888.   "\u0a2a\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59\u0a5c\u0a72\u0a74" +
  2889.   "\u0a85\u0a8b\u0a8f\u0a91\u0a93\u0aa8\u0aaa\u0ab0\u0ab2\u0ab3\u0ab5\u0ab9" +
  2890.   "\u0b05\u0b0c\u0b0f\u0b10\u0b13\u0b28\u0b2a\u0b30\u0b32\u0b33\u0b36\u0b39" +
  2891.   "\u0b5c\u0b5d\u0b5f\u0b61\u0b85\u0b8a\u0b8e\u0b90\u0b92\u0b95\u0b99\u0b9a" +
  2892.   "\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8\u0baa\u0bae\u0bb5\u0bb7\u0bb9\u0c05\u0c0c" +
  2893.   "\u0c0e\u0c10\u0c12\u0c28\u0c2a\u0c33\u0c35\u0c39\u0c60\u0c61\u0c85\u0c8c" +
  2894.   "\u0c8e\u0c90\u0c92\u0ca8\u0caa\u0cb3\u0cb5\u0cb9\u0ce0\u0ce1\u0d05\u0d0c" +
  2895.   "\u0d0e\u0d10\u0d12\u0d28\u0d2a\u0d39\u0d60\u0d61\u0e01\u0e2e\u0e32\u0e33" +
  2896.   "\u0e40\u0e45\u0e81\u0e82\u0e87\u0e88\u0e94\u0e97\u0e99\u0e9f\u0ea1\u0ea3" +
  2897.   "\u0eaa\u0eab\u0ead\u0eae\u0eb2\u0eb3\u0ec0\u0ec4\u0f40\u0f47\u0f49\u0f69" +
  2898.   "\u10a0\u10c5\u10d0\u10f6\u1102\u1103\u1105\u1107\u110b\u110c\u110e\u1112" +
  2899.   "\u1154\u1155\u115f\u1161\u116d\u116e\u1172\u1173\u11ae\u11af\u11b7\u11b8" +
  2900.   "\u11bc\u11c2\u1e00\u1e9b\u1ea0\u1ef9\u1f00\u1f15\u1f18\u1f1d\u1f20\u1f45" +
  2901.   "\u1f48\u1f4d\u1f50\u1f57\u1f5f\u1f7d\u1f80\u1fb4\u1fb6\u1fbc\u1fc2\u1fc4" +
  2902.   "\u1fc6\u1fcc\u1fd0\u1fd3\u1fd6\u1fdb\u1fe0\u1fec\u1ff2\u1ff4\u1ff6\u1ffc" +
  2903.   "\u212a\u212b\u2180\u2182\u3041\u3094\u30a1\u30fa\u3105\u312c\uac00\ud7a3" +
  2904.   "\u4e00\u9fa5\u3021\u3029";
  2905.   private static final String nameSingles =
  2906.   "\u002d\u002e\u05bf\u05c4\u0670\u093c\u094d\u09bc\u09be\u09bf\u09d7\u0a02" +
  2907.   "\u0a3c\u0a3e\u0a3f\u0abc\u0b3c\u0bd7\u0d57\u0e31\u0eb1\u0f35\u0f37\u0f39" +
  2908.   "\u0f3e\u0f3f\u0f97\u0fb9\u20e1\u3099\u309a\u00b7\u02d0\u02d1\u0387\u0640" +
  2909.   "\u0e46\u0ec6\u3005";
  2910.   private static final String nameRanges =
  2911.   "\u0300\u0345\u0360\u0361\u0483\u0486\u0591\u05a1\u05a3\u05b9\u05bb\u05bd" +
  2912.   "\u05c1\u05c2\u064b\u0652\u06d6\u06dc\u06dd\u06df\u06e0\u06e4\u06e7\u06e8" +
  2913.   "\u06ea\u06ed\u0901\u0903\u093e\u094c\u0951\u0954\u0962\u0963\u0981\u0983" +
  2914.   "\u09c0\u09c4\u09c7\u09c8\u09cb\u09cd\u09e2\u09e3\u0a40\u0a42\u0a47\u0a48" +
  2915.   "\u0a4b\u0a4d\u0a70\u0a71\u0a81\u0a83\u0abe\u0ac5\u0ac7\u0ac9\u0acb\u0acd" +
  2916.   "\u0b01\u0b03\u0b3e\u0b43\u0b47\u0b48\u0b4b\u0b4d\u0b56\u0b57\u0b82\u0b83" +
  2917.   "\u0bbe\u0bc2\u0bc6\u0bc8\u0bca\u0bcd\u0c01\u0c03\u0c3e\u0c44\u0c46\u0c48" +
  2918.   "\u0c4a\u0c4d\u0c55\u0c56\u0c82\u0c83\u0cbe\u0cc4\u0cc6\u0cc8\u0cca\u0ccd" +
  2919.   "\u0cd5\u0cd6\u0d02\u0d03\u0d3e\u0d43\u0d46\u0d48\u0d4a\u0d4d\u0e34\u0e3a" +
  2920.   "\u0e47\u0e4e\u0eb4\u0eb9\u0ebb\u0ebc\u0ec8\u0ecd\u0f18\u0f19\u0f71\u0f84" +
  2921.   "\u0f86\u0f8b\u0f90\u0f95\u0f99\u0fad\u0fb1\u0fb7\u20d0\u20dc\u302a\u302f" +
  2922.   "\u0030\u0039\u0660\u0669\u06f0\u06f9\u0966\u096f\u09e6\u09ef\u0a66\u0a6f" +
  2923.   "\u0ae6\u0aef\u0b66\u0b6f\u0be7\u0bef\u0c66\u0c6f\u0ce6\u0cef\u0d66\u0d6f" +
  2924.   "\u0e50\u0e59\u0ed0\u0ed9\u0f20\u0f29\u3031\u3035\u309d\u309e\u30fc\u30fe";
  2925.  
  2926.   /* final */ static byte[][] charTypeTable;
  2927.   private static void setCharType(char c, int type) {
  2928.     if (c < 0x80)
  2929.       return;
  2930.     int hi = c >> 8;
  2931.     if (charTypeTable[hi] == null) {
  2932.       charTypeTable[hi] = new byte[256];
  2933.       for (int i = 0; i < 256; i++)
  2934.     charTypeTable[hi][i] = BT_OTHER;
  2935.     }
  2936.     charTypeTable[hi][c & 0xFF] = (byte)type;
  2937.   }
  2938.  
  2939.   private static void setCharType(char min, char max, int type) {
  2940.     byte[] shared = null;
  2941.     do {
  2942.       if ((min & 0xFF) == 0) {
  2943.     for (; min + 0xFF <= max; min += 0x100) {
  2944.       if (shared == null) {
  2945.         shared = new byte[256];
  2946.         for (int i = 0; i < 256; i++)
  2947.           shared[i] = (byte)type;
  2948.       }
  2949.       charTypeTable[min >> 8] = shared;
  2950.       if (min + 0xFF == max)
  2951.         return;
  2952.     }
  2953.       }
  2954.       setCharType(min, type);
  2955.     } while (min++ != max);
  2956.   }
  2957.  
  2958.   static {
  2959.     charTypeTable = new byte[256][];
  2960.     for (int i = 0; i < nameSingles.length(); i++)
  2961.       setCharType(nameSingles.charAt(i), BT_NAME);
  2962.     for (int i = 0; i < nameRanges.length(); i += 2)
  2963.       setCharType(nameRanges.charAt(i), nameRanges.charAt(i + 1), BT_NAME);
  2964.     for (int i = 0; i < nameStartSingles.length(); i++)
  2965.       setCharType(nameStartSingles.charAt(i), BT_NMSTRT);
  2966.     for (int i = 0; i < nameStartRanges.length(); i += 2)
  2967.       setCharType(nameStartRanges.charAt(i), nameStartRanges.charAt(i + 1),
  2968.           BT_NMSTRT);
  2969.     setCharType('\uD800', '\uDBFF', BT_LEAD4);
  2970.     setCharType('\uDC00', '\uDFFF', BT_MALFORM);
  2971.     setCharType('\uFFFE', '\uFFFF', BT_NONXML);
  2972.     byte[] other = new byte[256];
  2973.     for (int i = 0; i < 256; i++)
  2974.       other[i] = BT_OTHER;
  2975.     for (int i = 0; i < 256; i++)
  2976.       if (charTypeTable[i] == null)
  2977.     charTypeTable[i] = other;
  2978.     System.arraycopy(asciiTypeTable, 0, charTypeTable[0], 0, 128);
  2979.   }
  2980.  
  2981.   /**
  2982.    * Returns the minimum number of bytes required to represent a single
  2983.    * character in this encoding.  The value will be 1, 2 or 4.
  2984.    */
  2985.   public final int getMinBytesPerChar() {
  2986.     return minBPC;
  2987.   }
  2988. }
  2989.