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

org.xdef.sys.StringParser Maven / Gradle / Ivy

The newest version!
package org.xdef.sys;

import org.xdef.msg.SYS;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URL;
import java.net.URLConnection;
import java.text.DateFormatSymbols;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.Stack;
import java.util.TimeZone;
import static org.xdef.sys.SParser.NOCHAR;

/** String parser used for constructing specific parsers.
 * @author  Vaclav Trojan
 */
public class StringParser extends SReporter implements SParser {

	/** XML version 1.0. */
	public static final byte XMLVER1_0 = 10;
	/** XML version 1.1. */
	public static final byte XMLVER1_1 = 11;
	/** Illegal XML character. */
	public static final byte XML_CHAR_ILLEGAL = 0;
	/** Valid XML character. */
	public static final byte XML_CHAR = 1;
	/** Whitespace XML character. */
	public static final byte XML_CHAR_WHITESPACE = 2;
	/** Colon character. */
	public static final byte XML_CHAR_COLON = 4;
	/** Start character of XML name. */
	public static final byte XML_CHAR_NAME_START = 8;
	/** XML name character (not the first one). */
	public static final byte XML_CHAR_NAME_EXT = 16;

	/** Table of XML version 1.0 characters. */
	private static final byte[] XML_CHARTAB0 = new byte[65536];
	/** Table of XML version 1.1 characters. */
	private static final byte[] XML_CHARTAB1 = new byte[65536];

// 
	static {

		////////////////////////////////////////////////////////////////////////
		// Don't modify following part - it was authomaticaly generated!
		////////////////////////////////////////////////////////////////////////

		// UTF16 character table of XML version 1.0
		// (default value is 0 -> illegal character)
		XML_CHARTAB0[0x0009] = XML_CHAR_WHITESPACE; // TAB
		XML_CHARTAB0[0x000a] = XML_CHAR_WHITESPACE; // LF
		XML_CHARTAB0[0x000d] = XML_CHAR_WHITESPACE; // CR
		XML_CHARTAB0[0x0020] = XML_CHAR_WHITESPACE; // SPACE
		Arrays.fill(XML_CHARTAB0, 0x0021, 0x002d, XML_CHAR); // !"#$%&'()*+,
		XML_CHARTAB0[0x002d] = XML_CHAR_NAME_EXT; // -
		XML_CHARTAB0[0x002e] = XML_CHAR_NAME_EXT; // .
		XML_CHARTAB0[0x002f] = XML_CHAR; // /
		Arrays.fill(XML_CHARTAB0, 0x0030, 0x003a, XML_CHAR_NAME_EXT); //0-9
		XML_CHARTAB0[0x003a] = XML_CHAR_COLON; // :
		Arrays.fill(XML_CHARTAB0, 0x003b, 0x0041, XML_CHAR); // ;<=>?@
		Arrays.fill(XML_CHARTAB0, 0x0041, 0x005b, XML_CHAR_NAME_START); // A-Z
		Arrays.fill(XML_CHARTAB0, 0x005b, 0x005f, XML_CHAR); // ^
		XML_CHARTAB0[0x005f] = XML_CHAR_NAME_START; // _
		XML_CHARTAB0[0x0060] = XML_CHAR; // `
		Arrays.fill(XML_CHARTAB0, 0x0061, 0x007b, XML_CHAR_NAME_START); // a-z
		Arrays.fill(XML_CHARTAB0, 0x007b, 0x00b7, XML_CHAR); // {|}~DEL ...
		XML_CHARTAB0[0x00b7] = XML_CHAR_NAME_EXT;
		Arrays.fill(XML_CHARTAB0, 0x00b8, 0x00c0, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x00c0, 0x00d7, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x00d7] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x00d8, 0x00f7, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x00f7] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x00f8, 0x0132, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0132] = XML_CHAR;
		XML_CHARTAB0[0x0133] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0134, 0x013f, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x013f] = XML_CHAR;
		XML_CHARTAB0[0x0140] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0141, 0x0149, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0149] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x014a, 0x017f, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x017f] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0180, 0x01c4, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x01c4, 0x01cd, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x01cd, 0x01f1, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x01f1, 0x01f4, XML_CHAR);
		XML_CHARTAB0[0x01f4] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x01f5] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x01f6, 0x01fa, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x01fa, 0x0218, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x0218, 0x0250, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0250, 0x02a9, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x02a9, 0x02bb, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x02bb, 0x02c2, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x02c2, 0x02d0, XML_CHAR);
		XML_CHARTAB0[0x02d0] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x02d1] = XML_CHAR_NAME_EXT;
		Arrays.fill(XML_CHARTAB0, 0x02d2, 0x0300, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0300, 0x0346, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0346, 0x0360, XML_CHAR);
		XML_CHARTAB0[0x0360] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0361] = XML_CHAR_NAME_EXT;
		Arrays.fill(XML_CHARTAB0, 0x0362, 0x0386, XML_CHAR);
		XML_CHARTAB0[0x0386] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0387] = XML_CHAR_NAME_EXT;
		Arrays.fill(XML_CHARTAB0, 0x0388, 0x038b, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x038b] = XML_CHAR;
		XML_CHARTAB0[0x038c] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x038d] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x038e, 0x03a2, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x03a2] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x03a3, 0x03cf, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x03cf] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x03d0, 0x03d7, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x03d7, 0x03da, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x03da, 0x03dd, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x03dd] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x03de, 0x03e1, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x03e1] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x03e2, 0x03f4, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x03f4, 0x0401, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0401, 0x040d, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x040d] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x040e, 0x0450, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0450] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0451, 0x045d, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x045d] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x045e, 0x0482, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0482] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0483, 0x0487, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0487, 0x0490, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0490, 0x04c5, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x04c5] = XML_CHAR;
		XML_CHARTAB0[0x04c6] = XML_CHAR;
		XML_CHARTAB0[0x04c7] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x04c8] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x04c9] = XML_CHAR;
		XML_CHARTAB0[0x04ca] = XML_CHAR;
		XML_CHARTAB0[0x04cb] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x04cc] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x04cd, 0x04d0, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x04d0, 0x04ec, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x04ec] = XML_CHAR;
		XML_CHARTAB0[0x04ed] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x04ee, 0x04f6, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x04f6] = XML_CHAR;
		XML_CHARTAB0[0x04f7] = XML_CHAR;
		XML_CHARTAB0[0x04f8] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x04f9] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x04fa, 0x0531, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0531, 0x0557, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0557] = XML_CHAR;
		XML_CHARTAB0[0x0558] = XML_CHAR;
		XML_CHARTAB0[0x0559] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x055a, 0x0561, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0561, 0x0587, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x0587, 0x0591, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0591, 0x05a2, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x05a2] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x05a3, 0x05ba, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x05ba] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x05bb, 0x05be, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x05be] = XML_CHAR;
		XML_CHARTAB0[0x05bf] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x05c0] = XML_CHAR;
		XML_CHARTAB0[0x05c1] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x05c2] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x05c3] = XML_CHAR;
		XML_CHARTAB0[0x05c4] = XML_CHAR_NAME_EXT;
		Arrays.fill(XML_CHARTAB0, 0x05c5, 0x05d0, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x05d0, 0x05eb, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x05eb, 0x05f0, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x05f0, 0x05f3, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x05f3, 0x0621, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0621, 0x063b, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x063b, 0x0640, XML_CHAR);
		XML_CHARTAB0[0x0640] = XML_CHAR_NAME_EXT;
		Arrays.fill(XML_CHARTAB0, 0x0641, 0x064b, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x064b, 0x0653, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0653, 0x0660, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0660, 0x066a, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x066a, 0x0670, XML_CHAR);
		XML_CHARTAB0[0x0670] = XML_CHAR_NAME_EXT;
		Arrays.fill(XML_CHARTAB0, 0x0671, 0x06b8, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x06b8] = XML_CHAR;
		XML_CHARTAB0[0x06b9] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x06ba, 0x06bf, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x06bf] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x06c0, 0x06cf, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x06cf] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x06d0, 0x06d4, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x06d4] = XML_CHAR;
		XML_CHARTAB0[0x06d5] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x06d6, 0x06e5, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x06e5] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x06e6] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x06e7] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x06e8] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x06e9] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x06ea, 0x06ee, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x06ee] = XML_CHAR;
		XML_CHARTAB0[0x06ef] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x06f0, 0x06fa, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x06fa, 0x0901, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0901, 0x0904, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0904] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0905, 0x093a, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x093a] = XML_CHAR;
		XML_CHARTAB0[0x093b] = XML_CHAR;
		XML_CHARTAB0[0x093c] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x093d] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x093e, 0x094e, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x094e, 0x0951, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0951, 0x0955, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0955, 0x0958, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0958, 0x0962, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0962] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0963] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0964] = XML_CHAR;
		XML_CHARTAB0[0x0965] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0966, 0x0970, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0970, 0x0981, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0981, 0x0984, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0984] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0985, 0x098d, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x098d] = XML_CHAR;
		XML_CHARTAB0[0x098e] = XML_CHAR;
		XML_CHARTAB0[0x098f] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0990] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0991] = XML_CHAR;
		XML_CHARTAB0[0x0992] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0993, 0x09a9, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x09a9] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x09aa, 0x09b1, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x09b1] = XML_CHAR;
		XML_CHARTAB0[0x09b2] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x09b3, 0x09b6, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x09b6, 0x09ba, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x09ba] = XML_CHAR;
		XML_CHARTAB0[0x09bb] = XML_CHAR;
		XML_CHARTAB0[0x09bc] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x09bd] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x09be, 0x09c5, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x09c5] = XML_CHAR;
		XML_CHARTAB0[0x09c6] = XML_CHAR;
		XML_CHARTAB0[0x09c7] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x09c8] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x09c9] = XML_CHAR;
		XML_CHARTAB0[0x09ca] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x09cb, 0x09ce, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x09ce, 0x09d7, XML_CHAR);
		XML_CHARTAB0[0x09d7] = XML_CHAR_NAME_EXT;
		Arrays.fill(XML_CHARTAB0, 0x09d8, 0x09dc, XML_CHAR);
		XML_CHARTAB0[0x09dc] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x09dd] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x09de] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x09df, 0x09e2, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x09e2] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x09e3] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x09e4] = XML_CHAR;
		XML_CHARTAB0[0x09e5] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x09e6, 0x09f0, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x09f0] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x09f1] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x09f2, 0x0a02, XML_CHAR);
		XML_CHARTAB0[0x0a02] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0a03] = XML_CHAR;
		XML_CHARTAB0[0x0a04] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0a05, 0x0a0b, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x0a0b, 0x0a0f, XML_CHAR);
		XML_CHARTAB0[0x0a0f] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0a10] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0a11] = XML_CHAR;
		XML_CHARTAB0[0x0a12] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0a13, 0x0a29, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0a29] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0a2a, 0x0a31, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0a31] = XML_CHAR;
		XML_CHARTAB0[0x0a32] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0a33] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0a34] = XML_CHAR;
		XML_CHARTAB0[0x0a35] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0a36] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0a37] = XML_CHAR;
		XML_CHARTAB0[0x0a38] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0a39] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0a3a] = XML_CHAR;
		XML_CHARTAB0[0x0a3b] = XML_CHAR;
		XML_CHARTAB0[0x0a3c] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0a3d] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0a3e, 0x0a43, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0a43, 0x0a47, XML_CHAR);
		XML_CHARTAB0[0x0a47] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0a48] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0a49] = XML_CHAR;
		XML_CHARTAB0[0x0a4a] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0a4b, 0x0a4e, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0a4e, 0x0a59, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0a59, 0x0a5d, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0a5d] = XML_CHAR;
		XML_CHARTAB0[0x0a5e] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x0a5f, 0x0a66, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0a66, 0x0a72, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0a72, 0x0a75, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x0a75, 0x0a81, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0a81, 0x0a84, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0a84] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0a85, 0x0a8c, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0a8c] = XML_CHAR;
		XML_CHARTAB0[0x0a8d] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0a8e] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0a8f, 0x0a92, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0a92] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0a93, 0x0aa9, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0aa9] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0aaa, 0x0ab1, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0ab1] = XML_CHAR;
		XML_CHARTAB0[0x0ab2] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0ab3] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0ab4] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0ab5, 0x0aba, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0aba] = XML_CHAR;
		XML_CHARTAB0[0x0abb] = XML_CHAR;
		XML_CHARTAB0[0x0abc] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0abd] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x0abe, 0x0ac6, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0ac6] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0ac7, 0x0aca, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0aca] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0acb, 0x0ace, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0ace, 0x0ae0, XML_CHAR);
		XML_CHARTAB0[0x0ae0] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x0ae1, 0x0ae6, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0ae6, 0x0af0, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0af0, 0x0b01, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0b01, 0x0b04, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0b04] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0b05, 0x0b0d, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0b0d] = XML_CHAR;
		XML_CHARTAB0[0x0b0e] = XML_CHAR;
		XML_CHARTAB0[0x0b0f] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0b10] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0b11] = XML_CHAR;
		XML_CHARTAB0[0x0b12] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0b13, 0x0b29, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0b29] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0b2a, 0x0b31, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0b31] = XML_CHAR;
		XML_CHARTAB0[0x0b32] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0b33] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0b34] = XML_CHAR;
		XML_CHARTAB0[0x0b35] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0b36, 0x0b3a, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0b3a] = XML_CHAR;
		XML_CHARTAB0[0x0b3b] = XML_CHAR;
		XML_CHARTAB0[0x0b3c] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0b3d] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x0b3e, 0x0b44, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0b44, 0x0b47, XML_CHAR);
		XML_CHARTAB0[0x0b47] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0b48] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0b49] = XML_CHAR;
		XML_CHARTAB0[0x0b4a] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0b4b, 0x0b4e, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0b4e, 0x0b56, XML_CHAR);
		XML_CHARTAB0[0x0b56] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0b57] = XML_CHAR_NAME_EXT;
		Arrays.fill(XML_CHARTAB0, 0x0b58, 0x0b5c, XML_CHAR);
		XML_CHARTAB0[0x0b5c] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0b5d] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0b5e] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0b5f, 0x0b62, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x0b62, 0x0b66, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0b66, 0x0b70, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0b70, 0x0b82, XML_CHAR);
		XML_CHARTAB0[0x0b82] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0b83] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0b84] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0b85, 0x0b8b, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x0b8b, 0x0b8e, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0b8e, 0x0b91, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0b91] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0b92, 0x0b96, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x0b96, 0x0b99, XML_CHAR);
		XML_CHARTAB0[0x0b99] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0b9a] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0b9b] = XML_CHAR;
		XML_CHARTAB0[0x0b9c] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0b9d] = XML_CHAR;
		XML_CHARTAB0[0x0b9e] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0b9f] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x0ba0, 0x0ba3, XML_CHAR);
		XML_CHARTAB0[0x0ba3] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0ba4] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x0ba5, 0x0ba8, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0ba8, 0x0bab, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x0bab, 0x0bae, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0bae, 0x0bb6, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0bb6] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0bb7, 0x0bba, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x0bba, 0x0bbe, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0bbe, 0x0bc3, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0bc3, 0x0bc6, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0bc6, 0x0bc9, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0bc9] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0bca, 0x0bce, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0bce, 0x0bd7, XML_CHAR);
		XML_CHARTAB0[0x0bd7] = XML_CHAR_NAME_EXT;
		Arrays.fill(XML_CHARTAB0, 0x0bd8, 0x0be7, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0be7, 0x0bf0, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0bf0, 0x0c01, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0c01, 0x0c04, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0c04] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0c05, 0x0c0d, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0c0d] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0c0e, 0x0c11, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0c11] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0c12, 0x0c29, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0c29] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0c2a, 0x0c34, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0c34] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0c35, 0x0c3a, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x0c3a, 0x0c3e, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0c3e, 0x0c45, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0c45] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0c46, 0x0c49, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0c49] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0c4a, 0x0c4e, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0c4e, 0x0c55, XML_CHAR);
		XML_CHARTAB0[0x0c55] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0c56] = XML_CHAR_NAME_EXT;
		Arrays.fill(XML_CHARTAB0, 0x0c57, 0x0c60, XML_CHAR);
		XML_CHARTAB0[0x0c60] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0c61] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x0c62, 0x0c66, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0c66, 0x0c70, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0c70, 0x0c82, XML_CHAR);
		XML_CHARTAB0[0x0c82] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0c83] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0c84] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0c85, 0x0c8d, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0c8d] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0c8e, 0x0c91, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0c91] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0c92, 0x0ca9, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0ca9] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0caa, 0x0cb4, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0cb4] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0cb5, 0x0cba, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x0cba, 0x0cbe, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0cbe, 0x0cc5, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0cc5] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0cc6, 0x0cc9, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0cc9] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0cca, 0x0cce, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0cce, 0x0cd5, XML_CHAR);
		XML_CHARTAB0[0x0cd5] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0cd6] = XML_CHAR_NAME_EXT;
		Arrays.fill(XML_CHARTAB0, 0x0cd7, 0x0cde, XML_CHAR);
		XML_CHARTAB0[0x0cde] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0cdf] = XML_CHAR;
		XML_CHARTAB0[0x0ce0] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0ce1] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x0ce2, 0x0ce6, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0ce6, 0x0cf0, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0cf0, 0x0d02, XML_CHAR);
		XML_CHARTAB0[0x0d02] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0d03] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0d04] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0d05, 0x0d0d, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0d0d] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0d0e, 0x0d11, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0d11] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0d12, 0x0d29, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0d29] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0d2a, 0x0d3a, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x0d3a, 0x0d3e, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0d3e, 0x0d44, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0d44] = XML_CHAR;
		XML_CHARTAB0[0x0d45] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0d46, 0x0d49, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0d49] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0d4a, 0x0d4e, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0d4e, 0x0d57, XML_CHAR);
		XML_CHARTAB0[0x0d57] = XML_CHAR_NAME_EXT;
		Arrays.fill(XML_CHARTAB0, 0x0d58, 0x0d60, XML_CHAR);
		XML_CHARTAB0[0x0d60] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0d61] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x0d62, 0x0d66, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0d66, 0x0d70, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0d70, 0x0e01, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0e01, 0x0e2f, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0e2f] = XML_CHAR;
		XML_CHARTAB0[0x0e30] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0e31] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0e32] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0e33] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x0e34, 0x0e3b, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0e3b, 0x0e40, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0e40, 0x0e46, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x0e46, 0x0e4f, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0e4f] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0e50, 0x0e5a, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0e5a, 0x0e81, XML_CHAR);
		XML_CHARTAB0[0x0e81] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0e82] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0e83] = XML_CHAR;
		XML_CHARTAB0[0x0e84] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0e85] = XML_CHAR;
		XML_CHARTAB0[0x0e86] = XML_CHAR;
		XML_CHARTAB0[0x0e87] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0e88] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0e89] = XML_CHAR;
		XML_CHARTAB0[0x0e8a] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0e8b] = XML_CHAR;
		XML_CHARTAB0[0x0e8c] = XML_CHAR;
		XML_CHARTAB0[0x0e8d] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x0e8e, 0x0e94, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0e94, 0x0e98, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0e98] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0e99, 0x0ea0, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0ea0] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0ea1, 0x0ea4, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0ea4] = XML_CHAR;
		XML_CHARTAB0[0x0ea5] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0ea6] = XML_CHAR;
		XML_CHARTAB0[0x0ea7] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0ea8] = XML_CHAR;
		XML_CHARTAB0[0x0ea9] = XML_CHAR;
		XML_CHARTAB0[0x0eaa] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0eab] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0eac] = XML_CHAR;
		XML_CHARTAB0[0x0ead] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0eae] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0eaf] = XML_CHAR;
		XML_CHARTAB0[0x0eb0] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0eb1] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0eb2] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0eb3] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x0eb4, 0x0eba, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0eba] = XML_CHAR;
		XML_CHARTAB0[0x0ebb] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0ebc] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0ebd] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x0ebe] = XML_CHAR;
		XML_CHARTAB0[0x0ebf] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0ec0, 0x0ec5, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0ec5] = XML_CHAR;
		XML_CHARTAB0[0x0ec6] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0ec7] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0ec8, 0x0ece, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0ece] = XML_CHAR;
		XML_CHARTAB0[0x0ecf] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0ed0, 0x0eda, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0eda, 0x0f18, XML_CHAR);
		XML_CHARTAB0[0x0f18] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0f19] = XML_CHAR_NAME_EXT;
		Arrays.fill(XML_CHARTAB0, 0x0f1a, 0x0f20, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0f20, 0x0f2a, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0f2a, 0x0f35, XML_CHAR);
		XML_CHARTAB0[0x0f35] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0f36] = XML_CHAR;
		XML_CHARTAB0[0x0f37] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0f38] = XML_CHAR;
		XML_CHARTAB0[0x0f39] = XML_CHAR_NAME_EXT;
		Arrays.fill(XML_CHARTAB0, 0x0f3a, 0x0f3e, XML_CHAR);
		XML_CHARTAB0[0x0f3e] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0f3f] = XML_CHAR_NAME_EXT;
		Arrays.fill(XML_CHARTAB0, 0x0f40, 0x0f48, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x0f48] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0f49, 0x0f6a, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x0f6a, 0x0f71, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0f71, 0x0f85, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0f85] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0f86, 0x0f8c, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0f8c, 0x0f90, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0f90, 0x0f96, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0f96] = XML_CHAR;
		XML_CHARTAB0[0x0f97] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x0f98] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x0f99, 0x0fae, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x0fae, 0x0fb1, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x0fb1, 0x0fb8, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x0fb8] = XML_CHAR;
		XML_CHARTAB0[0x0fb9] = XML_CHAR_NAME_EXT;
		Arrays.fill(XML_CHARTAB0, 0x0fba, 0x10a0, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x10a0, 0x10c6, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x10c6, 0x10d0, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x10d0, 0x10f7, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x10f7, 0x1100, XML_CHAR);
		XML_CHARTAB0[0x1100] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x1101] = XML_CHAR;
		XML_CHARTAB0[0x1102] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x1103] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x1104] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x1105, 0x1108, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x1108] = XML_CHAR;
		XML_CHARTAB0[0x1109] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x110a] = XML_CHAR;
		XML_CHARTAB0[0x110b] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x110c] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x110d] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x110e, 0x1113, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x1113, 0x113c, XML_CHAR);
		XML_CHARTAB0[0x113c] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x113d] = XML_CHAR;
		XML_CHARTAB0[0x113e] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x113f] = XML_CHAR;
		XML_CHARTAB0[0x1140] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x1141, 0x114c, XML_CHAR);
		XML_CHARTAB0[0x114c] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x114d] = XML_CHAR;
		XML_CHARTAB0[0x114e] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x114f] = XML_CHAR;
		XML_CHARTAB0[0x1150] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x1151, 0x1154, XML_CHAR);
		XML_CHARTAB0[0x1154] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x1155] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x1156, 0x1159, XML_CHAR);
		XML_CHARTAB0[0x1159] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x115a, 0x115f, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x115f, 0x1162, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x1162] = XML_CHAR;
		XML_CHARTAB0[0x1163] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x1164] = XML_CHAR;
		XML_CHARTAB0[0x1165] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x1166] = XML_CHAR;
		XML_CHARTAB0[0x1167] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x1168] = XML_CHAR;
		XML_CHARTAB0[0x1169] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x116a, 0x116d, XML_CHAR);
		XML_CHARTAB0[0x116d] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x116e] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x116f, 0x1172, XML_CHAR);
		XML_CHARTAB0[0x1172] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x1173] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x1174] = XML_CHAR;
		XML_CHARTAB0[0x1175] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x1176, 0x119e, XML_CHAR);
		XML_CHARTAB0[0x119e] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x119f, 0x11a8, XML_CHAR);
		XML_CHARTAB0[0x11a8] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x11a9] = XML_CHAR;
		XML_CHARTAB0[0x11aa] = XML_CHAR;
		XML_CHARTAB0[0x11ab] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x11ac] = XML_CHAR;
		XML_CHARTAB0[0x11ad] = XML_CHAR;
		XML_CHARTAB0[0x11ae] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x11af] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x11b0, 0x11b7, XML_CHAR);
		XML_CHARTAB0[0x11b7] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x11b8] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x11b9] = XML_CHAR;
		XML_CHARTAB0[0x11ba] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x11bb] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x11bc, 0x11c3, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x11c3, 0x11eb, XML_CHAR);
		XML_CHARTAB0[0x11eb] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x11ec, 0x11f0, XML_CHAR);
		XML_CHARTAB0[0x11f0] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x11f1, 0x11f9, XML_CHAR);
		XML_CHARTAB0[0x11f9] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x11fa, 0x1e00, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x1e00, 0x1e9c, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x1e9c, 0x1ea0, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x1ea0, 0x1efa, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x1efa, 0x1f00, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x1f00, 0x1f16, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x1f16] = XML_CHAR;
		XML_CHARTAB0[0x1f17] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x1f18, 0x1f1e, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x1f1e] = XML_CHAR;
		XML_CHARTAB0[0x1f1f] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x1f20, 0x1f46, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x1f46] = XML_CHAR;
		XML_CHARTAB0[0x1f47] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x1f48, 0x1f4e, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x1f4e] = XML_CHAR;
		XML_CHARTAB0[0x1f4f] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x1f50, 0x1f58, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x1f58] = XML_CHAR;
		XML_CHARTAB0[0x1f59] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x1f5a] = XML_CHAR;
		XML_CHARTAB0[0x1f5b] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x1f5c] = XML_CHAR;
		XML_CHARTAB0[0x1f5d] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x1f5e] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x1f5f, 0x1f7e, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x1f7e] = XML_CHAR;
		XML_CHARTAB0[0x1f7f] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x1f80, 0x1fb5, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x1fb5] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x1fb6, 0x1fbd, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x1fbd] = XML_CHAR;
		XML_CHARTAB0[0x1fbe] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x1fbf, 0x1fc2, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x1fc2, 0x1fc5, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x1fc5] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x1fc6, 0x1fcd, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x1fcd, 0x1fd0, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x1fd0, 0x1fd4, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x1fd4] = XML_CHAR;
		XML_CHARTAB0[0x1fd5] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x1fd6, 0x1fdc, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x1fdc, 0x1fe0, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x1fe0, 0x1fed, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x1fed, 0x1ff2, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x1ff2, 0x1ff5, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x1ff5] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x1ff6, 0x1ffd, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x1ffd, 0x20d0, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x20d0, 0x20dd, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x20dd, 0x20e1, XML_CHAR);
		XML_CHARTAB0[0x20e1] = XML_CHAR_NAME_EXT;
		Arrays.fill(XML_CHARTAB0, 0x20e2, 0x2126, XML_CHAR);
		XML_CHARTAB0[0x2126] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x2127, 0x212a, XML_CHAR);
		XML_CHARTAB0[0x212a] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x212b] = XML_CHAR_NAME_START;
		XML_CHARTAB0[0x212c] = XML_CHAR;
		XML_CHARTAB0[0x212d] = XML_CHAR;
		XML_CHARTAB0[0x212e] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x212f, 0x2180, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x2180, 0x2183, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x2183, 0x3005, XML_CHAR);
		XML_CHARTAB0[0x3005] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x3006] = XML_CHAR;
		XML_CHARTAB0[0x3007] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB0, 0x3008, 0x3021, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x3021, 0x302a, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x302a, 0x3030, XML_CHAR_NAME_EXT);
		XML_CHARTAB0[0x3030] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x3031, 0x3036, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x3036, 0x3041, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x3041, 0x3095, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x3095, 0x3099, XML_CHAR);
		XML_CHARTAB0[0x3099] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x309a] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x309b] = XML_CHAR;
		XML_CHARTAB0[0x309c] = XML_CHAR;
		XML_CHARTAB0[0x309d] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x309e] = XML_CHAR_NAME_EXT;
		XML_CHARTAB0[0x309f] = XML_CHAR;
		XML_CHARTAB0[0x30a0] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x30a1, 0x30fb, XML_CHAR_NAME_START);
		XML_CHARTAB0[0x30fb] = XML_CHAR;
		Arrays.fill(XML_CHARTAB0, 0x30fc, 0x30ff, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB0, 0x30ff, 0x3105, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x3105, 0x312d, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x312d, 0x4e00, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0x4e00, 0x9fa6, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0x9fa6, 0xac00, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0xac00, 0xd7a4, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB0, 0xd7a4, 0xd800, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0xe000, 0xfffe, XML_CHAR);
		Arrays.fill(XML_CHARTAB0, 0xe000, 0xfffd, XML_CHAR);

		// UTF16 character table of XML version 1.1
		// (default value is 0 -> illegal character)

		// Copy beginning part of XML_CHARTAB0 to XML_CHARTAB1
		// (0x0000 .. 0x0132  is equal to XML_CHARTAB0).
		System.arraycopy(XML_CHARTAB0, 0, XML_CHARTAB1, 0, 0x0132);
		Arrays.fill(XML_CHARTAB1, 0x0132, 0x0300, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB1, 0x0300, 0x0370, XML_CHAR_NAME_EXT);
		Arrays.fill(XML_CHARTAB1, 0x0370, 0x03d8, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB1, 0x03d8, 0x03f7, XML_CHAR);
		Arrays.fill(XML_CHARTAB1, 0x03f7, 0x2000, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB1, 0x2000, 0x200c, XML_CHAR);
		XML_CHARTAB1[0x200c] = XML_CHAR_NAME_START;
		XML_CHARTAB1[0x200d] = XML_CHAR_NAME_START;
		Arrays.fill(XML_CHARTAB1, 0x200e, 0x203f, XML_CHAR);
		XML_CHARTAB1[0x203f] = XML_CHAR_NAME_EXT;
		XML_CHARTAB1[0x2040] = XML_CHAR_NAME_EXT;
		Arrays.fill(XML_CHARTAB1, 0x2041, 0x2070, XML_CHAR);
		Arrays.fill(XML_CHARTAB1, 0x2070, 0x2190, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB1, 0x2190, 0x2c00, XML_CHAR);
		Arrays.fill(XML_CHARTAB1, 0x2c00, 0x2ff0, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB1, 0x2ff0, 0x3001, XML_CHAR);
		Arrays.fill(XML_CHARTAB1, 0x3001, 0xd800, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB1, 0xe000, 0xf900, XML_CHAR);
		Arrays.fill(XML_CHARTAB1, 0xf900, 0xfdd0, XML_CHAR_NAME_START);
		Arrays.fill(XML_CHARTAB1, 0xfdd0, 0xfdf0, XML_CHAR);
		Arrays.fill(XML_CHARTAB1, 0xfdf0, 0xfffe, XML_CHAR_NAME_START);
	}
// 

	/** Actual character */
	private char _ch;
	/** Source buffer. */
	private String _source;
	/** Buffer position of end of buffer. */
	private int _endPos;
	/** Value of parsed string. */
	private String _parsedString;
	/** If true the parser will create detailed line position. By default the
	 * value of this is set to false. */
	private boolean _lineInfo;
	/** Parsed date and time. */
	private MyDate _parsedDatetime;
	/** Parsed date and time. */
	private SDuration _parsedDuration;
	/** Switch to close or not close reader. */
	boolean _closeReader = true;

	/** Creates a new instance of StringParser */
	public StringParser() {}// all fields are set to null by Java VM

	/** Creates a new instance of StringParser.
	 * @param source The string with source data.
	 */
	public StringParser(final String source) {
		// all fields are set to null by Java VM
		setLineNumber(1L);
		_endPos = (_source = source).length();
		_ch = _endPos > 0 ? _source.charAt(0) : NOCHAR;
	}

	/** Creates a new instance of StringParser.
	 * @param source The string with source data.
	 * @param pos position in source data.
	 */
	public StringParser(final String source, final int pos) {
		// all fields are set to null by Java VM
		setLineNumber(1L);
		_endPos = (_source = source).length();
		setIndex(pos);
	}

	/** Creates a new instance of StringParser.
	 * @param source The source parsed data.
	 */
	public StringParser(final SBuffer source) {
		// all fields are set to null by Java VM
		_source = source.getString();
		_endPos = _source.length();
		setFilePos(source.getFilePos() + source.getIndex());
		setLineNumber(source.getLineNumber());
		setStartLine(source.getStartLine());
		setSysId(source.getSysId());
		if (_lineInfo) {
			cloneModificationInfo(source);
		} else {
			clearModificationInfo();
		}
		_ch = _endPos > 0 ? _source.charAt(0) : NOCHAR;
	}

	/** Creates a new instance of StringParser.
	 * @param reporter Report writer.
	 */
	public StringParser(final ReportWriter reporter) {
		super(reporter); // all fields are set to null by Java VM
	}

	/** Creates a new instance of StringParser.
	 * @param source The string with source data.
	 * @param reporter Report writer.
	 */
	public StringParser(final String source,
		final ReportWriter reporter) {
		super(reporter);
		// all fields are set to null by Java VM
		setLineNumber(1L);
		_endPos = (_source = source).length();
		_ch = _endPos > 0 ? _source.charAt(0) : NOCHAR;
	}
////////////////////////////////////////////////////////////////////////////////

	/** Max. size of source buffer for stream parser. */
	private static final int SOURCE_BUFFER_SIZE = 2048;

	/** Counter of nested keepBuffer methods. */
	private int _keepBufferCounter;
	/** Source reader. */
	protected Reader _reader;
	/** Buffer for reading of source*/
	private char[] _cbuf;
	/** Stack of parsers. */
	Stack _parserStack;

	/** Creates a new instance of StreamParser with source reader and reporter.
	 * @param reader Source reader.
	 * @param reporter Report writer connected to parser.
	 * @throws SRuntimeException if an error occurs.
	 */
	public StringParser(final Reader reader, final ReportWriter reporter) {
		super(reporter);
		setSourceReader(reader);
	}

	/** Creates a new instance of StreamParser with source reader and reporter.
	 * @param url Source URL.
	 * @param reporter Report writer connected to parser.
	 * @param filePos RBA position of the start.
	 * @throws SRuntimeException if an error occurs.
	 */
	public StringParser(final URL url,
		final ReportWriter reporter,
		final long filePos) {
		super(reporter);
		try {
			URLConnection con = url.openConnection();
			setSourceReader(new InputStreamReader(con.getInputStream(),
				con.getContentEncoding()), filePos);
			setSysId(url.toExternalForm());
		} catch (IOException ex) {
			throw new SRuntimeException(SYS.SYS076,//URL &{0} error: &{1}{; }
				url.toExternalForm(), ex.getMessage());
		}
	}

	/** Creates a new instance of StreamParser with source reader and reporter.
	 * @param reader Source reader.
	 * @param reporter Report writer connected to parser.
	 * @param filePos RBA position of the start.
	 */
	public StringParser(final Reader reader,
		final ReportWriter reporter,
		final long filePos) {
		super(reporter);
		setSourceReader(reader, filePos);
	}

	/** Set source file.
	 * @param file the file with source data.
	 * @param charset Name of character table.
	 * @throws SRuntimeException if an IO error occurs
	 */
	final void setSourceReader(final File file, final String charset) {
		try {
			if (charset == null) {
				setSourceReader(new InputStreamReader(
				new FileInputStream(file)));
			} else {
				setSourceReader(new InputStreamReader(
					new FileInputStream(file),charset));
			}
			setSysId("file:" + file.getCanonicalPath().replace('\\','/'));
		} catch (UnsupportedEncodingException ex) {
			setSourceBuffer("");
			//Unsupported character set name: &{0}
			throw new SRuntimeException(SYS.SYS035, charset);
		} catch (IOException ex) {
			setSourceBuffer("");
			//File doesn't exist: &{0}
			throw new SRuntimeException(SYS.SYS024, file);
		}
	}

	/** Set input from URL.
	 * @param url The input url.
	 * @throws SRuntimeException if error occurs
	 */
	final void setSourceReader(final URL url) {
		String s = url.toExternalForm();
		try {
			URLConnection con = url.openConnection();
			setSourceReader(new InputStreamReader(con.getInputStream(),
				con.getContentEncoding()));
			setSysId(s);
		} catch (IOException ex) {
			setSourceBuffer("");
			//URL &{0} error: &{1}{; }
			throw new SRuntimeException(SYS.SYS076, s,ex);
		}
	}

	/** Set source reader.
	 * @param reader Input reader.
	 * @throws SRuntimeException if an error occurs.
	 */
	private void setSourceReader(final Reader reader) {
		setSourceReader(reader, 0L, null);
	}

	/** Set source reader.
	 * @param reader Input reader.
	 * @param sourceName the name of source file.
	 * @throws SRuntimeException if an error occurs.
	 */
	final void setSourceReader(final Reader reader,
		final String sourceName) {
		setSourceReader(reader, 0L, null);
		setSysId(sourceName);
	}

	/** Set source reader.
	 * @param reader Input reader.
	 * @param pos Starting position of the file.
	 * @throws SRuntimeException if an error occurs.
	 */
	private void setSourceReader(final Reader reader, final long pos) {
		setSourceReader(reader, pos, null);
	}

	/** Set source reader with reader and initial buffer.
	 * @param reader The reader.
	 * @param pos Starting position of the file.
	 * @param source Initial source buffer.
	 * @throws SRuntimeException if an error occurs.
	 */
	public final void setSourceReader(final Reader reader,
		final long pos,
		final String source) {
		setLineNumber(1L);
		setFilePos(pos);
		setStartLine(getFilePos());
		clearModificationInfo();
		_keepBufferCounter = 0;
		setBuffer(source);
		if (_reader != null) {
			try {
				_reader.close();
			} catch (IOException ex) {}
		}
		_reader = reader;
		if (_cbuf == null) {
			_cbuf = new char[SOURCE_BUFFER_SIZE];
		}
		if (pos > 0) {
			try {
				_reader.skip(pos);
			} catch (IOException ex) {
				throw new SRuntimeException(//Program exception&{0}{: }
					SYS.SYS036, STester.printThrowable(ex));
			}
		}
		setIndex(0);
		if (_endPos == 0) {
			nextChar();
		}
	}

	/** Close source reader (if exists). */
	public final void closeReader() {
		_keepBufferCounter = 0;
		if (_reader != null) {
			if (_closeReader) {
				try {_reader.close();} catch (IOException ex) {}//ignore it
			}
			_reader = null;
		}
	}

	/** Push keepBuffer. */
	private void keepBuffer() {
		if (_reader != null) {
			_keepBufferCounter++;
			ensureBuffer(10);
		}
	}

	/** Pop freeBuffer. */
	public final void freeBuffer() {
		if (_reader != null) {
			_keepBufferCounter--;
		}
	}

	/** Fill up buffer from input stream (if available).
	 * @return true if data are available in buffer.
	 * @throws SRuntimeException if an error occurs
	 */
	private boolean readNextBuffer() {
		if (_reader == null) {
			if (getIndex() < _endPos) {
				return true;
			}
			super.setIndex(_endPos);
			if (_parserStack == null || _parserStack.size() <= 0) {
				return false;
			}
			return popParser();
		}
		if (_keepBufferCounter > 0) {
			return ensureBuffer(10);
		}
		int len;
		try {
			if (getIndex() > _endPos) {
				super.setIndex(_endPos);
			}
			if ((len = _reader.read(_cbuf)) <= 0) {
				int count = 0;
				while (len == 0) {//some streams may return length == 0 ???
					if (count++ > 1000) {
						//IO error detected on &{0}&{1}{, reason: }
						throw new SIOException(SYS.SYS034,
							getSystemId(), "block length=0");
					}
					try {
						sleepwile();
					} catch (InterruptedException ex) {
						//IO error detected on &{0}&{1}{, reason: }
						throw new SIOException(SYS.SYS034, getSystemId(), ex);
					}
					len = _reader.read(_cbuf);
				}
				if (len < 0) {
					closeReader();
					if (getIndex() < _endPos) {
						return true;
					}
					super.setIndex(_endPos);
					if (_parserStack == null || _parserStack.size() <= 0) {
						return false;
					}
					return popParser();
				}
			}
			int remains;
			if ((remains = _endPos - getIndex()) > 0) {
				setEndBuffer(remains + len);
				if (len == _cbuf.length) {
					setBuffer(new StringBuilder(_endPos).
						append(getBuffer().substring(getIndex(),
							getIndex() + remains))
						.append(_cbuf).toString());
				} else {
					setBuffer(new StringBuilder(_endPos).
						append(getBuffer().substring(getIndex(),
							getIndex() + remains))
						.append(_cbuf, 0, len).toString());
				}
			} else {
				setBuffer(len == _cbuf.length ?
					new String(_cbuf) :	new String(_cbuf, 0, len));
			}
			setFilePos(getFilePos() + getIndex());
			setIndex(0);
			return true;
		} catch (IOException ex) {
			//this should never happen
			closeReader();
			//Program exception&{0}{: }
			throw new SRuntimeException(SYS.SYS036, STester.printThrowable(ex));
		}
	}
	private void sleepwile() throws InterruptedException {
		Thread.sleep(5);
	}

	/** Add character to actual buffer from input stream (if necessary and
	 * if available and).
	 * @return true if character was added to buffer.
	 */
	public final boolean increaseBuffer() {
		if (getIndex() + 1 < _endPos) {
			return true;
		}
		return ensureBuffer(1);
	}

	/** Increase buffer length for given number of characters.
	 * @param len length to be ensured.
	 * @return true if buffer was correctly increased.
	 */
	private boolean ensureBuffer(final int len) {
		int n;
		if ((n = getIndex() + len) <= _endPos) {
			return true;
		}
		if (getIndex() > _endPos) {
			super.setIndex(_endPos);
		}
		if (_reader == null) {
			return false;
		}
		StringBuilder sb = new StringBuilder(n).append(getBuffer());
		do {
			try {
				int c;
				if ((c = _reader.read()) >= 0) {
					sb.append((char) c); //append character
					setEndBuffer(_endPos + 1); //increase buffer end
				} else { // end of stream
					closeReader();
					int pos = getIndex(); //save position
					if (popParser()) {
						if (getIndex() < _endPos) {
							// append remaining buffer part
							sb.append(getUnparsedBufferPart());
							setEndBuffer(sb.length()); // update buffer length
							super.setIndex(pos);
							if (n <= _endPos) { // finished
								break;
							}
							continue;
						}
						super.setIndex(pos); //restore bufffer position
						continue;
					}
					super.setIndex(pos); //restore bufffer position
					break; // we have no more parsers.
				}
			} catch (IOException ex) {
				setBuffer(sb.toString());
				//this should never happen
				closeReader();
				throw new SRuntimeException(//Program exception&{0}{: }
					SYS.SYS036, STester.printThrowable(ex));
			}
		} while (n > _endPos);
		setBuffer(sb.toString());
		return getIndex() < _endPos;
	}

	/** Get previous parser from stack.
	 * @return true if parser has something to be parsed.
	 */
	public final boolean popParser() {
		while (_parserStack != null && !_parserStack.isEmpty()) {
			StringParser parser  = _parserStack.pop();
			_keepBufferCounter = parser._keepBufferCounter;
			setReportWriter(parser.getReportWriter());
			setFilePos(parser.getFilePos());
			setStartLine(parser.getStartLine());
			setLineNumber(parser.getLineNumber());
			setBuffer(parser.getBuffer());
			setIndex(parser.getIndex());
			setSysId(parser.getSysId());
			copyModificationInfo(parser);
			setLineInfoFlag(parser.isLineInfoFlag());
			_reader = parser._reader;
			if (getIndex() < _endPos) {
				return true;
			}
		}
		return false;
	}

	/** Save actual parser to stack.
	 * @param savedObject SParserSavedObject to be saved.
	 */
	public final void pushParser(final SParserSavedObject savedObject) {
		if (_parserStack == null) {
			_parserStack = new Stack<>();
		} else if (_parserStack.size() > 64) {//too many nested includes
			fatal(SYS.SYS033);//Parser can't continue; too many nested includes
			return;
		}
		StringParser parser = new StringParser();
		parser._keepBufferCounter = _keepBufferCounter;
		parser.setReportWriter(getReportWriter());
		parser.setFilePos(getFilePos());
		parser.setStartLine(getStartLine());
		parser.setLineNumber(getLineNumber());
		parser.setBuffer(getBuffer());
		parser.setIndex(getIndex());

		parser.setSysId(getSysId());
		parser.copyModificationInfo(this);
		parser.setLineInfoFlag(isLineInfoFlag());
		parser._reader = _reader;
//		parser._savedObject = _savedObject;
		_parserStack.push(parser);
//		_savedObject = savedObject;
		setLineNumber(0L);
		setStartLine(0L);
		setFilePos(0L);
		setSysId(null);
		setBuffer("");
		setIndex(0);
		clearModificationInfo();
		_reader = null;
//		_cbuf = null;
	}

	/** Get size of internal parser stack.
	 * @return size of internal parser stack.
	 */
	public final int getParserStackSize() {
		return _parserStack == null ? 0 : _parserStack.size();
	}

	/** Save old parser and set new source buffer.
	 * @param reader The reader.
	 * @param pos Starting position of the file.
	 * @param source Initial source buffer.
	 * @param sourceName Name of source (may be null).
	 * @param savedObject a SParserSavedObject with saved parameters or null.
	*/
	public final void pushSourceReader(final Reader reader,
		final int pos,
		final String source,
		final String sourceName,
		final SParserSavedObject savedObject) {
		pushParser(savedObject);
		setLineNumber(1L);
		setStartLine(getIndex());
		setFilePos(pos);
		setSysId(sourceName);
		setBuffer(source);
		setIndex(0);
	}

	/** Save old parser and set new source buffer.
	 * @param reader The reader.
	 * @param sourceName Name of source (may be null).
	 * @param savedObject a SParserSavedObject with saved parameters or null.
	*/
	public final void pushSourceReader(final Reader reader,
		final String sourceName,
		final SParserSavedObject savedObject) {
		pushSourceReader(reader, 0, null, sourceName, savedObject);
	}

	/** Set the parser to create detailed line positions. By default
	 * the value of this is set to false.
	 * @param lineInfo set the lineInfo flag.
	 */
	public final void setLineInfoFlag(final boolean lineInfo) {
		_lineInfo = lineInfo;
	}

	/** Check if the detailed line positions are required.
	 * @return true if and only if the detailed line positions are required.
	 */
	public final boolean isLineInfoFlag() {return _lineInfo;}

	/** Get part of source buffer from given position to end.
	 * @param index starting position.
	 * @return string with part of the source buffer from index to end.
	 */
	public final String getBufferPartFrom(final int index) {
		return index < _endPos ? _source.substring(index, _endPos) : "";
	}

	/** Increase buffer index.
	 * @return new buffer index or -1 if position exceeds buffer.
	 */
	public final int incBufIndex() {
		int pos = incIndex();
		if (pos < _endPos) {
			if ((_ch = _source.charAt(pos)) == '\n') {
				setNewLine();
			}
			return pos;
		} else {
			super.setIndex(_endPos);
			_ch = NOCHAR;
			return -1;
		}
	}

	@Override
	/** Get end index of source buffer.
	 * @return end index of source buffer.
	 */
	public int endPos() {return _endPos;}

	@Override
	/** Prepare character from the next position.
	 * @return next character or NOCHAR if the position is at
	 * the end of source.
	 */
	public final char nextChar() {
		int index = incIndex();
		return _ch = index <_endPos ? _source.charAt(index)
			: readNextBuffer() ? _source.charAt(getIndex()) : NOCHAR;
	}

	@Override
	/** Get character at the current position and set position to the next
	 * character in the source. If the position is at the end of source
	 * return NOCHAR.
	 * @return character at the current position or if the position is at
	 * the end of source return NOCHAR.
	 */
	public final char peekChar() {
		char result;
		if ((result = _ch) == '\n') {
			setNewLine();
		}
		nextChar();
		return result;
	}

	@Override
	/** Get the character on actual position.
	 * @return character on actual position or NOCHAR.
	 */
	public final char getCurrentChar() {return _ch;}

	/** Get character at the given position in the source buffer
	 * @param pos position of required character in the source buffer.
	 * @return required character or NOCHAR.
	 */
	public final char getCharAtPos(int pos) {
		return pos < _endPos ? _source.charAt(pos) : NOCHAR;
	}

	@Override
	/** Set source buffer position.
	 * @param index position to be set.
	 */
	public final void setIndex(final int index) {
		if (index >= _endPos) {
			_ch = NOCHAR;
			super.setIndex(_endPos);
		} else {
			super.setIndex(index);
			_ch = _source.charAt(index);
		}
	}

	/** Check if position is in buffer.
	 * @return true if and only if position is in buffer.
	 */
	public final boolean chkBufferIndex() {return getIndex() < _endPos;}

	/** Get actual SPosition of parsed source.
	 * @return actual source position.
	 */
	public final SPosition getPosition() {return new SPosition(this);}

	/** Reset buffer position to the previous position from parameter. If
	 * buffer was changed this method throws an exception. The position MUST be
	 * a position previously generated by this parser and MUST NOT be modified!
	 * @param pos a position previously generated by this parser.
	 * @throws SRuntimeException if position can't be set.
	 */
	public final void resetPosition(SPosition pos) {
		int x = pos.getIndex();
		long filePos = pos.getFilePos();
		String sysId = pos.getSysId();
		String mySysId = getSysId();
		if (x > _endPos || filePos != getFilePos() ||
			mySysId != null && !mySysId.equals(sysId) ||
			mySysId == null && sysId != null) {
			//"Can't set this buffer position for this parser&{0}{: }",
			throw new SRuntimeException(SYS.SYS081, x);
		}
		setLineNumber(pos.getLineNumber());
		setStartLine(pos.getStartLine());
		copyModificationInfo(pos);
		setIndex(x);
	}

	/** Set switch if reader should be closed.
	 * @param x if true, then reader is closed at the end of parsing.
	 */
	public final void setCloseReader(boolean x) {_closeReader = x;}

	@Override
	/** Get value of parsed item as string.
	 * @return value of parsed item as string.
	 */
	public final String getParsedString() { return _parsedString; }

	/** Set parsed string. This value will be returned by method
	 * getParsedString().
	 * @param s string to be set as parsed string.
	 */
	public final void setParsedString(final String s){_parsedString = s;}

	/** Get SDuration object with value of parsed duration.
	 * @return SDuration object with parsed values or null.
	 */
	public final SDuration getParsedSDuration() {return _parsedDuration;}

	/** Get SDatetime object with value of parsed date.
	 * @return SDatetime object with parsed values or null.
	 */
	public final SDatetime getParsedSDatetime() {
		return _parsedDatetime == null ? null : new SDatetime(_parsedDatetime);
	}

	/** Get value of parsed date. Returns instance of Calendar with parsed
	 * values. Values which were not parsed are set to zero.
	 * @return Calendar with parsed values.
	 * @throws SRuntimeException SYS072 Data error
	 */
	public final Calendar getParsedCalendar() {
		return _parsedDatetime == null ? null : _parsedDatetime.getCalendar();
	}

	@Override
	/** Check if actual position points to a character in given interval. Set
	 * the actual position to the next character if given character was
	 * in the specified interval.
	 * @param minCh minimum of checked interval.
	 * @param maxCh maximum of checked interval.
	 * @return the actual character character from actual position,
	 * otherwise return NOCHAR.
	 */
	public final char isInInterval(final char minCh, final char maxCh) {
		if (_ch < minCh || _ch > maxCh) {
			return NOCHAR;
		}
		char c;
		if ((c = _ch) == '\n') {
			setNewLine();
		}
		nextChar();
		return c;
	}

	@Override
	/** Check if actual position points to a character out of given interval.
	 * Set the actual position to the next character if given character was
	 * recognized.
	 * @param minCh minimum of checked interval.
	 * @param maxCh maximum of checked interval.
	 * @return the actual character character from actual position,
	 * otherwise return NOCHAR.
	 */
	public final char notInInterval(final char minCh, final char maxCh) {
		if (_ch >= minCh && _ch <= maxCh) {
			return NOCHAR;
		}
		char c;
		if ((c = _ch) == '\n') {
			setNewLine();
		}
		nextChar();
		return c;
	}

	/** Check if actual position points to given character ignoring case. Set
	 * the actual position to the next character if given character was
	 * not in specified interval.
	 * @param ch Character to be checked.
	 * @return true if character was present at actual position,
	 * otherwise return false.
	 */
	public final boolean isCharIgnoreCase(final char ch) {
		if (Character.toLowerCase(_ch)!=Character.toLowerCase(ch)) {
			return false;
		}
		nextChar();
		return true;
	}

	@Override
	/** If character on actual position is not character specified by
	 * argument the method returns the actual character and sets
	 * position to next character. Otherwise it returns NOCHAR and actual
	 * position remains unchanged.
	 * @param ch Character to be checked.
	 * @return character on actual position or NOCHAR.
	 */
	public final char notChar(final char ch) {
		if (_ch == ch) {
			return NOCHAR;
		}
		char c;
		if ((c = _ch) == '\n') {
			setNewLine();
		}
		nextChar();
		return c;
	}

	/** Check if actual position points to new line. If check is successful
	 * set the actual position to the next character.
	 * @return true if new line is at actual position, otherwise return false.
	 */
	public final boolean isNewLine() {
		if (_ch != '\n')  {
			return false;
		}
		setNewLine();
		nextChar();
		return true;
	}

	/** If character on actual position is not one of characters specified by
	 * given string argument the method returns the actual character and sets
	 * position to next character. Otherwise it returns NOCHAR and actual
	 * position remains unchanged.
	 * @param chars String with set of characters to be checked.
	 * @return character on actual position or NOCHAR.
	 */
	public final char notOneOfChars(final String chars) {
		if (_ch == NOCHAR || chars.indexOf(_ch) >= 0) {
			return NOCHAR;
		}
		char c;
		if ((c = _ch) == '\n') {
			setNewLine();
		}
		nextChar();
		return c;
	}

	@Override
	/** Check if actual position points to upper case letter. Set the source
	 * position to the next character if letter was recognized and return the
	 * character otherwise return NOCHAR and source position remains unchanged.
	 * @return character or NOCHAR.
	 */
	public final char isUpperCaseLetter() {
		if (Character.isLetter(_ch) && _ch == Character.toUpperCase(_ch)) {
			char c = _ch;
			nextChar();
			return c;
		}
		return NOCHAR;
	}

	@Override
	/** Check if actual position points to lower case letter. Set the source
	 * position to the next character if letter was recognized and return the
	 * character otherwise return NOCHAR and source position remains unchanged.
	 * @return character or NOCHAR.
	 */
	public final char isLowerCaseLetter() {
		if (Character.isLetter(_ch) && _ch == Character.toLowerCase(_ch)) {
			char c = _ch;
			nextChar();
			return c;
		}
		return NOCHAR;
	}

	@Override
	/** If on source position is one of tokens specified in the argument the
	 * method returns index to this item and sets position to the next position
	 * after a token. Otherwise it returns -1.
	 * @param tokens Array of tokens be checked.
	 * @return Index of found token or -1.
	 */
	public final int isOneOfTokens(final String... tokens) {
		int result = -1, len = -1;
		int pos = getIndex();
		for (int i = 0; i < tokens.length; i++) {
			int tlen;
			if (ensureBuffer(tlen = tokens[i].length()) &&
				_source.startsWith(tokens[i], pos)) {
				if (tlen > len) {
					result = i;
					len = tokens[i].length();
				}
			}
		}
		if (result != -1) {
			ensureBuffer(len+1);
			super.setIndex(pos += len);
			_ch = pos + len < _endPos || readNextBuffer()
				? _source.charAt(getIndex()) : NOCHAR;
		}
		return result;
	}

	@Override
	/** If on source position is one of tokens (ignored case) specified
	 * in the argument the method returns index to this item and sets position
	 * to the next position after a token. Otherwise it returns -1.
	 * @param tokens Array of tokens be checked.
	 * @return Index of found token or -1.
	 */
	public final int isOneOfTokensIgnoreCase(final String... tokens) {
		int result = -1, len = -1;
		int pos = getIndex();
		for (int i = 0; i < tokens.length; i++) {
			String token = tokens[i];
			int tlen = token.length();
			if (ensureBuffer(tlen) &&
				token.equalsIgnoreCase(_source.substring(pos, pos + tlen))) {
				if (tlen > len) {
					result = i;
					len = tlen;
				}
			}
		}
		if (result != -1) {
			ensureBuffer(len+1);
			super.setIndex(pos += len);
			_ch = pos + len < _endPos || readNextBuffer()
				? _source.charAt(getIndex()) : NOCHAR;
		}
		return result;
	}

	@Override
	/** Check if actual position points to given token (case insensitive). Set
	 * the actual position to the next character after the token if given token
	 * was recognized.
	 * @param token The token to be checked case insensitive.
	 * @return true if token was present at actual position.
	 */
	public final boolean isTokenIgnoreCase(final String token) {
		if (Character.toLowerCase(_ch) ==
			Character.toLowerCase(token.charAt(0))) {
			int len = token.length();
			int pos = getIndex();
			if (pos + len <= _endPos || ensureBuffer(len)) {
				if (token.equalsIgnoreCase(
					_source.substring(pos, pos + len))) {
					ensureBuffer(len+1);
					super.setIndex(pos += len);
					_ch = pos<_endPos || readNextBuffer()
						? _source.charAt(getIndex()) : NOCHAR;
					return true;
				}
			}
		}
		return false;
	}

	@Override
	/** Check if actual position points to signed integer number. Set the actual
	 * position to the next character after the number if number was recognized.
	 * @return true if signed integer was parsed, otherwise return false.
	 */
	public final boolean isSignedInteger() {
		if (getIndex() + 1 >= _endPos && !readNextBuffer()) {
			return false;
		}
		int i = getIndex();
		keepBuffer();
		int startToken = i;
		isOneOfChars("+-");
		if (isInteger()) {
			_parsedString = _source.substring(startToken, getIndex());
			freeBuffer();
			return true;
		}
		super.setIndex(startToken);
		_ch = _source.charAt(startToken);
		freeBuffer();
		return false;
	}

	@Override
	/** Check if actual position points to signed float number. Set the actual
	 * position to the next character after the number if number was recognized.
	 * @return true if number was parsed, otherwise return false.
	 */
	public final boolean isSignedFloat() {
		if (getIndex() + 2 >= _endPos && !readNextBuffer()) {
			return false;
		}
		int i = getIndex();
		keepBuffer();
		int startToken = i;
		isOneOfChars("+-");
		if (isFloat()) {
			_parsedString = _source.substring(startToken, getIndex());
			freeBuffer();
			return true;
		}
		super.setIndex(startToken);
		_ch = _source.charAt(startToken);
		freeBuffer();
		return false;
	}

	/** Set position to first character of next line or to the end od source.
	 * @return true if and only if next line was reached.
	 */
	public final boolean skipToNextLine() {
		if (_ch == '\n') {
			setNewLine();
		}
		while (incIndex() < _endPos || readNextBuffer()) {
			if (_source.charAt(getIndex()) == '\n') {
				setNewLine();
				break;
			}
		}
		if (incIndex() < _endPos || readNextBuffer()) {
			_ch = _source.charAt(getIndex());
			return true;
		}
		super.setIndex(_endPos);
		_ch = NOCHAR;
		return false;
	}

	@Override
	/** Skip to specified character. The position is set to the found
	 * character. Returns true and sets position to
	 * the position of character. Otherwise returns false and sets
	 * position to the end of source.
	 * @param ch Character to be searched for.
	 * @return true if the character was found.
	 */
	public final boolean findChar(final char ch) {
		if (_ch == ch) {
			return true;
		}
		while (incIndex() < _endPos || readNextBuffer()) {
			if ((_ch = _source.charAt(getIndex())) == ch) {
				return true;
			}
			if (_ch == '\n') {
				setNewLine();
			}
		}
		super.setIndex(_endPos);
		_ch = NOCHAR;
		return false;
	}

	/** Skip to next character after the argument. The position is set
	 * after the found character. Returns true and sets
	 * position after the position of character. Otherwise returns
	 * false and sets position to the end of source.
	 * @param ch Character to be searched for.
	 * @return true if the character was found.
	 */
	public final boolean findCharAndSkip(final char ch) {
		if (_ch == '\n') {
			setNewLine();
		}
		if (_ch == ch) {
			nextChar();
			return true;
		}
		while (incIndex() < _endPos || readNextBuffer()) {
			char c = _source.charAt(getIndex());
			if (c == '\n') {
				setNewLine();
			}
			if (c == ch) {
				nextChar();
				return true;
			}
		}
		super.setIndex(_endPos);
		_ch = NOCHAR;
		return false;
	}

	@Override
	/** Skip to first occurrence of one of specified character set. The position
	 * is set to the found character.Return the character from the list
	 * of characters if the character was found, otherwise return NOCHAR and
	 *  set the position to the end of source.
	 * @param chars String with set of characters.
	 * @return found character or NOCHAR.
	 */
	public final char findOneOfChars(final String chars) {
		while (getIndex() < _endPos || readNextBuffer()) {
			if (chars.indexOf(_ch = _source.charAt(getIndex())) >= 0) {
				return _ch;
			}
			incIndex();
			if (_ch == '\n') {
				setNewLine();
			}
		}
		super.setIndex(_endPos);
		return NOCHAR;
	}

	/** Skip to next character after the first occurrence of one of specified
	 * character set. Return the character from the list of characters if the
	 * character was found, otherwise return NOCHAR and set position
	 * to the end of source.
	 * @param chars String with set of characters.
	 * @return found character or NOCHAR.
	 */
	public final char findOneOfCharsAndSkip(final String chars) {
		while (getIndex() < _endPos || readNextBuffer()) {
			char c;
			if ((c = _source.charAt(getIndex())) == '\n') {
				setNewLine();
			}
			int i = incIndex();
			if (chars.indexOf(c) >= 0) {
				_ch = i <_endPos || readNextBuffer()
					? _source.charAt(getIndex()) : NOCHAR;
				return c;
			}
		}
		super.setIndex(_endPos);
		return NOCHAR;
	}

	@Override
	/** Find token. If the token was found returns true and sets
	 * position to the position of token. Otherwise returns
	 * false and sets position to the end of source.
	 * @param token Token to be found.
	 * @return true if the token was found.
	 */
	public final boolean findToken(final String token) {
		int len = token.length();
		char c = token.charAt(0);
		while (getIndex() + len <= _endPos || readNextBuffer()) {
			if (!ensureBuffer(len)) {
				break;
			}
			for (int j = getIndex(); j + len <= _endPos; j++) {
			id:
				if ((_ch = _source.charAt(j)) == c) {
					for (int i = 1; i < len; i++) {
						if ((_ch = _source.charAt(i+j)) != token.charAt(i)) {
							break id;
						}
					}
					ensureBuffer(len+1);
					setIndex(j);
					return true;
				}
				if (_ch == '\n') {
					setNewLine();
				}
			}
			nextChar();
		}
		super.setIndex(_endPos);
		_ch = NOCHAR;
		return false;
	}

	/** Find token in source text and set position to next character after
	 * the found token. Returns true if the token was found, otherwise
	 * returns false and sets position to the end of source.
	 * @param token Token to be found.
	 * @return true if the token was found.
	 */
	public final boolean findTokenAndSkip(final String token) {
		if (findToken(token)) {
			int len = token.length();
			ensureBuffer(len+1);
			setIndex(getIndex() + len);
			return true;
		}
		return false;
	}

	/** Get end of buffer (first not existing position).
	 * @return the end of buffer (first not existing position).
	 */
	public final int getEndBufferIndex() { return _endPos; }

	/** Get parsed part of source buffer from starting position to
	 * the actual position.
	 * @return string with parsed part of the source buffer from beginning.
	 */
	public String getParsedBufferPart() {
		int x = getIndex();
		return x < _endPos ? _source.substring(0, x) : _source;
	}

	@Override
	/** Get parsed part of source buffer from given position to actual
	 * position.
	 * @param index starting position.
	 * @return string with parsed part of the source buffer starting from index.
	 */
	public final String getParsedBufferPartFrom(final int index) {
		int x = getIndex();
		return index 0 ? _source.charAt(0) : NOCHAR;
	}

	/** Set source buffer and set position to value from argument.
	 * @param source Parsed string.
	 */
	public final void setSourceBuffer(final SBuffer source) {
		super.setIndex(0);
		_source = source.getString();
		_endPos = _source.length();
		setFilePos(source.getFilePos());
		setLineNumber(source.getLineNumber());
		setStartLine(source.getStartLine());
		setSysId(source.getSysId());
		if (_lineInfo) {
			cloneModificationInfo(source);
		} else {
			clearModificationInfo();
		}
		closeReader();
		_ch = _endPos > 0 ? _source.charAt(0) : NOCHAR;
	}

	/** Change source buffer and position info.
	 * @param pos position where to make change.
	 * @param length number of characters to be changed.
	 * @param replacement string with the replacement data.
	 * @param fixed if true one position will be used for whole range.
	 */
	public final void changeBuffer(final int pos,
		final int length,
		final String replacement,
		final boolean fixed) {
		int newLength = replacement == null ? 0 : replacement.length();
		if (newLength == 0) {
			if (length > 0) { //delete
				if (isLineInfoFlag()) {
					updatePositions(pos, length, 0, fixed);
				}
				_endPos = (_source = new StringBuilder(_source)
					.delete(pos, pos + length).toString()).length();
			}
		} else {
			if (isLineInfoFlag()) {
				updatePositions(pos, length, newLength, fixed);
			}
			_endPos = (_source = new StringBuilder(_source)
				.replace(pos, pos + length, replacement).toString()).length();
		}
		setIndex(pos);
	}

	/** Get value of parsed integer.
	 * @return the parsed integer.
	 * @throws SRuntimeException SYS072 Data error
	 */
	public final int getParsedInt() {
		try {
			return Integer.parseInt(_parsedString.charAt(0) == '+'
				? _parsedString.substring(1):_parsedString);
		} catch(NumberFormatException ex) {
			throw new SRuntimeException(SYS.SYS072, ex); //Data error&{0}{: }
		}
	}

	/** Get value of parsed integer as long.
	 * @return Parsed long.
	 * @throws SRuntimeException SYS072 Data error
	 */
	public final long getParsedLong() {
		try {
			return Long.parseLong(_parsedString.charAt(0) == '+'
				? _parsedString.substring(1):_parsedString);
		} catch(NumberFormatException ex) {
			throw new SRuntimeException(SYS.SYS072, ex);//Data error&{0}{: }
		}
	}

	/** Get value of parsed float.
	 * @return Parsed float.
	 * @throws SRuntimeException SYS072 Data error
	 */
	public final float getParsedFloat() throws SRuntimeException {
		try {
			return Float.parseFloat(_parsedString.charAt(0) == '+'
				? _parsedString.substring(1) : _parsedString);
		} catch(NumberFormatException ex) {
			throw new SRuntimeException(SYS.SYS072, ex); //Data error&{0}{: }

		}
	}

	/** Get value of parsed float number as double.
	 * @return Parsed double.
	 * @throws SRuntimeException SYS072 Data error
	 */
	public final double getParsedDouble() throws SRuntimeException {
		try {
			return Double.parseDouble(_parsedString.charAt(0) == '+'
				? _parsedString.substring(1) : _parsedString);
		} catch(NumberFormatException ex) {
			throw new SRuntimeException(SYS.SYS072, ex); //Data error&{0}{: }
		}
	}

	/** Get value of parsed float number as BigInteger.
	 * @return Parsed BigInteger.
	 * @throws SRuntimeException SYS072 Data error
	 */
	public final BigInteger getParsedBigIteger() throws SRuntimeException {
		try {
			return new BigInteger(_parsedString.charAt(0) == '+'
				? _parsedString.substring(1) : _parsedString);
		} catch(Exception ex) {
			throw new SRuntimeException(SYS.SYS072, ex); //Data error&{0}{: }
		}
	}

	/** Get value of parsed float number as BigDecimal.
	 * @return Parsed BigDecimal.
	 * @throws SRuntimeException SYS072 Data error
	 */
	public final BigDecimal getParsedDecimal() throws SRuntimeException {
		try {
			return new BigDecimal(_parsedString.charAt(0) == '+'
				? _parsedString.substring(1) : _parsedString);
		} catch(Exception ex) {
			throw new SRuntimeException(SYS.SYS072, ex); //Data error&{0}{: }
		}
	}

	/** Check if parsed datetime is valid .
	 * @return true if parsed date is OK.
	 */
	public boolean testParsedDatetime() {
		return _parsedDatetime != null && _parsedDatetime.check();
	}

	@Override
	/** Check if parser reached the end of source.
	 * @return true if parser reached the end of source, otherwise
	 * return false.
	 */
	public final boolean eos() {return (getIndex()>=_endPos&&!readNextBuffer());}

	/** Get character from buffer index.
	 * @param index index to source buffer.
	 * @return character or NOCHAR.
	 */
	public final char charFromBuffer(final int index) {
		return index < _endPos ? _source.charAt(index) : NOCHAR;
	}

	@Override
	/** Parse white space.
	 * @return true if white space was present at actual position,
	 * otherwise return false.
	 */
	public final boolean isSpace() {
		if (XML_CHARTAB0[_ch] != XML_CHAR_WHITESPACE) {
			return false;
		}
		if (_ch == '\n') {
			setNewLine();
		}
		nextChar();
		return true;
	}

	@Override
	/** Parse one or more white spaces.
	 * @return true if white spaces were present at actual position,
	 * otherwise return false.
	 */
	public final boolean isSpaces() {
		if (XML_CHARTAB0[_ch] != XML_CHAR_WHITESPACE) {
			return false;
		}
		if (_ch == '\n') {
			setNewLine();
		}
		if (incIndex() < _endPos || readNextBuffer()) {
			while (XML_CHARTAB0[_ch = _source.charAt(getIndex())] ==
				XML_CHAR_WHITESPACE) {
				if (_ch == '\n') {
					setNewLine();
				}
				if (incIndex() >= _endPos && !readNextBuffer()) {
					_ch = NOCHAR;
					break;
				}
			}
		} else {
			_ch = NOCHAR;
		}
		return true;
	}

	@Override
	/** Check if actual position points to given character. Set the actual
	 * position to the next character if given character was recognized.
	 * @param ch Character to be checked.
	 * @return true if character was present at actual position,
	 * otherwise return false.
	 */
	public final boolean isChar(final char ch) {
		if (_ch != ch)  {
			return false;
		}
		nextChar();
		return true;
	}

	@Override
	/** If actual character is one of characters specified in given string the
	 * method returns this character and sets position to the next
	 * character. Otherwise it returns NOCHAR.
	 * @param chars String with characters to be checked.
	 * @return the actual character or NOCHAR.
	 */
	public final char isOneOfChars(final String chars) {
		if (chars.indexOf(_ch) < 0) {
			return NOCHAR;
		}
		char c;
		if ((c = _ch) == '\n') {
			setNewLine();
		}
		nextChar();
		return c;
	}

	@Override
	/** Check if at the current position is a digit.
	 * @return digital value of digit or -1;
	 */
	public final int isDigit() {
		if (_ch >= '0' && _ch <= '9') {
			int i = _ch - '0';
			nextChar();
			return i;
		}
		return -1;
	}

	@Override
	/** Check if actual position points to letter. Set the source position
	 * to the next character if letter was recognized and return the character
	 * otherwise return NOCHAR and source position remains unchanged.
	 * @return character or NOCHAR.
	 */
	public final char isLetter() {
		if (Character.isLetter(_ch)) {
			char c = _ch;
			nextChar();
			return c;
		}
		return NOCHAR;
	}

	@Override
	/** Check if actual position points to letter or digit. Set the source
	 *  position to the next character if letter was recognized and return
	 * the character otherwise return NOCHAR and source position remains
	 * unchanged.
	 * @return character or NOCHAR.
	 */
	public final char isLetterOrDigit() {
		if (Character.isLetterOrDigit(_ch)) {
			char c = _ch;
			nextChar();
			return c;
		}
		return NOCHAR;
	}

	@Override
	/** Check if actual position points to given token. Set the actual
	 * position to the next character after the token if given token was
	 * recognized.
	 * @param token The token.
	 * @return true if token was present at actual position.
	 */
	public final boolean isToken(final String token) {
		if (_ch == token.charAt(0)) {
			int len;
			if (getIndex() + (len =  token.length()) <= _endPos
				|| ensureBuffer(len)){
				int x = getIndex();
				if (!_source.startsWith(token, x)) {
					return false;
				}
				ensureBuffer(len+1);
				setIndex(getIndex() + len);
				return true;
			}
		}
		return false;
	}

	@Override
	/** Parse integer number (ASCII digits '0' .. '9'). Set the actual position
	 * to the next character after the number.
	 * @return true if and only if integer was parsed.
	 */
	public final boolean isInteger() {
		if (_ch > '9' || _ch < '0') {
			return false;
		}
		keepBuffer();
		int startToken = getIndex();
		while(_ch >= '0' && _ch <= '9') {
			nextChar();
		}
		int x = getIndex();
		_parsedString = _source.substring(startToken, x);
		_ch = x < _endPos || readNextBuffer()?_source.charAt(getIndex()):NOCHAR;
		freeBuffer();
		return true;
	}

	@Override
	/** Parse unsigned float number. Set actual position to the next character
	 * after the number if number was recognized.
	 * @return true if and only if float number was parsed.
	 */
	public final boolean isFloat() {
		if (getIndex() + 2 >= _endPos && !readNextBuffer()) {
			return false;
		}
		int x = getIndex();
		keepBuffer();
		int startToken = x;
		if (!isInteger()) {
			if (_ch != '.' && _ch != 'e' && _ch != 'E') {
				freeBuffer();
				return false;
			}
		}
		if (isFloatPart()) {
			_parsedString = _source.substring(startToken, getIndex());
			freeBuffer();
			return true;
		}
		super.setIndex(startToken);
		_ch = _source.charAt(startToken);
		freeBuffer();
		return false;
	}

	/** Check if actual position points to part of float number. Set the actual
	 * position to the next character after the number if number part
	 * was recognized.
	 * @return true if number was parsed, otherwise return false.
	 */
	private boolean isFloatPart() {
		if (getIndex() >= _endPos) {
			return false;
		}
		int x = getIndex();
		boolean wasDecPoint;
		if (wasDecPoint = isChar('.')) {
			while(_ch >= '0' && _ch <= '9') {
				nextChar();
			}
			x = getIndex();
			_ch = x < _endPos || readNextBuffer()
				? _source.charAt(x = getIndex()) : NOCHAR;
		}
		if (isOneOfChars("eE") > 0) {//exponent
			isOneOfChars("+-");
			if (_ch < '0' || _ch > '9') {
				setIndex(x); //missing number after exponent; reset position x
				return wasDecPoint;
			}
			while(_ch >= '0' && _ch <= '9') {
				nextChar();
			}
			return true;
		}
		return wasDecPoint;
	}

////////////////////////////////////////////////////////////////////////////////
// parsing of date and time
////////////////////////////////////////////////////////////////////////////////

	/** Parse date in ISO8601 format (see
	 * 
	 * www.w3.org/TR/NOTE-datetime).
	 * @return true if date on current position suits to ISO8601
	 * date format.
	 */
	public final boolean isISO8601Date() {
		return isDatetime(
			"yyyy-MM-dd[Z]|yyyy-DDD[Z]|yyyy-'W'w-e[Z]|yyyy'W'wwe[Z]");
	}

	/** Parse time in ISO8601 format (see
	 * 
	 * www.w3.org/TR/NOTE-datetime).
	 * @return true if date on current position suits to ISO8601
	 * time format.
	 */
	public final boolean isISO8601Time() {
		return isDatetime("HH:mm[:ss[.S]][Z]");
	}

	/** Parse date according to RFC822 (email format). (see
	 * rfc822).
	 * @return true if date on current position suits to RFC822 date
	 * and time format.
	 */
	public final boolean isRFC822Datetime() {
		return isDatetime("[EEE, ]d MMM yyyy HH:mm[:ss][ ZZZZZ][ (z)]"
			+ "|[EEE, ]d MMM YY HH:mm[:ss][ ZZZZZ][ (z)]");
	}

	/** Parse date in the printable form.
	 * @return true if date on current position is in printable form.
	 */
	public final boolean isPrintableDatetime() {
		return isDatetime("[EEE ]MMM d HH:mm[:ss[.S]][ ZZZZZ] y"
			+ "|{L(*)}[EEE ]MMM d HH:mm[:ss[.S]][ ZZZZZ] y");
	}

	/** Parse date in ISO8601 date or date and time (see
	 * 
	 * www.w3.org/TR/NOTE-datetime).
	 * @return true if date on current position suits to ISO8601
	 * date and time format.
	 */
	public final boolean isISO8601Datetime() {
		return isDatetime("yyyy-MM-dd['T'HH:mm[:ss[.S]][Z]]" +
			"|yyyy-DDD['T'HH:mm[:ss[.S]][Z]]" +
			"|yyyy-'W'w-e['T'HH:mm[:ss[.S]][Z]]" +
			"|yyyy'W'wwe['T'HH:mm[:ss[.S]]][Z]" +
			"|--MM[-dd][Z]" + //month or month day
			"|---dd[Z]"+ //day
			"|yyyy[-MM][Z]"+ // year or year momth
			"|HH:mm[:ss[.S]][Z]]"); //time
	}

	/** Parse ISO8601 date and time format (see
	 * 
	 * www.w3.org/TR/NOTE-datetime).
	 * @return true if date on current position suits to ISO8601 date format.
	 */
	public final boolean isISO8601DateAndTime() {
		return isDatetime("yyyy-MM-dd'T'HH:mm[:ss[.S]][Z]" +
			"|yyyy-DDD'T'HH:mm[:ss[.S]][Z]" +
			"|yyyy-'W'w-e'T'HH:mm[:ss[.S]][Z]" +
			"|yyyy'W'wwe'T'HH:mm[:ss[.S]][Z]");
	}

	/** Parse date and/or time. Argument is string with format mask where
	 * characters are interpreted as follows:
	 * 
a AM/PM marker *
D day in year *
d day of month (1 through 31) *
E day of week (text) *

E, EE, EEE - abbreviated day name (Mon, Tue, .. Sun *

EEEE (and more)- full month name (Monday, Tuesday, .. Sunday *
e day of week (number 1=Monday, 7=Sunday) *
F day of week in month *
G era (0=BC, 1=AD) *
H hour (0 through 23) *
h hour (1..12 with am/pm) *
K hour 0..11 with am/pm) *
k hour 1..23 *
M month in year (1=January .. 12=December). *

M - number without leading zero *

MM - number with leading zero *

MMM - abbreviated month name (Jan, Feb, .. Dec *

MMMM (and more)- full month name (January, February, .. December *
m minute (0 through 59) *
s second (0 through 59, may be 60) *
S digits representing a decimal fraction of a second *
y year *
Y year (ISO variant, including negative numbers and leading * zeroes) *
YY year (two digits specification, century is added from * the actual year) *
RR year - two digits specification, century is added * according to ORACLE specification: *

Let c is century of actual date and y is number representing the year * in actual century. Let r be the specified two-digit year; then *

if 00 <= y <= 49 and 00 <= r <= 49 then * result = c * 100 + r *

if 00 <= y <= 49 and 50 <= r <= 99 then * result = (c + 1) * 100 + r *

if 50 <= y <= 99 and 00 <= r <= 49 then * result = (c - 1) * 100 + r *

if 50 <= y <= 99 and 50 <= r <= 99 then * result = c * 100 + r *
W week in month *
w week in year *
Z time zone designator (Z or +hh:mm or -hh:mm) *

ZZ time zone designator (Z or +h:m or -h:m) *

ZZZZZ time zone designator (Z or +hhmm or -hhmm) *

ZZZZZZ time zone designator (Z or +hh:mm or -hh:mm) *
z zone name *

z, zz, zzz abbreviated zone name (CET) *

zzzz and more full zone name (Central European Time) *

One occurrence of above characters represent number without leading * zeroes. Repeated characters M,d,H,h,m and s represents n-digit number * with leading zeroes. However, the only year specifications 'y', 'yy' * and 'yyyy' are permitted, otherwise the exception SYS059 is thrown. *

Other characters are interpreted as strings which must match. If the * mask should describe one of above characters it must be quoted in * apostrophes. The character apostrophe itself must be doubled. *

Parts of mask in square brackets are optional (e.g.: *

"HH:mm[:ss[.SSS]][z]" *

describes time specification where fields with seconds, milliseconds * or zone are optional). *

Variants of mask are separated by bar character '|' (e.g. *

"yyyyMMdd|EEE, d MMM y H:m:s" *

allows to specify date in format of number or in "unix" format). * Specification of default (predefined) value is in {} brackets and must * precede each variant specification (e.g.: *

"{H8m30}[HH:mm]ss|{H8m30}yyyyMMdd[HH:mm]" * - if hours and minutes are not specified the value is set to 08:30). * @param mask String with date format. * @return true if the date source on current position suits * to given format. * @throws SRuntimeException if mask format is incorrect: *
SYS059 incorrect year specification *
SYS049 unclosed quoted literal */ public final boolean isDatetime(final String mask) throws SRuntimeException{ if (getIndex() + 10 >= _endPos && !readNextBuffer()) { return false; } MyDate myDate = new MyDate(getIndex()); keepBuffer(); int startPos = getIndex(); int flen = mask.length(); //(year,month,date,hour,minute,second) int fpos = 0; boolean failVariant = false; //true if variant fails int i; char hourKind = ' '; int ampm = -1; int era = 0; List _variants = null; loop: while (fpos < flen || failVariant) { char pat; if (failVariant) { if (myDate._chain != null) { setIndex(myDate._startPos); //(year,month,date,hour,minute,second) myDate = myDate._chain; while (fpos < flen) { if ((pat = mask.charAt(fpos++)) == ']') {//reset failVariant = false; continue loop; } else if (pat == '\'' || pat == '"') {// literal while (fpos + 1 < flen) { if (mask.charAt(fpos++) == pat) { if (fpos < flen && mask.charAt(fpos) == pat) { fpos++; continue; } break; } } } } } else { setIndex(startPos); //reset position while (fpos < flen) { if ((pat = mask.charAt(fpos++)) == '|') {// reset myDate.reset(startPos); failVariant = false; break; } else if (pat == '\'') {// literal fpos++; while (fpos < flen) { if (mask.charAt(fpos++) == '\'') { if (fpos < flen && mask.charAt(fpos) == '\'') { fpos++; continue; } break; } } } } if (fpos < flen) { continue; } else { if (_variants == null) { freeBuffer(); return false; } break; } } } int n; pat = mask.charAt(fpos++); if (fpos >= flen || pat == '\'' || mask.charAt(fpos) != pat) { n = 0; //one character of specified format item } else { n = fpos - 1; do { fpos++; } while (fpos < flen && mask.charAt(fpos) == pat); n = fpos - n; } switch (pat) { case '|': //variant part if (_variants == null) { _variants = new ArrayList<>(); } MyDate md = new MyDate(myDate); md._endPos = getIndex(); _variants.add(md); myDate.reset(startPos); setIndex(myDate._startPos); continue; case '{': //initialize part myDate.reset(startPos); //??? StringParser p = new StringParser(mask, fpos); Report r = p.checkDateFormatDefaults(); if (r != null) { throw new SRuntimeException(r); // error in mask } fpos = p.getIndex(); myDate.setDefaults(p._parsedDatetime); continue; case '[': //optional part myDate = new MyDate(myDate, getIndex()); continue; case ']': //optional part if (myDate._chain != null) { myDate._chain = null; } continue; case 'D': //day in year if ((i = readUnsignedIntSpecifiedLength(n)) < 0) { failVariant = true; continue; } myDate._yearDay = i; continue; case 'F': //day of week in month if ((i = readUnsignedIntSpecifiedLength(n)) < 0) { failVariant = true; continue; } myDate._dayOfWeekInMonth = i; continue; case 'w': //week in year if ((i = readUnsignedIntSpecifiedLength(n)) < 0) { failVariant = true; continue; } myDate._weekInYear = i; continue; case 'W': //week in month if ((i = readUnsignedIntSpecifiedLength(n)) < 0) { failVariant = true; continue; } myDate._weekInMonth = i; continue; case 'G': //era designator (BC, AD) i = isOneOfTokens( myDate.getLocaleFormatSymbols().getEras()); if (i < 0) { //error failVariant = true; continue; } era = i == 0 ? -1 : 1; continue; case 'd': //day if ((i = readUnsignedIntSpecifiedLength(n)) < 0) { failVariant = true; continue; } myDate._day = i; continue; case 'M': //month in year i = n < 3 ? readUnsignedIntSpecifiedLength(n) : n == 3 ? isOneOfTokens(myDate. getLocaleFormatSymbols().getShortMonths()) : isOneOfTokens(myDate. getLocaleFormatSymbols().getMonths()); if (i < 0) { failVariant = true; continue; } if ((n >= 3)) { i++; } myDate._month = i; continue; case 'm': //minute if ((i = readUnsignedIntSpecifiedLength(n)) < 0) { failVariant = true; continue; } myDate._minute = i; continue; case 's': //second if ((i = readUnsignedIntSpecifiedLength(n)) < 0) { failVariant = true; continue; } myDate._second = i; continue; case 'S': {//millisecond if (_ch < '0' || _ch > '9') { failVariant = true; continue; } i = _ch - '0'; nextChar(); double fraction = i / 10.0; double exp = 10.0; int j = 0; while (n == 0 || ++j < n) { if (_ch < '0' || _ch > '9') { if (n != 0 ) { failVariant = true; continue loop; } break; } int k = _ch - '0'; nextChar(); fraction += k / (exp *= 10.0); } myDate._fraction = fraction; continue; } case 'a': { //AM/PM marker int pm = isOneOfTokens(myDate. getLocaleFormatSymbols().getAmPmStrings()); if (pm < 0) { //error failVariant = true; continue; } ampm = pm; continue; } case 'E': //day of week (text) i = (n > 3) ? isOneOfTokens(myDate. getLocaleFormatSymbols().getWeekdays()) : isOneOfTokens(myDate. getLocaleFormatSymbols().getShortWeekdays()); if (i < 0) {//error failVariant = true; continue; } myDate._weekDay = i; continue; case 'e': //day of week (number) if ((i = readUnsignedIntSpecifiedLength(n)) < 0) { failVariant = true; continue; } switch (i) { case 1: myDate._weekDay = Calendar.MONDAY; break; case 2: myDate._weekDay = Calendar.TUESDAY; break; case 3: myDate._weekDay = Calendar.WEDNESDAY; break; case 4: myDate._weekDay = Calendar.THURSDAY; break; case 5: myDate._weekDay = Calendar.FRIDAY; break; case 6: myDate._weekDay = Calendar.SATURDAY; break; case 7: myDate._weekDay = Calendar.SUNDAY; break; default: failVariant = true; continue; } continue; case 'K': //hour 0..11 case 'k': //hour in day (1..24) case 'H': //hour in day (0..23) case 'h': //hour in am/pm (1..12) hourKind = pat; if ((i = readUnsignedIntSpecifiedLength(n)) < 0) { failVariant = true; continue; } myDate._hour = i; continue; case 'Y': //year - two digits, century from the actual year if (n != 0 && n != 2) { freeBuffer(); // Datetime mask: incorrect year // specification&{0}{, position: } throw new SRuntimeException(SYS.SYS059, fpos-3); } boolean minus; if (minus = _ch == '-') { nextChar(); } char first = _ch; int pos = getIndex(); if ((i = readUnsignedIntSpecifiedLength(0)) < 0) { failVariant = true; continue; } if (n == 2) { //actual century int c = new GregorianCalendar().get(Calendar.YEAR)/100; myDate._year = c * 100 + i; } else if (pos - getIndex() > 4 && first == '0') { failVariant = true; continue; } else { myDate._year = minus ? -i : i; } continue; case 'y': //year if (n == 3) { freeBuffer(); //Datetime mask: incorrect year // specification&{0}{, position: } throw new SRuntimeException(SYS.SYS059, fpos-3); } int sign = 1; if (n == 4 || n == 0) { if ((sign = _ch == '-' ? -1 : 1) == -1) { nextChar(); } int q = (fpos >= flen || "MD".indexOf(mask.charAt(fpos)) < 0) ? 0 : n; int k = getIndex(); i = readUnsignedIntSpecifiedLength(q); if (i >= 0 && n == 4 && getIndex() - k < 4) { i = -1; } } else { i = readUnsignedIntSpecifiedLength(n); } if (i < 0) { failVariant = true; continue; } if (n == 2 && i < 100) { // this is a nasty feature int century = new GregorianCalendar().get(Calendar.YEAR); int year = century % 100; // actual year in century; century /= 100; // actual century // decrease century if the actual year in in century // is lower then the parsed value. i += ((year < i) ? century - 1 : century) * 100; } myDate._year = i * sign; continue; case 'R': {//year - two digits (database) /* Two digits year (see Oracle format). Century is generated according to following rules: If RR is from the interval 00 .. 49 then a) if last two digits of the actual year are 00..49 then the century is taken from the actual year. b) if last two digits of the actual year are 50..99 then the century is taken from the actual year increased by 1. If RR is from the interval 50 .. 99 then c) if last two digits of the actual year are 00..49 then the century is taken from the actual year decreased by 1. d) if last two digits of the actual year are 50..99 then the century is taken from the actual year. */ if (n != 2) { //Datetime mask: incorrect year specification // &{0}{, position: } throw new SRuntimeException(SYS.SYS059, fpos-3); } if ((i = readUnsignedIntSpecifiedLength(n)) < 0) { failVariant = true; continue; } int y = new GregorianCalendar().get(Calendar.YEAR); int c = y /100; //actual century y = y % 100; //last two digits of the actual year //actual years in the actual century < 50 myDate._year = i < 50 ? y < 50 ? c * 100 + i : ((c + 1) * 100 + i) : y < 50 ? (c - 1) * 100 + i : (c * 100 + i); continue; } case 'Z': //ISO case 'z': {//RFC822 zone if (n != 0 && n != 2 && n != 5 && n != 6) { freeBuffer(); //Datetime mask: incorrect zone format // &{0}{, position: } throw new SRuntimeException(SYS.SYS050, fpos-n); } TimeZone tz = readTimeZone(n, pat); if (tz != null) { myDate._tz = tz; continue; } else { failVariant = true; //not parsed continue; } } case '"': case '\'': {//quoted string char delim = pat; int beg = fpos - 1; while (fpos < flen) { if ((pat = mask.charAt(fpos++)) == delim) { if (fpos >= flen || mask.charAt(fpos) != delim) { break; } pat = mask.charAt(fpos++); //double apos } if (_ch == pat) { nextChar(); } else { while (fpos < flen) { if (mask.charAt(fpos++) == delim) { if (fpos < flen && mask.charAt(fpos) == delim) { fpos++; continue; } failVariant = true; continue loop; } } pat = ' '; break; } } if (pat != delim) { freeBuffer(); //Datetime mask: unclosed quoted // literal&{0}{, position: } throw new SRuntimeException(SYS.SYS049, (beg+1)); } continue; } case '?': {//one of chars char delim; if (fpos < flen && ((delim=mask.charAt(fpos))=='\'' || delim == '"')) { //follows string specification int beg = fpos++; boolean foundChar = false; while (fpos < flen) { if ((pat = mask.charAt(fpos++)) == delim) { if (fpos >= flen || mask.charAt(fpos) != delim) { break; } pat = mask.charAt(fpos++); //double apos } if (!foundChar && _ch == pat) { foundChar = true; do { if (_ch != pat) { foundChar = false; } else { if (incIndex() < _endPos) { _ch = _source.charAt(getIndex()); } else { _ch = NOCHAR; } } } while (--n > 0); } } if (pat != delim) { freeBuffer(); //Datetime mask: unclosed quoted // literal&{0}{, position: } throw new SRuntimeException(SYS.SYS049, beg); } if (foundChar) { continue; } else { failVariant = true; continue; } } do { if (_ch != pat) { failVariant = true; } else { if (incIndex() < _endPos) { _ch = _source.charAt(getIndex()); } else { _ch = NOCHAR; } } } while (--n > 0); continue; } default: do { if (_ch != pat) { failVariant = true; break; } else { nextChar(); } } while (--n > 0); } } if (_variants != null) { MyDate x = myDate; x._endPos = getIndex(); int endPos = 0; _variants.add(x); for (MyDate y: _variants) { if (y._endPos > endPos) { endPos = y._endPos; x = y; } } myDate = x; setIndex(myDate._endPos); } _parsedString = _source.substring(startPos, getIndex()); if (ampm == 1 && (hourKind == 'h' || hourKind == 'K')) { myDate._hour += 12; } if (myDate._hour == 24 && (hourKind == 'h' || hourKind == 'k')) { myDate._hour = 0; } if (era < 0) { myDate._year = - myDate._year; } if (myDate._year != Integer.MIN_VALUE && myDate._month == Integer.MIN_VALUE && myDate._day == Integer.MIN_VALUE) { if (myDate._yearDay != Integer.MIN_VALUE) { GregorianCalendar gc =//compute month and date from year day new GregorianCalendar(myDate._year, 0, 1); gc.add(Calendar.DAY_OF_YEAR, myDate._yearDay - 1); myDate._yearDay = Integer.MIN_VALUE; myDate._year = gc.get(Calendar.YEAR); myDate._month = gc.get(Calendar.MONTH) + 1; myDate._day = gc.get(Calendar.DAY_OF_MONTH); } else if (myDate._weekInYear != Integer.MIN_VALUE && myDate._weekDay != Integer.MIN_VALUE) { GregorianCalendar gc =//compute month and date from week and day new GregorianCalendar(myDate._year, 0, 1); if (Calendar.SUNDAY == myDate._weekDay) { myDate._weekInYear++; } //Week is between 1 to 52 (or 53 the last week in year) gc.add(Calendar.WEEK_OF_YEAR, myDate._weekInYear -1); gc.add(Calendar.DATE, myDate._weekDay - gc.get(Calendar.DAY_OF_WEEK)); myDate._weekInYear = Integer.MIN_VALUE; myDate._weekDay = Integer.MIN_VALUE; myDate._year = gc.get(Calendar.YEAR); myDate._month = gc.get(Calendar.MONTH) + 1; myDate._day = gc.get(Calendar.DAY_OF_MONTH); } } freeBuffer(); _parsedDatetime = myDate; return true; } /** Read from source an unsigned integer with specified number of digits. * If the argument with number of digits is 0 the number of digits is * considered as unspecified. If on the current source position is not * required integer number the method returns value of Integer.MIN_VALUE. * @param digits Required number of digits. * @return Parsed integer value of unsigned integer or Integer.MIN_VALUE. */ private int readUnsignedIntSpecifiedLength(final int digits) { int result; if ((result = isDigit()) >= 0) { int i; if (digits == 0) { while((i = isDigit()) >= 0) { result = result * 10 + i; } } else { int ndigits = digits; while (--ndigits > 0) { if ((i = isDigit()) < 0) { return Integer.MIN_VALUE; } result = result * 10 + i; } } return result; } return Integer.MIN_VALUE; } private TimeZone readTimeZone(final int n, final char pat) { if (pat == 'Z' && isChar('Z') && (n == 0 || n == 6)) { //Z => UTC+00:00 return TimeZone.getTimeZone("UTC"); } char ch; if ((ch = isOneOfChars("+-")) == NOCHAR && (pat == 'Z' && (n > 0 && n < 6) || pat == 'z')) {//zone name ParsePosition pp = new ParsePosition(getIndex()); boolean zoneOffsetSpec = false; new SimpleDateFormat( SUtils.makeStringOfChars(n==0 ? 1 : n, 'z')).parse(_source, pp); int newPos = pp.getIndex(); if (newPos != getIndex()) { String s = _source.substring(getIndex(), pp.getIndex()); int ndx; if ((ndx=s.indexOf('+')) > 0 || (ndx=s.indexOf('-')) > 0) { ch = s.charAt(ndx); newPos = getIndex() + ndx; zoneOffsetSpec = true; } } else { return null; //not parsed } String s = _source.substring(getIndex(), newPos); TimeZone tz = TimeZone.getTimeZone(s); if (tz == null || "GMT".equals(tz.getID()) && !(s.equalsIgnoreCase("GMT") || s.equalsIgnoreCase("UTC"))) { if ("CEST". equals(s)) { tz = TimeZone.getTimeZone("CET"); } else { return null; //????? } } // parsed OK if (!zoneOffsetSpec) { setIndex(newPos); return tz; }//after UTC or GMT we still try to read offset! setIndex(newPos + 1); } if (eos() || ch == NOCHAR) { return null; //'+' or '-' expected } boolean minus = ch == '-'; int j; int i; if (pat == 'Z' && n == 6) { i = readUnsignedIntSpecifiedLength(2); if (!isChar(':')) { return null; // expected explicit zone (+-)HH:mm } j = readUnsignedIntSpecifiedLength(2); } else if (n == 5) { // expected explicit zone (+-)HHmm i = readUnsignedIntSpecifiedLength(2); j = readUnsignedIntSpecifiedLength(2); } else { int pos = getIndex(); int nn = pat == 'Z' ? 2 : 0; i = readUnsignedIntSpecifiedLength(nn); if (i < 0) { return null; //number expected } if (isChar(':')) { if (getIndex() - pos > 3 || eos()) { return null; //number expected after ':' } pos = getIndex(); if ((j = readUnsignedIntSpecifiedLength(nn)) < 0 || getIndex() - pos > 2) { return null; //number expected } } else { if (n != 0 && n != 4) { return null; // ':' required } if ((j = getIndex() - pos) < 3 || j > 4) { return null; //if not colon then 3 or 4 digits required!! } j = i % 100; // j was 3 or 4 -> HHmm; we divide it i /= 100; } } if (i == Integer.MIN_VALUE || j == Integer.MIN_VALUE || i > 14 || j > 59) { return null; //something wrong } i *= 3600000; i += 60000 * j; TimeZone tz = TimeZone.getTimeZone("UTC"); tz.setRawOffset(minus ? -i : i); return tz; } /** Parse duration in format format ISO 8061. * @return true if correct format of duration was parsed. */ public final boolean isDuration() { if (getIndex() + 1 >= _endPos && !readNextBuffer()) { return false; } keepBuffer(); int startPos = getIndex(); try { if (chkDuration(false)) { _parsedString = _source.substring(startPos, getIndex()); freeBuffer(); return true; } } catch (SRuntimeException ex) {} setIndex(startPos); freeBuffer(); return false; } /** Parse duration in format format ISO 8061. * @param xmlSchema if true the interval is according to XML schema format. * @return true if correct format of duration was parsed. */ final boolean chkDuration(final boolean xmlSchema) { _parsedDuration = new SDuration(); if (xmlSchema) { return chkInterval(true); } if (isChar('R')) { if (isInteger()) { _parsedDuration.setRecurrence(getParsedInt()); } else { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } if (!isChar('/')) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } } if (isISO8601Datetime()) { if (!testParsedDatetime()) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } _parsedDuration.setStart(getParsedSDatetime()); if (!isChar('/')) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } if (isISO8601Datetime()) { if (!testParsedDatetime()) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } _parsedDuration.setEnd(getParsedSDatetime()); } else if (!chkInterval(xmlSchema)) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } else if (isChar('/')) { if (!isISO8601Datetime()) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } _parsedDuration.setEnd(getParsedSDatetime()); } } else if (chkInterval(xmlSchema)) { if (isChar('/')) { if (isISO8601Datetime()) { if (!testParsedDatetime()) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } _parsedDuration.setEnd(getParsedSDatetime()); } else { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } } } else { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } return true; } /** Check if source buffer contains at actual position correct format of * ISO 8061 duration. * @param xmlSchema if true the interval is according to XML schema format. * @return true if correct format of duration was parsed. * @throw SRuntimeException if an error occurs. */ private boolean chkInterval(boolean xmlSchema) { boolean date = false; boolean time = false; _parsedDuration.setNegative(isChar('-')); if (isChar('P')) { if (!xmlSchema && isDatetime("yyyy-M-dTH:m[:s[.S]][Z]")) { _parsedDuration.setYears(_parsedDatetime._year); _parsedDuration.setMonths(_parsedDatetime._month); _parsedDuration.setDays(_parsedDatetime._day); _parsedDuration.setHours(_parsedDatetime._hour); _parsedDuration.setMinutes(_parsedDatetime._minute); _parsedDuration.setSeconds(_parsedDatetime._second); _parsedDuration.setFraction(_parsedDatetime.getFraction()); date = true; time = true; } else if (!xmlSchema && isDatetime("yyyy-M-d[Z]")) { _parsedDuration.setYears(_parsedDatetime._year); _parsedDuration.setMonths(_parsedDatetime._month); _parsedDuration.setDays(_parsedDatetime._day); date = true; } else if (isInteger()){ boolean weeks = false; int iweeks = 0; boolean years = false; boolean months = false; boolean days = false; char c; while ((c = isOneOfChars( xmlSchema ? "YMD" : "YMDW")) != StringParser.NOCHAR) { date = true; switch (c) { case 'Y': if (years) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } if (months || weeks || days) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } years = true; _parsedDuration.setYears(getParsedInt()); break; case 'M': if (months) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } if (weeks || days) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } months = true; _parsedDuration.setMonths(getParsedInt()); break; case 'W': if (weeks) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } if (days) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } weeks = true; iweeks = getParsedInt(); break; default: //if(c == 'D') { if (days) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } days = true; _parsedDuration.setDays(getParsedInt()); break; } if (!isInteger()) { break; } } if (weeks) { _parsedDuration.setDays(_parsedDuration.getDays()+iweeks*7); } } } if (isChar('T')) { if (time) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } time = true; if (!xmlSchema && isDatetime("TH:m[:s[.S]]][Z]")) { _parsedDuration.setHours(_parsedDatetime._hour); _parsedDuration.setMinutes(_parsedDatetime._minute); _parsedDuration.setSeconds(_parsedDatetime._second); _parsedDuration.setFraction(_parsedDatetime.getFraction()); } else { if (!isInteger()) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } boolean hours = false; boolean minutes = false; boolean seconds = false; boolean millis = false; char c; while ((c = isOneOfChars("HMS.")) != StringParser.NOCHAR) { switch (c) { case 'H': if (hours) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } hours = true; if (minutes || seconds || millis) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } _parsedDuration.setHours(getParsedInt()); break; case 'M': if (minutes) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } minutes = true; if (seconds || millis) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } _parsedDuration.setMinutes(getParsedInt()); break; case 'S': if (seconds) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } seconds = true; if (millis) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } _parsedDuration.setSeconds(getParsedInt()); break; case '.': if (seconds || millis) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } seconds = true; millis = true; _parsedDuration.setSeconds(getParsedInt()); double fraction = 0.0; double exp = 1.0; while(_ch >= '0' && _ch <= '9') { fraction += (_ch - '0')/(exp *= 10.0); nextChar(); } if (fraction != 0.0) { _parsedDuration.setFraction(fraction); } if (exp == 1.0) {//no digits after '.' //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } if (!isChar('S')) { //Icorrect format of time period throw new SRuntimeException(SYS.SYS056); } break; default: break; } if (!isInteger()) { break; } } } } return date || time; } /** Parse initial defaults section of datetime mask. * @return position where parsing has finished. */ final Report checkDateFormatDefaults() { int beg = getIndex(); _parsedDatetime = new MyDate(beg); for (;;) { switch (_ch) { case NOCHAR: //Datetime mask: missing closing character //&{0}{: '}{'}&{1}{, position: } return Report.error(SYS.SYS064, null, beg); case '}': nextChar(); return null; case 'z': case 'L': { char ch = _ch; nextChar(); if (!isChar('(')) { //Datetime mask: expected character //&{0}{: '}{'}&{1}{, position: } return Report.error(SYS.SYS079, "(", getIndex()); } if (isChar('*')) { if (!isChar(')')) { //Datetime mask: missing closing character //&{0}{: '}{'}&{1}{, position: } return Report.error(SYS.SYS064, ")", beg); } if (ch == 'z') {// zone _parsedDatetime._tz = TimeZone.getDefault(); } else {// L language _parsedDatetime.setLocaleFormatSymbols( new DateFormatSymbols(Locale.getDefault())); } continue; } int start = getIndex(); String p1 = null; String p2 = ""; String p3 = ""; int i = 0; for (;;) { if (eos()) { //Error in datetime mask format: missing closing // character&{0}{: '}{'}&{1}{, position: } return Report.error(SYS.SYS064, null, beg); } char c; if ((c = isOneOfChars( "\t\n\r |;!@#$%^&(=[]{}\"'?><\\")) != NOCHAR) { //Datetime mask: incorrect control //character&{0}{: '}{'}&{1}{, position: } return Report.error(SYS.SYS063, c, getIndex()); } if (isChar(',')) { if (ch == 'z') { //Datetime mask: incorrect control //character&{0}{: '}{'}&{1}{, position: } return Report.error(SYS.SYS063, null, start); } if(i == 2) { continue; } if (i++ <= 1) { String s = _source.substring(start, getIndex() - 1); if (i == 1) { p1 = s; } else { p2 = s; } } else { //Datetime mask: incorrect control //character&{0}{: '}{'}&{1}{, position: } return Report.error(SYS.SYS063,null,getIndex()); } start = getIndex(); } else if (isChar(')')) { switch (i) { case 2: p3 = _source.substring(start, getIndex()-1); break; case 1: p2 = _source.substring(start, getIndex()-1); break; case 0: p1 = _source.substring(start, getIndex()-1); break; default: break; } if (ch == 'z') { TimeZone tz; if ((tz = TimeZone.getTimeZone(p1)) == null || ("GMT".equals(tz.getID()) && !"GMT".equalsIgnoreCase(p1))) { //Datetime mask error: // unsupported timezone name //&{0}{: '}{'}&{1}{, position: } return Report.error(SYS.SYS061, p1, start); } _parsedDatetime._tz = tz; } else { try { //check language code SUtils.getISO3Language(p1); } catch (SRuntimeException ex) { //Datetime mask error: // unsupported language code //&{0}{: '}{'}&{1}{, position: } return Report.error(SYS.SYS060, "" + p1, "" + (i == 2 ? start - p3.length() - p2.length() : i == 1 ? start - p2.length() : start)); } if ( i > 0 && !SUtils.isCountryCode(p2)) { //Datetime mask error: // unsupported country code //&{0}{: '}{'}&{1}{, position: } return Report.error(SYS.SYS067, p2, (i==2 ? start-p2.length() : start)); } _parsedDatetime.setLocaleFormatSymbols( new DateFormatSymbols( new Locale(p1,p2,p3))); } break; } else { nextChar(); } } continue; } case 'Y': //year ISO case 'y': //year case 'M': //month in year case 'd': //day in month case 'H': //hour in day (0..23) case 'm': //minute case 's': //second case 'S': //millisecond case 'Z': { //RFC822 zone (-0800) char ch = _ch; String s = String.valueOf(_ch); nextChar(); while(isChar(ch)) { s += ch; } int start = getIndex(); MyDate parsedDatetime = _parsedDatetime; _parsedDatetime = null; try { if (!isDatetime(s) || !_parsedDatetime.chkDatetime()) { //Datetime mask: incorrect initial value //{0}{: '}{'}&{1}{, position: } return Report.error(SYS.SYS062, _source.substring(start, getIndex()), start); } } catch (SRuntimeException ex) { //Datetime mask: incorrect initial value //{0}{: '}{'}&{1}{, position: } return Report.error(SYS.SYS062, _source.substring(start, getIndex()), start); } switch (ch) { case 'Y': //year ISO case 'y': //year parsedDatetime._year = _parsedDatetime._year; break; case 'M': //month in year parsedDatetime._month = _parsedDatetime._month; break; case 'd': //day in month parsedDatetime._day = _parsedDatetime._day; break; case 'H': //hour in day (0..23) parsedDatetime._hour = _parsedDatetime._hour; break; case 'm': //minute parsedDatetime._minute = _parsedDatetime._minute; break; case 's': //second parsedDatetime._second = _parsedDatetime._second; break; case 'S': //millisecond parsedDatetime._fraction =_parsedDatetime._fraction; break; case 'Z': //RFC822 zone (-0800) parsedDatetime._tz = _parsedDatetime._tz; break; } _parsedDatetime = parsedDatetime; continue; } default: //Datetime mask: incorrect control character //&{0}{: '}{'}&{1}{, position: } return Report.error(SYS.SYS063, _ch, getIndex()); } } } /** Check quoted string. * @return null or Report if format is not valid. */ private Report checkLiteral() { int pos = getIndex(); nextChar(); while (!eos()) { if (isChar('\'')) { if (!isChar('\'')) { return null; } } else { nextChar(); } } //Datetime mask: unclosed quoted literal &{0}{, position: } return Report.error(SYS.SYS049, pos + 1); } /** Check executable part of mask. * @return null or Report if format is not valid. */ private Report checkDateFormatMask() { if (_ch == '|') { //Datetime mask: section can't start with '|' (variant) // &{0}{, position: } return Report.error(SYS.SYS078, getIndex()); } Report r; for(;;) { switch (_ch) { case NOCHAR: return null; case '|': nextChar(); if (isChar('{')) { if ((r = checkDateFormatDefaults()) != null) { return r; } } if ((r = checkDateFormatMask()) != null) { return r; } continue; case '[': nextChar(); if ((r = checkDateFormatOptional()) != null) { return r; } continue; case '{': case '}': //Datetime mask: format: incorrect control character //&{0}{: '}{'}&{1}{, position: } return Report.error(SYS.SYS063, _ch, getIndex()); case ']': return null; case 'D': //day in year case 'F': //day of week in month case 'w': //week in year case 'W': //week in month case 'G': //era designator (BC, AD) case 'd': //day case 'M': //month in year case 'm': //minute case 's': //second case 'S': //millisecond case 'a': //AM/PM marker case 'E': //day of week (text) case 'e': //day of week (number) case 'K': //hour 0..11 case 'k': //hour in day (1..24) case 'H': //hour in day (0..23) case 'h': //hour in am/pm (1..12) case 'Y': //year ISO case 'y': //year case 'R': //year (two digits database) case 'Z': //RFC822 zone case 'z': //general zone { char ch = _ch; int n = 0; while (isChar(ch)) { n++; } if (ch == 'y' && n == 3 || ch == 'Y' && n != 1 && n != 2 || ch == 'R'&& n != 2) { //Datetime mask: incorrect year specification //&{0}{, position: } return Report.error(SYS.SYS059, getIndex() - 3); } continue; } case '?': //one of chars nextChar(); if (_ch != '\'') { //Datetime mask: expected character //&{0}{: '}{'}&{1}{, position: } return Report.error(SYS.SYS079, "'", getIndex()); } if ((r = checkLiteral()) != null) { return r; } continue; case '\'': { if ((r = checkLiteral()) != null) { return r; } continue; } default: if (eos()) { return null; } nextChar(); } } } /** Check optional part of mask. * @return null or Report if format is not valid. */ private Report checkDateFormatOptional() { Report r; int beg = getIndex(); if ((r = checkDateFormatMask()) != null) { return r; } if (!isChar(']')) { //Datetime mask: missing closing character //&{0}{: '}{'}&{1}{, position: } return Report.error(SYS.SYS064, "]", beg); } return null; } /** Check if date format is valid. * @return null or Report if format is not valid. */ public final Report checkDateFormat() { Report r; if (isChar('{')) { if ((r = checkDateFormatDefaults()) != null) { return r; } } return checkDateFormatMask(); } /** Check if date format is valid. * @param format String with format data. * @return null or Report if format is not valid. */ public final static Report checkDateFormat(final String format) { StringParser p = new StringParser(format); Report r; if ((r = p.checkDateFormat()) == null) { if (!p.eos()) { //Datetime mask: incorrect control character //&{0}{: '}{'}&{1}{, position: } r = Report.error(SYS.SYS063, p._ch, p.getIndex()); } } return r; } /** Parse Java identifier and save result to _parsedString. * @return true if actual input is Java identifier. */ public final boolean isJavaName() { if (_ch > ' ' && Character.isJavaIdentifierStart(_ch)) { _parsedString = String.valueOf(_ch); nextChar(); while(_ch > ' ' && Character.isJavaIdentifierPart(_ch)) { _parsedString += _ch; nextChar(); } return true; } return false; } /** Parse Java fully qualified identifier and save result to _parsedString. * @return true if actual input is Java fully qualified identifier. */ public final boolean isJavaQName() { if (isJavaName()) { String s = _parsedString; while(ensureBuffer(2) && isChar('.')) { if (!isJavaName()) { setIndex(getIndex() - 1); break; } s += "." + _parsedString; } _parsedString = s; return true; } return false; } //////////////////////////////////////////////////////////////////////////////// // XML parsing methods //////////////////////////////////////////////////////////////////////////////// /** Get type of character. This method returns one of: *
XML_CHAR_ILLEGAL .. unknown type (0) *
XML_CHAR .. valid XML character (1) *
XML_CHAR_WHITESPACE .. space, TAB, CR, LF (2) *
XML_CHAR_COLON .. ':' (4) *
XML_CHAR_NAME_START .. first character of XML name (8) *
XML_CHAR_NAME_EXT .. character of XML name (16) * @param xmlVersion 10 .. "1.0", 11 .. "1.1" (see XMLVER1_0 and XMLVER1_1). * @return type of character. */ public final byte getXmlCharType(final byte xmlVersion) { return xmlVersion == XMLVER1_1 ? XML_CHARTAB1[_ch] : XML_CHARTAB0[_ch]; } /** Parse Nmtoken. * [7] Nmtoken::= (NameChar)+ * [4] NameChar::= Letter | Digit | '.' | '-' | '_' | ':' * | CombiningChar | Extender * @param xmlVersion 10 .. "1.0", 11 .. "1.1" (see XMLVER1_0 and XMLVER1_1). * @return true if rule passed. */ public final boolean isNMToken(final byte xmlVersion) { if (getXmlCharType(xmlVersion) < XML_CHAR_COLON) { return false; } if (getIndex() >= _endPos && !readNextBuffer()) { _parsedString = String.valueOf(_ch); super.setIndex(_endPos); _ch = NOCHAR; return true; } StringBuilder result = new StringBuilder(String.valueOf(_ch)); while (incIndex() < _endPos || readNextBuffer()) { _ch = _source.charAt(getIndex()); if (getXmlCharType(xmlVersion) < XML_CHAR_COLON) { break; } result.append(_ch); } _parsedString = result.toString(); if (getIndex() >= _endPos) { super.setIndex(_endPos); _ch = NOCHAR; } return true; } /** Parse NCName according to Namespaces in W3C. * [4] NCName::= (Letter | '_') (NCNameChar)* //An XML Name, minus the ":" * [5] NCNameChar::= Letter | Digit | '.' | '-' | '_' * | CombiningChar | Extender * @param xmlVersion 10 .. "1.0", 11 .. "1.1" (see XMLVER1_0 and XMLVER1_1). * @return true if NCNname was recognized. */ public final boolean isNCName(final byte xmlVersion) { if (getXmlCharType(xmlVersion) != XML_CHAR_NAME_START) { return false; } if (getIndex() >= _endPos && !readNextBuffer()) { _parsedString = String.valueOf(_ch); super.setIndex(_endPos); _ch = NOCHAR; return true; } StringBuilder result = new StringBuilder(String.valueOf(_ch)); while ((incIndex() < _endPos || readNextBuffer())) { _ch = _source.charAt(getIndex()); if (getXmlCharType(xmlVersion) < XML_CHAR_NAME_START) { break; } result.append(_ch); } _parsedString = result.toString(); if (getIndex() >= _endPos) { super.setIndex(_endPos); _ch = NOCHAR; } return true; } /** Parse XML name and save result to _parsedString. * @param xmlVersion 10 .. "1.0", 11 .. "1.1" (see XMLVER1_0 and XMLVER1_1). * @return true if XMLName was parsed. */ public final boolean isXMLName(final byte xmlVersion) { if (getXmlCharType(xmlVersion) != XML_CHAR_NAME_START && _ch != ':') { return false; } int pos = getIndex(); if (pos >= _endPos && !increaseBuffer()) { _parsedString = String.valueOf(_ch); super.setIndex(_endPos); _ch = NOCHAR; return true; } while (incIndex() < _endPos || increaseBuffer()) { _ch = _source.charAt(getIndex()); if (getXmlCharType(xmlVersion) < XML_CHAR_COLON) { break; } } int pos1 = getIndex(); SPosition spos = getPosition(); isSpaces(); if (isChar('(')) { int lastDot = _source.substring(pos, pos1).lastIndexOf('.'); if (lastDot > 0) { pos1 = pos + lastDot; } } else if (_source.charAt(pos1 - 1) == '.') { isSpaces(); if (isJavaName()) { isSpaces(); if (isChar('(')) { pos1--; } } } setPosition(spos); setIndex(pos1); _parsedString = _source.substring(pos, pos1); if (getIndex() >= _endPos) { super.setIndex(_endPos); _ch = NOCHAR; } return true; } /** Parse valid XML character. * @param xmlVersion 10 .. "1.0", 11 .. "1.1" (see XMLVER1_0 and XMLVER1_1). * @return parsed character or NOCHAR. */ public final char isXMLChar(final byte xmlVersion) { if (getXmlCharType(xmlVersion) == 0) { return NOCHAR; } char c = _ch; nextChar(); return c; } /** Parse XML whitespace character. * @return parsed character or NOCHAR. */ public final char isXMLWhitespaceChar() { if ( XML_CHARTAB0[_ch] != XML_CHAR_WHITESPACE) { return NOCHAR; } char c; if ((c = _ch) == '\n') { setNewLine(); } nextChar(); return c; } /** Parse XML name start character. * @param xmlVersion 10 .. "1.0", 11 .. "1.1" (see XMLVER1_0 and XMLVER1_1). * @return parsed character or NOCHAR. */ public final char isXMLNamestartChar(final byte xmlVersion) { if (getXmlCharType(xmlVersion) != XML_CHAR_NAME_START) { return NOCHAR; } char c = _ch; nextChar(); return c; } /** Parse XML name extension character. * @param xmlVersion 10 .. "1.0", 11 .. "1.1" (see XMLVER1_0 and XMLVER1_1). * @return parsed character or NOCHAR. */ public final char isXMLNameExtensionChar(final byte xmlVersion) { if (getXmlCharType(xmlVersion) != XML_CHAR_NAME_EXT) { return NOCHAR; } char c = _ch; nextChar(); return c; } /** Get XML character table. * @param xmlVersion1 false: XML version 1.0, true: XML version 1.1. * @return character table (byte[65536]). */ protected final byte[] getXMLCharTab(final boolean xmlVersion1) { if (xmlVersion1) { return XML_CHARTAB1; } return XML_CHARTAB0; } /** Parse duration in format format ISO 8061. * @return true if correct format of duration was parsed. */ public final boolean isXMLDuration() { if (getIndex() + 1 >= _endPos && !readNextBuffer()) { return false; } keepBuffer(); int startPos = getIndex(); try { if (chkDuration(true)) { _parsedString = _source.substring(startPos, getIndex()); freeBuffer(); return true; } } catch (SRuntimeException ex) {} freeBuffer(); setIndex(startPos); return false; } /** Parse date in format ISO 8061 (y:MM:ddTHH:mm:ss[.S][Z]). * @return true if correct format of duration was parsed. */ public final boolean isXMLDatetime() { if (getIndex() + 17 >= _endPos && !readNextBuffer()) { return false; } int start = getIndex(); keepBuffer(); _parsedDatetime = new MyDate(getIndex()); if (!readXMLDate()) { freeBuffer(); return false; } if (_parsedDatetime._tz != null) { //zone can't be here setIndex(start); freeBuffer(); return false; } if (!isChar('T')) { setIndex(start); freeBuffer(); return false; } if (!readXMLTime()) { setIndex(start); freeBuffer(); return false; } return true; } private boolean readXMLZone() { _parsedDatetime._tz = null; int start = getIndex(); char sign; if ((sign = isOneOfChars("+-Z")) == 0) { return false; } _parsedDatetime._tz = TimeZone.getTimeZone("GMT"); //UTC if (sign == 'Z') { return true; } int pos1 = getIndex(); int i; if (!isInteger() || getIndex() - pos1 != 2) { setIndex(start); _parsedDatetime._tz = null; return false; } i = getParsedInt(); if (i > 14) { //Time zone must be in interval -14 .. 14 hours getReportWriter().putReport(Report.error(SYS.SYS086)); i = 0; } int offset = i * 3600000; pos1 = getIndex(); if (isChar(':') && isInteger()) { if (getIndex() - pos1 != 3) { setIndex(start); return false; } int j = getParsedInt(); if (j > 59) { //Minutes must be in interval 0 .. 59 getReportWriter().putReport(Report.error(SYS.SYS087)); j = 59; } else if (i == 14 && j > 0) { //Time zone must be in interval -14 .. 14 hours getReportWriter().putReport(Report.error(SYS.SYS086)); j = 0; } offset += j * 60000; } else { setIndex(start); return false; } if (sign == '-') { offset = -offset; } _parsedDatetime._tz.setRawOffset(offset); return true; } private boolean readXMLDate() { int start = getIndex(); boolean wasQuote = isChar('"');//year without zone may be quoted in JSON int sign = isChar('-') ? -1 : 1; int pos = getIndex(); //migt be start + 1 char firstdigit = getCurrentChar(); if (!isInteger()) { setIndex(start); return false; } if (sign == 1 && getIndex() - pos < 4) { setIndex(start); return false; } if (sign == 1 && firstdigit == '0' && getIndex() - pos > 4) { setIndex(start); return false; } _parsedDatetime._year = getParsedInt() * sign; if (wasQuote) { //quoted year if (!isChar('"')) { setIndex(start); return false; } return true; } freeBuffer(); pos = getIndex(); if (!isChar('-') || !isInteger() || getIndex() - pos != 3){ setIndex(start); return false; } _parsedDatetime._month = getParsedInt(); pos = getIndex(); if (!isChar('-') || !isInteger() || getIndex() - pos != 3){ setIndex(start); return false; } _parsedDatetime._day = getParsedInt(); return true; } /** Parse date in format y:MM:dd[Z] * @return true if correct format of date was parsed. */ public final boolean isXMLDate() { if (getIndex() + 10 >= _endPos && !readNextBuffer()) { return false; } _parsedDatetime = new MyDate(getIndex()); keepBuffer(); if (!readXMLDate()) { freeBuffer(); return false; } readXMLZone(); freeBuffer(); return true; } /** Parse date in format HH:mm:ss[.S][Z]. * @return true if correct format of time was parsed. */ public final boolean readXMLTime() { int start = getIndex(); if (!isInteger() || getIndex() - start != 2) { setIndex(start); return false; } _parsedDatetime._hour = getParsedInt(); int pos = getIndex(); if (!isChar(':') || !isInteger() || getIndex() - pos != 3) { setIndex(start); return false; } _parsedDatetime._minute = getParsedInt(); pos = getIndex(); if (!isChar(':') || !isInteger() || getIndex() - pos != 3){ setIndex(start); return false; } else { _parsedDatetime._second = getParsedInt(); if (isChar('.')) { if (!isInteger()) { setIndex(start); return false; } _parsedDatetime._fraction = Double.parseDouble("0."+_parsedString); } } readXMLZone(); return true; } /** Parse date in format HH:mm:ss[Z]. * @return true if correct format of time was parsed. */ public final boolean isXMLTime() { if (getIndex() + 5 >= _endPos && !readNextBuffer()) { return false; } _parsedDatetime = new MyDate(getIndex()); keepBuffer(); boolean result = readXMLTime(); freeBuffer(); return result; } private boolean readXMLYear() { int start = getIndex(); boolean wasQuote = isChar('"');//year without zone may be quoted in JSON boolean negative = isChar('-'); if (!isInteger()) { setIndex(start); return false; } _parsedDatetime._year = getParsedInt() * (negative? -1 : 1); if (wasQuote) { //quoted year if (!isChar('"')) { setIndex(start); return false; } } freeBuffer(); return true; } /** Parse date in format y[Z]. * @return true if correct format of date was parsed. */ public final boolean isXMLYear() { if (getIndex() + 1 >= _endPos && !readNextBuffer()) { return false; } _parsedDatetime = new MyDate(getIndex()); keepBuffer(); if (!readXMLYear()) { freeBuffer(); return false; } readXMLZone(); freeBuffer(); return true; } /** Parse date in format y-MM[Z]. * @return true if correct format of date was parsed. */ public final boolean isXMLYearMonth() { if (getIndex() + 4 >= _endPos && !readNextBuffer()) { return false; } _parsedDatetime = new MyDate(getIndex()); keepBuffer(); int start = getIndex(); boolean negative = isChar('-'); int pos = getIndex(); char firstdigit = getCurrentChar(); if (!isInteger()) { setIndex(start); freeBuffer(); return false; } if (!negative && getIndex() - pos < 4) { setIndex(start); freeBuffer(); return false; } if (!negative && firstdigit == '0' && getIndex() - pos > 4) { setIndex(start); freeBuffer(); return false; } _parsedDatetime._year = getParsedInt() * (negative? -1 : 1); pos = getIndex(); if (!isChar('-') || !isInteger() || getIndex() - pos != 3) { setIndex(start); freeBuffer(); return false; } _parsedDatetime._month = getParsedInt(); readXMLZone(); freeBuffer(); return true; } private boolean readXMLMonth() { int start = getIndex(); if (!isToken("--")) { return false; } int pos = getIndex(); if (!isInteger()) { setIndex(start); return false; } if (getIndex() - pos != 2) { setIndex(start); return false; } _parsedDatetime._month = getParsedInt(); return true; } /** Parse date in format --MM[Z]. * @return true if correct format of date was parsed. */ public final boolean isXMLMonth() { if (getIndex() + 4 >= _endPos && !readNextBuffer()) { return false; } _parsedDatetime = new MyDate(getIndex()); keepBuffer(); boolean result = readXMLMonth(); if (result) { readXMLZone(); } freeBuffer(); return result; } /** Parse date in format --MM-dd-[Z]. * @return true if correct format of date was parsed. */ public final boolean isXMLMonthDay() { if (getIndex() + 7 >= _endPos && !readNextBuffer()) { return false; } _parsedDatetime = new MyDate(getIndex()); keepBuffer(); int start = getIndex(); if (!isToken("--")) { return false; } int pos = getIndex(); if (!isInteger()) { setIndex(start); return false; } if (getIndex() - pos != 2) { setIndex(start); return false; } _parsedDatetime._month = getParsedInt(); if (!isChar('-')) { setIndex(start); freeBuffer(); return false; } pos = getIndex(); if (!isInteger()) { setIndex(start); return false; } if (getIndex() - pos != 2) { setIndex(start); return false; } _parsedDatetime._day = getParsedInt(); readXMLZone(); freeBuffer(); return true; } /** Parse date in format ---dd[Z]. * @return true if correct format of date was parsed. */ public final boolean isXMLDay() { if (getIndex() + 7 >= _endPos && !readNextBuffer()) { return false; } if (!isToken("---")) { return false; } _parsedDatetime = new MyDate(getIndex()); keepBuffer(); int start = getIndex(); int pos = start; if (!isInteger()) { setIndex(start); return false; } if (getIndex() - pos != 2) { setIndex(start); return false; } _parsedDatetime._day = getParsedInt(); readXMLZone(); freeBuffer(); return true; } /** Read string enclosed in delimiters (' or "). * string::= S ('"' ^['"']* '"' | "'" ^["'"]* "'") * @return string or null if on the source position is not a valid * string declaration. */ public final String readString() { isSpaces(); char delimiter; if ((delimiter = isOneOfChars("'\"")) == NOCHAR) { return null; } int pos = getIndex(); char c; while ((c = peekChar()) != NOCHAR) { if (c == delimiter) { return getBufferPart(pos, getIndex() -1); } } return null; } //////////////////////////////////////////////////////////////////////////////// // Auxiliary methods for stream paresr. //////////////////////////////////////////////////////////////////////////////// /** Set end of buffer (first not existing position). * @param endPos the end of buffer (first not existing position). */ final void setEndBuffer(final int endPos) {_endPos = endPos;} /** Get the source buffer. * @return string with source buffer. */ final String getBuffer() {return _source;} /** Set source buffer (position is not changed). * @param source the source buffer. */ final void setBuffer(final String source) { if (source == null || source.isEmpty()) { _source = ""; _endPos = 0; } else { _source = source; _endPos = _source.length(); } } /** This class is used in the datetime parser. */ private static class MyDate extends SDatetime { private MyDate _chain; private int _weekDay; private int _yearDay; private int _dayOfWeekInMonth; private int _weekInYear; private int _weekInMonth; private int _startPos; private int _endPos; private SDatetime _defaults; private MyDate(final MyDate date) { super(date); _weekDay = date._weekDay; _yearDay = date._yearDay; _dayOfWeekInMonth = date._dayOfWeekInMonth; _weekInYear = date._weekInYear; _weekInMonth = date._weekInMonth; _startPos = date._startPos; _defaults = date._defaults; } private MyDate(final int sourcePos) { super(); _weekDay = Integer.MIN_VALUE; _yearDay = Integer.MIN_VALUE; _dayOfWeekInMonth = Integer.MIN_VALUE; _weekInYear = Integer.MIN_VALUE; _weekInMonth = Integer.MIN_VALUE; _startPos = sourcePos; } private MyDate(final MyDate chain, final int sourcePos) { _defaults = chain._defaults; _day = chain._day; _month = chain._month; _year = chain._year; _hour = chain._hour; _minute = chain._minute; _second = chain._second; _fraction = chain._fraction; if (chain._tz != null) { _tz = (TimeZone) chain._tz.clone(); } _calendar = null; _weekDay = chain._weekDay; _yearDay = chain._yearDay; _dayOfWeekInMonth = chain._dayOfWeekInMonth; _weekInYear = chain._weekInYear; _weekInMonth = chain._weekInMonth; _chain = chain; _startPos = sourcePos; _endPos = 0; } private void setDefaults(SDatetime defaults) { _defaults = new SDatetime(defaults); resetDefaults(); } private void resetDefaults() { if (_defaults != null) { _dfs = _defaults._dfs; _day = _defaults._day; _eon = _defaults._eon; _fraction = _defaults._fraction; _hour = _defaults._hour; _minute = _defaults._minute; _month = _defaults._month; _second = _defaults._second; _tz = _defaults._tz; _year = _defaults._year; } } private void reset(final int sourcePos) { clear(); _chain = null; resetDefaults(); _weekDay = Integer.MIN_VALUE; _yearDay = Integer.MIN_VALUE; _dayOfWeekInMonth = Integer.MIN_VALUE; _weekInYear = Integer.MIN_VALUE; _weekInMonth = Integer.MIN_VALUE; _startPos = sourcePos; _endPos = 0; } private boolean check() { if (!chkDatetime()) { return false; } if (_weekDay >= 0 && getCalendar().get(Calendar.DAY_OF_WEEK) != _weekDay) { return false; } if (_yearDay >= 0 && getCalendar().get(Calendar.DAY_OF_YEAR) != _yearDay) { return false; } if (_dayOfWeekInMonth >= 0 && getCalendar().get(Calendar.DAY_OF_WEEK_IN_MONTH) != _dayOfWeekInMonth) { return false; } if (_weekInYear >= 0 && getCalendar().get(Calendar.WEEK_OF_YEAR) != _weekInYear) { return false; } return _weekInMonth < 0 || getCalendar().get(Calendar.WEEK_OF_MONTH) == _weekInYear; } } //////////////////////////////////////////////////////////////////////////////// // static methods //////////////////////////////////////////////////////////////////////////////// /** Check if the string in argument is a number (can be negative). * @param s the string to be checked. * @return true if argument is a number. */ public static final boolean chkNumber(final String s) { StringParser p = new StringParser(s); p.isChar('-'); return (p.isFloat() || p.isInteger()) && p.eos(); } /** Check if the string in argument is Java identifier. * @param s the string to be checked. * @return true if argument is Java identifier. */ public static final boolean chkJavaName(final String s) { StringParser p = new StringParser(s); return p.isJavaName() && p.eos(); } /** Check if the string in argument is Java qualified identifier. * @param s the string to be checked. * @return true if argument is Java qualified identifier. */ public static final boolean chkJavaQName(final String s) { StringParser p = new StringParser(s); return p.isJavaQName() && p.eos(); } /** Check if argument is a whitespace - see {@link StringParser#isSpace()}. * @param ch character to be checked. * @return true is only if argument is a whitespace according to * XML specification.. */ public static final boolean chkXmlWhiteSpaceChar(final char ch) { return XML_CHARTAB0[ch] == XML_CHAR_WHITESPACE; } /** Get type of character - static version of {@link * StringParser#getXmlCharType(byte)}. * @param ch character to be checked. * @param xmlVersion 10 .. "1.0", 11 .. "1.1" (see XMLVER1_0 and XMLVER1_1). * @return type of character. */ public static final byte getXmlCharType(final char ch, final byte xmlVersion) { return xmlVersion == XMLVER1_1 ? XML_CHARTAB1[ch] : XML_CHARTAB0[ch]; } /** Parse NCName - see {@link StringParser#isNCName(byte)}. * @param name string to be checked. * @param xmlVersion 10 .. "1.0", 11 .. "1.1" (see XMLVER1_0 and XMLVER1_1). * @return true if the argument is NCName according to XML specification. */ public static final boolean chkNCName(final String name, final byte xmlVersion) { int max; if (name == null || (max = name.length()) == 0 || getXmlCharType(name.charAt(0), xmlVersion) != XML_CHAR_NAME_START) { return false; } int i = 0; while ((++i < max) && getXmlCharType(name.charAt(i), xmlVersion) >= XML_CHAR_NAME_START){} return i == max; } /** Parse XML name - see {@link StringParser#isXMLName(byte)}. * @param name string to be checked. * @param xmlVersion 10 .. "1.0", 11 .. "1.1" (see XMLVER1_0 and XMLVER1_1). * @return true if the argument is XML name according to XML specification. * {@link StringParser#isXMLName(byte)}. */ public static final boolean chkXMLName(final String name, final byte xmlVersion) { int max; byte type; if (name == null || (max = name.length()) == 0 || (type = getXmlCharType(name.charAt(0), xmlVersion)) != XML_CHAR_NAME_START && type != XML_CHAR_COLON) { return false; } int i = 0; while ((++i < max) && getXmlCharType(name.charAt(i), xmlVersion) >= XML_CHAR_COLON) {} return i == max; } /** Parse NMToken - see {@link StringParser#isNMToken(byte)}. * @param name string to be checked. * @param xmlVersion 10 .. "1.0", 11 .. "1.1" (see XMLVER1_0 and XMLVER1_1). * @return true if the argument is NMToken according to XML specification. * {@link StringParser#isNMToken(byte)}. */ public static final boolean chkNMToken(final String name, final byte xmlVersion) { int max; if (name == null || (max = name.length()) == 0 || getXmlCharType(name.charAt(0), xmlVersion) < XML_CHAR_COLON) { return false; } int i = 0; while ((++i < max) && getXmlCharType(name.charAt(i), xmlVersion) >= XML_CHAR_COLON) {} return i == max; } //////////////////////////////////////////////////////////////////////////////// // deprecated methods //////////////////////////////////////////////////////////////////////////////// /** Check if the string in argument is Java identifier. * @deprecated Please use StringParser.5Name instead. * @param s the string to be checked. * @return true if argument is Java identifier. */ public static final boolean isJavaName(final String s) { return chkJavaName(s); } /** Check if the string in argument is Java qualified identifier. * @deprecated Please use StringParser.chkJavaQName instead. * @param s the string to be checked. * @return true if argument is Java qualified identifier. */ public static final boolean isJavaQName(final String s) { StringParser p = new StringParser(s); return p.isJavaQName() && p.eos(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy