From 7f10d78b8971c812127b996fdb1d556a53fd378f Mon Sep 17 00:00:00 2001 From: ?? ? <ulysseskao@ximple.com.tw> Date: Thu, 13 Mar 2008 19:09:08 +0800 Subject: [PATCH] update for EOFM-16 --- ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2ShpJob.java | 184 + .gitattributes | 12 ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertJobContext.java | 291 ++ ximple-spatialjob/src/main/java/com/ximple/eofms/util/Bits.java | 323 ++ ximple-spatialjob/src/main/java/com/ximple/eofms/util/GeomUtil.java | 30 ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleUpgradeBlob2UDTJob.java | 53 ximple-spatialjob/src/main/java/com/ximple/eofms/util/BinConverter.java | 354 +++ ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java | 486 ++++ /dev/null | 51 ximple-spatialjob/src/main/java/com/ximple/eofms/util/ByteArrayCompressor.java | 97 ximple-spatialjob/src/main/java/com/ximple/eofms/util/LangUtil.java | 104 ximple-spatialjob/src/main/java/com/ximple/eofms/util/PrintfFormat.java | 4774 +++++++++++++++++++++++++++++++++++++++++ ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleDatabaseJob.java | 108 13 files changed, 6,815 insertions(+), 52 deletions(-) diff --git a/.gitattributes b/.gitattributes index 848ed91..8bdb178 100644 --- a/.gitattributes +++ b/.gitattributes @@ -38,4 +38,14 @@ ximple-jobcarrier/src/main/java/com/ximple/eofms/App.java svneol=native#text/plain ximple-jobcarrier/src/test/java/com/ximple/eofms/AppTest.java svneol=native#text/plain ximple-spatialjob/pom.xml svneol=native#text/xml -ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/ConvertDgn2ShpJob.java svneol=native#text/plain +ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleDatabaseJob.java svneol=native#text/plain +ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2ShpJob.java svneol=native#text/plain +ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertJobContext.java svneol=native#text/plain +ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleUpgradeBlob2UDTJob.java svneol=native#text/plain +ximple-spatialjob/src/main/java/com/ximple/eofms/util/BinConverter.java svneol=native#text/plain +ximple-spatialjob/src/main/java/com/ximple/eofms/util/Bits.java svneol=native#text/plain +ximple-spatialjob/src/main/java/com/ximple/eofms/util/ByteArrayCompressor.java svneol=native#text/plain +ximple-spatialjob/src/main/java/com/ximple/eofms/util/GeomUtil.java svneol=native#text/plain +ximple-spatialjob/src/main/java/com/ximple/eofms/util/LangUtil.java svneol=native#text/plain +ximple-spatialjob/src/main/java/com/ximple/eofms/util/PrintfFormat.java svneol=native#text/plain +ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java svneol=native#text/plain diff --git a/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleDatabaseJob.java b/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleDatabaseJob.java new file mode 100644 index 0000000..1699047 --- /dev/null +++ b/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleDatabaseJob.java @@ -0,0 +1,108 @@ +package com.ximple.eofms.jobs; + +import java.io.File; +import java.io.InputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.sql.SQLException; + +import org.quartz.Job; +import org.quartz.JobDataMap; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +import com.vividsolutions.jts.util.Assert; + +import oracle.sql.BLOB; + +public abstract class AbstractOracleDatabaseJob implements Job +{ + private static final String SHPDATA_DIR = "SHPDATA_DIR"; + private static final String SPATAILSCHEMA = "ORGSCHEMA"; + private static final String ORAHOST = "ORAHOST"; + private static final String ORAINST = "ORAINST"; + private static final String ORAPORT = "ORAPORT"; + private static final String ORAUSER = "ORAUSER"; + private static final String ORAPASS = "ORAPASS"; + + protected String _dataPath; + protected String _oracleHost; + protected String _oracleInstance; + protected String _oraclePort; + protected String _username; + protected String _password; + protected String _orgSchema; + + public abstract void execute(JobExecutionContext context) throws JobExecutionException; + + protected void extractJobConfiguration(JobDetail jobDetail) throws JobExecutionException + { + // The directory to scan is stored in the job map + JobDataMap dataMap = jobDetail.getJobDataMap(); + _dataPath = dataMap.getString(SHPDATA_DIR); + _oracleHost = dataMap.getString(ORAHOST); + _oracleInstance = dataMap.getString(ORAINST); + _oraclePort = dataMap.getString(ORAPORT); + _username = dataMap.getString(ORAUSER); + _password = dataMap.getString(ORAPASS); + _orgSchema = dataMap.getString(SPATAILSCHEMA); + + // Validate the required input + if (_dataPath == null) + { + throw new JobExecutionException("Directory not configured"); + } + + // Make sure the directory exists + File dir = new File(_dataPath); + if (!dir.exists()) + { + throw new JobExecutionException("Invalid Dir " + _dataPath); + } + } + + protected OracleConvertJobContext prepareJobContext() + { + return new OracleConvertJobContext(); + } + + protected static byte[] getBytesFromBLOB(BLOB blob) throws SQLException + { + byte[] raw = null; + + // BLOB blob = (BLOB) rs.getBlob(1); + int optimalSize = blob.getChunkSize(); + byte[] chunk = new byte[optimalSize]; + InputStream is = blob.getBinaryStream(0); + ByteBuffer buffer = null; // ByteBuffer.allocate(optimalSize); + int len = 0; + + try + { + while ((len = (is.read(chunk))) != -1) + { + if (buffer != null) + { + buffer.limit(buffer.limit() + len); + } else + { + buffer = ByteBuffer.allocate(len); + } + + buffer.put(chunk); + } + + is.close(); + buffer.position(0); + raw = buffer.array(); + } catch (IOException e) + { + e.printStackTrace(); // To change body of catch statement use File | Settings | File Templates. + Assert.shouldNeverReachHere(); + } + + return raw; + } + +} diff --git a/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/ConvertDgn2ShpJob.java b/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/ConvertDgn2ShpJob.java deleted file mode 100644 index 23a9524..0000000 --- a/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/ConvertDgn2ShpJob.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.ximple.eofms.jobs; - -import java.io.File; -import java.util.Date; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.quartz.Job; -import org.quartz.JobDataMap; -import org.quartz.JobDetail; -import org.quartz.JobExecutionContext; -import org.quartz.JobExecutionException; - -/** - * - */ -public class ConvertDgn2ShpJob implements Job -{ - static Log logger = LogFactory.getLog(ConvertDgn2ShpJob.class); - - public void execute(JobExecutionContext context) throws JobExecutionException - { - // Every job has its own job detail - JobDetail jobDetail = context.getJobDetail(); - - // The name is defined in the job definition - String jobName = jobDetail.getName(); - - // Log the time the job started - logger.info(jobName + " fired at " + new Date()); - - // The directory to scan is stored in the job map - JobDataMap dataMap = jobDetail.getJobDataMap(); - String dirName = dataMap.getString("SHPDATA_DIR"); - - // Validate the required input - if (dirName == null) - { - throw new JobExecutionException("Directory not configured"); - } - - // Make sure the directory exists - File dir = new File(dirName); - if (!dir.exists()) - { - throw new JobExecutionException("Invalid Dir " + dirName); - } - - - } -} diff --git a/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2ShpJob.java b/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2ShpJob.java new file mode 100644 index 0000000..3bed880 --- /dev/null +++ b/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2ShpJob.java @@ -0,0 +1,184 @@ +package com.ximple.eofms.jobs; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Types; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.TimeZone; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +import oracle.jdbc.OracleConnection; +import oracle.jdbc.OracleResultSet; +import oracle.sql.ARRAY; +import oracle.sql.BLOB; + +import com.ximple.eofms.util.BinConverter; +import com.ximple.eofms.util.ByteArrayCompressor; +import com.ximple.util.PrintfFormat; + +/** + * + */ +public class OracleConvertDgn2ShpJob extends AbstractOracleDatabaseJob +{ + static Log logger = LogFactory.getLog(OracleConvertDgn2ShpJob.class); + + private static final int FETCHSIZE = 30; + private static final int BATCHSIZE = 25; + + public void execute(JobExecutionContext context) throws JobExecutionException + { + // Every job has its own job detail + JobDetail jobDetail = context.getJobDetail(); + + // The name is defined in the job definition + String jobName = jobDetail.getName(); + + // Log the time the job started + logger.info(jobName + " fired at " + new Date()); + extractJobConfiguration(jobDetail); + + OracleConvertJobContext jobContext = prepareJobContext(); + jobContext.setConnectionInfo(_oracleHost, _oraclePort, _oracleInstance); + jobContext.setLogin(_username, _password); + + try + { + exetcuteConvert(jobContext, _orgSchema, _dataPath); + } catch (SQLException e) + { + throw new JobExecutionException("Database error.", e); + } + + } + + private void exetcuteConvert(OracleConvertJobContext jobContext, + String querySchema, String dataPath) throws SQLException + { + // verify igdsset_seed + String srcTable = "IGSET_1"; + String destTable = OracleConvertJobContext.TABLE_PREFIX + "ELMSET_1"; + long startTime = System.currentTimeMillis(); + ArrayList srcElms = queryIgsetElement(jobContext, querySchema, srcTable); + long currentTime = System.currentTimeMillis(); + SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss:SSS"); + + dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); + + long elapsed = currentTime - startTime; + + System.out.println("Old Format:" + dateFormat.format(new Date(elapsed))); + logger.info("query source element complete."); + startTime = System.currentTimeMillis(); + + ArrayList dstElms = queryRawElement(jobContext, querySchema, destTable); + + currentTime = System.currentTimeMillis(); + dateFormat = new SimpleDateFormat("HH:mm:ss:SSS"); + dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); + elapsed = currentTime - startTime; + System.out.println("New Format:" + dateFormat.format(new Date(elapsed))); + logger.info("query dest element complete."); + // Assert.isTrue(srcElms.size() == dstElms.size(), "src[" + srcElms.size() + "] != dest[" + dstElms.size() + "]"); + } + + private ArrayList queryIgsetElement(OracleConvertJobContext jobContext, + String srcschema, String srctable) throws SQLException + { + ArrayList result = new ArrayList(); + OracleConnection connection = jobContext.getOracleConnection(); + String fetchSrcStmtFmt = "SELECT IGDSELM FROM \"%s\".\"%s\" ORDER BY ROWID"; + PrintfFormat spf = new PrintfFormat(fetchSrcStmtFmt); + String fetchSrcStmt = spf.sprintf(new Object[]{srcschema, srctable}); + Statement stmtSrc = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + + stmtSrc.setFetchSize(FETCHSIZE); + + ResultSet rsSrc = stmtSrc.executeQuery(fetchSrcStmt); + + while (rsSrc.next()) + { + byte[] raw = null; + + if (rsSrc.getMetaData().getColumnType(1) == Types.BLOB) + { + BLOB blob = (BLOB) rsSrc.getBlob(1); + + raw = getBytesFromBLOB(blob); + blob.close(); + } else + { + raw = rsSrc.getBytes(1); + } + + result.add(raw); + } + + return result; + } + + private ArrayList queryRawElement(OracleConvertJobContext jobContext, + String srcschema, String srctable) throws SQLException + { + ArrayList result = new ArrayList(); + OracleConnection connection = jobContext.getOracleConnection(); + String fetchDestStmtFmt = "SELECT ELEMENT FROM \"%s\".\"%s\" ORDER BY ROWID"; + PrintfFormat spf = new PrintfFormat(fetchDestStmtFmt); + String fetchDestStmt = spf.sprintf(new Object[]{srcschema, srctable}); + Statement stmtDest = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + + stmtDest.setFetchSize(FETCHSIZE); + + ResultSet rsDest = stmtDest.executeQuery(fetchDestStmt); + + while (rsDest.next()) + { + ARRAY rawsValue = ((OracleResultSet) rsDest).getARRAY(1); + long[] rawData = rawsValue.getLongArray(); + byte[] comparessedValue; + + /* + if (dataMode == TransferTask.DataMode.Normal) + { + comparessedValue = BinConverter.unmarshalByteArray(rawData, true); + } else + { + comparessedValue = BinConverter.unmarshalCompactByteArray(rawData); + } + */ + comparessedValue = BinConverter.unmarshalByteArray(rawData, true); + + byte[] rawDest = ByteArrayCompressor.decompressByteArray(comparessedValue); + + result.add(rawDest); + } + + return result; + } + + private boolean equalRawData(byte[] rawSrc, byte[] rawDest) + { + if (rawSrc.length != rawDest.length) + { + return false; + } + + for (int i = 0; i < rawSrc.length; i++) + { + if (rawSrc[i] != rawDest[i]) + { + return false; + } + } + + return true; + } +} diff --git a/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertJobContext.java b/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertJobContext.java new file mode 100644 index 0000000..fee578a --- /dev/null +++ b/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertJobContext.java @@ -0,0 +1,291 @@ +package com.ximple.eofms.jobs; + +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.vividsolutions.jts.util.Assert; + +import oracle.jdbc.OracleConnection; + +public class OracleConvertJobContext +{ + static Log logger = LogFactory.getLog(OracleConvertJobContext.class); + + private static final String ORACLE_URL = "jdbc:oracle:thin:@"; + private static final String PROPUsrKey = "user"; + private static final String PROPPassKey = "password"; + + /** + * Table Prefiex + */ + protected static final String TABLE_PREFIX = "GEO$"; + protected static final String UDT_SCHEMA = "SPATIALDB"; + + /** + * User Types + */ + protected static final String UDT_RAWS = "CREATE OR REPLACE TYPE \"" + UDT_SCHEMA + "\".\"RAWS\" AS VARRAY (1048576) OF NUMBER(38)"; + protected static final String UDT_OFMID = "CREATE OR REPLACE TYPE \"" + UDT_SCHEMA + "\".\"OFMID\" AS OBJECT (" + + "\"CLSID\" NUMBER(5), \"OID\" NUMBER(10), \"STATUS\" NUMBER(5), \"COMPID\" NUMBER(3), " + + "\"RULEID\" NUMBER(3), \"OCCID\" NUMBER(3))"; + + protected static final String UDT_RAWSNAME = "RAWS"; + protected static final String UDT_OFMIDNAME = "OFMID"; + + /** + * Utility SQL + */ + protected static final String TAB_DROP = "DROP TABLE %s.%s CASCADE CONSTRAINTS"; + + protected static final String TAB_DELETE = "DELETE FROM %s.%s"; + + /** + * Table Schema + */ + protected static final String TAB_RANGENODEINDEX_1 = "CREATE TABLE \"%s\".\"%s\"\n" + + " ( \"RNID\" INTEGER NOT NULL ENABLE,\n" + + " \"RPID\" INTEGER NOT NULL ENABLE,\n" + + " \"RNG_LOWX\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"RNG_LOWY\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"RNG_HIGHX\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"RNG_HIGHY\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"EXTENTS\" MDSYS.SDO_GEOMETRY,\n" + + " \"RNDESCR\" VARCHAR2(255), \n" + + " PRIMARY KEY ( \"RNID\" ) ENABLE )"; + + protected static final String TAB_RANGENODEINDEX = "CREATE TABLE \"%s\".\"%s\"\n" + + " ( \"RNID\" INTEGER NOT NULL ENABLE,\n" + + " \"RPID\" INTEGER NOT NULL ENABLE,\n" + + " \"RNG_LOWX\" FLOAT NOT NULL ENABLE,\n" + + " \"RNG_LOWY\" FLOAT NOT NULL ENABLE,\n" + + " \"RNG_HIGHX\" FLOAT NOT NULL ENABLE,\n" + + " \"RNG_HIGHY\" FLOAT NOT NULL ENABLE,\n" + + " \"RNDESCR\" VARCHAR2(255), \n" + + " PRIMARY KEY ( \"RNID\" ) ENABLE )"; + + protected static final String TAB_RANGENODESTORAGE = "CREATE TABLE \"%s\".\"%s\"\n" + + " ( \"RNID\" INTEGER NOT NULL ENABLE,\n" + + " \"LAYERID\" NUMBER(5,0) NOT NULL ENABLE,\n" + + " \"LASTUPDATE\" DATE NOT NULL ENABLE,\n" + + " \"SPACETABLE\" VARCHAR2(255)\n" + " )"; + + protected static final String TAB_ELEMENTINDEX_1 = "CREATE TABLE %s.%s (\n" + + " \"ELMNO\" INTEGER NOT NULL ENABLE,\n" + + " \"TYPE\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"XLOW\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"YLOW\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"ZLOW\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"XHIGH\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"YHIGH\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"ZHIGH\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"TAG_LUFID\" NUMBER(10) NOT NULL ENABLE,\n" + + " \"TAG_SFSC\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"TAG_SSTAT\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"TAG_BCOMPID\" NUMBER(3) NOT NULL ENABLE,\n" + + " \"TAG_BRULENO\" NUMBER(3) NOT NULL ENABLE,\n" + + " \"TAG_SOCCID\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"SPACENAME\" VARCHAR2(255) NOT NULL ENABLE,\n" + + " PRIMARY KEY (\"ELMNO\") ENABLE\n" + + " )"; + + protected static final String TAB_ELEMENTINDEX = "CREATE TABLE %s.%s (\n" + + " \"ELMNO\" INTEGER NOT NULL ENABLE,\n" + + " \"TYPE\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"XLOW\" FLOAT NOT NULL ENABLE,\n" + + " \"YLOW\" FLOAT NOT NULL ENABLE,\n" + + " \"ZLOW\" FLOAT NOT NULL ENABLE,\n" + + " \"XHIGH\" FLOAT NOT NULL ENABLE,\n" + + " \"YHIGH\" FLOAT NOT NULL ENABLE,\n" + + " \"ZHIGH\" FLOAT NOT NULL ENABLE,\n" + + " \"TAG_LUFID\" NUMBER(10) NOT NULL ENABLE,\n" + + " \"TAG_SFSC\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"TAG_SSTAT\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"TAG_BCOMPID\" NUMBER(3) NOT NULL ENABLE,\n" + + " \"TAG_BRULENO\" NUMBER(3) NOT NULL ENABLE,\n" + + " \"TAG_SOCCID\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"SPACENAME\" VARCHAR2(255) NOT NULL ENABLE,\n" + + " PRIMARY KEY (\"ELMNO\") ENABLE\n" + + " )"; + + protected static final String TAB_IGDSSEED = "CREATE TABLE %s.%s (\n" + + " \"ELMNO\" INTEGER NOT NULL ENABLE,\n" + + " \"SEEDELM\" \"" + UDT_SCHEMA + + "\".\"RAWS\" NOT NULL ENABLE\n" + " )"; + + protected static final String TAB_STORAGE_1 = "CREATE TABLE %s.%s (\n" + + " \"ELMNO\" INTEGER NOT NULL ENABLE,\n" + + " \"XLOW\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"YLOW\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"XHIGH\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"YHIGH\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"EXTENTS\" MDSYS.SDO_GEOMETRY, \n" + + " \"PROPS\" INTEGER NOT NULL ENABLE,\n" + + " \"TAG_LUFID\" NUMBER(10) NOT NULL ENABLE,\n" + + " \"TAG_SFSC\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"TAG_SSTAT\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"TAG_BCOMPID\" NUMBER(3) NOT NULL ENABLE,\n" + + " \"TAG_BRULENO\" NUMBER(3) NOT NULL ENABLE,\n" + + " \"TAG_SOCCID\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"LAYERID\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"ELEMENT\" \"" + UDT_SCHEMA + "\".\"RAWS\" NOT NULL ENABLE, \n" + + " \"GEOM\" MDSYS.SDO_GEOMETRY \n" + + " )"; + + protected static final String TAB_STORAGE = "CREATE TABLE %s.%s (\n" + + " \"ELMNO\" INTEGER NOT NULL ENABLE,\n" + + " \"XLOW\" FLOAT NOT NULL ENABLE,\n" + + " \"YLOW\" FLOAT NOT NULL ENABLE,\n" + + " \"XHIGH\" FLOAT NOT NULL ENABLE,\n" + + " \"YHIGH\" FLOAT NOT NULL ENABLE,\n" + + " \"PROPS\" INTEGER NOT NULL ENABLE,\n" + + " \"TAG_LUFID\" NUMBER(10) NOT NULL ENABLE,\n" + + " \"TAG_SFSC\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"TAG_SSTAT\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"TAG_BCOMPID\" NUMBER(3) NOT NULL ENABLE,\n" + + " \"TAG_BRULENO\" NUMBER(3) NOT NULL ENABLE,\n" + + " \"TAG_SOCCID\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"LAYERID\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"ELEMENT\" \"" + UDT_SCHEMA + "\".\"RAWS\" NOT NULL ENABLE \n" + + " )"; + + protected static final String TAB_STORAGE2 = "CREATE TABLE %s.%s (\n" + + " \"ELMNO\" INTEGER NOT NULL ENABLE,\n" + + " \"XLOW\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"YLOW\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"XHIGH\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"YHIGH\" BINARY_DOUBLE NOT NULL ENABLE,\n" + + " \"EXTENTS\" MDSYS.SDO_GEOMETRY, \n" + + " \"PROPS\" INTEGER NOT NULL ENABLE,\n" + + " \"ID\" " + UDT_SCHEMA + ".OFMID NOT NULL ENABLE,\n" + + " \"LAYERID\" NUMBER(5) NOT NULL ENABLE,\n" + + " \"ELEMENT\" \"" + UDT_SCHEMA + "\".\"RAWS\" NOT NULL ENABLE \n" + + " )"; + /** + * Trigger + */ + protected static final String TRG_SPACENODE = "CREATE OR REPLACE TRIGGER \"%s\".\"%s\"\n" + + " AFTER DELETE OR INSERT OR UPDATE ON \"%s\".\"%s\"\n" + " BEGIN\n" + + " UPDATE SPACENODES SET LASTUPDATE = SYSDATE\n" + " WHERE SNID = \"%d\";\n" + + " END;"; + + protected static final String TRG_ELMINDEX = + "CREATE OR REPLACE TRIGGER \"%s\".\"%s\"\n" + + " AFTER INSERT OR UPDATE OR DELETE ON \"%s\".\"%s\"\n" + + " REFERENCING OLD AS OLD NEW AS NEW FOR EACH ROW\n" + + " BEGIN\n" + + " IF INSERTING THEN\n" + + " INSERT INTO \"%s\".\"%s\" (ELMNO, TYPE, XLOW, YLOW, XHIGH, YHIGH,\n" + + " UFID, FSC, COMPID, OCCID, SPACENAME)\n" + + " VALUES (SD$ELEMENTNUMBER_SEQ.NEXTVAL, :new.ELMTYPE, :new.XLOW, :new.YLOW, :new.XHIGH, :new.YHIGH,\n" + + " :new.UFID, :new.FSC, :new.COMPID, :new.OCCID, '%s');\n" + + " ELSIF DELETING THEN\n" + + " DELETE FROM \"%s\".\"%s\"\n" + + " WHERE \"%s\".UFID = :old.UFID AND\n" + + " \"%s\".FSC = :old.FSC AND\n" + + " \"%s\".COMPID = :old.COMPID AND\n" + + " \"%s\".OCCID = :old.OCCID;\n" + + " ELSE\n" + " UPDATE \"%s\"\n" + + " SET XLOW = :new.XLOW, YLOW = :new.YLOW, XHIGH = :new.XHIGH, YHIGH = :new.YHIGH\n" + + " WHERE FSC = :new.FSC AND UFID = :new.UFID AND COMPID = :new.COMPID AND OCCID = :new.OCCID;\n" + + " END IF;\n" + " END;"; + + /** + * + */ + protected static final String TAB_ELEMENTSET_PREFIX = "ELMSET_"; + + protected static final String STMT_CLEARCYCLEBIN = "PURGE RECYCLEBIN"; + + protected static final String SMTM_GRANTOBJECTTYPE = "GRANT EXECUTE ANY TYPE TO \"" + UDT_SCHEMA + "\""; + + private String _oracleHost; + private String _oracleInstance; + private String _oraclePort; + + static + { + try + { + DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); + } catch (SQLException e) + { + Assert.shouldNeverReachHere(e.getMessage()); + } + } + + public static String getCurrentURL(String oracleHost, String oraclePort, String oracleInstance) + { + StringBuilder builder = new StringBuilder(); + + builder.append(ORACLE_URL); + builder.append(oracleHost); + builder.append(":"); + builder.append(oraclePort); + builder.append(":"); + builder.append(oracleInstance); + + return builder.toString(); + } + + private OracleConnection oracleConnection = null; + private Properties properties; + + public OracleConvertJobContext() + { + properties = new Properties(); + } + + public void setLogin(String userName, String password) + { + properties.put(PROPUsrKey, userName); + properties.put(PROPPassKey, password); + } + + public OracleConnection getOracleConnection() + { + try + { + if (oracleConnection == null) + { + oracleConnection = (OracleConnection) DriverManager.getConnection( + getCurrentURL(_oracleHost, _oraclePort, _oracleInstance), + properties); + } + + return oracleConnection; + } catch (SQLException e) + { + logger.warn(e.getMessage(), e); + } + + oracleConnection = null; + + return null; + } + + public void closeConnection() + { + try + { + if (oracleConnection != null) + { + oracleConnection.close(); + oracleConnection = null; + } + } catch (SQLException e) + { + logger.warn(e.getMessage(), e); + } + } + + public void setConnectionInfo(String oracleHost, String oraclePort, String oracleInstance) + { + _oracleHost = oracleHost; + _oracleInstance = oracleInstance; + _oraclePort = oraclePort; + } +} diff --git a/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleUpgradeBlob2UDTJob.java b/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleUpgradeBlob2UDTJob.java new file mode 100644 index 0000000..eb653c0 --- /dev/null +++ b/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleUpgradeBlob2UDTJob.java @@ -0,0 +1,53 @@ +package com.ximple.eofms.jobs; + +import java.util.Date; +import java.sql.SQLException; + +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.quartz.JobDetail; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import oracle.jdbc.OracleConnection; +import oracle.jdbc.OracleDatabaseMetaData; +import oracle.jdbc.OracleStatement; + +public class OracleUpgradeBlob2UDTJob extends AbstractOracleDatabaseJob +{ + static Log logger = LogFactory.getLog(OracleUpgradeBlob2UDTJob.class); + + public void execute(JobExecutionContext context) throws JobExecutionException + { + // Every job has its own job detail + JobDetail jobDetail = context.getJobDetail(); + + // The name is defined in the job definition + String jobName = jobDetail.getName(); + + // Log the time the job started + logger.info(jobName + " fired at " + new Date()); + extractJobConfiguration(jobDetail); + + OracleConvertJobContext jobContext = prepareJobContext(); + jobContext.setConnectionInfo(_oracleHost, _oraclePort, _oracleInstance); + jobContext.setLogin(_username, _password); + + try + { + exetcuteConvert(jobContext, _orgSchema, _dataPath); + } catch (SQLException e) + { + throw new JobExecutionException("Database error.", e); + } + } + + private void exetcuteConvert(OracleConvertJobContext jobContext, + String orgSchema, String dataPath) throws SQLException + { + OracleConnection connection = jobContext.getOracleConnection(); + OracleDatabaseMetaData metaData = (OracleDatabaseMetaData) connection.getMetaData(); + OracleStatement statement = (OracleStatement) connection.createStatement(); + } +} diff --git a/ximple-spatialjob/src/main/java/com/ximple/eofms/util/BinConverter.java b/ximple-spatialjob/src/main/java/com/ximple/eofms/util/BinConverter.java new file mode 100644 index 0000000..707ad61 --- /dev/null +++ b/ximple-spatialjob/src/main/java/com/ximple/eofms/util/BinConverter.java @@ -0,0 +1,354 @@ +package com.ximple.eofms.util; + +//~--- JDK imports ------------------------------------------------------------ + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.LongBuffer; + +import org.testng.Assert; + +/** + * BinConverter + * User: Ulysses + * Date: 2007/9/17 + * Time: �W�� 01:13:13 + */ +public class BinConverter +{ + // our table for binhex conversion + final static char[] HEXTAB = + { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + + /** + * gets bytes from an array into a long + * @param buffer where to get the bytes + * @param nStartIndex index from where to read the data + * @return the 64bit integer + */ + public static long byteArrayToLong(byte[] buffer, int nStartIndex) + { + return (((long) buffer[nStartIndex]) << 56) | (((long) buffer[nStartIndex + 1] & 0x0ffL) << 48) + | (((long) buffer[nStartIndex + 2] & 0x0ffL) << 40) | (((long) buffer[nStartIndex + 3] & 0x0ffL) << 32) + | (((long) buffer[nStartIndex + 4] & 0x0ffL) << 24) | (((long) buffer[nStartIndex + 5] & 0x0ffL) << 16) + | (((long) buffer[nStartIndex + 6] & 0x0ffL) << 8) | ((long) buffer[nStartIndex + 7] & 0x0ff); + } + + /** + * converts a long o bytes which are put into a given array + * @param lValue the 64bit integer to convert + * @param buffer the target buffer + * @param nStartIndex where to place the bytes in the buffer + */ + public static void longToByteArray(long lValue, byte[] buffer, int nStartIndex) + { + buffer[nStartIndex] = (byte) (lValue >>> 56); + buffer[nStartIndex + 1] = (byte) ((lValue >>> 48) & 0x0ff); + buffer[nStartIndex + 2] = (byte) ((lValue >>> 40) & 0x0ff); + buffer[nStartIndex + 3] = (byte) ((lValue >>> 32) & 0x0ff); + buffer[nStartIndex + 4] = (byte) ((lValue >>> 24) & 0x0ff); + buffer[nStartIndex + 5] = (byte) ((lValue >>> 16) & 0x0ff); + buffer[nStartIndex + 6] = (byte) ((lValue >>> 8) & 0x0ff); + buffer[nStartIndex + 7] = (byte) lValue; + } + + /** + * converts values from an integer array to a long + * @param buffer where to get the bytes + * @param nStartIndex index from where to read the data + * @return the 64bit integer + */ + public static long intArrayToLong(int[] buffer, int nStartIndex) + { + return (((long) buffer[nStartIndex]) << 32) | (((long) buffer[nStartIndex + 1]) & 0x0ffffffffL); + } + + /** + * converts a long to integers which are put into a given array + * @param lValue the 64bit integer to convert + * @param buffer the target buffer + * @param nStartIndex where to place the bytes in the buffer + */ + public static void longToIntArray(long lValue, int[] buffer, int nStartIndex) + { + buffer[nStartIndex] = (int) (lValue >>> 32); + buffer[nStartIndex + 1] = (int) lValue; + } + + /** + * makes a long from two integers (treated unsigned) + * @param nLo lower 32bits + * @param nHi higher 32bits + * @return the built long + */ + public static long makeLong(int nLo, int nHi) + { + return (((long) nHi << 32) | ((long) nLo & 0x00000000ffffffffL)); + } + + /** + * gets the lower 32 bits of a long + * @param lVal the long integer + * @return lower 32 bits + */ + public static int longLo32(long lVal) + { + return (int) lVal; + } + + /** + * gets the higher 32 bits of a long + * @param lVal the long integer + * @return higher 32 bits + */ + public static int longHi32(long lVal) + { + return (int) ((long) (lVal >>> 32)); + } + + /** + * converts a byte array to a binhex string + * @param data the byte array + * @return the binhex string + */ + public static String bytesToBinHex(byte[] data) + { + // just map the call + return bytesToBinHex(data, 0, data.length); + } + + /** + * converts a byte array to a binhex string + * @param data the byte array + * @param nStartPos start index where to get the bytes + * @param nNumOfBytes number of bytes to convert + * @return the binhex string + */ + public static String bytesToBinHex(byte[] data, int nStartPos, int nNumOfBytes) + { + StringBuffer sbuf = new StringBuffer(); + + sbuf.setLength(nNumOfBytes << 1); + + int nPos = 0; + + for (int nI = 0; nI < nNumOfBytes; nI++) + { + sbuf.setCharAt(nPos++, HEXTAB[(data[nI + nStartPos] >> 4) & 0x0f]); + sbuf.setCharAt(nPos++, HEXTAB[data[nI + nStartPos] & 0x0f]); + } + + return sbuf.toString(); + } + + /** + * converts a binhex string back into a byte array (invalid codes will be skipped) + * @param sBinHex binhex string + * @param data the target array + * @param nSrcPos from which character in the string the conversion should begin, + * remember that (nSrcPos modulo 2) should equals 0 normally + * @param nDstPos to store the bytes from which position in the array + * @param nNumOfBytes number of bytes to extract + * @return number of extracted bytes + */ + public static int binHexToBytes(String sBinHex, byte[] data, int nSrcPos, int nDstPos, int nNumOfBytes) + { + // check for correct ranges + int nStrLen = sBinHex.length(); + int nAvailBytes = (nStrLen - nSrcPos) >> 1; + + if (nAvailBytes < nNumOfBytes) + { + nNumOfBytes = nAvailBytes; + } + + int nOutputCapacity = data.length - nDstPos; + + if (nNumOfBytes > nOutputCapacity) + { + nNumOfBytes = nOutputCapacity; + } + + // convert now + int nResult = 0; + + for (int nI = 0; nI < nNumOfBytes; nI++) + { + byte bActByte = 0; + boolean blConvertOK = true; + + for (int nJ = 0; nJ < 2; nJ++) + { + bActByte <<= 4; + + char cActChar = sBinHex.charAt(nSrcPos++); + + if ((cActChar >= 'a') && (cActChar <= 'f')) + { + bActByte |= (byte) (cActChar - 'a') + 10; + } else if ((cActChar >= '0') && (cActChar <= '9')) + { + bActByte |= (byte) (cActChar - '0'); + } else + { + blConvertOK = false; + } + } + + if (blConvertOK) + { + data[nDstPos++] = bActByte; + nResult++; + } + } + + return nResult; + } + + /** + * converts a byte array into an UNICODE string + * @param data the byte array + * @param nStartPos where to begin the conversion + * @param nNumOfBytes number of bytes to handle + * @return the string + */ + public static String byteArrayToUNCString(byte[] data, int nStartPos, int nNumOfBytes) + { + // we need two bytes for every character + nNumOfBytes &= ~1; + + // enough bytes in the buffer? + int nAvailCapacity = data.length - nStartPos; + + if (nAvailCapacity < nNumOfBytes) + { + nNumOfBytes = nAvailCapacity; + } + + StringBuffer sbuf = new StringBuffer(); + + sbuf.setLength(nNumOfBytes >> 1); + + int nSBufPos = 0; + + while (nNumOfBytes > 0) + { + sbuf.setCharAt(nSBufPos++, (char) (((int) data[nStartPos] << 8) | ((int) data[nStartPos + 1] & 0x0ff))); + nStartPos += 2; + nNumOfBytes -= 2; + } + + return sbuf.toString(); + } + + public static long[] marshalByteArray(byte[] raws, boolean hasSignature) + { + int remainder = raws.length % 8; + ByteBuffer rawData = ByteBuffer.wrap(raws); + + rawData.rewind(); + rawData.order(ByteOrder.LITTLE_ENDIAN); + + LongBuffer longBuffer = ((ByteBuffer) rawData.rewind()).asLongBuffer(); + int resultSize = longBuffer.limit() + ((remainder != 0) + ? 1 + : 0) + (hasSignature + ? 1 + : 0); + long[] result = new long[resultSize]; + int i = 0; + + if (hasSignature) + { + result[i] = raws.length; + i++; + } + + while (longBuffer.hasRemaining()) + { + result[i] = longBuffer.get(); + i++; + } + + if (remainder != 0) + { + int pos = (i - (hasSignature + ? 1 + : 0)) * 8; + + // int pos = rawData.position(); + byte[] temp = new byte[8]; + + for (int j = 0; j < remainder; j++) + { + temp[7 - j] = raws[pos + j]; + } + + // System.arraycopy(raws, pos, temp, 0, remainder); + result[i] = BinConverter.byteArrayToLong(temp, 0); + } + + return result; + } + + public static byte[] unmarshalByteArray(long[] raws, boolean hasSignature) + { + LongBuffer longBuffer = LongBuffer.wrap(raws); + int resultBufferSize = (raws.length - (hasSignature + ? 1 + : 0)) * 8; + int resultSize = resultBufferSize; + + if (hasSignature) + { + resultSize = (int) longBuffer.get(); + } + + ByteBuffer result = ByteBuffer.allocate(resultBufferSize); + + result.order(ByteOrder.LITTLE_ENDIAN); + + while (longBuffer.hasRemaining()) + { + result.putLong(longBuffer.get()); + } + + if (resultSize == resultBufferSize) + { + return result.array(); + } + + byte[] resultData = new byte[resultSize]; + + result.position(0); + result.get(resultData, 0, resultSize); + + return resultData; + } + + public static long[] marshalCompactByteArray(byte[] raws) + { + byte[] compactRaws = new byte[raws.length + 2]; + ByteBuffer bbCompact = ByteBuffer.wrap(compactRaws); + bbCompact.order(ByteOrder.LITTLE_ENDIAN); + bbCompact.putShort((short) raws.length); + bbCompact.put(raws); + long[] longData = BinConverter.marshalByteArray(compactRaws, false); + return longData; + } + + public static byte[] unmarshalCompactByteArray(long[] raws) + { + byte[] rawData = BinConverter.unmarshalByteArray(raws, false); + + ByteBuffer bbCompact = ByteBuffer.wrap(rawData); + bbCompact.order(ByteOrder.LITTLE_ENDIAN); + short originSize = bbCompact.getShort(); + + byte[] rawOriginData = new byte[originSize]; + bbCompact.get(rawOriginData, 0, originSize); + return rawOriginData; + } +} diff --git a/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Bits.java b/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Bits.java new file mode 100644 index 0000000..092569c --- /dev/null +++ b/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Bits.java @@ -0,0 +1,323 @@ +package com.ximple.eofms.util; + +//~--- JDK imports ------------------------------------------------------------ + +import java.nio.ByteOrder; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import sun.misc.Unsafe; +import sun.misc.VM; + +/** + * Bits + * User: Ulysses + * Date: 2007/6/17 + * Time: �W�� 01:16:39 + */ +public class Bits +{ + // -- Unsafe access -- + // private static final Unsafe unsafe = Unsafe.getUnsafe(); + + // -- Processor and memory-system properties -- + private static ByteOrder byteOrder = null; + private static int pageSize = -1; + private static boolean unaligned; + private static boolean unalignedKnown = false; + + // -- Direct memory management -- + // A user-settable upper limit on the maximum amount of allocatable +// direct buffer memory. This value may be changed during VM + // initialization if it is launched with "-XX:MaxDirectMemorySize=<size>". + private static volatile long maxMemory = VM.maxDirectMemory(); + private static volatile long reservedMemory = 0; + private static boolean memoryLimitSet = false; + + private Bits() + { + } + + // -- Swapping -- + public static short swap(short x) + { + return (short) ((x << 8) | ((x >> 8) & 0xff)); + } + + public static char swap(char x) + { + return (char) ((x << 8) | ((x >> 8) & 0xff)); + } + + public static int swap(int x) + { + return (int) ((swap((short) x) << 16) | (swap((short) (x >> 16)) & 0xffff)); + } + + public static long swap(long x) + { + return (long) (((long) swap((int) (x)) << 32) | ((long) swap((int) (x >> 32)) & 0xffffffffL)); + } + + // -- get/put char -- + static private char makeChar(byte b1, byte b0) + { + return (char) ((b1 << 8) | (b0 & 0xff)); + } + + private static byte char1(char x) + { + return (byte) (x >> 8); + } + + private static byte char0(char x) + { + return (byte) (x >> 0); + } + + // --get/put short-- + public static short makeShort(byte b1, byte b0) + { + return (short) ((b1 << 8) | (b0 & 0xff)); + } + + private static byte short1(short x) + { + return (byte) (x >> 8); + } + + public static byte short0(short x) + { + return (byte) (x >> 0); + } + + // -- get/put int -- + public static int makeInt(byte b3, byte b2, byte b1, byte b0) + { + return (int) ((((b3 & 0xff) << 24) | ((b2 & 0xff) << 16) | ((b1 & 0xff) << 8) | ((b0 & 0xff) << 0))); + } + + public static int makeInt(short hiword, short loword) + { + return ((hiword & 0xffff) << 16) + (loword & 0xffff); + } + + public static short getHiShort(int qwValue) + { + return ((short) (qwValue >>> 16)); + } + + public static short getLoShort(int qwValue) + { + return ((short) (qwValue & 0xFFFF)); + } + + public static byte int3(int x) + { + return (byte) (x >> 24); + } + + public static byte int2(int x) + { + return (byte) (x >> 16); + } + + private static byte int1(int x) + { + return (byte) (x >> 8); + } + + private static byte int0(int x) + { + return (byte) (x >> 0); + } + + // -- get/put long -- + public static long makeLong(byte b7, byte b6, byte b5, byte b4, byte b3, byte b2, byte b1, byte b0) + { + return ((((long) b7 & 0xff) << 56) | (((long) b6 & 0xff) << 48) | (((long) b5 & 0xff) << 40) | (((long) b4 & 0xff) << 32) + | (((long) b3 & 0xff) << 24) | (((long) b2 & 0xff) << 16) | (((long) b1 & 0xff) << 8) + | (((long) b0 & 0xff) << 0)); + } + + public static long makeLong(int LoValue, int HiValue) + { + return (((long) HiValue & 0xFFFFFFFF) << 32) + (((long) LoValue) & 0xFFFFFFFF); + } + + public static int getHiInt(long qwValue) + { + return ((int)(qwValue >>> 32)); + } + + public static int getLoInt(long qwValue) + { + return ((int) (qwValue & 0xFFFFFFFF)); + } + + private static byte long7(long x) + { + return (byte) (x >> 56); + } + + private static byte long6(long x) + { + return (byte) (x >> 48); + } + + private static byte long5(long x) + { + return (byte) (x >> 40); + } + + private static byte long4(long x) + { + return (byte) (x >> 32); + } + + private static byte long3(long x) + { + return (byte) (x >> 24); + } + + private static byte long2(long x) + { + return (byte) (x >> 16); + } + + private static byte long1(long x) + { + return (byte) (x >> 8); + } + + private static byte long0(long x) + { + return (byte) (x >> 0); + } + + // -- get/put float -- + + // -- get/put double -- + + /* + private static byte _get(long a) + { + return unsafe.getByte(a); + } + + private static void _put(long a, byte b) + { + unsafe.putByte(a, b); + } + + static Unsafe unsafe() + { + return unsafe; + } + + static ByteOrder byteOrder() + { + if (byteOrder != null) + { + return byteOrder; + } + + long a = unsafe.allocateMemory(8); + + try + { + unsafe.putLong(a, 0x0102030405060708L); + + byte b = unsafe.getByte(a); + + switch (b) + { + case 0x01 : + byteOrder = ByteOrder.BIG_ENDIAN; + + break; + + case 0x08 : + byteOrder = ByteOrder.LITTLE_ENDIAN; + + break; + + default : + throw new Error("Unknown byte order"); + } + } finally + { + unsafe.freeMemory(a); + } + + return byteOrder; + } + */ + static boolean unaligned() + { + if (unalignedKnown) + { + return unaligned; + } + + PrivilegedAction pa = new sun.security.action.GetPropertyAction("os.arch"); + String arch = (String) AccessController.doPrivileged(pa); + + unaligned = arch.equals("i386") || arch.equals("x86"); + unalignedKnown = true; + + return unaligned; + } + + // These methods should be called whenever direct memory is allocated or + // freed. They allow the user to control the amount of direct memory + // which a process may access. All sizes are specified in bytes. + static void reserveMemory(long size) + { + synchronized (Bits.class) + { + if (!memoryLimitSet && VM.isBooted()) + { + maxMemory = VM.maxDirectMemory(); + memoryLimitSet = true; + } + + if (size <= maxMemory - reservedMemory) + { + reservedMemory += size; + + return; + } + } + + System.gc(); + + try + { + Thread.sleep(100); + } catch (InterruptedException x) + { + // Restore interrupt status + Thread.currentThread().interrupt(); + } + + synchronized (Bits.class) + { + if (reservedMemory + size > maxMemory) + { + throw new OutOfMemoryError("Direct buffer memory"); + } + + reservedMemory += size; + } + } + + static synchronized void unreserveMemory(long size) + { + if (reservedMemory > 0) + { + reservedMemory -= size; + assert(reservedMemory > -1); + } + } +} diff --git a/ximple-spatialjob/src/main/java/com/ximple/eofms/util/ByteArrayCompressor.java b/ximple-spatialjob/src/main/java/com/ximple/eofms/util/ByteArrayCompressor.java new file mode 100644 index 0000000..f22eaec --- /dev/null +++ b/ximple-spatialjob/src/main/java/com/ximple/eofms/util/ByteArrayCompressor.java @@ -0,0 +1,97 @@ +package com.ximple.eofms.util; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; +import java.util.zip.Inflater; + +/** + * ByteArrayCompressor + * User: Ulysses + * Date: 2007/6/15 + * Time: �U�� 02:21:00 + * To change this template use File | Settings | File Templates. + */ +public final class ByteArrayCompressor +{ + public static byte[] decompressByteArray(byte[] raw) + { + // Create the decompressor and give it the data to compress + Inflater decompressor = new Inflater(); + + decompressor.setInput(raw); + + // Create an expandable byte array to hold the decompressed data + ByteArrayOutputStream bos = new ByteArrayOutputStream(raw.length); + + // Decompress the data + byte[] buf = new byte[1024]; + + while (!decompressor.finished()) + { + try + { + int count = decompressor.inflate(buf); + + bos.write(buf, 0, count); + } catch (DataFormatException e) + { + } + } + + try + { + bos.close(); + } catch (IOException e) + { + } + + // Get the decompressed data + byte[] decompressedData = bos.toByteArray(); + + return decompressedData; + } + + public static byte[] compressByteArray(byte[] raw) + { + // Create the compressor with highest level of compression + Deflater compressor = new Deflater(); + + compressor.setLevel(Deflater.BEST_SPEED); + + // Give the compressor the data to compress + compressor.setInput(raw); + compressor.finish(); + + // Create an expandable byte array to hold the compressed data. + // You cannot use an array that's the same size as the orginal because + // there is no guarantee that the compressed data will be smaller than + // the uncompressed data. + ByteArrayOutputStream bos = new ByteArrayOutputStream(raw.length); + + // Compress the data + byte[] buf = new byte[1024]; + + while (!compressor.finished()) + { + int count = compressor.deflate(buf); + + bos.write(buf, 0, count); + } + + try + { + bos.close(); + } catch (IOException e) + { + } + + // Get the compressed data + byte[] compressedData = bos.toByteArray(); + + return compressedData; + } +} diff --git a/ximple-spatialjob/src/main/java/com/ximple/eofms/util/GeomUtil.java b/ximple-spatialjob/src/main/java/com/ximple/eofms/util/GeomUtil.java new file mode 100644 index 0000000..023ee69 --- /dev/null +++ b/ximple-spatialjob/src/main/java/com/ximple/eofms/util/GeomUtil.java @@ -0,0 +1,30 @@ +package com.ximple.eofms.util; + +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Coordinate; + +/** + * Created by IntelliJ IDEA. + * User: Ulysses + * Date: 2007/6/15 + * Time: �W�� 01:20:20 + * To change this template use File | Settings | File Templates. + */ +public final class GeomUtil +{ + public static double convertLogicalValue(double value) + { + return value / 1000.0 + 2147483.648; + } + + public static Coordinate convertLogicalCooridate(Coordinate value) + { + return new Coordinate(convertLogicalValue(value.x), convertLogicalValue(value.y), convertLogicalValue(value.z)); + } + + public static Envelope convertLogicalEnvelope(Envelope value) + { + return new Envelope(convertLogicalValue(value.getMinX()), convertLogicalValue(value.getMaxX()), + convertLogicalValue(value.getMinY()), convertLogicalValue(value.getMaxY())); + } +} diff --git a/ximple-spatialjob/src/main/java/com/ximple/eofms/util/LangUtil.java b/ximple-spatialjob/src/main/java/com/ximple/eofms/util/LangUtil.java new file mode 100644 index 0000000..794c27b --- /dev/null +++ b/ximple-spatialjob/src/main/java/com/ximple/eofms/util/LangUtil.java @@ -0,0 +1,104 @@ +package com.ximple.eofms.util; + +import java.util.Collection; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Map; +import java.util.HashMap; + +import com.vividsolutions.jts.util.Assert; + +/** + * Created by IntelliJ IDEA. + * User: Ulysses + * Date: 2007/6/15 + * Time: �W�� 01:21:25 + * To change this template use File | Settings | File Templates. + */ +public class LangUtil +{ + private static Map primitiveToWrapperMap = new HashMap() + { + + { + put(byte.class, Byte.class); + put(char.class, Character.class); + put(short.class, Short.class); + put(int.class, Integer.class); + put(long.class, Long.class); + put(float.class, Float.class); + put(double.class, Double.class); + put(boolean.class, Boolean.class); + } + }; + + public static String emptyStringIfNull(String s) + { + return (s == null) ? "" : s; + } + + /** + * Useful because an expression used to generate o need only be + * evaluated once. + */ + public static Object ifNull(Object o, Object alternative) + { + return (o == null) ? alternative : o; + } + + public static Object ifNotNull(Object o, Object alternative) + { + return (o != null) ? alternative : o; + } + + public static Class toPrimitiveWrapperClass(Class primitiveClass) + { + return (Class) primitiveToWrapperMap.get(primitiveClass); + } + + public static boolean isPrimitive(Class c) + { + return primitiveToWrapperMap.containsKey(c); + } + + public static boolean bothNullOrEqual(Object a, Object b) + { + return (a == null && b == null) || (a != null && b != null && a.equals(b)); + } + + public static Object newInstance(Class c) + { + try + { + return c.newInstance(); + } catch (Exception e) + { + Assert.shouldNeverReachHere(e.toString()); + return null; + } + } + + public static Collection classesAndInterfaces(Class c) + { + ArrayList classesAndInterfaces = new ArrayList(); + classesAndInterfaces.add(c); + superclasses(c, classesAndInterfaces); + for (Iterator i = new ArrayList(classesAndInterfaces).iterator(); i.hasNext();) + { + Class x = (Class) i.next(); + classesAndInterfaces.addAll(Arrays.asList(x.getInterfaces())); + } + return classesAndInterfaces; + } + + private static void superclasses(Class c, Collection results) + { + if (c.getSuperclass() == null) + { + return; + } + results.add(c.getSuperclass()); + superclasses(c.getSuperclass(), results); + } +} diff --git a/ximple-spatialjob/src/main/java/com/ximple/eofms/util/PrintfFormat.java b/ximple-spatialjob/src/main/java/com/ximple/eofms/util/PrintfFormat.java new file mode 100644 index 0000000..b7a6ade --- /dev/null +++ b/ximple-spatialjob/src/main/java/com/ximple/eofms/util/PrintfFormat.java @@ -0,0 +1,4774 @@ +// +//(c) 2000 Sun Microsystems, Inc. +//ALL RIGHTS RESERVED +// +//License Grant- +// +// +//Permission to use, copy, modify, and distribute this Software and its +//documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee is +//hereby granted. +// +//This Software is provided "AS IS". All express warranties, including any +//implied warranty of merchantability, satisfactory quality, fitness for a +//particular purpose, or non-infringement, are disclaimed, except to the extent +//that such disclaimers are held to be legally invalid. +// +//You acknowledge that Software is not designed, licensed or intended for use in +//the design, construction, operation or maintenance of any nuclear facility +//("High Risk Activities"). Sun disclaims any express or implied warranty of +//fitness for such uses. +// +//Please refer to the file http://www.sun.com/policies/trademarks/ for further +//important trademark information and to +//http://java.sun.com/nav/business/index.html for further important licensing +//information for the Java Technology. +// + +package com.ximple.eofms.util; + +//~--- JDK imports ------------------------------------------------------------ + +import java.text.DecimalFormatSymbols; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Vector; + +/** + * PrintfFormat allows the formatting of an array of + * objects embedded within a string. Primitive types + * must be passed using wrapper types. The formatting + * is controlled by a control string. + * <p> + * A control string is a Java string that contains a + * control specification. The control specification + * starts at the first percent sign (%) in the string, + * provided that this percent sign + * <ol> + * <li>is not escaped protected by a matching % or is + * not an escape % character, + * <li>is not at the end of the format string, and + * <li>precedes a sequence of characters that parses as + * a valid control specification. + * </ol> + * </p><p> + * A control specification usually takes the form: + * <pre> % ['-+ #0]* [0..9]* { . [0..9]* }+ + * { [hlL] }+ [idfgGoxXeEcs] + * </pre> + * There are variants of this basic form that are + * discussed below.</p> + * <p> + * The format is composed of zero or more directives + * defined as follows: + * <ul> + * <li>ordinary characters, which are simply copied to + * the output stream; + * <li>escape sequences, which represent non-graphic + * characters; and + * <li>conversion specifications, each of which + * results in the fetching of zero or more arguments. + * </ul></p> + * <p> + * The results are undefined if there are insufficient + * arguments for the format. Usually an unchecked + * exception will be thrown. If the format is + * exhausted while arguments remain, the excess + * arguments are evaluated but are otherwise ignored. + * In format strings containing the % form of + * conversion specifications, each argument in the + * argument list is used exactly once.</p> + * <p> + * Conversions can be applied to the <code>n</code>th + * argument after the format in the argument list, + * rather than to the next unused argument. In this + * case, the conversion characer % is replaced by the + * sequence %<code>n</code>$, where <code>n</code> is + * a decimal integer giving the position of the + * argument in the argument list.</p> + * <p> + * In format strings containing the %<code>n</code>$ + * form of conversion specifications, each argument + * in the argument list is used exactly once.</p> + * + * <h4>Escape Sequences</h4> + * <p> + * The following table lists escape sequences and + * associated actions on display devices capable of + * the action. + * <table> + * <tr><th align=left>Sequence</th> + * <th align=left>Name</th> + * <th align=left>Description</th></tr> + * <tr><td>\\</td><td>backlash</td><td>None. + * </td></tr> + * <tr><td>\a</td><td>alert</td><td>Attempts to alert + * the user through audible or visible + * notification. + * </td></tr> + * <tr><td>\b</td><td>backspace</td><td>Moves the + * printing position to one column before + * the current position, unless the + * current position is the start of a line. + * </td></tr> + * <tr><td>\f</td><td>form-feed</td><td>Moves the + * printing position to the initial + * printing position of the next logical + * page. + * </td></tr> + * <tr><td>\n</td><td>newline</td><td>Moves the + * printing position to the start of the + * next line. + * </td></tr> + * <tr><td>\r</td><td>carriage-return</td><td>Moves + * the printing position to the start of + * the current line. + * </td></tr> + * <tr><td>\t</td><td>tab</td><td>Moves the printing + * position to the next implementation- + * defined horizontal tab position. + * </td></tr> + * <tr><td>\v</td><td>vertical-tab</td><td>Moves the + * printing position to the start of the + * next implementation-defined vertical + * tab position. + * </td></tr> + * </table></p> + * <h4>Conversion Specifications</h4> + * <p> + * Each conversion specification is introduced by + * the percent sign character (%). After the character + * %, the following appear in sequence:</p> + * <p> + * Zero or more flags (in any order), which modify the + * meaning of the conversion specification.</p> + * <p> + * An optional minimum field width. If the converted + * value has fewer characters than the field width, it + * will be padded with spaces by default on the left; + * t will be padded on the right, if the left- + * adjustment flag (-), described below, is given to + * the field width. The field width takes the form + * of a decimal integer. If the conversion character + * is s, the field width is the the minimum number of + * characters to be printed.</p> + * <p> + * An optional precision that gives the minumum number + * of digits to appear for the d, i, o, x or X + * conversions (the field is padded with leading + * zeros); the number of digits to appear after the + * radix character for the e, E, and f conversions, + * the maximum number of significant digits for the g + * and G conversions; or the maximum number of + * characters to be written from a string is s and S + * conversions. The precision takes the form of an + * optional decimal digit string, where a null digit + * string is treated as 0. If a precision appears + * with a c conversion character the precision is + * ignored. + * </p> + * <p> + * An optional h specifies that a following d, i, o, + * x, or X conversion character applies to a type + * short argument (the argument will be promoted + * according to the integral promotions and its value + * converted to type short before printing).</p> + * <p> + * An optional l (ell) specifies that a following + * d, i, o, x, or X conversion character applies to a + * type long argument.</p> + * <p> + * A field width or precision may be indicated by an + * asterisk (*) instead of a digit string. In this + * case, an integer argument supplised the field width + * precision. The argument that is actually converted + * is not fetched until the conversion letter is seen, + * so the the arguments specifying field width or + * precision must appear before the argument (if any) + * to be converted. If the precision argument is + * negative, it will be changed to zero. A negative + * field width argument is taken as a - flag, followed + * by a positive field width.</p> + * <p> + * In format strings containing the %<code>n</code>$ + * form of a conversion specification, a field width + * or precision may be indicated by the sequence + * *<code>m</code>$, where m is a decimal integer + * giving the position in the argument list (after the + * format argument) of an integer argument containing + * the field width or precision.</p> + * <p> + * The format can contain either numbered argument + * specifications (that is, %<code>n</code>$ and + * *<code>m</code>$), or unnumbered argument + * specifications (that is % and *), but normally not + * both. The only exception to this is that %% can + * be mixed with the %<code>n</code>$ form. The + * results of mixing numbered and unnumbered argument + * specifications in a format string are undefined.</p> + * + * <h4>Flag Characters</h4> + * <p> + * The flags and their meanings are:</p> + * <dl> + * <dt>'<dd> integer portion of the result of a + * decimal conversion (%i, %d, %f, %g, or %G) will + * be formatted with thousands' grouping + * characters. For other conversions the flag + * is ignored. The non-monetary grouping + * character is used. + * <dt>-<dd> result of the conversion is left-justified + * within the field. (It will be right-justified + * if this flag is not specified).</td></tr> + * <dt>+<dd> result of a signed conversion always + * begins with a sign (+ or -). (It will begin + * with a sign only when a negative value is + * converted if this flag is not specified.) + * <dt><space><dd> If the first character of a + * signed conversion is not a sign, a space + * character will be placed before the result. + * This means that if the space character and + + * flags both appear, the space flag will be + * ignored. + * <dt>#<dd> value is to be converted to an alternative + * form. For c, d, i, and s conversions, the flag + * has no effect. For o conversion, it increases + * the precision to force the first digit of the + * result to be a zero. For x or X conversion, a + * non-zero result has 0x or 0X prefixed to it, + * respectively. For e, E, f, g, and G + * conversions, the result always contains a radix + * character, even if no digits follow the radix + * character (normally, a decimal point appears in + * the result of these conversions only if a digit + * follows it). For g and G conversions, trailing + * zeros will not be removed from the result as + * they normally are. + * <dt>0<dd> d, i, o, x, X, e, E, f, g, and G + * conversions, leading zeros (following any + * indication of sign or base) are used to pad to + * the field width; no space padding is + * performed. If the 0 and - flags both appear, + * the 0 flag is ignored. For d, i, o, x, and X + * conversions, if a precision is specified, the + * 0 flag will be ignored. For c conversions, + * the flag is ignored. + * </dl> + * + * <h4>Conversion Characters</h4> + * <p> + * Each conversion character results in fetching zero + * or more arguments. The results are undefined if + * there are insufficient arguments for the format. + * Usually, an unchecked exception will be thrown. + * If the format is exhausted while arguments remain, + * the excess arguments are ignored.</p> + * + * <p> + * The conversion characters and their meanings are: + * </p> + * <dl> + * <dt>d,i<dd>The int argument is converted to a + * signed decimal in the style [-]dddd. The + * precision specifies the minimum number of + * digits to appear; if the value being + * converted can be represented in fewer + * digits, it will be expanded with leading + * zeros. The default precision is 1. The + * result of converting 0 with an explicit + * precision of 0 is no characters. + * <dt>o<dd> The int argument is converted to unsigned + * octal format in the style ddddd. The + * precision specifies the minimum number of + * digits to appear; if the value being + * converted can be represented in fewer + * digits, it will be expanded with leading + * zeros. The default precision is 1. The + * result of converting 0 with an explicit + * precision of 0 is no characters. + * <dt>x<dd> The int argument is converted to unsigned + * hexadecimal format in the style dddd; the + * letters abcdef are used. The precision + * specifies the minimum numberof digits to + * appear; if the value being converted can be + * represented in fewer digits, it will be + * expanded with leading zeros. The default + * precision is 1. The result of converting 0 + * with an explicit precision of 0 is no + * characters. + * <dt>X<dd> Behaves the same as the x conversion + * character except that letters ABCDEF are + * used instead of abcdef. + * <dt>f<dd> The floating point number argument is + * written in decimal notation in the style + * [-]ddd.ddd, where the number of digits after + * the radix character (shown here as a decimal + * point) is equal to the precision + * specification. A Locale is used to determine + * the radix character to use in this format. + * If the precision is omitted from the + * argument, six digits are written after the + * radix character; if the precision is + * explicitly 0 and the # flag is not specified, + * no radix character appears. If a radix + * character appears, at least 1 digit appears + * before it. The value is rounded to the + * appropriate number of digits. + * <dt>e,E<dd>The floating point number argument is + * written in the style [-]d.ddde{+-}dd + * (the symbols {+-} indicate either a plus or + * minus sign), where there is one digit before + * the radix character (shown here as a decimal + * point) and the number of digits after it is + * equal to the precision. A Locale is used to + * determine the radix character to use in this + * format. When the precision is missing, six + * digits are written after the radix character; + * if the precision is 0 and the # flag is not + * specified, no radix character appears. The + * E conversion will produce a number with E + * instead of e introducing the exponent. The + * exponent always contains at least two digits. + * However, if the value to be written requires + * an exponent greater than two digits, + * additional exponent digits are written as + * necessary. The value is rounded to the + * appropriate number of digits. + * <dt>g,G<dd>The floating point number argument is + * written in style f or e (or in sytle E in the + * case of a G conversion character), with the + * precision specifying the number of + * significant digits. If the precision is + * zero, it is taken as one. The style used + * depends on the value converted: style e + * (or E) will be used only if the exponent + * resulting from the conversion is less than + * -4 or greater than or equal to the precision. + * Trailing zeros are removed from the result. + * A radix character appears only if it is + * followed by a digit. + * <dt>c,C<dd>The integer argument is converted to a + * char and the result is written. + * + * <dt>s,S<dd>The argument is taken to be a string and + * bytes from the string are written until the + * end of the string or the number of bytes + * indicated by the precision specification of + * the argument is reached. If the precision + * is omitted from the argument, it is taken to + * be infinite, so all characters up to the end + * of the string are written. + * <dt>%<dd>Write a % character; no argument is + * converted. + * </dl> + * <p> + * If a conversion specification does not match one of + * the above forms, an IllegalArgumentException is + * thrown and the instance of PrintfFormat is not + * created.</p> + * <p> + * If a floating point value is the internal + * representation for infinity, the output is + * [+]Infinity, where Infinity is either Infinity or + * Inf, depending on the desired output string length. + * Printing of the sign follows the rules described + * above.</p> + * <p> + * If a floating point value is the internal + * representation for "not-a-number," the output is + * [+]NaN. Printing of the sign follows the rules + * described above.</p> + * <p> + * In no case does a non-existent or small field width + * cause truncation of a field; if the result of a + * conversion is wider than the field width, the field + * is simply expanded to contain the conversion result. + * </p> + * <p> + * The behavior is like printf. One exception is that + * the minimum number of exponent digits is 3 instead + * of 2 for e and E formats when the optional L is used + * before the e, E, g, or G conversion character. The + * optional L does not imply conversion to a long long + * double. </p> + * <p> + * The biggest divergence from the C printf + * specification is in the use of 16 bit characters. + * This allows the handling of characters beyond the + * small ASCII character set and allows the utility to + * interoperate correctly with the rest of the Java + * runtime environment.</p> + * <p> + * Omissions from the C printf specification are + * numerous. All the known omissions are present + * because Java never uses bytes to represent + * characters and does not have pointers:</p> + * <ul> + * <li>%c is the same as %C. + * <li>%s is the same as %S. + * <li>u, p, and n conversion characters. + * <li>%ws format. + * <li>h modifier applied to an n conversion character. + * <li>l (ell) modifier applied to the c, n, or s + * conversion characters. + * <li>ll (ell ell) modifier to d, i, o, u, x, or X + * conversion characters. + * <li>ll (ell ell) modifier to an n conversion + * character. + * <li>c, C, d,i,o,u,x, and X conversion characters + * apply to Byte, Character, Short, Integer, Long + * types. + * <li>f, e, E, g, and G conversion characters apply + * to Float and Double types. + * <li>s and S conversion characters apply to String + * types. + * <li>All other reference types can be formatted + * using the s or S conversion characters only. + * </ul> + * <p> + * Most of this specification is quoted from the Unix + * man page for the sprintf utility.</p> + * + * @author Allan Jacobs + * @version 1 + * Release 1: Initial release. + * Release 2: Asterisk field widths and precisions + * %n$ and *m$ + * Bug fixes + * g format fix (2 digits in e form corrupt) + * rounding in f format implemented + * round up when digit not printed is 5 + * formatting of -0.0f + * round up/down when last digits are 50000... + */ +public final class PrintfFormat +{ + /** Vector of control strings and format literals. */ + private Vector vFmt = new Vector(); + + /** Character position. Used by the constructor. */ + private int cPos = 0; + + /** Character position. Used by the constructor. */ + private DecimalFormatSymbols dfs = null; + + /** + * Constructs an array of control specifications + * possibly preceded, separated, or followed by + * ordinary strings. Control strings begin with + * unpaired percent signs. A pair of successive + * percent signs designates a single percent sign in + * the format. + * @param fmtArg Control string. + * @exception IllegalArgumentException if the control + * string is null, zero length, or otherwise + * malformed. + */ + public PrintfFormat(String fmtArg) throws IllegalArgumentException + { + this(Locale.getDefault(), fmtArg); + } + + /** + * Constructs an array of control specifications + * possibly preceded, separated, or followed by + * ordinary strings. Control strings begin with + * unpaired percent signs. A pair of successive + * percent signs designates a single percent sign in + * the format. + * @param fmtArg Control string. + * @exception IllegalArgumentException if the control + * string is null, zero length, or otherwise + * malformed. + */ + public PrintfFormat(Locale locale, String fmtArg) throws IllegalArgumentException + { + dfs = new DecimalFormatSymbols(locale); + + int ePos = 0; + ConversionSpecification sFmt = null; + String unCS = this.nonControl(fmtArg, 0); + + if (unCS != null) + { + sFmt = new ConversionSpecification(); + sFmt.setLiteral(unCS); + vFmt.addElement(sFmt); + } + + while ((cPos != -1) && (cPos < fmtArg.length())) + { + for (ePos = cPos + 1; ePos < fmtArg.length(); ePos++) + { + char c = 0; + + c = fmtArg.charAt(ePos); + + if (c == 'i') + { + break; + } + + if (c == 'd') + { + break; + } + + if (c == 'f') + { + break; + } + + if (c == 'g') + { + break; + } + + if (c == 'G') + { + break; + } + + if (c == 'o') + { + break; + } + + if (c == 'x') + { + break; + } + + if (c == 'X') + { + break; + } + + if (c == 'e') + { + break; + } + + if (c == 'E') + { + break; + } + + if (c == 'c') + { + break; + } + + if (c == 's') + { + break; + } + + if (c == '%') + { + break; + } + } + + ePos = Math.min(ePos + 1, fmtArg.length()); + sFmt = new ConversionSpecification(fmtArg.substring(cPos, ePos)); + vFmt.addElement(sFmt); + unCS = this.nonControl(fmtArg, ePos); + + if (unCS != null) + { + sFmt = new ConversionSpecification(); + sFmt.setLiteral(unCS); + vFmt.addElement(sFmt); + } + } + } + + /** + * Return a substring starting at + * <code>start</code> and ending at either the end + * of the String <code>s</code>, the next unpaired + * percent sign, or at the end of the String if the + * last character is a percent sign. + * @param s Control string. + * @param start Position in the string + * <code>s</code> to begin looking for the start + * of a control string. + * @return the substring from the start position + * to the beginning of the control string. + */ + private String nonControl(String s, int start) + { + String ret = ""; + + cPos = s.indexOf("%", start); + + if (cPos == -1) + { + cPos = s.length(); + } + + return s.substring(start, cPos); + } + + /** + * Format an array of objects. Byte, Short, + * Integer, Long, Float, Double, and Character + * arguments are treated as wrappers for primitive + * types. + * @param o The array of objects to format. + * @return The formatted String. + */ + public String sprintf(Object[] o) + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + int i = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } else + { + if (cs.isPositionalSpecification()) + { + i = cs.getArgumentPosition() - 1; + + if (cs.isPositionalFieldWidth()) + { + int ifw = cs.getArgumentPositionForFieldWidth() - 1; + + cs.setFieldWidthWithArg(((Integer) o[ifw]).intValue()); + } + + if (cs.isPositionalPrecision()) + { + int ipr = cs.getArgumentPositionForPrecision() - 1; + + cs.setPrecisionWithArg(((Integer) o[ipr]).intValue()); + } + } else + { + if (cs.isVariableFieldWidth()) + { + cs.setFieldWidthWithArg(((Integer) o[i]).intValue()); + i++; + } + + if (cs.isVariablePrecision()) + { + cs.setPrecisionWithArg(((Integer) o[i]).intValue()); + i++; + } + } + + if (o[i] instanceof Byte) + { + sb.append(cs.internalsprintf(((Byte) o[i]).byteValue())); + } else if (o[i] instanceof Short) + { + sb.append(cs.internalsprintf(((Short) o[i]).shortValue())); + } else if (o[i] instanceof Integer) + { + sb.append(cs.internalsprintf(((Integer) o[i]).intValue())); + } else if (o[i] instanceof Long) + { + sb.append(cs.internalsprintf(((Long) o[i]).longValue())); + } else if (o[i] instanceof Float) + { + sb.append(cs.internalsprintf(((Float) o[i]).floatValue())); + } else if (o[i] instanceof Double) + { + sb.append(cs.internalsprintf(((Double) o[i]).doubleValue())); + } else if (o[i] instanceof Character) + { + sb.append(cs.internalsprintf(((Character) o[i]).charValue())); + } else if (o[i] instanceof String) + { + sb.append(cs.internalsprintf((String) o[i])); + } else + { + sb.append(cs.internalsprintf(o[i])); + } + + if (!cs.isPositionalSpecification()) + { + i++; + } + } + } + + return sb.toString(); + } + + /** + * Format nothing. Just use the control string. + * @return the formatted String. + */ + public String sprintf() + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } + } + + return sb.toString(); + } + + /** + * Format an int. + * @param x The int to format. + * @return The formatted String. + * @exception IllegalArgumentException if the + * conversion character is f, e, E, g, G, s, + * or S. + */ + public String sprintf(int x) throws IllegalArgumentException + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } else + { + sb.append(cs.internalsprintf(x)); + } + } + + return sb.toString(); + } + + /** + * Format an long. + * @param x The long to format. + * @return The formatted String. + * @exception IllegalArgumentException if the + * conversion character is f, e, E, g, G, s, + * or S. + */ + public String sprintf(long x) throws IllegalArgumentException + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } else + { + sb.append(cs.internalsprintf(x)); + } + } + + return sb.toString(); + } + + /** + * Format a double. + * @param x The double to format. + * @return The formatted String. + * @exception IllegalArgumentException if the + * conversion character is c, C, s, S, + * d, d, x, X, or o. + */ + public String sprintf(double x) throws IllegalArgumentException + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } else + { + sb.append(cs.internalsprintf(x)); + } + } + + return sb.toString(); + } + + /** + * Format a String. + * @param x The String to format. + * @return The formatted String. + * @exception IllegalArgumentException if the + * conversion character is neither s nor S. + */ + public String sprintf(String x) throws IllegalArgumentException + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } else + { + sb.append(cs.internalsprintf(x)); + } + } + + return sb.toString(); + } + + /** + * Format an Object. Convert wrapper types to + * their primitive equivalents and call the + * appropriate internal formatting method. Convert + * Strings using an internal formatting method for + * Strings. Otherwise use the default formatter + * (use toString). + * @param x the Object to format. + * @return the formatted String. + * @exception IllegalArgumentException if the + * conversion character is inappropriate for + * formatting an unwrapped value. + */ + public String sprintf(Object x) throws IllegalArgumentException + { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb = new StringBuffer(); + + while (e.hasMoreElements()) + { + cs = (ConversionSpecification) e.nextElement(); + c = cs.getConversionCharacter(); + + if (c == '\0') + { + sb.append(cs.getLiteral()); + } else if (c == '%') + { + sb.append("%"); + } else + { + if (x instanceof Byte) + { + sb.append(cs.internalsprintf(((Byte) x).byteValue())); + } else if (x instanceof Short) + { + sb.append(cs.internalsprintf(((Short) x).shortValue())); + } else if (x instanceof Integer) + { + sb.append(cs.internalsprintf(((Integer) x).intValue())); + } else if (x instanceof Long) + { + sb.append(cs.internalsprintf(((Long) x).longValue())); + } else if (x instanceof Float) + { + sb.append(cs.internalsprintf(((Float) x).floatValue())); + } else if (x instanceof Double) + { + sb.append(cs.internalsprintf(((Double) x).doubleValue())); + } else if (x instanceof Character) + { + sb.append(cs.internalsprintf(((Character) x).charValue())); + } else if (x instanceof String) + { + sb.append(cs.internalsprintf((String) x)); + } else + { + sb.append(cs.internalsprintf(x)); + } + } + } + + return sb.toString(); + } + + /** + * <p> + * ConversionSpecification allows the formatting of + * a single primitive or object embedded within a + * string. The formatting is controlled by a + * format string. Only one Java primitive or + * object can be formatted at a time. + * <p> + * A format string is a Java string that contains + * a control string. The control string starts at + * the first percent sign (%) in the string, + * provided that this percent sign + * <ol> + * <li>is not escaped protected by a matching % or + * is not an escape % character, + * <li>is not at the end of the format string, and + * <li>precedes a sequence of characters that parses + * as a valid control string. + * </ol> + * <p> + * A control string takes the form: + * <pre> % ['-+ #0]* [0..9]* { . [0..9]* }+ + * { [hlL] }+ [idfgGoxXeEcs] + * </pre> + * <p> + * The behavior is like printf. One (hopefully the + * only) exception is that the minimum number of + * exponent digits is 3 instead of 2 for e and E + * formats when the optional L is used before the + * e, E, g, or G conversion character. The + * optional L does not imply conversion to a long + * long double. + */ + private class ConversionSpecification + { + /** Default precision. */ + private final static int defaultDigits = 6; + + /** + * The integer portion of the result of a decimal + * conversion (i, d, u, f, g, or G) will be + * formatted with thousands' grouping characters. + * For other conversions the flag is ignored. + */ + private boolean thousands = false; + + /** + * The result of the conversion will be + * left-justified within the field. + */ + private boolean leftJustify = false; + + /** + * The result of a signed conversion will always + * begin with a sign (+ or -). + */ + private boolean leadingSign = false; + + /** + * Flag indicating that left padding with spaces is + * specified. + */ + private boolean leadingSpace = false; + + /** + * For an o conversion, increase the precision to + * force the first digit of the result to be a + * zero. For x (or X) conversions, a non-zero + * result will have 0x (or 0X) prepended to it. + * For e, E, f, g, or G conversions, the result + * will always contain a radix character, even if + * no digits follow the point. For g and G + * conversions, trailing zeros will not be removed + * from the result. + */ + private boolean alternateForm = false; + + /** + * Flag indicating that left padding with zeroes is + * specified. + */ + private boolean leadingZeros = false; + + /** + * Flag indicating that the field width is *. + */ + private boolean variableFieldWidth = false; + + /** + * If the converted value has fewer bytes than the + * field width, it will be padded with spaces or + * zeroes. + */ + private int fieldWidth = 0; + + /** + * Flag indicating whether or not the field width + * has been set. + */ + private boolean fieldWidthSet = false; + + /** + * The minimum number of digits to appear for the + * d, i, o, u, x, or X conversions. The number of + * digits to appear after the radix character for + * the e, E, and f conversions. The maximum number + * of significant digits for the g and G + * conversions. The maximum number of bytes to be + * printed from a string in s and S conversions. + */ + private int precision = 0; + + /** + * Flag indicating that the precision is *. + */ + private boolean variablePrecision = false; + + /** + * Flag indicating whether or not the precision has + * been set. + */ + private boolean precisionSet = false; + + /* + */ + private boolean positionalSpecification = false; + private int argumentPosition = 0; + private boolean positionalFieldWidth = false; + private int argumentPositionForFieldWidth = 0; + private boolean positionalPrecision = false; + private int argumentPositionForPrecision = 0; + + /** + * Flag specifying that a following d, i, o, u, x, + * or X conversion character applies to a type + * short int. + */ + private boolean optionalh = false; + + /** + * Flag specifying that a following d, i, o, u, x, + * or X conversion character applies to a type lont + * int argument. + */ + private boolean optionall = false; + + /** + * Flag specifying that a following e, E, f, g, or + * G conversion character applies to a type double + * argument. This is a noop in Java. + */ + private boolean optionalL = false; + + /** Control string type. */ + private char conversionCharacter = '\0'; + + /** + * Position within the control string. Used by + * the constructor. + */ + private int pos = 0; + + /** Literal or control format string. */ + private String fmt; + + /** + * Constructor. Used to prepare an instance + * to hold a literal, not a control string. + */ + ConversionSpecification() + { + } + + /** + * Constructor for a conversion specification. + * The argument must begin with a % and end + * with the conversion character for the + * conversion specification. + * @param fmtArg String specifying the + * conversion specification. + * @exception IllegalArgumentException if the + * input string is null, zero length, or + * otherwise malformed. + */ + ConversionSpecification(String fmtArg) throws IllegalArgumentException + { + if (fmtArg == null) + { + throw new NullPointerException(); + } + + if (fmtArg.length() == 0) + { + throw new IllegalArgumentException("Control strings must have positive" + " lengths."); + } + + if (fmtArg.charAt(0) == '%') + { + fmt = fmtArg; + pos = 1; + setArgPosition(); + setFlagCharacters(); + setFieldWidth(); + setPrecision(); + setOptionalHL(); + + if (setConversionCharacter()) + { + if (pos == fmtArg.length()) + { + if (leadingZeros && leftJustify) + { + leadingZeros = false; + } + + if (precisionSet && leadingZeros) + { + if ((conversionCharacter == 'd') || (conversionCharacter == 'i') || (conversionCharacter == 'o') + || (conversionCharacter == 'x')) + { + leadingZeros = false; + } + } + } else + { + throw new IllegalArgumentException("Malformed conversion specification=" + fmtArg); + } + } else + { + throw new IllegalArgumentException("Malformed conversion specification=" + fmtArg); + } + } else + { + throw new IllegalArgumentException("Control strings must begin with %."); + } + } + + /** + * Set the String for this instance. + * @param s the String to store. + */ + void setLiteral(String s) + { + fmt = s; + } + + /** + * Get the String for this instance. Translate + * any escape sequences. + * + * @return s the stored String. + */ + String getLiteral() + { + StringBuffer sb = new StringBuffer(); + int i = 0; + + while (i < fmt.length()) + { + if (fmt.charAt(i) == '\\') + { + i++; + + if (i < fmt.length()) + { + char c = fmt.charAt(i); + + switch (c) + { + case 'a' : + sb.append((char) 0x07); + + break; + + case 'b' : + sb.append('\b'); + + break; + + case 'f' : + sb.append('\f'); + + break; + + case 'n' : + sb.append(System.getProperty("line.separator")); + + break; + + case 'r' : + sb.append('\r'); + + break; + + case 't' : + sb.append('\t'); + + break; + + case 'v' : + sb.append((char) 0x0b); + + break; + + case '\\' : + sb.append('\\'); + + break; + } + + i++; + } else + { + sb.append('\\'); + } + } else + { + i++; + } + } + + return fmt; + } + + /** + * Get the conversion character that tells what + * type of control character this instance has. + * + * @return the conversion character. + */ + char getConversionCharacter() + { + return conversionCharacter; + } + + /** + * Check whether the specifier has a variable + * field width that is going to be set by an + * argument. + * @return <code>true</code> if the conversion + * uses an * field width; otherwise + * <code>false</code>. + */ + boolean isVariableFieldWidth() + { + return variableFieldWidth; + } + + /** + * Set the field width with an argument. A + * negative field width is taken as a - flag + * followed by a positive field width. + * @param fw the field width. + */ + void setFieldWidthWithArg(int fw) + { + if (fw < 0) + { + leftJustify = true; + } + + fieldWidthSet = true; + fieldWidth = Math.abs(fw); + } + + /** + * Check whether the specifier has a variable + * precision that is going to be set by an + * argument. + * @return <code>true</code> if the conversion + * uses an * precision; otherwise + * <code>false</code>. + */ + boolean isVariablePrecision() + { + return variablePrecision; + } + + /** + * Set the precision with an argument. A + * negative precision will be changed to zero. + * @param pr the precision. + */ + void setPrecisionWithArg(int pr) + { + precisionSet = true; + precision = Math.max(pr, 0); + } + + /** + * Format an int argument using this conversion + * specification. + * @param s the int to format. + * @return the formatted String. + * @exception IllegalArgumentException if the + * conversion character is f, e, E, g, or G. + */ + String internalsprintf(int s) throws IllegalArgumentException + { + String s2 = ""; + + switch (conversionCharacter) + { + case 'd' : + case 'i' : + if (optionalh) + { + s2 = printDFormat((short) s); + } else if (optionall) + { + s2 = printDFormat((long) s); + } else + { + s2 = printDFormat(s); + } + + break; + + case 'x' : + case 'X' : + if (optionalh) + { + s2 = printXFormat((short) s); + } else if (optionall) + { + s2 = printXFormat((long) s); + } else + { + s2 = printXFormat(s); + } + + break; + + case 'o' : + if (optionalh) + { + s2 = printOFormat((short) s); + } else if (optionall) + { + s2 = printOFormat((long) s); + } else + { + s2 = printOFormat(s); + } + + break; + + case 'c' : + case 'C' : + s2 = printCFormat((char) s); + + break; + + default : + throw new IllegalArgumentException("Cannot format a int with a format using a " + conversionCharacter + + " conversion character."); + } + + return s2; + } + + /** + * Format a long argument using this conversion + * specification. + * @param s the long to format. + * @return the formatted String. + * @exception IllegalArgumentException if the + * conversion character is f, e, E, g, or G. + */ + String internalsprintf(long s) throws IllegalArgumentException + { + String s2 = ""; + + switch (conversionCharacter) + { + case 'd' : + case 'i' : + if (optionalh) + { + s2 = printDFormat((short) s); + } else if (optionall) + { + s2 = printDFormat(s); + } else + { + s2 = printDFormat((int) s); + } + + break; + + case 'x' : + case 'X' : + if (optionalh) + { + s2 = printXFormat((short) s); + } else if (optionall) + { + s2 = printXFormat(s); + } else + { + s2 = printXFormat((int) s); + } + + break; + + case 'o' : + if (optionalh) + { + s2 = printOFormat((short) s); + } else if (optionall) + { + s2 = printOFormat(s); + } else + { + s2 = printOFormat((int) s); + } + + break; + + case 'c' : + case 'C' : + s2 = printCFormat((char) s); + + break; + + default : + throw new IllegalArgumentException("Cannot format a long with a format using a " + conversionCharacter + + " conversion character."); + } + + return s2; + } + + /** + * Format a double argument using this conversion + * specification. + * @param s the double to format. + * @return the formatted String. + * @exception IllegalArgumentException if the + * conversion character is c, C, s, S, i, d, + * x, X, or o. + */ + String internalsprintf(double s) throws IllegalArgumentException + { + String s2 = ""; + + switch (conversionCharacter) + { + case 'f' : + s2 = printFFormat(s); + + break; + + case 'E' : + case 'e' : + s2 = printEFormat(s); + + break; + + case 'G' : + case 'g' : + s2 = printGFormat(s); + + break; + + default : + throw new IllegalArgumentException("Cannot " + "format a double with a format using a " + conversionCharacter + + " conversion character."); + } + + return s2; + } + + /** + * Format a String argument using this conversion + * specification. + * @param s the String to format. + * @return the formatted String. + * @exception IllegalArgumentException if the + * conversion character is neither s nor S. + */ + String internalsprintf(String s) throws IllegalArgumentException + { + String s2 = ""; + + if ((conversionCharacter == 's') || (conversionCharacter == 'S')) + { + s2 = printSFormat(s); + } else + { + throw new IllegalArgumentException("Cannot " + "format a String with a format using a " + conversionCharacter + + " conversion character."); + } + + return s2; + } + + /** + * Format an Object argument using this conversion + * specification. + * @param s the Object to format. + * @return the formatted String. + * @exception IllegalArgumentException if the + * conversion character is neither s nor S. + */ + String internalsprintf(Object s) + { + String s2 = ""; + + if ((conversionCharacter == 's') || (conversionCharacter == 'S')) + { + s2 = printSFormat(s.toString()); + } else + { + throw new IllegalArgumentException("Cannot format a String with a format using" + " a " + conversionCharacter + + " conversion character."); + } + + return s2; + } + + /** + * For f format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both + * a '+' and a ' ' are specified, the blank flag + * is ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * + * The precision, if set, is the number of digits + * to appear after the radix character. Padding is + * with trailing 0s. + */ + private char[] fFormatDigits(double x) + { + // int defaultDigits=6; + String sx, sxOut; + int i, j, k; + int n1In, n2In; + int expon = 0; + boolean minusSign = false; + + if (x > 0.0) + { + sx = Double.toString(x); + } else if (x < 0.0) + { + sx = Double.toString(-x); + minusSign = true; + } else + { + sx = Double.toString(x); + + if (sx.charAt(0) == '-') + { + minusSign = true; + sx = sx.substring(1); + } + } + + int ePos = sx.indexOf('E'); + int rPos = sx.indexOf('.'); + + if (rPos != -1) + { + n1In = rPos; + } else if (ePos != -1) + { + n1In = ePos; + } else + { + n1In = sx.length(); + } + + if (rPos != -1) + { + if (ePos != -1) + { + n2In = ePos - rPos - 1; + } else + { + n2In = sx.length() - rPos - 1; + } + } else + { + n2In = 0; + } + + if (ePos != -1) + { + int ie = ePos + 1; + + expon = 0; + + if (sx.charAt(ie) == '-') + { + for (++ie; ie < sx.length(); ie++) + { + if (sx.charAt(ie) != '0') + { + break; + } + } + + if (ie < sx.length()) + { + expon = -Integer.parseInt(sx.substring(ie)); + } + } else + { + if (sx.charAt(ie) == '+') + { + ++ie; + } + + for (; ie < sx.length(); ie++) + { + if (sx.charAt(ie) != '0') + { + break; + } + } + + if (ie < sx.length()) + { + expon = Integer.parseInt(sx.substring(ie)); + } + } + } + + int p; + + if (precisionSet) + { + p = precision; + } else + { + p = defaultDigits - 1; + } + + char[] ca1 = sx.toCharArray(); + char[] ca2 = new char[n1In + n2In]; + char[] ca3, ca4, ca5; + + for (j = 0; j < n1In; j++) + { + ca2[j] = ca1[j]; + } + + i = j + 1; + + for (k = 0; k < n2In; j++, i++, k++) + { + ca2[j] = ca1[i]; + } + + if (n1In + expon <= 0) + { + ca3 = new char[-expon + n2In]; + + for (j = 0, k = 0; k < (-n1In - expon); k++, j++) + { + ca3[j] = '0'; + } + + for (i = 0; i < (n1In + n2In); i++, j++) + { + ca3[j] = ca2[i]; + } + } else + { + ca3 = ca2; + } + + boolean carry = false; + + if (p < -expon + n2In) + { + if (expon < 0) + { + i = p; + } else + { + i = p + n1In; + } + + carry = checkForCarry(ca3, i); + + if (carry) + { + carry = startSymbolicCarry(ca3, i - 1, 0); + } + } + + if (n1In + expon <= 0) + { + ca4 = new char[2 + p]; + + if (!carry) + { + ca4[0] = '0'; + } else + { + ca4[0] = '1'; + } + + if (alternateForm ||!precisionSet || (precision != 0)) + { + ca4[1] = '.'; + + for (i = 0, j = 2; i < Math.min(p, ca3.length); i++, j++) + { + ca4[j] = ca3[i]; + } + + for (; j < ca4.length; j++) + { + ca4[j] = '0'; + } + } + } else + { + if (!carry) + { + if (alternateForm ||!precisionSet || (precision != 0)) + { + ca4 = new char[n1In + expon + p + 1]; + } else + { + ca4 = new char[n1In + expon]; + } + + j = 0; + } else + { + if (alternateForm ||!precisionSet || (precision != 0)) + { + ca4 = new char[n1In + expon + p + 2]; + } else + { + ca4 = new char[n1In + expon + 1]; + } + + ca4[0] = '1'; + j = 1; + } + + for (i = 0; i < Math.min(n1In + expon, ca3.length); i++, j++) + { + ca4[j] = ca3[i]; + } + + for (; i < n1In + expon; i++, j++) + { + ca4[j] = '0'; + } + + if (alternateForm ||!precisionSet || (precision != 0)) + { + ca4[j] = '.'; + j++; + + for (k = 0; (i < ca3.length) && (k < p); i++, j++, k++) + { + ca4[j] = ca3[i]; + } + + for (; j < ca4.length; j++) + { + ca4[j] = '0'; + } + } + } + + int nZeros = 0; + + if (!leftJustify && leadingZeros) + { + int xThousands = 0; + + if (thousands) + { + int xlead = 0; + + if ((ca4[0] == '+') || (ca4[0] == '-') || (ca4[0] == ' ')) + { + xlead = 1; + } + + int xdp = xlead; + + for (; xdp < ca4.length; xdp++) + { + if (ca4[xdp] == '.') + { + break; + } + } + + xThousands = (xdp - xlead) / 3; + } + + if (fieldWidthSet) + { + nZeros = fieldWidth - ca4.length; + } + + if ((!minusSign && (leadingSign || leadingSpace)) || minusSign) + { + nZeros--; + } + + nZeros -= xThousands; + + if (nZeros < 0) + { + nZeros = 0; + } + } + + j = 0; + + if ((!minusSign && (leadingSign || leadingSpace)) || minusSign) + { + ca5 = new char[ca4.length + nZeros + 1]; + j++; + } else + { + ca5 = new char[ca4.length + nZeros]; + } + + if (!minusSign) + { + if (leadingSign) + { + ca5[0] = '+'; + } + + if (leadingSpace) + { + ca5[0] = ' '; + } + } else + { + ca5[0] = '-'; + } + + for (i = 0; i < nZeros; i++, j++) + { + ca5[j] = '0'; + } + + for (i = 0; i < ca4.length; i++, j++) + { + ca5[j] = ca4[i]; + } + + int lead = 0; + + if ((ca5[0] == '+') || (ca5[0] == '-') || (ca5[0] == ' ')) + { + lead = 1; + } + + int dp = lead; + + for (; dp < ca5.length; dp++) + { + if (ca5[dp] == '.') + { + break; + } + } + + int nThousands = (dp - lead) / 3; + + // Localize the decimal point. + if (dp < ca5.length) + { + ca5[dp] = dfs.getDecimalSeparator(); + } + + char[] ca6 = ca5; + + if (thousands && (nThousands > 0)) + { + ca6 = new char[ca5.length + nThousands + lead]; + ca6[0] = ca5[0]; + + for (i = lead, k = lead; i < dp; i++) + { + if ((i > 0) && (dp - i) % 3 == 0) + { + // ca6[k]=','; + ca6[k] = dfs.getGroupingSeparator(); + ca6[k + 1] = ca5[i]; + k += 2; + } else + { + ca6[k] = ca5[i]; + k++; + } + } + + for (; i < ca5.length; i++, k++) + { + ca6[k] = ca5[i]; + } + } + + return ca6; + } + + /** + * An intermediate routine on the way to creating + * an f format String. The method decides whether + * the input double value is an infinity, + * not-a-number, or a finite double and formats + * each type of input appropriately. + * @param x the double value to be formatted. + * @return the converted double value. + */ + private String fFormatString(double x) + { + boolean noDigits = false; + char[] ca6, ca7; + + if (Double.isInfinite(x)) + { + if (x == Double.POSITIVE_INFINITY) + { + if (leadingSign) + { + ca6 = "+Inf".toCharArray(); + } else if (leadingSpace) + { + ca6 = " Inf".toCharArray(); + } else + { + ca6 = "Inf".toCharArray(); + } + } else + { + ca6 = "-Inf".toCharArray(); + } + + noDigits = true; + } else if (Double.isNaN(x)) + { + if (leadingSign) + { + ca6 = "+NaN".toCharArray(); + } else if (leadingSpace) + { + ca6 = " NaN".toCharArray(); + } else + { + ca6 = "NaN".toCharArray(); + } + + noDigits = true; + } else + { + ca6 = fFormatDigits(x); + } + + ca7 = applyFloatPadding(ca6, false); + + return new String(ca7); + } + + /** + * For e format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both a + * '+' and a ' ' are specified, the blank flag is + * ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * + * The precision, if set, is the minimum number of + * digits to appear after the radix character. + * Padding is with trailing 0s. + * + * The behavior is like printf. One (hopefully the + * only) exception is that the minimum number of + * exponent digits is 3 instead of 2 for e and E + * formats when the optional L is used before the + * e, E, g, or G conversion character. The optional + * L does not imply conversion to a long long + * double. + */ + private char[] eFormatDigits(double x, char eChar) + { + char[] ca1, ca2, ca3; + + // int defaultDigits=6; + String sx, sxOut; + int i, j, k, p; + int n1In, n2In; + int expon = 0; + int ePos, rPos, eSize; + boolean minusSign = false; + + if (x > 0.0) + { + sx = Double.toString(x); + } else if (x < 0.0) + { + sx = Double.toString(-x); + minusSign = true; + } else + { + sx = Double.toString(x); + + if (sx.charAt(0) == '-') + { + minusSign = true; + sx = sx.substring(1); + } + } + + ePos = sx.indexOf('E'); + + if (ePos == -1) + { + ePos = sx.indexOf('e'); + } + + rPos = sx.indexOf('.'); + + if (rPos != -1) + { + n1In = rPos; + } else if (ePos != -1) + { + n1In = ePos; + } else + { + n1In = sx.length(); + } + + if (rPos != -1) + { + if (ePos != -1) + { + n2In = ePos - rPos - 1; + } else + { + n2In = sx.length() - rPos - 1; + } + } else + { + n2In = 0; + } + + if (ePos != -1) + { + int ie = ePos + 1; + + expon = 0; + + if (sx.charAt(ie) == '-') + { + for (++ie; ie < sx.length(); ie++) + { + if (sx.charAt(ie) != '0') + { + break; + } + } + + if (ie < sx.length()) + { + expon = -Integer.parseInt(sx.substring(ie)); + } + } else + { + if (sx.charAt(ie) == '+') + { + ++ie; + } + + for (; ie < sx.length(); ie++) + { + if (sx.charAt(ie) != '0') + { + break; + } + } + + if (ie < sx.length()) + { + expon = Integer.parseInt(sx.substring(ie)); + } + } + } + + if (rPos != -1) + { + expon += rPos - 1; + } + + if (precisionSet) + { + p = precision; + } else + { + p = defaultDigits - 1; + } + + if ((rPos != -1) && (ePos != -1)) + { + ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1, ePos)).toCharArray(); + } else if (rPos != -1) + { + ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1)).toCharArray(); + } else if (ePos != -1) + { + ca1 = sx.substring(0, ePos).toCharArray(); + } else + { + ca1 = sx.toCharArray(); + } + + boolean carry = false; + int i0 = 0; + + if (ca1[0] != '0') + { + i0 = 0; + } else + { + for (i0 = 0; i0 < ca1.length; i0++) + { + if (ca1[i0] != '0') + { + break; + } + } + } + + if (i0 + p < ca1.length - 1) + { + carry = checkForCarry(ca1, i0 + p + 1); + + if (carry) + { + carry = startSymbolicCarry(ca1, i0 + p, i0); + } + + if (carry) + { + ca2 = new char[i0 + p + 1]; + ca2[i0] = '1'; + + for (j = 0; j < i0; j++) + { + ca2[j] = '0'; + } + + for (i = i0, j = i0 + 1; j < p + 1; i++, j++) + { + ca2[j] = ca1[i]; + } + + expon++; + ca1 = ca2; + } + } + + if ((Math.abs(expon) < 100) &&!optionalL) + { + eSize = 4; + } else + { + eSize = 5; + } + + if (alternateForm ||!precisionSet || (precision != 0)) + { + ca2 = new char[2 + p + eSize]; + } else + { + ca2 = new char[1 + eSize]; + } + + if (ca1[0] != '0') + { + ca2[0] = ca1[0]; + j = 1; + } else + { + for (j = 1; j < ((ePos == -1) + ? ca1.length + : ePos); j++) + { + if (ca1[j] != '0') + { + break; + } + } + + if (((ePos != -1) && (j < ePos)) || ((ePos == -1) && (j < ca1.length))) + { + ca2[0] = ca1[j]; + expon -= j; + j++; + } else + { + ca2[0] = '0'; + j = 2; + } + } + + if (alternateForm ||!precisionSet || (precision != 0)) + { + ca2[1] = '.'; + i = 2; + } else + { + i = 1; + } + + for (k = 0; (k < p) && (j < ca1.length); j++, i++, k++) + { + ca2[i] = ca1[j]; + } + + for (; i < ca2.length - eSize; i++) + { + ca2[i] = '0'; + } + + ca2[i++] = eChar; + + if (expon < 0) + { + ca2[i++] = '-'; + } else + { + ca2[i++] = '+'; + } + + expon = Math.abs(expon); + + if (expon >= 100) + { + switch (expon / 100) + { + case 1 : + ca2[i] = '1'; + + break; + + case 2 : + ca2[i] = '2'; + + break; + + case 3 : + ca2[i] = '3'; + + break; + + case 4 : + ca2[i] = '4'; + + break; + + case 5 : + ca2[i] = '5'; + + break; + + case 6 : + ca2[i] = '6'; + + break; + + case 7 : + ca2[i] = '7'; + + break; + + case 8 : + ca2[i] = '8'; + + break; + + case 9 : + ca2[i] = '9'; + + break; + } + + i++; + } + + switch ((expon % 100) / 10) + { + case 0 : + ca2[i] = '0'; + + break; + + case 1 : + ca2[i] = '1'; + + break; + + case 2 : + ca2[i] = '2'; + + break; + + case 3 : + ca2[i] = '3'; + + break; + + case 4 : + ca2[i] = '4'; + + break; + + case 5 : + ca2[i] = '5'; + + break; + + case 6 : + ca2[i] = '6'; + + break; + + case 7 : + ca2[i] = '7'; + + break; + + case 8 : + ca2[i] = '8'; + + break; + + case 9 : + ca2[i] = '9'; + + break; + } + + i++; + + switch (expon % 10) + { + case 0 : + ca2[i] = '0'; + + break; + + case 1 : + ca2[i] = '1'; + + break; + + case 2 : + ca2[i] = '2'; + + break; + + case 3 : + ca2[i] = '3'; + + break; + + case 4 : + ca2[i] = '4'; + + break; + + case 5 : + ca2[i] = '5'; + + break; + + case 6 : + ca2[i] = '6'; + + break; + + case 7 : + ca2[i] = '7'; + + break; + + case 8 : + ca2[i] = '8'; + + break; + + case 9 : + ca2[i] = '9'; + + break; + } + + int nZeros = 0; + + if (!leftJustify && leadingZeros) + { + int xThousands = 0; + + if (thousands) + { + int xlead = 0; + + if ((ca2[0] == '+') || (ca2[0] == '-') || (ca2[0] == ' ')) + { + xlead = 1; + } + + int xdp = xlead; + + for (; xdp < ca2.length; xdp++) + { + if (ca2[xdp] == '.') + { + break; + } + } + + xThousands = (xdp - xlead) / 3; + } + + if (fieldWidthSet) + { + nZeros = fieldWidth - ca2.length; + } + + if ((!minusSign && (leadingSign || leadingSpace)) || minusSign) + { + nZeros--; + } + + nZeros -= xThousands; + + if (nZeros < 0) + { + nZeros = 0; + } + } + + j = 0; + + if ((!minusSign && (leadingSign || leadingSpace)) || minusSign) + { + ca3 = new char[ca2.length + nZeros + 1]; + j++; + } else + { + ca3 = new char[ca2.length + nZeros]; + } + + if (!minusSign) + { + if (leadingSign) + { + ca3[0] = '+'; + } + + if (leadingSpace) + { + ca3[0] = ' '; + } + } else + { + ca3[0] = '-'; + } + + for (k = 0; k < nZeros; j++, k++) + { + ca3[j] = '0'; + } + + for (i = 0; (i < ca2.length) && (j < ca3.length); i++, j++) + { + ca3[j] = ca2[i]; + } + + int lead = 0; + + if ((ca3[0] == '+') || (ca3[0] == '-') || (ca3[0] == ' ')) + { + lead = 1; + } + + int dp = lead; + + for (; dp < ca3.length; dp++) + { + if (ca3[dp] == '.') + { + break; + } + } + + int nThousands = dp / 3; + + // Localize the decimal point. + if (dp < ca3.length) + { + ca3[dp] = dfs.getDecimalSeparator(); + } + + char[] ca4 = ca3; + + if (thousands && (nThousands > 0)) + { + ca4 = new char[ca3.length + nThousands + lead]; + ca4[0] = ca3[0]; + + for (i = lead, k = lead; i < dp; i++) + { + if ((i > 0) && (dp - i) % 3 == 0) + { + // ca4[k]=','; + ca4[k] = dfs.getGroupingSeparator(); + ca4[k + 1] = ca3[i]; + k += 2; + } else + { + ca4[k] = ca3[i]; + k++; + } + } + + for (; i < ca3.length; i++, k++) + { + ca4[k] = ca3[i]; + } + } + + return ca4; + } + + /** + * Check to see if the digits that are going to + * be truncated because of the precision should + * force a round in the preceding digits. + * @param ca1 the array of digits + * @param icarry the index of the first digit that + * is to be truncated from the print + * @return <code>true</code> if the truncation forces + * a round that will change the print + */ + private boolean checkForCarry(char[] ca1, int icarry) + { + boolean carry = false; + + if (icarry < ca1.length) + { + if ((ca1[icarry] == '6') || (ca1[icarry] == '7') || (ca1[icarry] == '8') || (ca1[icarry] == '9')) + { + carry = true; + } else if (ca1[icarry] == '5') + { + int ii = icarry + 1; + + for (; ii < ca1.length; ii++) + { + if (ca1[ii] != '0') + { + break; + } + } + + carry = ii < ca1.length; + + if (!carry && (icarry > 0)) + { + carry = ((ca1[icarry - 1] == '1') || (ca1[icarry - 1] == '3') || (ca1[icarry - 1] == '5') + || (ca1[icarry - 1] == '7') || (ca1[icarry - 1] == '9')); + } + } + } + + return carry; + } + + /** + * Start the symbolic carry process. The process + * is not quite finished because the symbolic + * carry may change the length of the string and + * change the exponent (in e format). + * @param cLast index of the last digit changed + * by the round + * @param cFirst index of the first digit allowed + * to be changed by this phase of the round + * @return <code>true</code> if the carry forces + * a round that will change the print still + * more + */ + private boolean startSymbolicCarry(char[] ca, int cLast, int cFirst) + { + boolean carry = true; + + for (int i = cLast; carry && (i >= cFirst); i--) + { + carry = false; + + switch (ca[i]) + { + case '0' : + ca[i] = '1'; + + break; + + case '1' : + ca[i] = '2'; + + break; + + case '2' : + ca[i] = '3'; + + break; + + case '3' : + ca[i] = '4'; + + break; + + case '4' : + ca[i] = '5'; + + break; + + case '5' : + ca[i] = '6'; + + break; + + case '6' : + ca[i] = '7'; + + break; + + case '7' : + ca[i] = '8'; + + break; + + case '8' : + ca[i] = '9'; + + break; + + case '9' : + ca[i] = '0'; + carry = true; + + break; + } + } + + return carry; + } + + /** + * An intermediate routine on the way to creating + * an e format String. The method decides whether + * the input double value is an infinity, + * not-a-number, or a finite double and formats + * each type of input appropriately. + * @param x the double value to be formatted. + * @param eChar an 'e' or 'E' to use in the + * converted double value. + * @return the converted double value. + */ + private String eFormatString(double x, char eChar) + { + boolean noDigits = false; + char[] ca4, ca5; + + if (Double.isInfinite(x)) + { + if (x == Double.POSITIVE_INFINITY) + { + if (leadingSign) + { + ca4 = "+Inf".toCharArray(); + } else if (leadingSpace) + { + ca4 = " Inf".toCharArray(); + } else + { + ca4 = "Inf".toCharArray(); + } + } else + { + ca4 = "-Inf".toCharArray(); + } + + noDigits = true; + } else if (Double.isNaN(x)) + { + if (leadingSign) + { + ca4 = "+NaN".toCharArray(); + } else if (leadingSpace) + { + ca4 = " NaN".toCharArray(); + } else + { + ca4 = "NaN".toCharArray(); + } + + noDigits = true; + } else + { + ca4 = eFormatDigits(x, eChar); + } + + ca5 = applyFloatPadding(ca4, false); + + return new String(ca5); + } + + /** + * Apply zero or blank, left or right padding. + * @param ca4 array of characters before padding is + * finished + * @param noDigits NaN or signed Inf + * @return a padded array of characters + */ + private char[] applyFloatPadding(char[] ca4, boolean noDigits) + { + char[] ca5 = ca4; + + if (fieldWidthSet) + { + int i, j, nBlanks; + + if (leftJustify) + { + nBlanks = fieldWidth - ca4.length; + + if (nBlanks > 0) + { + ca5 = new char[ca4.length + nBlanks]; + + for (i = 0; i < ca4.length; i++) + { + ca5[i] = ca4[i]; + } + + for (j = 0; j < nBlanks; j++, i++) + { + ca5[i] = ' '; + } + } + } else if (!leadingZeros || noDigits) + { + nBlanks = fieldWidth - ca4.length; + + if (nBlanks > 0) + { + ca5 = new char[ca4.length + nBlanks]; + + for (i = 0; i < nBlanks; i++) + { + ca5[i] = ' '; + } + + for (j = 0; j < ca4.length; i++, j++) + { + ca5[i] = ca4[j]; + } + } + } else if (leadingZeros) + { + nBlanks = fieldWidth - ca4.length; + + if (nBlanks > 0) + { + ca5 = new char[ca4.length + nBlanks]; + i = 0; + j = 0; + + if (ca4[0] == '-') + { + ca5[0] = '-'; + i++; + j++; + } + + for (int k = 0; k < nBlanks; i++, k++) + { + ca5[i] = '0'; + } + + for (; j < ca4.length; i++, j++) + { + ca5[i] = ca4[j]; + } + } + } + } + + return ca5; + } + + /** + * Format method for the f conversion character. + * @param x the double to format. + * @return the formatted String. + */ + private String printFFormat(double x) + { + return fFormatString(x); + } + + /** + * Format method for the e or E conversion + * character. + * @param x the double to format. + * @return the formatted String. + */ + private String printEFormat(double x) + { + if (conversionCharacter == 'e') + { + return eFormatString(x, 'e'); + } else + { + return eFormatString(x, 'E'); + } + } + + /** + * Format method for the g conversion character. + * + * For g format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both a + * '+' and a ' ' are specified, the blank flag is + * ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * + * The precision, if set, is the minimum number of + * digits to appear after the radix character. + * Padding is with trailing 0s. + * @param x the double to format. + * @return the formatted String. + */ + private String printGFormat(double x) + { + String sx, sy, sz, ret; + int savePrecision = precision; + int i; + char[] ca4, ca5; + boolean noDigits = false; + + if (Double.isInfinite(x)) + { + if (x == Double.POSITIVE_INFINITY) + { + if (leadingSign) + { + ca4 = "+Inf".toCharArray(); + } else if (leadingSpace) + { + ca4 = " Inf".toCharArray(); + } else + { + ca4 = "Inf".toCharArray(); + } + } else + { + ca4 = "-Inf".toCharArray(); + } + + noDigits = true; + } else if (Double.isNaN(x)) + { + if (leadingSign) + { + ca4 = "+NaN".toCharArray(); + } else if (leadingSpace) + { + ca4 = " NaN".toCharArray(); + } else + { + ca4 = "NaN".toCharArray(); + } + + noDigits = true; + } else + { + if (!precisionSet) + { + precision = defaultDigits; + } + + if (precision == 0) + { + precision = 1; + } + + int ePos = -1; + + if (conversionCharacter == 'g') + { + sx = eFormatString(x, 'e').trim(); + ePos = sx.indexOf('e'); + } else + { + sx = eFormatString(x, 'E').trim(); + ePos = sx.indexOf('E'); + } + + i = ePos + 1; + + int expon = 0; + + if (sx.charAt(i) == '-') + { + for (++i; i < sx.length(); i++) + { + if (sx.charAt(i) != '0') + { + break; + } + } + + if (i < sx.length()) + { + expon = -Integer.parseInt(sx.substring(i)); + } + } else + { + if (sx.charAt(i) == '+') + { + ++i; + } + + for (; i < sx.length(); i++) + { + if (sx.charAt(i) != '0') + { + break; + } + } + + if (i < sx.length()) + { + expon = Integer.parseInt(sx.substring(i)); + } + } + + // Trim trailing zeros. + // If the radix character is not followed by + // a digit, trim it, too. + if (!alternateForm) + { + if ((expon >= -4) && (expon < precision)) + { + sy = fFormatString(x).trim(); + } else + { + sy = sx.substring(0, ePos); + } + + i = sy.length() - 1; + + for (; i >= 0; i--) + { + if (sy.charAt(i) != '0') + { + break; + } + } + + if ((i >= 0) && (sy.charAt(i) == '.')) + { + i--; + } + + if (i == -1) + { + sz = "0"; + } else if (!Character.isDigit(sy.charAt(i))) + { + sz = sy.substring(0, i + 1) + "0"; + } else + { + sz = sy.substring(0, i + 1); + } + + if ((expon >= -4) && (expon < precision)) + { + ret = sz; + } else + { + ret = sz + sx.substring(ePos); + } + } else + { + if ((expon >= -4) && (expon < precision)) + { + ret = fFormatString(x).trim(); + } else + { + ret = sx; + } + } + + // leading space was trimmed off during + // construction + if (leadingSpace) + { + if (x >= 0) + { + ret = " " + ret; + } + } + + ca4 = ret.toCharArray(); + } + + // Pad with blanks or zeros. + ca5 = applyFloatPadding(ca4, false); + precision = savePrecision; + + return new String(ca5); + } + + /** + * Format method for the d conversion specifer and + * short argument. + * + * For d format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. A '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both a + * '+' and a ' ' are specified, the blank flag is + * ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * @param x the short to format. + * @return the formatted String. + */ + private String printDFormat(short x) + { + return printDFormat(Short.toString(x)); + } + + /** + * Format method for the d conversion character and + * long argument. + * + * For d format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. A '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both a + * '+' and a ' ' are specified, the blank flag is + * ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * @param x the long to format. + * @return the formatted String. + */ + private String printDFormat(long x) + { + return printDFormat(Long.toString(x)); + } + + /** + * Format method for the d conversion character and + * int argument. + * + * For d format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. A '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both a + * '+' and a ' ' are specified, the blank flag is + * ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * @param x the int to format. + * @return the formatted String. + */ + private String printDFormat(int x) + { + return printDFormat(Integer.toString(x)); + } + + /** + * Utility method for formatting using the d + * conversion character. + * @param sx the String to format, the result of + * converting a short, int, or long to a + * String. + * @return the formatted String. + */ + private String printDFormat(String sx) + { + int nLeadingZeros = 0; + int nBlanks = 0, + n = 0; + int i = 0, + jFirst = 0; + boolean neg = sx.charAt(0) == '-'; + + if (sx.equals("0") && precisionSet && (precision == 0)) + { + sx = ""; + } + + if (!neg) + { + if (precisionSet && (sx.length() < precision)) + { + nLeadingZeros = precision - sx.length(); + } + } else + { + if (precisionSet && (sx.length() - 1) < precision) + { + nLeadingZeros = precision - sx.length() + 1; + } + } + + if (nLeadingZeros < 0) + { + nLeadingZeros = 0; + } + + if (fieldWidthSet) + { + nBlanks = fieldWidth - nLeadingZeros - sx.length(); + + if (!neg && (leadingSign || leadingSpace)) + { + nBlanks--; + } + } + + if (nBlanks < 0) + { + nBlanks = 0; + } + + if (leadingSign) + { + n++; + } else if (leadingSpace) + { + n++; + } + + n += nBlanks; + n += nLeadingZeros; + n += sx.length(); + + char[] ca = new char[n]; + + if (leftJustify) + { + if (neg) + { + ca[i++] = '-'; + } else if (leadingSign) + { + ca[i++] = '+'; + } else if (leadingSpace) + { + ca[i++] = ' '; + } + + char[] csx = sx.toCharArray(); + + jFirst = neg + ? 1 + : 0; + + for (int j = 0; j < nLeadingZeros; i++, j++) + { + ca[i] = '0'; + } + + for (int j = jFirst; j < csx.length; j++, i++) + { + ca[i] = csx[j]; + } + + for (int j = 0; j < nBlanks; i++, j++) + { + ca[i] = ' '; + } + } else + { + if (!leadingZeros) + { + for (i = 0; i < nBlanks; i++) + { + ca[i] = ' '; + } + + if (neg) + { + ca[i++] = '-'; + } else if (leadingSign) + { + ca[i++] = '+'; + } else if (leadingSpace) + { + ca[i++] = ' '; + } + } else + { + if (neg) + { + ca[i++] = '-'; + } else if (leadingSign) + { + ca[i++] = '+'; + } else if (leadingSpace) + { + ca[i++] = ' '; + } + + for (int j = 0; j < nBlanks; j++, i++) + { + ca[i] = '0'; + } + } + + for (int j = 0; j < nLeadingZeros; j++, i++) + { + ca[i] = '0'; + } + + char[] csx = sx.toCharArray(); + + jFirst = neg + ? 1 + : 0; + + for (int j = jFirst; j < csx.length; j++, i++) + { + ca[i] = csx[j]; + } + } + + return new String(ca); + } + + /** + * Format method for the x conversion character and + * short argument. + * + * For x format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. The '#' flag character means to lead with + * '0x'. + * + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * @param x the short to format. + * @return the formatted String. + */ + private String printXFormat(short x) + { + String sx = null; + + if (x == Short.MIN_VALUE) + { + sx = "8000"; + } else if (x < 0) + { + String t; + + if (x == Short.MIN_VALUE) + { + t = "0"; + } else + { + t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 16); + + if ((t.charAt(0) == 'F') || (t.charAt(0) == 'f')) + { + t = t.substring(16, 32); + } + } + + switch (t.length()) + { + case 1 : + sx = "800" + t; + + break; + + case 2 : + sx = "80" + t; + + break; + + case 3 : + sx = "8" + t; + + break; + + case 4 : + switch (t.charAt(0)) + { + case '1' : + sx = "9" + t.substring(1, 4); + + break; + + case '2' : + sx = "a" + t.substring(1, 4); + + break; + + case '3' : + sx = "b" + t.substring(1, 4); + + break; + + case '4' : + sx = "c" + t.substring(1, 4); + + break; + + case '5' : + sx = "d" + t.substring(1, 4); + + break; + + case '6' : + sx = "e" + t.substring(1, 4); + + break; + + case '7' : + sx = "f" + t.substring(1, 4); + + break; + } + + break; + } + } else + { + sx = Integer.toString((int) x, 16); + } + + return printXFormat(sx); + } + + /** + * Format method for the x conversion character and + * long argument. + * + * For x format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. The '#' flag character means to lead with + * '0x'. + * + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * @param x the long to format. + * @return the formatted String. + */ + private String printXFormat(long x) + { + String sx = null; + + if (x == Long.MIN_VALUE) + { + sx = "8000000000000000"; + } else if (x < 0) + { + String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 16); + + switch (t.length()) + { + case 1 : + sx = "800000000000000" + t; + + break; + + case 2 : + sx = "80000000000000" + t; + + break; + + case 3 : + sx = "8000000000000" + t; + + break; + + case 4 : + sx = "800000000000" + t; + + break; + + case 5 : + sx = "80000000000" + t; + + break; + + case 6 : + sx = "8000000000" + t; + + break; + + case 7 : + sx = "800000000" + t; + + break; + + case 8 : + sx = "80000000" + t; + + break; + + case 9 : + sx = "8000000" + t; + + break; + + case 10 : + sx = "800000" + t; + + break; + + case 11 : + sx = "80000" + t; + + break; + + case 12 : + sx = "8000" + t; + + break; + + case 13 : + sx = "800" + t; + + break; + + case 14 : + sx = "80" + t; + + break; + + case 15 : + sx = "8" + t; + + break; + + case 16 : + switch (t.charAt(0)) + { + case '1' : + sx = "9" + t.substring(1, 16); + + break; + + case '2' : + sx = "a" + t.substring(1, 16); + + break; + + case '3' : + sx = "b" + t.substring(1, 16); + + break; + + case '4' : + sx = "c" + t.substring(1, 16); + + break; + + case '5' : + sx = "d" + t.substring(1, 16); + + break; + + case '6' : + sx = "e" + t.substring(1, 16); + + break; + + case '7' : + sx = "f" + t.substring(1, 16); + + break; + } + + break; + } + } else + { + sx = Long.toString(x, 16); + } + + return printXFormat(sx); + } + + /** + * Format method for the x conversion character and + * int argument. + * + * For x format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. The '#' flag character means to lead with + * '0x'. + * + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * @param x the int to format. + * @return the formatted String. + */ + private String printXFormat(int x) + { + String sx = null; + + if (x == Integer.MIN_VALUE) + { + sx = "80000000"; + } else if (x < 0) + { + String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 16); + + switch (t.length()) + { + case 1 : + sx = "8000000" + t; + + break; + + case 2 : + sx = "800000" + t; + + break; + + case 3 : + sx = "80000" + t; + + break; + + case 4 : + sx = "8000" + t; + + break; + + case 5 : + sx = "800" + t; + + break; + + case 6 : + sx = "80" + t; + + break; + + case 7 : + sx = "8" + t; + + break; + + case 8 : + switch (t.charAt(0)) + { + case '1' : + sx = "9" + t.substring(1, 8); + + break; + + case '2' : + sx = "a" + t.substring(1, 8); + + break; + + case '3' : + sx = "b" + t.substring(1, 8); + + break; + + case '4' : + sx = "c" + t.substring(1, 8); + + break; + + case '5' : + sx = "d" + t.substring(1, 8); + + break; + + case '6' : + sx = "e" + t.substring(1, 8); + + break; + + case '7' : + sx = "f" + t.substring(1, 8); + + break; + } + + break; + } + } else + { + sx = Integer.toString(x, 16); + } + + return printXFormat(sx); + } + + /** + * Utility method for formatting using the x + * conversion character. + * @param sx the String to format, the result of + * converting a short, int, or long to a + * String. + * @return the formatted String. + */ + private String printXFormat(String sx) + { + int nLeadingZeros = 0; + int nBlanks = 0; + + if (sx.equals("0") && precisionSet && (precision == 0)) + { + sx = ""; + } + + if (precisionSet) + { + nLeadingZeros = precision - sx.length(); + } + + if (nLeadingZeros < 0) + { + nLeadingZeros = 0; + } + + if (fieldWidthSet) + { + nBlanks = fieldWidth - nLeadingZeros - sx.length(); + + if (alternateForm) + { + nBlanks = nBlanks - 2; + } + } + + if (nBlanks < 0) + { + nBlanks = 0; + } + + int n = 0; + + if (alternateForm) + { + n += 2; + } + + n += nLeadingZeros; + n += sx.length(); + n += nBlanks; + + char[] ca = new char[n]; + int i = 0; + + if (leftJustify) + { + if (alternateForm) + { + ca[i++] = '0'; + ca[i++] = 'x'; + } + + for (int j = 0; j < nLeadingZeros; j++, i++) + { + ca[i] = '0'; + } + + char[] csx = sx.toCharArray(); + + for (int j = 0; j < csx.length; j++, i++) + { + ca[i] = csx[j]; + } + + for (int j = 0; j < nBlanks; j++, i++) + { + ca[i] = ' '; + } + } else + { + if (!leadingZeros) + { + for (int j = 0; j < nBlanks; j++, i++) + { + ca[i] = ' '; + } + } + + if (alternateForm) + { + ca[i++] = '0'; + ca[i++] = 'x'; + } + + if (leadingZeros) + { + for (int j = 0; j < nBlanks; j++, i++) + { + ca[i] = '0'; + } + } + + for (int j = 0; j < nLeadingZeros; j++, i++) + { + ca[i] = '0'; + } + + char[] csx = sx.toCharArray(); + + for (int j = 0; j < csx.length; j++, i++) + { + ca[i] = csx[j]; + } + } + + String caReturn = new String(ca); + + if (conversionCharacter == 'X') + { + caReturn = caReturn.toUpperCase(); + } + + return caReturn; + } + + /** + * Format method for the o conversion character and + * short argument. + * + * For o format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. The '#' flag character means that the + * output begins with a leading 0 and the precision + * is increased by 1. + * + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * @param x the short to format. + * @return the formatted String. + */ + private String printOFormat(short x) + { + String sx = null; + + if (x == Short.MIN_VALUE) + { + sx = "100000"; + } else if (x < 0) + { + String t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 8); + + switch (t.length()) + { + case 1 : + sx = "10000" + t; + + break; + + case 2 : + sx = "1000" + t; + + break; + + case 3 : + sx = "100" + t; + + break; + + case 4 : + sx = "10" + t; + + break; + + case 5 : + sx = "1" + t; + + break; + } + } else + { + sx = Integer.toString((int) x, 8); + } + + return printOFormat(sx); + } + + /** + * Format method for the o conversion character and + * long argument. + * + * For o format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. The '#' flag character means that the + * output begins with a leading 0 and the precision + * is increased by 1. + * + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * @param x the long to format. + * @return the formatted String. + */ + private String printOFormat(long x) + { + String sx = null; + + if (x == Long.MIN_VALUE) + { + sx = "1000000000000000000000"; + } else if (x < 0) + { + String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 8); + + switch (t.length()) + { + case 1 : + sx = "100000000000000000000" + t; + + break; + + case 2 : + sx = "10000000000000000000" + t; + + break; + + case 3 : + sx = "1000000000000000000" + t; + + break; + + case 4 : + sx = "100000000000000000" + t; + + break; + + case 5 : + sx = "10000000000000000" + t; + + break; + + case 6 : + sx = "1000000000000000" + t; + + break; + + case 7 : + sx = "100000000000000" + t; + + break; + + case 8 : + sx = "10000000000000" + t; + + break; + + case 9 : + sx = "1000000000000" + t; + + break; + + case 10 : + sx = "100000000000" + t; + + break; + + case 11 : + sx = "10000000000" + t; + + break; + + case 12 : + sx = "1000000000" + t; + + break; + + case 13 : + sx = "100000000" + t; + + break; + + case 14 : + sx = "10000000" + t; + + break; + + case 15 : + sx = "1000000" + t; + + break; + + case 16 : + sx = "100000" + t; + + break; + + case 17 : + sx = "10000" + t; + + break; + + case 18 : + sx = "1000" + t; + + break; + + case 19 : + sx = "100" + t; + + break; + + case 20 : + sx = "10" + t; + + break; + + case 21 : + sx = "1" + t; + + break; + } + } else + { + sx = Long.toString(x, 8); + } + + return printOFormat(sx); + } + + /** + * Format method for the o conversion character and + * int argument. + * + * For o format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. The '#' flag character means that the + * output begins with a leading 0 and the precision + * is increased by 1. + * + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * @param x the int to format. + * @return the formatted String. + */ + private String printOFormat(int x) + { + String sx = null; + + if (x == Integer.MIN_VALUE) + { + sx = "20000000000"; + } else if (x < 0) + { + String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 8); + + switch (t.length()) + { + case 1 : + sx = "2000000000" + t; + + break; + + case 2 : + sx = "200000000" + t; + + break; + + case 3 : + sx = "20000000" + t; + + break; + + case 4 : + sx = "2000000" + t; + + break; + + case 5 : + sx = "200000" + t; + + break; + + case 6 : + sx = "20000" + t; + + break; + + case 7 : + sx = "2000" + t; + + break; + + case 8 : + sx = "200" + t; + + break; + + case 9 : + sx = "20" + t; + + break; + + case 10 : + sx = "2" + t; + + break; + + case 11 : + sx = "3" + t.substring(1); + + break; + } + } else + { + sx = Integer.toString(x, 8); + } + + return printOFormat(sx); + } + + /** + * Utility method for formatting using the o + * conversion character. + * @param sx the String to format, the result of + * converting a short, int, or long to a + * String. + * @return the formatted String. + */ + private String printOFormat(String sx) + { + int nLeadingZeros = 0; + int nBlanks = 0; + + if (sx.equals("0") && precisionSet && (precision == 0)) + { + sx = ""; + } + + if (precisionSet) + { + nLeadingZeros = precision - sx.length(); + } + + if (alternateForm) + { + nLeadingZeros++; + } + + if (nLeadingZeros < 0) + { + nLeadingZeros = 0; + } + + if (fieldWidthSet) + { + nBlanks = fieldWidth - nLeadingZeros - sx.length(); + } + + if (nBlanks < 0) + { + nBlanks = 0; + } + + int n = nLeadingZeros + sx.length() + nBlanks; + char[] ca = new char[n]; + int i; + + if (leftJustify) + { + for (i = 0; i < nLeadingZeros; i++) + { + ca[i] = '0'; + } + + char[] csx = sx.toCharArray(); + + for (int j = 0; j < csx.length; j++, i++) + { + ca[i] = csx[j]; + } + + for (int j = 0; j < nBlanks; j++, i++) + { + ca[i] = ' '; + } + } else + { + if (leadingZeros) + { + for (i = 0; i < nBlanks; i++) + { + ca[i] = '0'; + } + } else + { + for (i = 0; i < nBlanks; i++) + { + ca[i] = ' '; + } + } + + for (int j = 0; j < nLeadingZeros; j++, i++) + { + ca[i] = '0'; + } + + char[] csx = sx.toCharArray(); + + for (int j = 0; j < csx.length; j++, i++) + { + ca[i] = csx[j]; + } + } + + return new String(ca); + } + + /** + * Format method for the c conversion character and + * char argument. + * + * The only flag character that affects c format is + * the '-', meaning that the output should be left + * justified within the field. The default is to + * pad with blanks on the left. + * + * The field width is treated as the minimum number + * of characters to be printed. Padding is with + * blanks by default. The default width is 1. + * + * The precision, if set, is ignored. + * @param x the char to format. + * @return the formatted String. + */ + private String printCFormat(char x) + { + int nPrint = 1; + int width = fieldWidth; + + if (!fieldWidthSet) + { + width = nPrint; + } + + char[] ca = new char[width]; + int i = 0; + + if (leftJustify) + { + ca[0] = x; + + for (i = 1; i <= width - nPrint; i++) + { + ca[i] = ' '; + } + } else + { + for (i = 0; i < width - nPrint; i++) + { + ca[i] = ' '; + } + + ca[i] = x; + } + + return new String(ca); + } + + /** + * Format method for the s conversion character and + * String argument. + * + * The only flag character that affects s format is + * the '-', meaning that the output should be left + * justified within the field. The default is to + * pad with blanks on the left. + * + * The field width is treated as the minimum number + * of characters to be printed. The default is the + * smaller of the number of characters in the the + * input and the precision. Padding is with blanks + * by default. + * + * The precision, if set, specifies the maximum + * number of characters to be printed from the + * string. A null digit string is treated + * as a 0. The default is not to set a maximum + * number of characters to be printed. + * @param x the String to format. + * @return the formatted String. + */ + private String printSFormat(String x) + { + int nPrint = x.length(); + int width = fieldWidth; + + if (precisionSet && (nPrint > precision)) + { + nPrint = precision; + } + + if (!fieldWidthSet) + { + width = nPrint; + } + + int n = 0; + + if (width > nPrint) + { + n += width - nPrint; + } + + if (nPrint >= x.length()) + { + n += x.length(); + } else + { + n += nPrint; + } + + char[] ca = new char[n]; + int i = 0; + + if (leftJustify) + { + if (nPrint >= x.length()) + { + char[] csx = x.toCharArray(); + + for (i = 0; i < x.length(); i++) + { + ca[i] = csx[i]; + } + } else + { + char[] csx = x.substring(0, nPrint).toCharArray(); + + for (i = 0; i < nPrint; i++) + { + ca[i] = csx[i]; + } + } + + for (int j = 0; j < width - nPrint; j++, i++) + { + ca[i] = ' '; + } + } else + { + for (i = 0; i < width - nPrint; i++) + { + ca[i] = ' '; + } + + if (nPrint >= x.length()) + { + char[] csx = x.toCharArray(); + + for (int j = 0; j < x.length(); i++, j++) + { + ca[i] = csx[j]; + } + } else + { + char[] csx = x.substring(0, nPrint).toCharArray(); + + for (int j = 0; j < nPrint; i++, j++) + { + ca[i] = csx[j]; + } + } + } + + return new String(ca); + } + + /** + * Check for a conversion character. If it is + * there, store it. + * @return <code>true</code> if the conversion + * character is there, and + * <code>false</code> otherwise. + */ + private boolean setConversionCharacter() + { + /* idfgGoxXeEcs */ + boolean ret = false; + + conversionCharacter = '\0'; + + if (pos < fmt.length()) + { + char c = fmt.charAt(pos); + + if ((c == 'i') || (c == 'd') || (c == 'f') || (c == 'g') || (c == 'G') || (c == 'o') || (c == 'x') || (c == 'X') + || (c == 'e') || (c == 'E') || (c == 'c') || (c == 's') || (c == '%')) + { + conversionCharacter = c; + pos++; + ret = true; + } + } + + return ret; + } + + /** + * Check for an h, l, or L in a format. An L is + * used to control the minimum number of digits + * in an exponent when using floating point + * formats. An l or h is used to control + * conversion of the input to a long or short, + * respectively, before formatting. If any of + * these is present, store them. + */ + private void setOptionalHL() + { + optionalh = false; + optionall = false; + optionalL = false; + + if (pos < fmt.length()) + { + char c = fmt.charAt(pos); + + if (c == 'h') + { + optionalh = true; + pos++; + } else if (c == 'l') + { + optionall = true; + pos++; + } else if (c == 'L') + { + optionalL = true; + pos++; + } + } + } + + /** + * Set the precision. + */ + private void setPrecision() + { + int firstPos = pos; + + precisionSet = false; + + if ((pos < fmt.length()) && (fmt.charAt(pos) == '.')) + { + pos++; + + if ((pos < fmt.length()) && (fmt.charAt(pos) == '*')) + { + pos++; + + if (!setPrecisionArgPosition()) + { + variablePrecision = true; + precisionSet = true; + } + + return; + } else + { + while (pos < fmt.length()) + { + char c = fmt.charAt(pos); + + if (Character.isDigit(c)) + { + pos++; + } else + { + break; + } + } + + if (pos > firstPos + 1) + { + String sz = fmt.substring(firstPos + 1, pos); + + precision = Integer.parseInt(sz); + precisionSet = true; + } + } + } + } + + /** + * Set the field width. + */ + private void setFieldWidth() + { + int firstPos = pos; + + fieldWidth = 0; + fieldWidthSet = false; + + if ((pos < fmt.length()) && (fmt.charAt(pos) == '*')) + { + pos++; + + if (!setFieldWidthArgPosition()) + { + variableFieldWidth = true; + fieldWidthSet = true; + } + } else + { + while (pos < fmt.length()) + { + char c = fmt.charAt(pos); + + if (Character.isDigit(c)) + { + pos++; + } else + { + break; + } + } + + if ((firstPos < pos) && (firstPos < fmt.length())) + { + String sz = fmt.substring(firstPos, pos); + + fieldWidth = Integer.parseInt(sz); + fieldWidthSet = true; + } + } + } + + /** + * Store the digits <code>n</code> in %n$ forms. + */ + private void setArgPosition() + { + int xPos; + + for (xPos = pos; xPos < fmt.length(); xPos++) + { + if (!Character.isDigit(fmt.charAt(xPos))) + { + break; + } + } + + if ((xPos > pos) && (xPos < fmt.length())) + { + if (fmt.charAt(xPos) == '$') + { + positionalSpecification = true; + argumentPosition = Integer.parseInt(fmt.substring(pos, xPos)); + pos = xPos + 1; + } + } + } + + /** + * Store the digits <code>n</code> in *n$ forms. + */ + private boolean setFieldWidthArgPosition() + { + boolean ret = false; + int xPos; + + for (xPos = pos; xPos < fmt.length(); xPos++) + { + if (!Character.isDigit(fmt.charAt(xPos))) + { + break; + } + } + + if ((xPos > pos) && (xPos < fmt.length())) + { + if (fmt.charAt(xPos) == '$') + { + positionalFieldWidth = true; + argumentPositionForFieldWidth = Integer.parseInt(fmt.substring(pos, xPos)); + pos = xPos + 1; + ret = true; + } + } + + return ret; + } + + /** + * Store the digits <code>n</code> in *n$ forms. + */ + private boolean setPrecisionArgPosition() + { + boolean ret = false; + int xPos; + + for (xPos = pos; xPos < fmt.length(); xPos++) + { + if (!Character.isDigit(fmt.charAt(xPos))) + { + break; + } + } + + if ((xPos > pos) && (xPos < fmt.length())) + { + if (fmt.charAt(xPos) == '$') + { + positionalPrecision = true; + argumentPositionForPrecision = Integer.parseInt(fmt.substring(pos, xPos)); + pos = xPos + 1; + ret = true; + } + } + + return ret; + } + + boolean isPositionalSpecification() + { + return positionalSpecification; + } + + int getArgumentPosition() + { + return argumentPosition; + } + + boolean isPositionalFieldWidth() + { + return positionalFieldWidth; + } + + int getArgumentPositionForFieldWidth() + { + return argumentPositionForFieldWidth; + } + + boolean isPositionalPrecision() + { + return positionalPrecision; + } + + int getArgumentPositionForPrecision() + { + return argumentPositionForPrecision; + } + + /** + * Set flag characters, one of '-+#0 or a space. + */ + private void setFlagCharacters() + { + /* '-+ #0 */ + thousands = false; + leftJustify = false; + leadingSign = false; + leadingSpace = false; + alternateForm = false; + leadingZeros = false; + + for (; pos < fmt.length(); pos++) + { + char c = fmt.charAt(pos); + + if (c == '\'') + { + thousands = true; + } else if (c == '-') + { + leftJustify = true; + leadingZeros = false; + } else if (c == '+') + { + leadingSign = true; + leadingSpace = false; + } else if (c == ' ') + { + if (!leadingSign) + { + leadingSpace = true; + } + } else if (c == '#') + { + alternateForm = true; + } else if (c == '0') + { + if (!leftJustify) + { + leadingZeros = true; + } + } else + { + break; + } + } + } + } +} diff --git a/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java b/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java new file mode 100644 index 0000000..aae577e --- /dev/null +++ b/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java @@ -0,0 +1,486 @@ +package com.ximple.eofms.util; + +/** + * TWDDatumConverter + * User: Ulysses + * Date: 2007/10/8 + * Time: �U�� 01:35:03 + * To change this template use File | Settings | File Templates. + */ +public class TWDDatumConverter +{ + /* + * Definition of math related value + */ + private static final double COS67_5 = 0.3826834323650897717284599840304e0; + private static final double PI = 3.14159265358979323e0; + private static final double HALF_PI = 1.570796326794896615e0; + private static final double DEG_RAD = 0.01745329251994329572e0; + private static final double RAD_DEG = 57.295779513082321031e0; + + /* + * Definition of datum related value + */ + private static final double AD_C = 1.0026000e0; + private static final double TWD67_A = 6378160.0e0; + private static final double TWD67_B = 6356774.7192e0; + private static final double TWD67_ECC = 0.00669454185458e0; + private static final double TWD67_ECC2 = 0.00673966079586e0; + + // different from garmin and already knowned value, but those all value only + private static final double TWD67_DX = -752.32e0; + + // got 5-15m accuracy. the real offical value is holded by somebody and not + private static final double TWD67_DY = -361.32e0; + + // release to public. if can got more enough twd67/twd97 control point coordinare, + private static final double TWD67_DZ = -180.51e0; + private static final double TWD67_RX = -0.00000117e0; // then we can calculate a better value than now. + private static final double TWD67_RY = 0.00000184e0; // + private static final double TWD67_RZ = 0.00000098e0; // and, also lack twd67/twd97 altitude convertion value... + private static final double TWD67_S = 0.00002329e0; // + private static final double TWD97_A = 6378137.0e0; + private static final double TWD97_B = 6356752.3141e0; + private static final double TWD97_ECC = 0.00669438002290e0; + private static final double TWD97_ECC2 = 0.00673949677556e0; + private static final double TWD67_TM2 = 0.9999e0; // TWD67->TM2 scale + private static final double TWD97_TM2 = 0.9999e0; // TWD97->TM2 scale + + /* + * datum convert function + */ + void toTWD97(double x, double y, double z) + { + double newX, newY, newZ; + double r, pole, sin_lat, cos_lat; + double lat, lon, height; + double x1, y1, z1, x2, y2, z2; + double q, q2, t, t1, s, s1, sum, sin_b, cos_b, sin_p, cos_p; + + lon = x * DEG_RAD; + lat = y * DEG_RAD; + height = z * DEG_RAD; + + if ((lat < -HALF_PI) && (lat > -1.001 * HALF_PI)) + { + lat = -HALF_PI; + } else if ((lat > HALF_PI) && (lat < 1.001 * HALF_PI)) + { + lat = HALF_PI; + } else if ((lat < -HALF_PI) || (lat > HALF_PI)) + { + return; + } + + if (lon > PI) + { + lon -= (2 * PI); + } + + sin_lat = Math.sin(lat); + cos_lat = Math.cos(lat); + r = TWD67_A / (Math.sqrt(1.0 - TWD67_ECC * sin_lat * sin_lat)); + x1 = (r + height) * cos_lat * Math.cos(lon); + y1 = (r + height) * cos_lat * Math.sin(lon); + z1 = ((r * (1 - TWD67_ECC)) + height) * sin_lat; + x2 = x1 + TWD67_DX + TWD67_S * (lon + TWD67_RZ * lat - TWD67_RY * height); + y2 = y1 + TWD67_DY + TWD67_S * (-TWD67_RZ * lon + lat + TWD67_RX * height); + z2 = z1 + TWD67_DZ + TWD67_S * (TWD67_RY * lon - TWD67_RX * lat + height); + pole = 0.0; + + if (x2 != 0.0) + { + lon = Math.atan2(y2, x2); + } else + { + if (y2 > 0) + { + lon = HALF_PI; + } else if (y2 < 0) + { + lon = -HALF_PI; + } else + { + pole = 1; + lon = 0; + + if (z2 > 0) + { + lat = HALF_PI; + } else if (z2 < 0) + { + lat = -HALF_PI; + } else + { + lat = HALF_PI; + newX = lon * RAD_DEG; + newY = lat * RAD_DEG; + newZ = -TWD97_B; + + return; + } + } + } + + q2 = x2 * x2 + y2 * y2; + q = Math.sqrt(q2); + t = z2 * AD_C; + s = Math.sqrt(t * t + q2); + sin_b = t / s; + cos_b = q / s; + t1 = z2 + TWD97_B * TWD97_ECC2 * sin_b * sin_b * sin_b; + sum = q - TWD97_A * TWD97_ECC * cos_b * cos_b * cos_b; + s1 = Math.sqrt(t1 * t1 + sum * sum); + sin_p = t1 / s1; + cos_p = sum / s1; + r = TWD97_A / Math.sqrt(1.0 - TWD97_ECC * sin_p * sin_p); + + if (cos_p >= COS67_5) + { + height = q / cos_p - r; + } else if (cos_p <= -COS67_5) + { + height = q / -cos_p - r; + } else + { + height = z2 / sin_p + r * (TWD97_ECC - 1.0); + } + + if (pole !=0.0) + { + lat = Math.atan(sin_p / cos_p); + } + + newX = lon * RAD_DEG; + newY = lat * RAD_DEG; + newZ = height; + } + + void toTWD67(double x, double y, double z) + { + double newX, newY, newZ; + double r, pole, sin_lat, cos_lat; + double lat, lon, height; + double x1, y1, z1, x2, y2, z2; + double q, q2, t, t1, s, s1, sum, sin_b, cos_b, sin_p, cos_p; + + lon = x * DEG_RAD; + lat = y * DEG_RAD; + height = z * DEG_RAD; + + if ((lat < -HALF_PI) && (lat > -1.001 * HALF_PI)) + { + lat = -HALF_PI; + } else if ((lat > HALF_PI) && (lat < 1.001 * HALF_PI)) + { + lat = HALF_PI; + } else if ((lat < -HALF_PI) || (lat > HALF_PI)) + { + return; + } + + if (lon > PI) + { + lon -= (2 * PI); + } + + sin_lat = Math.sin(lat); + cos_lat = Math.cos(lat); + r = TWD97_A / (Math.sqrt(1.0 - TWD97_ECC * sin_lat * sin_lat)); + x1 = (r + height) * cos_lat * Math.cos(lon); + y1 = (r + height) * cos_lat * Math.sin(lon); + z1 = ((r * (1 - TWD97_ECC)) + height) * sin_lat; + x2 = x1 - TWD67_DX - TWD67_S * (lon + TWD67_RZ * lat - TWD67_RY * height); + y2 = y1 - TWD67_DY - TWD67_S * (-TWD67_RZ * lon + lat + TWD67_RX * height); + z2 = z1 - TWD67_DZ - TWD67_S * (TWD67_RY * lon - TWD67_RX * lat + height); + pole = 0; + + if (x2 != 0.0) + { + lon = Math.atan2(y2, x2); + } else + { + if (y2 > 0) + { + lon = HALF_PI; + } else if (y2 < 0) + { + lon = -HALF_PI; + } else + { + pole = 1; + lon = 0; + + if (z2 > 0) + { + lat = HALF_PI; + } else if (z2 < 0) + { + lat = -HALF_PI; + } else + { + lat = HALF_PI; + newX = lon * RAD_DEG; + newY = lat * RAD_DEG; + newZ = -TWD67_B; + + return; + } + } + } + + q2 = x2 * x2 + y2 * y2; + q = Math.sqrt(q2); + t = z2 * AD_C; + s = Math.sqrt(t * t + q2); + sin_b = t / s; + cos_b = q / s; + t1 = z2 + TWD67_B * TWD67_ECC2 * sin_b * sin_b * sin_b; + sum = q - TWD67_A * TWD67_ECC * cos_b * cos_b * cos_b; + s1 = Math.sqrt(t1 * t1 + sum * sum); + sin_p = t1 / s1; + cos_p = sum / s1; + r = TWD67_A / Math.sqrt(1.0 - TWD67_ECC * sin_p * sin_p); + + if (cos_p >= COS67_5) + { + height = q / cos_p - r; + } else if (cos_p <= -COS67_5) + { + height = q / -cos_p - r; + } else + { + height = z2 / sin_p + r * (TWD67_ECC - 1.0); + } + + if (pole != 0.0) + { + lat = Math.atan(sin_p / cos_p); + } + + newX = lon * RAD_DEG; + newY = lat * RAD_DEG; + newZ = height; + } + + void toTM2(double a, double ecc, double ecc2, double lat, double lon, double scale, double x, double y) + { + double x0, y0, x1, y1, m0, m1; + double n, t, c, A; + double newX, newY; + + x0 = x * DEG_RAD; + y0 = y * DEG_RAD; + x1 = lon * DEG_RAD; + y1 = lat * DEG_RAD; + m0 = mercator(y1, a, ecc); + m1 = mercator(y0, a, ecc); + n = a / Math.sqrt(1 - ecc * Math.pow(Math.sin(y0), 2.0)); + t = Math.pow(Math.tan(y0), 2.0); + c = ecc2 * Math.pow(Math.cos(y0), 2.0); + A = (x0 - x1) * Math.cos(y0); + newX = scale * n + * (A + (1.0 - t + c) * A * A * A / 6.0 + + (5.0 - 18.0 * t + t * t + 72.0 * c - 58.0 * ecc2) * Math.pow(A, 5.0) / 120.0); + newY = scale + * (m1 - m0 + + n * Math.tan(y0) + * (A * A / 2.0 + (5.0 - t + 9.0 * c + 4 * c * c) * Math.pow(A, 4.0) / 24.0 + + (61.0 - 58.0 * t + t * t + 600.0 * c - 330.0 * ecc2) * Math.pow(A, 6.0) / 720.0)); + } + + void fromTM2(double a, double ecc, double ecc2, double lat, double lon, double scale, double x, double y) + { + double newX, newY; + double x0, y0, x1, y1, phi, m, m0, mu, e1; + double c1, t1, n1, r1, d; + + x0 = x; + y0 = y; + x1 = lon * DEG_RAD; + y1 = lat * DEG_RAD; + m0 = mercator(y1, a, ecc); + m = m0 + y0 / scale; + e1 = (1.0 - Math.sqrt(1.0 - ecc)) / (1.0 + Math.sqrt(1.0 - ecc)); + mu = m / (a * (1.0 - ecc / 4.0 - 3.0 * ecc * ecc / 64.0 - 5.0 * ecc * ecc * ecc / 256.0)); + phi = mu + (3.0 * e1 / 2.0 - 27.0 * Math.pow(e1, 3.0) / 32.0) * Math.sin(2.0 * mu) + + (21.0 * e1 * e1 / 16.0 - 55.0 * Math.pow(e1, 4.0) / 32.0) * Math.sin(4.0 * mu) + + 151.0 * Math.pow(e1, 3.0) / 96.0 * Math.sin(6.0 * mu) + 1097.0 * Math.pow(e1, 4.0) / 512.0 * Math.sin(8.0 * mu); + c1 = ecc2 * Math.pow(Math.cos(phi), 2.0); + t1 = Math.pow(Math.tan(phi), 2.0); + n1 = a / Math.sqrt(1 - ecc * Math.pow(Math.sin(phi), 2.0)); + r1 = a * (1.0 - ecc) / Math.pow(1.0 - ecc * Math.pow(Math.sin(phi), 2.0), 1.5); + d = x0 / (n1 * scale); + newX = (x1 + (d - (1.0 + 2.0 * t1 + c1) * Math.pow(d, 3.0) / 6.0 + + (5.0 - 2.0 * c1 + 28.0 * t1 - 3.0 * c1 * c1 + 8.0 * ecc2 + 24.0 * t1 * t1) * Math.pow(d, 5.0) + / 120.0) / Math.cos(phi)) * RAD_DEG; + newY = (phi + - n1 * Math.tan(phi) / r1 + * (d * d / 2.0 - (5.0 + 3.0 * t1 + 10.0 * c1 - 4.0 * c1 * c1 - 9.0 * ecc2) * Math.pow(d, 4.0) / 24.0 + + (61.0 + 90.0 * t1 + 298.0 * c1 + 45.0 * t1 * t1 - 252.0 * ecc2 - 3.0 * c1 * c1) * Math.pow(d, 6.0) + / 72.0)) * RAD_DEG; + } + + double mercator(double y, double a, double ecc) + { + if (y == 0.0) + { + return 0.0; + } else + { + return a * ((1.0 - ecc / 4.0 - 3.0 * ecc * ecc / 64.0 - 5.0 * ecc * ecc * ecc / 256.0) * y + - (3.0 * ecc / 8.0 + 3.0 * ecc * ecc / 32.0 + 45.0 * ecc * ecc * ecc / 1024.0) * Math.sin(2.0 * y) + + (15.0 * ecc * ecc / 256.0 + 45.0 * ecc * ecc * ecc / 1024.0) * Math.sin(4.0 * y) + - (35.0 * ecc * ecc * ecc / 3072.0) * Math.sin(6.0 * y)); + } + } + + /** + * + * Sample code below, using coordinate in Dan Jacob's website. + * + * + * int main() + * { + * double x1, y1, z1, x2, y2, z2; + * double tx1, ty1, tx2, ty2; + * double dx, dy, dz, dx1, dy1; + * + * x1 = 120.85788004; // TWD67 + * y1 = 24.18347242; + * z1 = 777; + * + * x2 = 120.86603958; // TWD97 + * y2 = 24.18170479; + * z2 = 777; + * + * tx1 = 235561; // TWD67->TM2 + * ty1 = 2675359; + * + * tx2 = 236389.849; // TWD97->TM2 + * ty2 = 2675153.168; + * + * //////////////////////////////////////////// + * / + * / + * // convert TWD67->TM2 + * / + * / + * //////////////////////////////////////////// + * + * dx = x1; + * dy = y1; + * + * toTM2(TWD67_A, TWD67_ECC, TWD67_ECC2, 0, 121, TWD67_TM2, &dx, &dy); + * // center longitude of taiwan is 121, for penghu is 119 + * + * dx += 250000; // TM2 in Taiwan should add 250000 + * + * printf("TWD67->TM2nTWD67 (%f, %f)nConvert (%.3f, %.3f)nOrigin (%.3f, %.3f)n", x1, y1, dx, dy, tx1, ty1); + * printf("Acuuracy (%.3f, X:%.3f, Y:%.3f)nn", sqrt((dx-tx1)*(dx-tx1)+(dy-ty1)*(dy-ty1)), (dx-tx1), (dy-ty1)); + * + * //////////////////////////////////////////// + * / + * / + * // convert TWD97->TM2 + * / + * / + * //////////////////////////////////////////// + * + * dx = x2; + * dy = y2; + * + * toTM2(TWD97_A, TWD97_ECC, TWD97_ECC2, 0, 121, TWD97_TM2, &dx, &dy); + * // center longitude of taiwan is 121, for penghu is 119 + * + * dx += 250000; // TM2 in Taiwan should add 250000 + * + * printf("TWD97->TM2nTWD97 (%f, %f)nConvert (%.3f, %.3f)nOrigin (%.3f, %.3f)n", x2, y2, dx, dy, tx2, ty2); + * printf("Acuuracy (%.3f, X:%.3f, Y:%.3f)nn", sqrt((dx-tx2)*(dx-tx2)+(dy-ty2)*(dy-ty2)), (dx-tx2), (dy-ty2)); + * + * //////////////////////////////////////////// + * / + * / + * // convert TM2->TWD67 + * / + * / + * //////////////////////////////////////////// + * + * dx = tx1-250000; // should minus 250000 first in Taiwan + * dy = ty1; + * + * fromTM2(TWD67_A, TWD67_ECC, TWD67_ECC2, 0, 121, TWD67_TM2, &dx, &dy); + * + * printf("TM2->TWD67nTM2 (%f, %f)nConvert (%.9f, %.9f)nOrigin (%.9f, %.9f)n", tx1, ty1, dx, dy, x1, y1); + * printf("Acuuracy (%.9f, X:%.9f, Y:%.9f)nn", sqrt((dx-x1)*(dx-x1)+(dy-y1)*(dy-y1)), (dx-x1), (dy-y1)); + * + * //////////////////////////////////////////// + * / + * / + * // convert TM2->TWD97 + * / + * / + * //////////////////////////////////////////// + * + * dx = tx2-250000; // should minus 250000 first in Taiwan + * dy = ty2; + * + * fromTM2(TWD97_A, TWD97_ECC, TWD97_ECC2, 0, 121, TWD97_TM2, &dx, &dy); + * + * printf("TM2->TWD97nTM2 (%f, %f)nConvert (%.9f, %.9f)nOrigin (%.9f, %.9f)n", tx2, ty2, dx, dy, x2, y2); + * printf("Acuuracy (%.9f, X:%.9f, Y:%.9f)nn", sqrt((dx-x2)*(dx-x2)+(dy-y2)*(dy-y2)), (dx-x2), (dy-y2)); + * + * //////////////////////////////////////////// + * / + * / + * // convert TWD67->TWD97 + * / + * / + * //////////////////////////////////////////// + * + * dx = x1; + * dy = y1; + * dz = z1; + * + * toTWD97(&dx, &dy, &dz); + * + * dx1 = dx; + * dy1 = dy; + * + * toTM2(TWD97_A, TWD97_ECC, TWD97_ECC2, 0, 121, TWD97_TM2, &dx1, &dy1); + * + * dx1 += 250000; // TM2 in Taiwan should add 250000 + * + * printf("TWD67->TWD97nTWD67 (%.9f, %.9f, %6.2f) (%.3f, %.3f)n", x1, y1, z1, tx1, ty1); + * printf("Convert (%.9f, %.9f, %6.2f) (%.3f, %.3f)n", dx, dy, dz, dx1, dy1); + * printf("Origin (%.9f, %.9f, %6.2f) (%.3f, %.3f)n", x2, y2, z2, tx2, ty2); + * printf("Acuuracy (%.4f, X:%.4f, Y:%.4f)nn", sqrt((dx1-tx2)*(dx1-tx2)+(dy1-ty2)*(dy1-ty2)), (dx1-tx2), (dy1-ty2)); + * + * //////////////////////////////////////////// + * / + * / + * // convert TWD97->TWD67 + * / + * / + * //////////////////////////////////////////// + * + * dx = x2; + * dy = y2; + * dz = z2; + * + * toTWD67(&dx, &dy, &dz); + * + * dx1 = dx; + * dy1 = dy; + * + * toTM2(TWD67_A, TWD67_ECC, TWD67_ECC2, 0, 121, TWD67_TM2, &dx1, &dy1); + * + * dx1 += 250000; // TM2 in Taiwan should add 250000 + * + * printf("TWD97->TWD67nTWD97 (%.9f, %.9f, %6.2f) (%.3f, %.3f)n", x2, y2, z2, tx2, ty2); + * printf("Convert (%.9f, %.9f, %6.2f) (%.3f, %.3f)n", dx, dy, dz, dx1, dy1); + * printf("Origin (%.9f, %.9f, %6.2f) (%.3f, %.3f)n", x1, y1, z1, tx1, ty1); + * printf("Acuuracy (%.4f, X:%.4f, Y:%.4f)nn", sqrt((dx1-tx1)*(dx1-tx1)+(dy1-ty1)*(dy1-ty1)), (dx1-tx1), (dy1-ty1)); + * } + */ +} -- Gitblit v0.0.0-SNAPSHOT