From 0ffea4eece9090db61ff0042ac26a6cb2a356cab Mon Sep 17 00:00:00 2001 From: ?? ? <ulysseskao@ximple.com.tw> Date: Tue, 06 May 2008 16:28:31 +0800 Subject: [PATCH] update for EOFM-73 --- xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleDatabaseJob.java | 49 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/IndexDgnConvertJobContext.java | 269 +++ xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TPCLIDConverter.java | 758 +++++++++ .gitattributes | 6 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleJobContext.java | 21 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertJobContext.java | 36 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2ShpJob.java | 293 +++ xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractDgnFileJobContext.java | 71 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/GeneralDgnConvertJobContext.java | 43 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Base64.java | 551 ++++++ xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java | 9 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/StringUtils.java | 2923 ++++++++++++++++++++++++++++++++++ 12 files changed, 5,022 insertions(+), 7 deletions(-) diff --git a/.gitattributes b/.gitattributes index 7d21620..9495191 100644 --- a/.gitattributes +++ b/.gitattributes @@ -56,13 +56,17 @@ xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeCompIdDispatchableFilter.java svneol=native#text/plain xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeCompLevelIdDispatchableFilter.java svneol=native#text/plain xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeIdDispatchableFilter.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractDgnFileJobContext.java svneol=native#text/plain xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleDatabaseJob.java svneol=native#text/plain xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/GeneralDgnConvertJobContext.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/IndexDgnConvertJobContext.java svneol=native#text/plain xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2ShpJob.java svneol=native#text/plain xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertJobContext.java svneol=native#text/plain xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleUpgradeBlob2UDTJob.java svneol=native#text/plain xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleUpgradeJobContext.java svneol=native#text/plain xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/TWD97GeometryConverterDecorator.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Base64.java svneol=native#text/plain xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/BinConverter.java svneol=native#text/plain xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Bits.java svneol=native#text/plain xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/ByteArrayCompressor.java svneol=native#text/plain @@ -71,6 +75,8 @@ xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/GeomUtil.java svneol=native#text/plain xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/LangUtil.java svneol=native#text/plain xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/PrintfFormat.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/StringUtils.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TPCLIDConverter.java svneol=native#text/plain xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java svneol=native#text/plain xdgnjobs/ximple-spatialjob/src/main/resources/com/ximple/eofms/filter/ElementDispatcherRules.xml svneol=native#text/xml xdgnjobs/ximple-spatialjob/src/main/resources/conf/ConvertShpFilterForLayer.xml svneol=native#text/xml diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractDgnFileJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractDgnFileJobContext.java new file mode 100644 index 0000000..313c4d2 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractDgnFileJobContext.java @@ -0,0 +1,71 @@ +package com.ximple.eofms.jobs; + +import java.util.Properties; + +import org.quartz.JobExecutionContext; + +import com.ximple.io.dgn7.Dgn7fileReader; + +public abstract class AbstractDgnFileJobContext +{ + /** + * Encoding of URL path. + */ + protected static final String ENCODING = "UTF-8"; + + private JobExecutionContext executionContext = null; + + protected String _dataPath = null; + protected Properties properties = null; + + private Dgn7fileReader reader = null; + private String filename = null; + + public AbstractDgnFileJobContext(String dataPath) + { + _dataPath = dataPath; + } + + public String getDataPath() + { + return _dataPath; + } + + public JobExecutionContext getExecutionContext() + { + return executionContext; + } + + public void setExecutionContext(JobExecutionContext context) + { + executionContext = context; + } + + public abstract void startTransaction(); + + public abstract void commitTransaction(); + + public abstract void rollbackTransaction(); + + public abstract String getDataOutPath(); + + public Dgn7fileReader getReader() + { + return this.reader; + } + + public void setReader(Dgn7fileReader reader) + { + this.reader = reader; + } + + public String getFilename() + { + return filename; + } + + public void setFilename(String filename) + { + this.filename = filename; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleDatabaseJob.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleDatabaseJob.java index 9df1ba5..79fdcf5 100644 --- a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleDatabaseJob.java +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleDatabaseJob.java @@ -155,4 +155,53 @@ return raw; } + public String getDataPath() + { + return _dataPath; + } + + public String getFilterPath() + { + return _filterPath; + } + + public String getOracleHost() + { + return _oracleHost; + } + + public String getOracleInstance() + { + return _oracleInstance; + } + + public String getOraclePort() + { + return _oraclePort; + } + + public String getUsername() + { + return _username; + } + + public String getPassword() + { + return _password; + } + + public ArrayList<String> getOriginSchema() + { + return _orgSchema; + } + + public boolean isTestMode() + { + return _testMode; + } + + public int getTestCount() + { + return _testCount; + } } diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleJobContext.java index 4be207f..a502127 100644 --- a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleJobContext.java +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleJobContext.java @@ -206,6 +206,7 @@ protected static final String STMT_CLEARCYCLEBIN = "PURGE RECYCLEBIN"; protected static final String SMTM_GRANTOBJECTTYPE = "GRANT EXECUTE ANY TYPE TO \"" + UDT_SCHEMA + "\""; protected static final long TIMEOUT = Long.MAX_VALUE; + /** * Encoding of URL path. */ @@ -286,6 +287,26 @@ _oraclePort = oraclePort; } + public String getDataPath() + { + return _dataPath; + } + + public String getOracleHost() + { + return _oracleHost; + } + + public String getOracleInstance() + { + return _oracleInstance; + } + + public String getOraclePort() + { + return _oraclePort; + } + public abstract void startTransaction(); public abstract void commitTransaction(); diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/GeneralDgnConvertJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/GeneralDgnConvertJobContext.java new file mode 100644 index 0000000..a2bf495 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/GeneralDgnConvertJobContext.java @@ -0,0 +1,43 @@ +package com.ximple.eofms.jobs; + +import java.io.File; + +public class GeneralDgnConvertJobContext extends AbstractDgnFileJobContext +{ + private final static String SHPOUTPATH = "shpout"; + private String dataOut = null; + + public GeneralDgnConvertJobContext(String dataPath) + { + super(dataPath); + } + + public void startTransaction() + { + } + + public void commitTransaction() + { + } + + public void rollbackTransaction() + { + } + + public String getDataOutPath() + { + if (dataOut == null) + { + File outPath = new File(getDataPath(), SHPOUTPATH); + if (!outPath.exists()) + { + outPath.mkdir(); + } else if (!outPath.isDirectory()) + { + outPath.mkdir(); + } + dataOut = getDataPath() + SHPOUTPATH; + } + return dataOut; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/IndexDgnConvertJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/IndexDgnConvertJobContext.java new file mode 100644 index 0000000..bdb7c76 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/IndexDgnConvertJobContext.java @@ -0,0 +1,269 @@ +package com.ximple.eofms.jobs; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.ArrayList; +import java.util.List; +import java.util.Iterator; +import java.net.MalformedURLException; + +import org.geotools.feature.Feature; +import org.geotools.feature.FeatureType; +import org.geotools.feature.SchemaException; +import org.geotools.feature.FeatureTypeBuilder; +import org.geotools.feature.AttributeTypeFactory; +import org.geotools.feature.FeatureTypeFactory; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SimpleFeature; +import org.geotools.data.FeatureWriter; +import org.geotools.data.Transaction; +import org.geotools.data.shapefile.ShapefileDataStore; +import org.apache.commons.transaction.memory.PessimisticMapWrapper; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.Coordinate; + +import com.ximple.io.dgn7.Dgn7fileReader; +import com.ximple.io.dgn7.Element; +import com.ximple.io.dgn7.FrammeAttributeData; +import com.ximple.io.dgn7.TextElement; +import com.ximple.io.dgn7.ShapeElement; +import com.ximple.io.dgn7.ComplexShapeElement; +import com.ximple.io.dgn7.UserAttributeData; +import com.ximple.eofms.filter.AbstractFLinkageDispatchableFilter; +import com.ximple.eofms.util.TPCLIDConverter; +import com.ximple.eofms.util.DefaultColorTable; +import com.ximple.eofms.util.StringUtils; + +public class IndexDgnConvertJobContext extends AbstractDgnFileJobContext +{ + static Log logger = LogFactory.getLog(IndexDgnConvertJobContext.class); + static GeometryFactory geometryFactory = new GeometryFactory(); + private final static String SHPOUTPATH = "shpout"; + + private String dataOut = null; + + private HashMap featuresContext = new HashMap(); + private HashMap featuresWriterContext = new HashMap(); + + private PessimisticMapWrapper txFeaturesContext; + private FeatureTypeBuilder typeBuilder = null; + private FeatureType featureType = null; + + public IndexDgnConvertJobContext(String dataPath) + { + super(dataPath); + } + + public void putFeatureCollection(Element element) throws IllegalAttributeException, SchemaException + { + if (!(element instanceof TextElement)) + { + return; + } + + Feature feature = createFeature((TextElement) element); + if (feature == null) + { + logger.info("cannot craete feature." + element.toString() + "'" + + ((TextElement) element).getText() + "'"); + return; + } + + if (!txFeaturesContext.containsKey(feature.getFeatureType())) + { + txFeaturesContext.put(feature.getFeatureType(), new ArrayList()); + } + ArrayList arrayList = (ArrayList) txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); + } + + public void startTransaction() + { + } + + public void commitTransaction() + { + if (!txFeaturesContext.isEmpty()) + { + logger.debug("Transaction size = " + txFeaturesContext.size()); + //txFeaturesContext.commitTransaction(); + } else + { + logger.debug("Transaction is empty."); + } + + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + public void rollbackTransaction() + { + //txFeaturesContext.rollbackTransaction(); + if (!featuresContext.isEmpty()) + { + updateDataStore(); + } + } + + private void updateDataStore() + { + Iterator it = featuresContext.keySet().iterator(); + + try + { + while (it.hasNext()) + { + FeatureType featureType = (FeatureType) it.next(); + File sfile = new File(getDataOutPath() + "\\" + featureType.getTypeName()); + logger.debug("Begin Save shapefile:" + sfile.toURI()); + + FeatureWriter writer = null; + if(featuresWriterContext.containsKey(featureType.getTypeName())) + { + writer = (FeatureWriter) featuresWriterContext.get(featureType.getTypeName()) ; + } + else + { + ShapefileDataStore shapefileDataStore = new ShapefileDataStore(sfile.toURI().toURL()); + shapefileDataStore.createSchema(featureType); + writer = shapefileDataStore.getFeatureWriter(featureType.getTypeName(), Transaction.AUTO_COMMIT); + if(this.featuresWriterContext == null) + { + this.featuresWriterContext = new HashMap(); + } + featuresWriterContext.put(featureType.getTypeName() , writer); + } + + ArrayList features = (ArrayList) featuresContext.get(featureType); + Iterator itFeature = features.iterator(); + while (itFeature.hasNext()) + { + Feature feature = (Feature) itFeature.next(); + ((SimpleFeature) writer.next()).setAttributes(feature.getAttributes(null)); + } + //writer.close(); + logger.debug("End Save shapefile:" + sfile.toURI()); + } + featuresContext.clear(); + } catch (MalformedURLException e) + { + logger.error(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + logger.error(e.getMessage(), e); + } catch (IOException e) + { + logger.error(e.getMessage(), e); + } + + } + + public String getDataOutPath() + { + if (dataOut == null) + { + File outPath = new File(getDataPath(), SHPOUTPATH); + if (!outPath.exists()) + { + outPath.mkdir(); + } else if (!outPath.isDirectory()) + { + outPath.mkdir(); + } + dataOut = getDataPath() + SHPOUTPATH; + } + return dataOut; + } + + public FeatureType createFeatureElement(String featureName) throws SchemaException + { + if (typeBuilder == null) + { + typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("GEOM", Geometry.class)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("X1", Double.class)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("Y1", Double.class)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("X2", Double.class)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("Y2", Double.class)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("TPCID", String.class)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("SYMCOLOR", String.class)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("SYMWEIGHT", Integer.class)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("SYMSTYLE", Integer.class)); + } + return typeBuilder.getFeatureType(); + } + + public Feature createFeature(FeatureType featureType, Element element) throws IllegalAttributeException + { + DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance(); + if (element instanceof TextElement) + { + TextElement textElm = (TextElement) element; + String tpclid = textElm.getText(); + + Envelope extent = TPCLIDConverter.convertTpclIdToEnvelope(tpclid); + Geometry geom = geometryFactory.createLinearRing(new Coordinate[] + { + new Coordinate(extent.getMinX(), extent.getMinY()), + new Coordinate(extent.getMaxX(), extent.getMinY()), + new Coordinate(extent.getMaxX(), extent.getMaxY()), + new Coordinate(extent.getMinX(), extent.getMaxY()), + new Coordinate(extent.getMinX(), extent.getMinY()), + }); + + TextElement textElement = (TextElement) element; + Feature feature = featureType.create(new Object[]{ + geom, + extent.getMinX(), + extent.getMinY(), + extent.getMaxX(), + extent.getMaxY(), + tpclid, + colorTable.getColorCode(textElement.getColorIndex()), + textElement.getWeight(), + textElement.getLineStyle() + }); + return feature; + } + return null; + } + + private Feature createFeature(TextElement element) throws SchemaException, IllegalAttributeException + { + if (featureType == null) + { + String dgnname = getFilename().toLowerCase(); + int i = dgnname.lastIndexOf("."); + if (i != -1) + { + dgnname = dgnname.substring(0, i); + } + featureType = createFeatureElement(dgnname); + } + return createFeature(featureType, element); + } + + protected FrammeAttributeData getFeatureLinkage(Element element) + { + if (!element.hasUserAttributeData()) + return null; + + List<UserAttributeData> usrDatas = element.getUserAttributeData(); + for (UserAttributeData anUsrData : usrDatas) + { + if (anUsrData instanceof FrammeAttributeData) + { + return (FrammeAttributeData) anUsrData; + } + } + return null; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2ShpJob.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2ShpJob.java index 7cf0442..82b14d9 100644 --- a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2ShpJob.java +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2ShpJob.java @@ -1,14 +1,21 @@ package com.ximple.eofms.jobs; import java.io.IOException; +import java.io.File; +import java.io.FilenameFilter; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.math.BigDecimal; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.nio.channels.FileChannel; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; import java.util.Date; +import java.util.List; +import java.util.Iterator; import org.apache.commons.collections.OrderedMap; import org.apache.commons.collections.OrderedMapIterator; @@ -18,8 +25,11 @@ import org.quartz.JobDetail; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; +import org.geotools.feature.IllegalAttributeException; +import org.geotools.feature.SchemaException; import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.Envelope; import oracle.jdbc.OracleConnection; import oracle.jdbc.OracleResultSet; @@ -28,11 +38,21 @@ import com.ximple.eofms.util.BinConverter; import com.ximple.eofms.util.ByteArrayCompressor; +import com.ximple.eofms.util.TPCLIDConverter; +import com.ximple.eofms.util.StringUtils; import com.ximple.io.dgn7.ComplexElement; import com.ximple.io.dgn7.Dgn7fileException; import com.ximple.io.dgn7.Element; import com.ximple.io.dgn7.ElementType; import com.ximple.io.dgn7.IElementHandler; +import com.ximple.io.dgn7.Dgn7fileReader; +import com.ximple.io.dgn7.Lock; +import com.ximple.io.dgn7.ComplexChainElement; +import com.ximple.io.dgn7.ComplexShapeElement; +import com.ximple.io.dgn7.TextNodeElement; +import com.ximple.io.dgn7.TextElement; +import com.ximple.io.dgn7.UserAttributeData; +import com.ximple.io.dgn7.FrammeAttributeData; import com.ximple.util.PrintfFormat; /** @@ -104,6 +124,9 @@ //close all open filewriter instance jobContext.closeFeatureWrite(); } + + convertIndexDesignFile(context); + convertOtherDesignFile(context); } catch (SQLException e) { logger.warn(e.getMessage(), e); @@ -115,7 +138,11 @@ } } - //Connectivity�ƻs�@�Ӫ����A�b�d�߹q�y��V�ɥΨӤ��OMS��Ʈw���q���s����(Connectivity) + /** + * Connectivity�ƻs�@�Ӫ����A�b�d�߹q�y��V�ɥΨӤ��OMS��Ʈw���q���s����(Connectivity) + * @param jobContext + * @throws SQLException + */ private void copyConnectivity(OracleConvertJobContext jobContext) throws SQLException { OracleConnection connection = jobContext.getOracleConnection(); @@ -421,4 +448,268 @@ return dgnElement; } + + /** + * �����ഫ�����ɪ��u�@ + * @param context �u�@�������� + */ + private void convertIndexDesignFile(JobExecutionContext context) throws JobExecutionException + { + File indexDir = new File(getDataPath(), "index"); + if (!indexDir.exists()) + { + logger.info("index dir=" + indexDir + " not exist."); + return; + } + + if (!indexDir.isDirectory()) + { + logger.info("index dir=" + indexDir + " is not a directory."); + } + + File[] dgnFiles = indexDir.listFiles(new FilenameFilter() + { + public boolean accept(File dir, String name) + { + return name.toLowerCase().endsWith(".dgn"); + } + }); + + for (File dgnFile : dgnFiles) + { + IndexDgnConvertJobContext convertContext = new IndexDgnConvertJobContext(getDataPath()); + try + { + convertContext.setExecutionContext(context); + String dgnPaths[] = StringUtils.splitToArray(dgnFile.toString(), File.pathSeparator); + convertContext.setFilename(dgnPaths[dgnPaths.length - 1]); + + FileInputStream fs = new FileInputStream(dgnFile); + FileChannel fc = fs.getChannel(); + Dgn7fileReader reader = new Dgn7fileReader(fc, new Lock()); + convertContext.setReader(reader); + + scanIndexDgnElement(convertContext); + + convertContext.commitTransaction(); + } catch (FileNotFoundException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (Dgn7fileException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IOException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (IllegalAttributeException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } catch (SchemaException e) + { + convertContext.rollbackTransaction(); + logger.warn(e.getMessage(), e); + throw new JobExecutionException(e.getMessage(), e); + } + } + } + + protected void scanIndexDgnElement(IndexDgnConvertJobContext convertContext) + throws Dgn7fileException, IOException, IllegalAttributeException, SchemaException + { + Dgn7fileReader reader = convertContext.getReader(); + int count = 0; + Element lastComplex = null; + while (reader.hasNext()) + { + Dgn7fileReader.Record record = reader.nextElement(); + if (record.element() != null) + { + Element element = (Element) record.element(); + ElementType type = element.getElementType(); + + if ((!type.isComplexElement()) && (!element.isComponentElement())) + { + lastComplex = null; + + processElement(element, convertContext); + } else if (element.isComponentElement()) + { + if (lastComplex != null) + { + ((ComplexElement) lastComplex).add(element); + } + } else if (type.isComplexElement()) + { + if (lastComplex == null) + { + lastComplex = element; + } else + { + processElement(element, convertContext); + lastComplex = element; + } + } + } + count++; + } + + logger.debug("ElementRecord Count=" + count); + } + + private void processElement(Element element, IndexDgnConvertJobContext convertContext) throws IllegalAttributeException, SchemaException + { + if (element instanceof TextElement) + { + convertContext.putFeatureCollection(element); + } + } + + + /** + * �����ഫ��L�]�p���ɪ��u�@ + * @param context + */ + private void convertOtherDesignFile(JobExecutionContext context) + { + File otherDir = new File(getDataPath(), "other"); + if (!otherDir.exists()) + { + logger.info("index dir=" + otherDir + " not exist."); + return; + } + + if (!otherDir.isDirectory()) + { + logger.info("index dir=" + otherDir + " is not a directory."); + } + + File[] dgnFiles = otherDir.listFiles(new FilenameFilter() + { + public boolean accept(File dir, String name) + { + return name.toLowerCase().endsWith(".dgn"); + } + }); + + for (File dgnFile : dgnFiles) + { + GeneralDgnConvertJobContext convertContext = new GeneralDgnConvertJobContext(getDataPath()); + convertContext.setExecutionContext(context); + } + } + + public void scanOtherDgnElement(GeneralDgnConvertJobContext convertContext) throws Dgn7fileException, IOException + { + Dgn7fileReader reader = convertContext.getReader(); + int count = 0; + Element lastComplex = null; + while (reader.hasNext()) + { + Dgn7fileReader.Record record = reader.nextElement(); + if (record.element() != null) + { + Element element = (Element) record.element(); + ElementType type = element.getElementType(); + + if ((!type.isComplexElement()) && (!element.isComponentElement())) + { + if (lastComplex != null) + { + // @todo add process in here + lastComplex = null; + } + + // @todo add process in here + } else if (element.isComponentElement()) + { + if (lastComplex != null) + { + ((ComplexElement) lastComplex).add(element); + } + } else if (type.isComplexElement()) + { + if (lastComplex == null) + { + lastComplex = element; + } else + { + // @todo add process in here + lastComplex = element; + } + } + + if (element.getElementType().isComplexElement()) + { + if (element instanceof ComplexChainElement) + { + ComplexChainElement complexChain = (ComplexChainElement) element; + int size = complexChain.size(); + for (Object aComplexChain : complexChain) + { + Element subElement = (Element) aComplexChain; + subElement.getType(); + } + } + + if (element instanceof ComplexShapeElement) + { + ComplexShapeElement complexShape = (ComplexShapeElement) element; + } + + if (element instanceof TextNodeElement) + { + TextNodeElement textNode = (TextNodeElement) element; + int size = textNode.size(); + for (int i = 0; i < size; i++) + { + Element subElement = (Element) textNode.get(i); + subElement.getElementType(); + } + } + + } else + { + boolean hasLinkage = false; + if (element instanceof TextElement) + { + TextElement textElm = (TextElement) element; + List<UserAttributeData> usrData = textElm.getUserAttributeData(); + Iterator<UserAttributeData> it = usrData.iterator(); + while (it.hasNext()) + { + UserAttributeData attr = it.next(); + if (attr instanceof FrammeAttributeData) + { + hasLinkage = true; + System.out.println("------------------------------------------"); + System.out.println("FSC=" + ((FrammeAttributeData) attr).getFsc() + ":" + + ((FrammeAttributeData) attr).getUfid()); + } + } + + if (hasLinkage) + { + System.out.println("Text.Font=" + textElm.getFontIndex()); + System.out.println("Text.Just=" + textElm.getJustification()); + System.out.println("usrData.len=" + usrData.size()); + System.out.println("text=" + textElm.getText()); + System.out.println("Origin=" + textElm.getOrigin()); + System.out.println("UserOrigin=" + textElm.getUserOrigin()); + } + } + } + } + count++; + } + + logger.info("ElementRecord Count=" + count); + } } diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertJobContext.java index 66e41ce..163163b 100644 --- a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertJobContext.java +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertJobContext.java @@ -42,6 +42,8 @@ static Log logger = LogFactory.getLog(OracleConvertJobContext.class); static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); + private static final String SHPOUTPATH = "shpout"; + static { try @@ -62,6 +64,8 @@ private PessimisticMapWrapper txFeaturesContext; private JobExecutionContext executionContext; + + private String dataOut = null; public OracleConvertJobContext(String filterConfig) { @@ -116,7 +120,7 @@ public void putFeatureCollection(Element element) { - //�P�_�O�_�ũM���� + // �P�_�O�_�ũM���� Feature feature = elementDispatcher.execute(element); if (feature == null) { @@ -170,15 +174,14 @@ private void updateDataStore() { - // todo: - Iterator it = featuresContext.keySet().iterator(); + Iterator it = featuresContext.keySet().iterator(); try { while (it.hasNext()) { FeatureType featureType = (FeatureType) it.next(); - File sfile = new File(_dataPath + "\\" + featureType.getTypeName()); + File sfile = new File(getDataOutPath() + "\\" + featureType.getTypeName()); logger.debug("Begin Save shapefile:" + sfile.toURI()); FeatureWriter writer = null; @@ -232,6 +235,10 @@ executionContext = context; } + /** + * �����]�Ƽg�J�� + * @throws IOException IO�o�Ϳ��~ + */ public void closeFeatureWrite() throws IOException { Iterator iter = this.featuresWriterContext.values().iterator(); @@ -243,4 +250,25 @@ this.featuresWriterContext = null; } + + /** + * ���o��ƿ�X���| + * @return ���|���r�� + */ + public String getDataOutPath() + { + if (dataOut == null) + { + File outPath = new File(getDataPath(), SHPOUTPATH); + if (!outPath.exists()) + { + outPath.mkdir(); + } else if (!outPath.isDirectory()) + { + outPath.mkdir(); + } + dataOut = getDataPath() + SHPOUTPATH; + } + return dataOut; + } } diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Base64.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Base64.java new file mode 100644 index 0000000..13d7c92 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Base64.java @@ -0,0 +1,551 @@ +package com.ximple.eofms.util; + +import java.util.Arrays; + +public class Base64 +{ + private static final char[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray(); + private static final int[] IA = new int[256]; + + static + { + Arrays.fill(IA, -1); + for (int i = 0, iS = CA.length; i < iS; i++) + IA[CA[i]] = i; + IA['='] = 0; + } + + // **************************************************************************************** + // * char[] version + // **************************************************************************************** + + /** + * Encodes a raw byte array into a BASE64 <code>char[]</code> representation i accordance with RFC 2045. + * + * @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned. + * @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br> + * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a + * little faster. + * @return A BASE64 encoded array. Never <code>null</code>. + */ + public static char[] encodeToChar(byte[] sArr, boolean lineSep) + { + // Check special case + int sLen = sArr != null ? sArr.length : 0; + if (sLen == 0) + return new char[0]; + + int eLen = (sLen / 3) * 3; // Length of even 24-bits. + int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count + int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array + char[] dArr = new char[dLen]; + + // Encode even 24-bits + for (int s = 0, d = 0, cc = 0; s < eLen;) + { + // Copy next three bytes into lower 24 bits of int, paying attension to sign. + int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff); + + // Encode the int into four chars + dArr[d++] = CA[(i >>> 18) & 0x3f]; + dArr[d++] = CA[(i >>> 12) & 0x3f]; + dArr[d++] = CA[(i >>> 6) & 0x3f]; + dArr[d++] = CA[i & 0x3f]; + + // Add optional line separator + if (lineSep && ++cc == 19 && d < dLen - 2) + { + dArr[d++] = '\r'; + dArr[d++] = '\n'; + cc = 0; + } + } + + // Pad and encode last bits if source isn't even 24 bits. + int left = sLen - eLen; // 0 - 2. + if (left > 0) + { + // Prepare the int + int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0); + + // Set last four chars + dArr[dLen - 4] = CA[i >> 12]; + dArr[dLen - 3] = CA[(i >>> 6) & 0x3f]; + dArr[dLen - 2] = left == 2 ? CA[i & 0x3f] : '='; + dArr[dLen - 1] = '='; + } + return dArr; + } + + /** + * Decodes a BASE64 encoded char array. All illegal characters will be ignored and can handle both arrays with + * and without line separators. + * + * @param sArr The source array. <code>null</code> or length 0 will return an empty array. + * @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters + * (including '=') isn't divideable by 4. (I.e. definitely corrupted). + */ + public static byte[] decode(char[] sArr) + { + // Check special case + int sLen = sArr != null ? sArr.length : 0; + if (sLen == 0) + return new byte[0]; + + // Count illegal characters (including '\r', '\n') to know what size the returned array will be, + // so we don't have to reallocate & copy it later. + int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...) + for (int i = 0; i < sLen; i++) // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out. + if (IA[sArr[i]] < 0) + sepCnt++; + + // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045. + if ((sLen - sepCnt) % 4 != 0) + return null; + + int pad = 0; + for (int i = sLen; i > 1 && IA[sArr[--i]] <= 0;) + if (sArr[i] == '=') + pad++; + + int len = ((sLen - sepCnt) * 6 >> 3) - pad; + + byte[] dArr = new byte[len]; // Preallocate byte[] of exact length + + for (int s = 0, d = 0; d < len;) + { + // Assemble three bytes into an int from four "valid" characters. + int i = 0; + for (int j = 0; j < 4; j++) + { // j only increased if a valid char was found. + int c = IA[sArr[s++]]; + if (c >= 0) + i |= c << (18 - j * 6); + else + j--; + } + // Add the bytes + dArr[d++] = (byte) (i >> 16); + if (d < len) + { + dArr[d++] = (byte) (i >> 8); + if (d < len) + dArr[d++] = (byte) i; + } + } + return dArr; + } + + /** + * Decodes a BASE64 encoded char array that is known to be resonably well formatted. The method is about twice as + * fast as {@link #decode(char[])}. The preconditions are:<br> + * + The array must have a line length of 76 chars OR no line separators at all (one line).<br> + * + Line separator must be "\r\n", as specified in RFC 2045 + * + The array must not contain illegal characters within the encoded string<br> + * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br> + * + * @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception. + * @return The decoded array of bytes. May be of length 0. + */ + public byte[] decodeFast(char[] sArr) + { + // Check special case + int sLen = sArr.length; + if (sLen == 0) + return new byte[0]; + + int sIx = 0, eIx = sLen - 1; // Start and end index after trimming. + + // Trim illegal chars from start + while (sIx < eIx && IA[sArr[sIx]] < 0) + sIx++; + + // Trim illegal chars from end + while (eIx > 0 && IA[sArr[eIx]] < 0) + eIx--; + + // get the padding count (=) (0, 1 or 2) + int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end. + int cCnt = eIx - sIx + 1; // Content count including possible separators + int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0; + + int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes + byte[] dArr = new byte[len]; // Preallocate byte[] of exact length + + // Decode all but the last 0 - 2 bytes. + int d = 0; + for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) + { + // Assemble three bytes into an int from four "valid" characters. + int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]]; + + // Add the bytes + dArr[d++] = (byte) (i >> 16); + dArr[d++] = (byte) (i >> 8); + dArr[d++] = (byte) i; + + // If line separator, jump over it. + if (sepCnt > 0 && ++cc == 19) + { + sIx += 2; + cc = 0; + } + } + + if (d < len) + { + // Decode last 1-3 bytes (incl '=') into 1-3 bytes + int i = 0; + for (int j = 0; sIx <= eIx - pad; j++) + i |= IA[sArr[sIx++]] << (18 - j * 6); + + for (int r = 16; d < len; r -= 8) + dArr[d++] = (byte) (i >> r); + } + + return dArr; + } + + // **************************************************************************************** + // * byte[] version + // **************************************************************************************** + + /** + * Encodes a raw byte array into a BASE64 <code>byte[]</code> representation i accordance with RFC 2045. + * + * @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned. + * @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br> + * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a + * little faster. + * @return A BASE64 encoded array. Never <code>null</code>. + */ + public static byte[] encodeToByte(byte[] sArr, boolean lineSep) + { + // Check special case + int sLen = sArr != null ? sArr.length : 0; + if (sLen == 0) + return new byte[0]; + + int eLen = (sLen / 3) * 3; // Length of even 24-bits. + int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count + int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array + byte[] dArr = new byte[dLen]; + + // Encode even 24-bits + for (int s = 0, d = 0, cc = 0; s < eLen;) + { + // Copy next three bytes into lower 24 bits of int, paying attension to sign. + int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff); + + // Encode the int into four chars + dArr[d++] = (byte) CA[(i >>> 18) & 0x3f]; + dArr[d++] = (byte) CA[(i >>> 12) & 0x3f]; + dArr[d++] = (byte) CA[(i >>> 6) & 0x3f]; + dArr[d++] = (byte) CA[i & 0x3f]; + + // Add optional line separator + if (lineSep && ++cc == 19 && d < dLen - 2) + { + dArr[d++] = '\r'; + dArr[d++] = '\n'; + cc = 0; + } + } + + // Pad and encode last bits if source isn't an even 24 bits. + int left = sLen - eLen; // 0 - 2. + if (left > 0) + { + // Prepare the int + int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0); + + // Set last four chars + dArr[dLen - 4] = (byte) CA[i >> 12]; + dArr[dLen - 3] = (byte) CA[(i >>> 6) & 0x3f]; + dArr[dLen - 2] = left == 2 ? (byte) CA[i & 0x3f] : (byte) '='; + dArr[dLen - 1] = '='; + } + return dArr; + } + + /** + * Decodes a BASE64 encoded byte array. All illegal characters will be ignored and can handle both arrays with + * and without line separators. + * + * @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception. + * @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters + * (including '=') isn't divideable by 4. (I.e. definitely corrupted). + */ + public static byte[] decode(byte[] sArr) + { + // Check special case + int sLen = sArr.length; + + // Count illegal characters (including '\r', '\n') to know what size the returned array will be, + // so we don't have to reallocate & copy it later. + int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...) + for (int i = 0; i < sLen; i++) // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out. + if (IA[sArr[i] & 0xff] < 0) + sepCnt++; + + // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045. + if ((sLen - sepCnt) % 4 != 0) + return null; + + int pad = 0; + for (int i = sLen; i > 1 && IA[sArr[--i] & 0xff] <= 0;) + if (sArr[i] == '=') + pad++; + + int len = ((sLen - sepCnt) * 6 >> 3) - pad; + + byte[] dArr = new byte[len]; // Preallocate byte[] of exact length + + for (int s = 0, d = 0; d < len;) + { + // Assemble three bytes into an int from four "valid" characters. + int i = 0; + for (int j = 0; j < 4; j++) + { // j only increased if a valid char was found. + int c = IA[sArr[s++] & 0xff]; + if (c >= 0) + i |= c << (18 - j * 6); + else + j--; + } + + // Add the bytes + dArr[d++] = (byte) (i >> 16); + if (d < len) + { + dArr[d++] = (byte) (i >> 8); + if (d < len) + dArr[d++] = (byte) i; + } + } + + return dArr; + } + + + /** + * Decodes a BASE64 encoded byte array that is known to be resonably well formatted. The method is about twice as + * fast as {@link #decode(byte[])}. The preconditions are:<br> + * + The array must have a line length of 76 chars OR no line separators at all (one line).<br> + * + Line separator must be "\r\n", as specified in RFC 2045 + * + The array must not contain illegal characters within the encoded string<br> + * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br> + * + * @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception. + * @return The decoded array of bytes. May be of length 0. + */ + public static byte[] decodeFast(byte[] sArr) + { + // Check special case + int sLen = sArr.length; + if (sLen == 0) + return new byte[0]; + + int sIx = 0, eIx = sLen - 1; // Start and end index after trimming. + + // Trim illegal chars from start + while (sIx < eIx && IA[sArr[sIx] & 0xff] < 0) + sIx++; + + // Trim illegal chars from end + while (eIx > 0 && IA[sArr[eIx] & 0xff] < 0) + eIx--; + + // get the padding count (=) (0, 1 or 2) + int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end. + int cCnt = eIx - sIx + 1; // Content count including possible separators + int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0; + + int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes + byte[] dArr = new byte[len]; // Preallocate byte[] of exact length + + // Decode all but the last 0 - 2 bytes. + int d = 0; + for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) + { + // Assemble three bytes into an int from four "valid" characters. + int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]]; + + // Add the bytes + dArr[d++] = (byte) (i >> 16); + dArr[d++] = (byte) (i >> 8); + dArr[d++] = (byte) i; + + // If line separator, jump over it. + if (sepCnt > 0 && ++cc == 19) + { + sIx += 2; + cc = 0; + } + } + + if (d < len) + { + // Decode last 1-3 bytes (incl '=') into 1-3 bytes + int i = 0; + for (int j = 0; sIx <= eIx - pad; j++) + i |= IA[sArr[sIx++]] << (18 - j * 6); + + for (int r = 16; d < len; r -= 8) + dArr[d++] = (byte) (i >> r); + } + + return dArr; + } + + // **************************************************************************************** + // * String version + // **************************************************************************************** + + /** + * Encodes a raw byte array into a BASE64 <code>String</code> representation i accordance with RFC 2045. + * + * @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned. + * @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br> + * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a + * little faster. + * @return A BASE64 encoded array. Never <code>null</code>. + */ + public static String encodeToString(byte[] sArr, boolean lineSep) + { + // Reuse char[] since we can't create a String incrementally anyway and StringBuffer/Builder would be slower. + return new String(encodeToChar(sArr, lineSep)); + } + + /** + * Decodes a BASE64 encoded <code>String</code>. All illegal characters will be ignored and can handle both strings with + * and without line separators.<br> + * <b>Note!</b> It can be up to about 2x the speed to call <code>decode(str.toCharArray())</code> instead. That + * will create a temporary array though. This version will use <code>str.charAt(i)</code> to iterate the string. + * + * @param str The source string. <code>null</code> or length 0 will return an empty array. + * @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters + * (including '=') isn't divideable by 4. (I.e. definitely corrupted). + */ + public static byte[] decode(String str) + { + // Check special case + int sLen = str != null ? str.length() : 0; + if (sLen == 0) + return new byte[0]; + + // Count illegal characters (including '\r', '\n') to know what size the returned array will be, + // so we don't have to reallocate & copy it later. + int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...) + for (int i = 0; i < sLen; i++) // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out. + if (IA[str.charAt(i)] < 0) + sepCnt++; + + // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045. + if ((sLen - sepCnt) % 4 != 0) + return null; + + // Count '=' at end + int pad = 0; + for (int i = sLen; i > 1 && IA[str.charAt(--i)] <= 0;) + if (str.charAt(i) == '=') + pad++; + + int len = ((sLen - sepCnt) * 6 >> 3) - pad; + + byte[] dArr = new byte[len]; // Preallocate byte[] of exact length + + for (int s = 0, d = 0; d < len;) + { + // Assemble three bytes into an int from four "valid" characters. + int i = 0; + for (int j = 0; j < 4; j++) + { // j only increased if a valid char was found. + int c = IA[str.charAt(s++)]; + if (c >= 0) + i |= c << (18 - j * 6); + else + j--; + } + // Add the bytes + dArr[d++] = (byte) (i >> 16); + if (d < len) + { + dArr[d++] = (byte) (i >> 8); + if (d < len) + dArr[d++] = (byte) i; + } + } + return dArr; + } + + /** + * Decodes a BASE64 encoded string that is known to be resonably well formatted. The method is about twice as + * fast as {@link #decode(String)}. The preconditions are:<br> + * + The array must have a line length of 76 chars OR no line separators at all (one line).<br> + * + Line separator must be "\r\n", as specified in RFC 2045 + * + The array must not contain illegal characters within the encoded string<br> + * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br> + * + * @param s The source string. Length 0 will return an empty array. <code>null</code> will throw an exception. + * @return The decoded array of bytes. May be of length 0. + */ + public static byte[] decodeFast(String s) + { + // Check special case + int sLen = s.length(); + if (sLen == 0) + return new byte[0]; + + int sIx = 0, eIx = sLen - 1; // Start and end index after trimming. + + // Trim illegal chars from start + while (sIx < eIx && IA[s.charAt(sIx) & 0xff] < 0) + sIx++; + + // Trim illegal chars from end + while (eIx > 0 && IA[s.charAt(eIx) & 0xff] < 0) + eIx--; + + // get the padding count (=) (0, 1 or 2) + int pad = s.charAt(eIx) == '=' ? (s.charAt(eIx - 1) == '=' ? 2 : 1) : 0; // Count '=' at end. + int cCnt = eIx - sIx + 1; // Content count including possible separators + int sepCnt = sLen > 76 ? (s.charAt(76) == '\r' ? cCnt / 78 : 0) << 1 : 0; + + int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes + byte[] dArr = new byte[len]; // Preallocate byte[] of exact length + + // Decode all but the last 0 - 2 bytes. + int d = 0; + for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) + { + // Assemble three bytes into an int from four "valid" characters. + int i = IA[s.charAt(sIx++)] << 18 | IA[s.charAt(sIx++)] << 12 | IA[s.charAt(sIx++)] << 6 | IA[s.charAt(sIx++)]; + + // Add the bytes + dArr[d++] = (byte) (i >> 16); + dArr[d++] = (byte) (i >> 8); + dArr[d++] = (byte) i; + + // If line separator, jump over it. + if (sepCnt > 0 && ++cc == 19) + { + sIx += 2; + cc = 0; + } + } + + if (d < len) + { + // Decode last 1-3 bytes (incl '=') into 1-3 bytes + int i = 0; + for (int j = 0; sIx <= eIx - pad; j++) + i |= IA[s.charAt(sIx++)] << (18 - j * 6); + + for (int r = 16; d < len; r -= 8) + dArr[d++] = (byte) (i >> r); + } + + return dArr; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/StringUtils.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/StringUtils.java new file mode 100644 index 0000000..06e869a --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/StringUtils.java @@ -0,0 +1,2923 @@ +package com.ximple.eofms.util; + +import java.util.Map; +import java.util.HashMap; +import java.util.Set; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Collection; +import java.util.Locale; +import java.util.regex.Pattern; +import java.util.regex.Matcher; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CharacterCodingException; +import java.nio.CharBuffer; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.lang.reflect.Array; +import java.text.BreakIterator; + +public abstract class StringUtils +{ + public static String ENCODING_US_ASCII = "US-ASCII"; + public static String ENCODING_ISO_8859_1 = "ISO-8859-1"; + public static String ENCODING_ISO_8859_2 = "ISO-8859-2"; + public static String ENCODING_ISO_8859_5 = "ISO-8859-5"; + public static String ENCODING_UTF_8 = "UTF-8"; + public static String ENCODING_UTF_16BE = "UTF-16BE"; + public static String ENCODING_UTF_16LE = "UTF-16LE"; + public static String ENCODING_UTF_16 = "UTF-16"; + + public static Charset CHARSET_US_ASCII = Charset.forName(StringUtils.ENCODING_US_ASCII); + + public static final Pattern BBCODE_COLOR = Pattern.compile("\\[color\\s*=\\s*([#\\w]*)\\s*\\]", Pattern.CASE_INSENSITIVE); + public static final Pattern BBCODE_SIZE = Pattern.compile("\\[size\\s*=\\s*([+\\-]?[0-9]*)\\s*\\]", Pattern.CASE_INSENSITIVE); + public static final Pattern BBCODE_URL_SHORT = Pattern.compile("\\[url\\]\\s*([^\\s]*)\\s*\\[\\/url\\]", Pattern.CASE_INSENSITIVE); + public static final Pattern BBCODE_URL_LONG = Pattern.compile("\\[url=([^\\[]*)\\]([^\\[]*)\\[/url\\]", Pattern.CASE_INSENSITIVE); + public static final Pattern BBCODE_IMG = Pattern.compile("\\[img\\]\\s*([^\\s]*)\\s*\\[\\/img\\]", Pattern.CASE_INSENSITIVE); + public static final Pattern BBCODE_QUOTE_LONG = Pattern.compile("\\[quote=([^\\]]+\\]*)\\]", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); + public static final Pattern BBCODE_BAREURL = Pattern.compile("(?:[^\"'=>\\]]|^)((?:http|ftp)s?://(?:%[\\p{Digit}A-Fa-f][\\p{Digit}A-Fa-f]|[\\-_\\.!~*';\\|/?:@#&=\\+$,\\p{Alnum}])+)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); + + private static final Map<Character, String> AGGRESSIVE_HTML_ENCODE_MAP = new HashMap<Character, String>(); + private static final Map<Character, String> DEFENSIVE_HTML_ENCODE_MAP = new HashMap<Character, String>(); + private static final Map<Character, String> XML_ENCODE_MAP = new HashMap<Character, String>(); + private static final Map<Character, String> STRING_ENCODE_MAP = new HashMap<Character, String>(); + private static final Map<Character, String> SQL_ENCODE_MAP = new HashMap<Character, String>(); + private static final Map<Character, String> LATEX_ENCODE_MAP = new HashMap<Character, String>(); + + private static final Map<String, Character> HTML_DECODE_MAP = new HashMap<String, Character>(); + + private static final HtmlEncoderFallbackHandler HTML_ENCODER_FALLBACK = new HtmlEncoderFallbackHandler(); + + static + { + // Html encoding mapping according to the HTML 4.0 spec + // http://www.w3.org/TR/REC-html40/sgml/entities.html + + // Special characters for HTML + AGGRESSIVE_HTML_ENCODE_MAP.put('\u0026',"&"); + AGGRESSIVE_HTML_ENCODE_MAP.put('\u003C',"<"); + AGGRESSIVE_HTML_ENCODE_MAP.put('\u003E',">"); + AGGRESSIVE_HTML_ENCODE_MAP.put('\u0022',"""); + + DEFENSIVE_HTML_ENCODE_MAP.put('\u0152',"Œ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0153',"œ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0160',"Š"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0161',"š"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0178',"Ÿ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u02C6',"ˆ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u02DC',"˜"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2002'," "); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2003'," "); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2009'," "); + DEFENSIVE_HTML_ENCODE_MAP.put('\u200C',"‌"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u200D',"‍"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u200E',"‎"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u200F',"‏"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2013',"–"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2014',"—"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2018',"‘"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2019',"’"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u201A',"‚"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u201C',"“"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u201D',"”"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u201E',"„"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2020',"†"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2021',"‡"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2030',"‰"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2039',"‹"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u203A',"›"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u20AC',"€"); + + // Character entity references for ISO 8859-1 characters + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A0'," "); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A1',"¡"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A2',"¢"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A3',"£"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A4',"¤"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A5',"¥"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A6',"¦"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A7',"§"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A8',"¨"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00A9',"©"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00AA',"ª"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00AB',"«"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00AC',"¬"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00AD',"­"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00AE',"®"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00AF',"¯"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B0',"°"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B1',"±"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B2',"²"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B3',"³"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B4',"´"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B5',"µ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B6',"¶"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B7',"·"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B8',"¸"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00B9',"¹"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00BA',"º"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00BB',"»"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00BC',"¼"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00BD',"½"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00BE',"¾"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00BF',"¿"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C0',"À"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C1',"Á"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C2',"Â"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C3',"Ã"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C4',"Ä"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C5',"Å"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C6',"Æ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C7',"Ç"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C8',"È"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00C9',"É"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00CA',"Ê"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00CB',"Ë"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00CC',"Ì"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00CD',"Í"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00CE',"Î"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00CF',"Ï"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D0',"Ð"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D1',"Ñ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D2',"Ò"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D3',"Ó"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D4',"Ô"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D5',"Õ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D6',"Ö"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D7',"×"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D8',"Ø"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00D9',"Ù"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00DA',"Ú"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00DB',"Û"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00DC',"Ü"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00DD',"Ý"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00DE',"Þ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00DF',"ß"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E0',"à"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E1',"á"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E2',"â"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E3',"ã"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E4',"ä"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E5',"å"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E6',"æ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E7',"ç"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E8',"è"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00E9',"é"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00EA',"ê"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00EB',"ë"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00EC',"ì"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00ED',"í"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00EE',"î"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00EF',"ï"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F0',"ð"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F1',"ñ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F2',"ò"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F3',"ó"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F4',"ô"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F5',"õ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F6',"ö"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F7',"÷"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F8',"ø"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00F9',"ù"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00FA',"ú"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00FB',"û"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00FC',"ü"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00FD',"ý"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00FE',"þ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u00FF',"ÿ"); + + // Mathematical, Greek and Symbolic characters for HTML + DEFENSIVE_HTML_ENCODE_MAP.put('\u0192',"ƒ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0391',"Α"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0392',"Β"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0393',"Γ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0394',"Δ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0395',"Ε"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0396',"Ζ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0397',"Η"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0398',"Θ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u0399',"Ι"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u039A',"Κ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u039B',"Λ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u039C',"Μ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u039D',"Ν"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u039E',"Ξ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u039F',"Ο"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03A0',"Π"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03A1',"Ρ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03A3',"Σ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03A4',"Τ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03A5',"Υ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03A6',"Φ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03A7',"Χ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03A8',"Ψ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03A9',"Ω"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03B1',"α"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03B2',"β"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03B3',"γ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03B4',"δ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03B5',"ε"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03B6',"ζ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03B7',"η"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03B8',"θ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03B9',"ι"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03BA',"κ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03BB',"λ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03BC',"μ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03BD',"ν"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03BE',"ξ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03BF',"ο"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C0',"π"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C1',"ρ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C2',"ς"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C3',"σ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C4',"τ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C5',"υ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C6',"φ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C7',"χ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C8',"ψ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03C9',"ω"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03D1',"ϑ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03D2',"ϒ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u03D6',"ϖ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2022',"•"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2026',"…"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2032',"′"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2033',"″"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u203E',"‾"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2044',"⁄"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2118',"℘"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2111',"ℑ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u211C',"ℜ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2122',"™"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2135',"ℵ"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2190',"←"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2191',"↑"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2192',"→"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2193',"↓"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2194',"↔"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u21B5',"↵"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u21D0',"⇐"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u21D1',"⇑"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u21D2',"⇒"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u21D3',"⇓"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u21D4',"⇔"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2200',"∀"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2202',"∂"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2203',"∃"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2205',"∅"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2207',"∇"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2208',"∈"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2209',"∉"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u220B',"∋"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u220F',"∏"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2211',"∑"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2212',"−"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2217',"∗"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u221A',"√"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u221D',"∝"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u221E',"∞"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2220',"∠"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2227',"∧"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2228',"∨"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2229',"∩"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u222A',"∪"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u222B',"∫"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2234',"∴"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u223C',"∼"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2245',"≅"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2248',"≈"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2260',"≠"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2261',"≡"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2264',"≤"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2265',"≥"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2282',"⊂"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2283',"⊃"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2284',"⊄"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2286',"⊆"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2287',"⊇"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2295',"⊕"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2297',"⊗"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u22A5',"⊥"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u22C5',"⋅"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2308',"⌈"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2309',"⌉"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u230A',"⌊"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u230B',"⌋"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2329',"⟨"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u232A',"⟩"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u25CA',"◊"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2660',"♠"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2663',"♣"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2665',"♥"); + DEFENSIVE_HTML_ENCODE_MAP.put('\u2666',"♦"); + + Set<Map.Entry<Character, String>> aggresive_entries = AGGRESSIVE_HTML_ENCODE_MAP.entrySet(); + for (Map.Entry<Character, String> entry : aggresive_entries) + { + HTML_DECODE_MAP.put(entry.getValue(), entry.getKey()); + } + + Set<Map.Entry<Character, String>> defensive_entries = DEFENSIVE_HTML_ENCODE_MAP.entrySet(); + for (Map.Entry<Character, String> entry : defensive_entries) + { + HTML_DECODE_MAP.put(entry.getValue(), entry.getKey()); + } + + XML_ENCODE_MAP.put('\u0026',"&"); + XML_ENCODE_MAP.put('\'',"'"); + XML_ENCODE_MAP.put('\u0022',"""); + XML_ENCODE_MAP.put('\u003C',"<"); + XML_ENCODE_MAP.put('\u003E',">"); + + SQL_ENCODE_MAP.put('\'',"''"); + + STRING_ENCODE_MAP.put('\\',"\\\\"); + STRING_ENCODE_MAP.put('\n',"\\n"); + STRING_ENCODE_MAP.put('\r',"\\r"); + STRING_ENCODE_MAP.put('\t',"\\t"); + STRING_ENCODE_MAP.put('"',"\\\""); + + LATEX_ENCODE_MAP.put('\\',"\\\\"); + LATEX_ENCODE_MAP.put('#',"\\#"); + LATEX_ENCODE_MAP.put('$',"\\$"); + LATEX_ENCODE_MAP.put('%',"\\%"); + LATEX_ENCODE_MAP.put('&',"\\&"); + LATEX_ENCODE_MAP.put('~',"\\~"); + LATEX_ENCODE_MAP.put('_',"\\_"); + LATEX_ENCODE_MAP.put('^',"\\^"); + LATEX_ENCODE_MAP.put('{',"\\{"); + LATEX_ENCODE_MAP.put('}',"\\}"); + LATEX_ENCODE_MAP.put('\u00A1',"!'"); + LATEX_ENCODE_MAP.put('\u00BF',"?'"); + LATEX_ENCODE_MAP.put('\u00C0',"\\`{A}"); + LATEX_ENCODE_MAP.put('\u00C1',"\\'{A}"); + LATEX_ENCODE_MAP.put('\u00C2',"\\^{A}"); + LATEX_ENCODE_MAP.put('\u00C3',"\\H{A}"); + LATEX_ENCODE_MAP.put('\u00C4',"\\\"{A}"); + LATEX_ENCODE_MAP.put('\u00C5',"\\AA"); + LATEX_ENCODE_MAP.put('\u00C6',"\\AE"); + LATEX_ENCODE_MAP.put('\u00C7',"\\c{C}"); + LATEX_ENCODE_MAP.put('\u00C8',"\\`{E}"); + LATEX_ENCODE_MAP.put('\u00C9',"\\'{E}"); + LATEX_ENCODE_MAP.put('\u00CA',"\\^{E}"); + LATEX_ENCODE_MAP.put('\u00CB',"\\\"{E}"); + LATEX_ENCODE_MAP.put('\u00CC',"\\`{I}"); + LATEX_ENCODE_MAP.put('\u00CD',"\\'{I}"); + LATEX_ENCODE_MAP.put('\u00CE',"\\^{I}"); + LATEX_ENCODE_MAP.put('\u00CF',"\\\"{I}"); +// todo \u00D0 + LATEX_ENCODE_MAP.put('\u00D1',"\\H{N}"); + LATEX_ENCODE_MAP.put('\u00D2',"\\`{O}"); + LATEX_ENCODE_MAP.put('\u00D3',"\\'{O}"); + LATEX_ENCODE_MAP.put('\u00D4',"\\^{O}"); + LATEX_ENCODE_MAP.put('\u00D5',"\\H{O}"); + LATEX_ENCODE_MAP.put('\u00D6',"\\\"{O}"); +// todo \u00D7 + LATEX_ENCODE_MAP.put('\u00D8',"\\O"); + LATEX_ENCODE_MAP.put('\u00D9',"\\`{U}"); + LATEX_ENCODE_MAP.put('\u00DA',"\\'{U}"); + LATEX_ENCODE_MAP.put('\u00DB',"\\^{U}"); + LATEX_ENCODE_MAP.put('\u00DC',"\\\"{U}"); + LATEX_ENCODE_MAP.put('\u00DD',"\\'{Y}"); +// todo \u00DE + LATEX_ENCODE_MAP.put('\u00DF',"\\ss"); + LATEX_ENCODE_MAP.put('\u00E0',"\\`{a}"); + LATEX_ENCODE_MAP.put('\u00E1',"\\'{a}"); + LATEX_ENCODE_MAP.put('\u00E2',"\\^{a}"); + LATEX_ENCODE_MAP.put('\u00E3',"\\H{a}"); + LATEX_ENCODE_MAP.put('\u00E4',"\\\"{a}"); + LATEX_ENCODE_MAP.put('\u00E5',"\\aa"); + LATEX_ENCODE_MAP.put('\u00E6',"\\ae"); + LATEX_ENCODE_MAP.put('\u00E7',"\\c{c}"); + LATEX_ENCODE_MAP.put('\u00E8',"\\`{e}"); + LATEX_ENCODE_MAP.put('\u00E9',"\\'{e}"); + LATEX_ENCODE_MAP.put('\u00EA',"\\^{e}"); + LATEX_ENCODE_MAP.put('\u00EB',"\\\"{e}"); + LATEX_ENCODE_MAP.put('\u00EC',"\\`{i}"); + LATEX_ENCODE_MAP.put('\u00ED',"\\'{i}"); + LATEX_ENCODE_MAP.put('\u00EE',"\\^{i}"); + LATEX_ENCODE_MAP.put('\u00EF',"\\\"{i}"); +// todo \u00F0 + LATEX_ENCODE_MAP.put('\u00F1',"\\H{n}"); + LATEX_ENCODE_MAP.put('\u00F2',"\\`{o}"); + LATEX_ENCODE_MAP.put('\u00F3',"\\'{o}"); + LATEX_ENCODE_MAP.put('\u00F4',"\\^{o}"); + LATEX_ENCODE_MAP.put('\u00F5',"\\H{o}"); + LATEX_ENCODE_MAP.put('\u00F6',"\\\"{o}"); +// todo \u00F7 + LATEX_ENCODE_MAP.put('\u00F8',"\\o"); + LATEX_ENCODE_MAP.put('\u00F9',"\\`{u}"); + LATEX_ENCODE_MAP.put('\u00FA',"\\'{u}"); + LATEX_ENCODE_MAP.put('\u00FB',"\\^{u}"); + LATEX_ENCODE_MAP.put('\u00FC',"\\\"{u}"); + LATEX_ENCODE_MAP.put('\u00FD',"\\'{y}"); +// todo \u00FE + LATEX_ENCODE_MAP.put('\u00FF',"\\\"{y}"); + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * containing only valid characters for a java class name. + * + * @param name The string that has to be transformed into a valid class + * name. + * @return The encoded <code>String</code> object. + * @see #encodeUrl(String) + * @see #encodeHtml(String) + * @see #encodeXml(String) + * @see #encodeSql(String) + * @see #encodeLatex(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeClassname(String name) + { + if (null == name) + { + return null; + } + + Pattern pattern = Pattern.compile("[^\\w]"); + Matcher matcher = pattern.matcher(name); + + return matcher.replaceAll("_"); + } + + private static boolean needsUrlEncoding(String source) + { + if (null == source) + { + return false; + } + + // check if the string needs encoding first since + // the URLEncoder always allocates a StringBuffer, even when the + // string is returned as-is + boolean encode = false; + char ch; + for (int i = 0; i < source.length(); i++) + { + ch = source.charAt(i); + + if (ch >= 'a' && ch <= 'z' || + ch >= 'A' && ch <= 'Z' || + ch >= '0' && ch <= '9' || + ch == '-' || ch == '_' || ch == '.' || ch == '*') + { + continue; + } + + encode = true; + break; + } + + return encode; + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * containing only valid URL characters. + * + * @param source The string that has to be transformed into a valid URL + * string. + * @return The encoded <code>String</code> object. + * @see #encodeClassname(String) + * @see #encodeUrlValue(String) + * @see #encodeHtml(String) + * @see #encodeXml(String) + * @see #encodeSql(String) + * @see #encodeLatex(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeUrl(String source) + { + if (!needsUrlEncoding(source)) + { + return source; + } + + try + { + return URLEncoder.encode(source, ENCODING_ISO_8859_1); + } + ///CLOVER:OFF + catch (UnsupportedEncodingException e) + { + // this should never happen, ISO-8859-1 is a standard encoding + throw new RuntimeException(e); + } + ///CLOVER:ON + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * only pure US Ascii strings are preserved and URL encoded in a regular + * way. Strings with characters from other encodings will be encoded in a + * RIFE-specific manner to allow international data to passed along the + * query string. + * + * @param source The string that has to be transformed into a valid URL + * parameter string. + * @return The encoded <code>String</code> object. + * @see #decodeUrlValue(String) + * @see #encodeClassname(String) + * @see #encodeUrl(String) + * @see #encodeHtml(String) + * @see #encodeXml(String) + * @see #encodeSql(String) + * @see #encodeLatex(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeUrlValue(String source) + { + if (!needsUrlEncoding(source)) + { + return source; + } + + // check if the string is valid US-ASCII encoding + boolean valid = true; + CharsetEncoder encoder = CHARSET_US_ASCII.newEncoder(); + try + { + encoder.encode(CharBuffer.wrap(source)); + } + catch (CharacterCodingException e) + { + valid = false; + } + + try + { + // if it is valid US-ASCII, use the regular URL encoding method + if (valid) + { + return URLEncoder.encode(source, ENCODING_US_ASCII); + } + // otherwise, base-64 encode the UTF-8 bytes and mark the string + // as being encoded in a special way + else + { + StringBuilder encoded = new StringBuilder("%02%02"); + String base64 = Base64.encodeToString(source.getBytes(ENCODING_UTF_8), false); + String base64_urlsafe = replace(base64, "=", "%3D"); + encoded.append(base64_urlsafe); + + return encoded.toString(); + } + } + ///CLOVER:OFF + catch (UnsupportedEncodingException e) + { + // this should never happen, ISO-8859-1 is a standard encoding + throw new RuntimeException(e); + } + ///CLOVER:ON + } + + /** + * Decodes a <code>String</code> that has been encoded in a RIFE-specific + * manner for URL usage.. Before calling this method, you should first + * verify if the value needs decoding by using the + * <code>doesUrlValueNeedDecoding(String)</code> method. + * + * @param source the value that has been encoded for URL usage in a + * RIFE-specific way + * @return The decoded <code>String</code> object. + * @see #encodeUrlValue(String) + * @see #doesUrlValueNeedDecoding(String) + * @since 1.0 + */ + public static String decodeUrlValue(String source) + { + try + { + byte[] decoded = Base64.decode(source.substring(2)); + if (null == decoded) + { + return null; + } + else + { + return new String(decoded, StringUtils.ENCODING_UTF_8); + } + } + ///CLOVER:OFF + catch (UnsupportedEncodingException e) + { + // this should never happen, UTF-8 is a standard encoding + throw new RuntimeException(e); + } + ///CLOVER:ON + } + + /** + * Checks if a <code>String</code> is encoded in a RIFE-specific manner + * for URL usage. + * + * @param source the value that might have been encoded for URL usage in a + * RIFE-specific way + * @return <code>true</code> if the value is encoded in the RIFE-specific + * format; and + * <p><code>false</code> otherwise + * @see #encodeUrlValue(String) + * @see #decodeUrlValue(String) + * @since 1.0 + */ + public static boolean doesUrlValueNeedDecoding(String source) + { + if (source != null && + source.length() > 2 && + source.startsWith("\u0002\u0002")) + { + return true; + } + + return false; + } + + private static boolean needsHtmlEncoding(String source, boolean defensive) + { + if (null == source) + { + return false; + } + + boolean encode = false; + char ch; + for (int i = 0; i < source.length(); i++) + { + ch = source.charAt(i); + + if ((defensive || (ch != '\u0022' && ch != '\u0026' && ch != '\u003C' && ch != '\u003E')) && + ch < '\u00A0') + { + continue; + } + + encode = true; + break; + } + + return encode; + } + + /** + * + * @since 1.6 + */ + public static String decodeHtml(String source) + { + if (null == source || + 0 == source.length()) + { + return source; + } + + int current_index = 0; + int delimiter_start_index = 0; + int delimiter_end_index = 0; + + StringBuilder result = null; + + while (current_index <= source.length()) + { + delimiter_start_index = source.indexOf('&', current_index); + if (delimiter_start_index != -1) + { + delimiter_end_index = source.indexOf(';', delimiter_start_index + 1); + if (delimiter_end_index != -1) + { + // ensure that the string builder is setup correctly + if (null == result) + { + result = new StringBuilder(); + } + + // add the text that leads up to this match + if (delimiter_start_index > current_index) + { + result.append(source.substring(current_index, delimiter_start_index)); + } + + // add the decoded entity + String entity = source.substring(delimiter_start_index, delimiter_end_index + 1); + + current_index = delimiter_end_index + 1; + + // try to decoded numeric entities + if (entity.charAt(1) == '#') + { + int start = 2; + int radix = 10; + // check if the number is hexadecimal + if (entity.charAt(2) == 'X' || entity.charAt(2) == 'x') + { + start++; + radix = 16; + } + try + { + Character c = new Character((char)Integer.parseInt(entity.substring(start, entity.length() - 1), radix)); + result.append(c); + } + // when the number of the entity can't be parsed, add the entity as-is + catch (NumberFormatException e) + { + result.append(entity); + } + } + else + { + // try to decode the entity as a literal + Character decoded = HTML_DECODE_MAP.get(entity); + if (decoded != null) + { + result.append(decoded); + } + // if there was no match, add the entity as-is + else + { + result.append(entity); + } + } + } + else + { + break; + } + } + else + { + break; + } + } + + if (null == result) + { + return source; + } + else if (current_index < source.length()) + { + result.append(source.substring(current_index)); + } + + return result.toString(); + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * containing only valid Html characters. + * + * @param source The string that has to be transformed into a valid Html + * string. + * @return The encoded <code>String</code> object. + * @see #encodeClassname(String) + * @see #encodeUrl(String) + * @see #encodeUrlValue(String) + * @see #encodeXml(String) + * @see #encodeSql(String) + * @see #encodeString(String) + * @see #encodeLatex(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeHtml(String source) + { + if (needsHtmlEncoding(source, false)) + { + return encode(source, HTML_ENCODER_FALLBACK, AGGRESSIVE_HTML_ENCODE_MAP, DEFENSIVE_HTML_ENCODE_MAP); + } + return source; + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * containing as much as possible Html characters. It is safe to already + * feed existing Html to this method since &, < and > will not + * be encoded. + * + * @param source The string that has to be transformed into a valid Html + * string. + * @return The encoded <code>String</code> object. + * @see #encodeClassname(String) + * @see #encodeUrl(String) + * @see #encodeUrlValue(String) + * @see #encodeXml(String) + * @see #encodeSql(String) + * @see #encodeString(String) + * @see #encodeLatex(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeHtmlDefensive(String source) + { + if (needsHtmlEncoding(source, true)) + { + return encode(source, null, DEFENSIVE_HTML_ENCODE_MAP); + } + return source; + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * containing only valid XML characters. + * + * @param source The string that has to be transformed into a valid XML + * string. + * @return The encoded <code>String</code> object. + * @see #encodeClassname(String) + * @see #encodeUrl(String) + * @see #encodeUrlValue(String) + * @see #encodeHtml(String) + * @see #encodeSql(String) + * @see #encodeString(String) + * @see #encodeLatex(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeXml(String source) + { + return encode(source, null, XML_ENCODE_MAP); + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * containing only valid <code>String</code> characters. + * + * @param source The string that has to be transformed into a valid + * sequence of <code>String</code> characters. + * @return The encoded <code>String</code> object. + * @see #encodeClassname(String) + * @see #encodeUrl(String) + * @see #encodeUrlValue(String) + * @see #encodeHtml(String) + * @see #encodeXml(String) + * @see #encodeSql(String) + * @see #encodeLatex(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeString(String source) + { + return encode(source, null, STRING_ENCODE_MAP); + } + + /** + * Transforms a provided <code>String</code> object into a series of + * unicode escape codes. + * + * @param source The string that has to be transformed into a valid + * sequence of unicode escape codes + * @return The encoded <code>String</code> object. + * @see #encodeClassname(String) + * @see #encodeUrl(String) + * @see #encodeUrlValue(String) + * @see #encodeHtml(String) + * @see #encodeXml(String) + * @see #encodeSql(String) + * @see #encodeLatex(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeUnicode(String source) + { + if (null == source) + { + return null; + } + + StringBuilder encoded = new StringBuilder(); + String hexstring = null; + for (int i = 0; i < source.length(); i++) + { + hexstring = Integer.toHexString((int)source.charAt(i)).toUpperCase(); + encoded.append("\\u"); + // fill with zeros + for (int j = hexstring.length(); j < 4; j++) + { + encoded.append("0"); + } + encoded.append(hexstring); + } + + return encoded.toString(); + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * containing only valid Sql characters. + * + * @param source The string that has to be transformed into a valid Sql + * string. + * @return The encoded <code>String</code> object. + * @see #encodeClassname(String) + * @see #encodeUrl(String) + * @see #encodeUrlValue(String) + * @see #encodeHtml(String) + * @see #encodeXml(String) + * @see #encodeString(String) + * @see #encodeLatex(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeSql(String source) + { + return encode(source, null, SQL_ENCODE_MAP); + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * containing only valid LaTeX characters. + * + * @param source The string that has to be transformed into a valid LaTeX + * string. + * @return The encoded <code>String</code> object. + * @see #encodeClassname(String) + * @see #encodeUrl(String) + * @see #encodeUrlValue(String) + * @see #encodeHtml(String) + * @see #encodeXml(String) + * @see #encodeSql(String) + * @see #encodeString(String) + * @see #encodeRegexp(String) + * @since 1.0 + */ + public static String encodeLatex(String source) + { + if (null == source) + { + return null; + } + + source = encode(source, null, LATEX_ENCODE_MAP); + source = StringUtils.replace(source, "latex", "\\LaTeX", false); + + return source; + } + + /** + * Transforms a provided <code>String</code> object into a new string, + * using the mapping that are provided through the supplied encoding + * table. + * + * @param source The string that has to be transformed into a valid + * string, using the mappings that are provided through the supplied + * encoding table. + * @param encodingTables A <code>Map</code> object containing the mappings + * to transform characters into valid entities. The keys of this map + * should be <code>Character</code> objects and the values + * <code>String</code> objects. + * @return The encoded <code>String</code> object. + * @since 1.0 + */ + private static String encode(String source, EncoderFallbackHandler fallbackHandler, Map<Character, String>... encodingTables) + { + if (null == source) + { + return null; + } + + if (null == encodingTables || + 0 == encodingTables.length) + { + return source; + } + + StringBuilder encoded_string = null; + char[] string_to_encode_array = source.toCharArray(); + int last_match = -1; + + for (int i = 0; i < string_to_encode_array.length; i++) + { + char char_to_encode = string_to_encode_array[i]; + for (Map<Character, String> encoding_table : encodingTables) + { + if (encoding_table.containsKey(char_to_encode)) + { + encoded_string = prepareEncodedString(source, encoded_string, i, last_match, string_to_encode_array); + + encoded_string.append(encoding_table.get(char_to_encode)); + last_match = i; + } + } + + if (fallbackHandler != null && + last_match < i && + fallbackHandler.hasFallback(char_to_encode)) + { + encoded_string = prepareEncodedString(source, encoded_string, i, last_match, string_to_encode_array); + + fallbackHandler.appendFallback(encoded_string, char_to_encode); + last_match = i; + } + } + + if (null == encoded_string) + { + return source; + } + else + { + int difference = string_to_encode_array.length-(last_match+1); + if (difference > 0) + { + encoded_string.append(string_to_encode_array, last_match+1, difference); + } + return encoded_string.toString(); + } + } + + private static StringBuilder prepareEncodedString(String source, StringBuilder encodedString, int i, int lastMatch, char[] stringToEncodeArray) + { + if (null == encodedString) + { + encodedString = new StringBuilder(source.length()); + } + + int difference = i - (lastMatch + 1); + if (difference > 0) + { + encodedString.append(stringToEncodeArray, lastMatch + 1, difference); + } + + return encodedString; + } + + private static interface EncoderFallbackHandler + { + abstract boolean hasFallback(char character); + abstract void appendFallback(StringBuilder encodedBuffer, char character); + } + + private static class HtmlEncoderFallbackHandler implements EncoderFallbackHandler + { + private final static String PREFIX = "&#"; + private final static String SUFFIX = ";"; + + public boolean hasFallback(char character) + { + if (character < '\u00A0') + { + return false; + } + + return true; + } + + public void appendFallback(StringBuilder encodedBuffer, char character) + { + encodedBuffer.append(PREFIX); + encodedBuffer.append((int)character); + encodedBuffer.append(SUFFIX); + } + } + + /** + * Transforms a provided <code>String</code> object into a literal that can + * be included into a regular expression {@link Pattern} as-is. None of the + * regular expression escapes in the string will be functional anymore. + * + * @param source The string that has to be escaped as a literal + * @return The encoded <code>String</code> object. + * @see #encodeClassname(String) + * @see #encodeUrl(String) + * @see #encodeUrlValue(String) + * @see #encodeHtml(String) + * @see #encodeXml(String) + * @see #encodeSql(String) + * @see #encodeString(String) + * @see #encodeLatex(String) + * @since 1.3 + */ + public static String encodeRegexp(String source) + { + int regexp_quote_start = source.indexOf("\\E"); + if (-1 == regexp_quote_start) + { + return "\\Q" + source + "\\E"; + } + + StringBuilder buffer = new StringBuilder(source.length() * 2); + buffer.append("\\Q"); + + regexp_quote_start = 0; + + int current = 0; + while (-1 == (regexp_quote_start = source.indexOf("\\E", current))) + { + buffer.append(source.substring(current, regexp_quote_start)); + current = regexp_quote_start + 2; + buffer.append("\\E\\\\E\\Q"); + } + + buffer.append(source.substring(current, source.length())); + buffer.append("\\E"); + + return buffer.toString(); + } + + /** + * Counts the number of times a substring occures in a provided string in + * a case-sensitive manner. + * + * @param source The <code>String</code> object that will be searched in. + * @param substring The string whose occurances will we counted. + * @return An <code>int</code> value containing the number of occurances + * of the substring. + * @since 1.0 + */ + public static int count(String source, String substring) + { + return count(source, substring, true); + } + + /** + * Counts the number of times a substring occures in a provided string. + * + * @param source The <code>String</code> object that will be searched in. + * @param substring The string whose occurances will we counted. + * @param matchCase A <code>boolean</code> indicating if the match is + * going to be performed in a case-sensitive manner or not. + * @return An <code>int</code> value containing the number of occurances + * of the substring. + * @since 1.0 + */ + public static int count(String source, String substring, boolean matchCase) + { + if (null == source) + { + return 0; + } + + if (null == substring) + { + return 0; + } + + int current_index = 0; + int substring_index = 0; + int count = 0; + + if (!matchCase) + { + source = source.toLowerCase(); + substring = substring.toLowerCase(); + } + + while (current_index < source.length()-1) + { + substring_index = source.indexOf(substring, current_index); + + if (-1 == substring_index) + { + break; + } + else + { + current_index = substring_index + substring.length(); + count++; + } + } + + return count; + } + + /** + * Splits a string into different parts, using a seperator string to + * detect the seperation boundaries in a case-sensitive manner. The + * seperator will not be included in the list of parts. + * + * @param source The string that will be split into parts. + * @param seperator The seperator string that will be used to determine + * the parts. + * @return An <code>ArrayList</code> containing the parts as + * <code>String</code> objects. + * @since 1.0 + */ + public static ArrayList<String> split(String source, String seperator) + { + return split(source, seperator, true); + } + + /** + * Splits a string into different parts, using a seperator string to + * detect the seperation boundaries. The seperator will not be included in + * the list of parts. + * + * @param source The string that will be split into parts. + * @param seperator The seperator string that will be used to determine + * the parts. + * @param matchCase A <code>boolean</code> indicating if the match is + * going to be performed in a case-sensitive manner or not. + * @return An <code>ArrayList</code> containing the parts as + * <code>String</code> objects. + * @since 1.0 + */ + public static ArrayList<String> split(String source, String seperator, boolean matchCase) + { + ArrayList<String> substrings = new ArrayList<String>(); + + if (null == source) + { + return substrings; + } + + if (null == seperator) + { + substrings.add(source); + return substrings; + } + + int current_index = 0; + int delimiter_index = 0; + String element = null; + + String source_lookup_reference = null; + if (!matchCase) + { + source_lookup_reference = source.toLowerCase(); + seperator = seperator.toLowerCase(); + } + else + { + source_lookup_reference = source; + } + + while (current_index <= source_lookup_reference.length()) + { + delimiter_index = source_lookup_reference.indexOf(seperator, current_index); + + if (-1 == delimiter_index) + { + element = new String(source.substring(current_index, source.length())); + substrings.add(element); + current_index = source.length() + 1; + } + else + { + element = new String(source.substring(current_index, delimiter_index)); + substrings.add(element); + current_index = delimiter_index + seperator.length(); + } + } + + return substrings; + } + + /** + * Splits a string into different parts, using a seperator string to + * detect the seperation boundaries in a case-sensitive manner. The + * seperator will not be included in the parts array. + * + * @param source The string that will be split into parts. + * @param seperator The seperator string that will be used to determine + * the parts. + * @return A <code>String[]</code> array containing the seperated parts. + * @since 1.0 + */ + public static String[] splitToArray(String source, String seperator) + { + return splitToArray(source, seperator, true); + } + + /** + * Splits a string into different parts, using a seperator string to + * detect the seperation boundaries. The seperator will not be included in + * the parts array. + * + * @param source The string that will be split into parts. + * @param seperator The seperator string that will be used to determine + * the parts. + * @param matchCase A <code>boolean</code> indicating if the match is + * going to be performed in a case-sensitive manner or not. + * @return A <code>String[]</code> array containing the seperated parts. + * @since 1.0 + */ + public static String[] splitToArray(String source, String seperator, boolean matchCase) + { + ArrayList<String> substrings = split(source, seperator, matchCase); + String[] substrings_array = new String[substrings.size()]; + substrings_array = substrings.toArray(substrings_array); + + return substrings_array; + } + + /** + * Splits a string into integers, using a seperator string to detect the + * seperation boundaries in a case-sensitive manner. If a part couldn't be + * converted to an integer, it will be omitted from the resulting array. + * + * @param source The string that will be split into integers. + * @param seperator The seperator string that will be used to determine + * the parts. + * @return An <code>int[]</code> array containing the seperated parts. + * @since 1.0 + */ + public static int[] splitToIntArray(String source, String seperator) + { + return splitToIntArray(source, seperator, true); + } + + /** + * Splits a string into integers, using a seperator string to detect the + * seperation boundaries. If a part couldn't be converted to an integer, + * it will be omitted from the resulting array. + * + * @param source The string that will be split into integers. + * @param seperator The seperator string that will be used to determine + * the parts. + * @param matchCase A <code>boolean</code> indicating if the match is + * going to be performed in a case-sensitive manner or not. + * @return An <code>int[]</code> array containing the seperated parts. + * @since 1.0 + */ + public static int[] splitToIntArray(String source, String seperator, boolean matchCase) + { + ArrayList<String> string_parts = split(source, seperator, matchCase); + int number_of_valid_parts = 0; + + for (String string_part : string_parts) + { + try + { + Integer.parseInt(string_part); + number_of_valid_parts++; + } + catch (NumberFormatException e) + { + // just continue + } + } + + int[] string_parts_int = (int[]) Array.newInstance(int.class, number_of_valid_parts); + int added_parts = 0; + + for (String string_part : string_parts) + { + try + { + string_parts_int[added_parts] = Integer.parseInt(string_part); + added_parts++; + } + catch (NumberFormatException e) + { + // just continue + } + } + + return string_parts_int; + } + + /** + * Splits a string into bytes, using a seperator string to detect the + * seperation boundaries in a case-sensitive manner. If a part couldn't be + * converted to a <code>byte</code>, it will be omitted from the resulting + * array. + * + * @param source The string that will be split into bytes. + * @param seperator The seperator string that will be used to determine + * the parts. + * @return A <code>byte[]</code> array containing the bytes. + * @since 1.0 + */ + public static byte[] splitToByteArray(String source, String seperator) + { + return splitToByteArray(source, seperator, true); + } + + /** + * Splits a string into bytes, using a seperator string to detect the + * seperation boundaries. If a part couldn't be converted to a + * <code>byte</code>, it will be omitted from the resulting array. + * + * @param source The string that will be split into bytes. + * @param seperator The seperator string that will be used to determine + * the parts. + * @param matchCase A <code>boolean</code> indicating if the match is + * going to be performed in a case-sensitive manner or not. + * @return A <code>byte[]</code> array containing the bytes. + * @since 1.0 + */ + public static byte[] splitToByteArray(String source, String seperator, boolean matchCase) + { + ArrayList<String> string_parts = split(source, seperator, matchCase); + int number_of_valid_parts = 0; + for (String string_part : string_parts) + { + try + { + Byte.parseByte(string_part); + number_of_valid_parts++; + } + catch (NumberFormatException e) + { + // just continue + } + } + + byte[] string_parts_byte = (byte[])Array.newInstance(byte.class, number_of_valid_parts); + int added_parts = 0; + for (String string_part : string_parts) + { + try + { + string_parts_byte[added_parts] = Byte.parseByte(string_part); + added_parts++; + } + catch (NumberFormatException e) + { + // just continue + } + } + + return string_parts_byte; + } + + /** + * Removes all occurances of a string from the front of another string in + * a case-sensitive manner. + * + * @param source The string in which the matching will be done. + * @param stringToStrip The string that will be stripped from the front. + * @return A new <code>String</code> containing the stripped result. + * @since 1.0 + */ + public static String stripFromFront(String source, String stringToStrip) + { + return stripFromFront(source, stringToStrip, true); + } + + /** + * Removes all occurances of a string from the front of another string. + * + * @param source The string in which the matching will be done. + * @param stringToStrip The string that will be stripped from the front. + * @param matchCase A <code>boolean</code> indicating if the match is + * going to be performed in a case-sensitive manner or not. + * @return A new <code>String</code> containing the stripping result. + * @since 1.0 + */ + public static String stripFromFront(String source, String stringToStrip, boolean matchCase) + { + if (null == source) + { + return null; + } + + if (null == stringToStrip) + { + return source; + } + + int strip_length = stringToStrip.length(); + int new_index = 0; + int last_index = 0; + + String source_lookup_reference = null; + if (!matchCase) + { + source_lookup_reference = source.toLowerCase(); + stringToStrip = stringToStrip.toLowerCase(); + } + else + { + source_lookup_reference = source; + } + + new_index = source_lookup_reference.indexOf(stringToStrip); + if (0 == new_index) + { + do + { + last_index = new_index; + new_index = source_lookup_reference.indexOf(stringToStrip, new_index+strip_length); + } + while (new_index != -1 && + new_index == last_index+strip_length); + + return source.substring(last_index+strip_length); + } + else + { + return source; + } + } + + /** + * Removes all occurances of a string from the end of another string in a + * case-sensitive manner. + * + * @param source The string in which the matching will be done. + * @param stringToStrip The string that will be stripped from the end. + * @return A new <code>String</code> containing the stripped result. + * @since 1.0 + */ + public static String stripFromEnd(String source, String stringToStrip) + { + return stripFromEnd(source, stringToStrip, true); + } + + /** + * Removes all occurances of a string from the end of another string. + * + * @param source The string in which the matching will be done. + * @param stringToStrip The string that will be stripped from the end. + * @param matchCase A <code>boolean</code> indicating if the match is + * going to be performed in a case-sensitive manner or not. + * @return A new <code>String</code> containing the stripped result. + * @since 1.0 + */ + public static String stripFromEnd(String source, String stringToStrip, boolean matchCase) + { + if (null == source) + { + return null; + } + + if (null == stringToStrip) + { + return source; + } + + int strip_length = stringToStrip.length(); + int new_index = 0; + int last_index = 0; + + String source_lookup_reference = null; + if (!matchCase) + { + source_lookup_reference = source.toLowerCase(); + stringToStrip = stringToStrip.toLowerCase(); + } + else + { + source_lookup_reference = source; + } + + new_index = source_lookup_reference.lastIndexOf(stringToStrip); + if (new_index != -1 && + source.length() == new_index+strip_length) + { + do + { + last_index = new_index; + new_index = source_lookup_reference.lastIndexOf(stringToStrip, last_index-1); + } + while (new_index != -1 && + new_index == last_index-strip_length); + + return source.substring(0, last_index); + } + else + { + return source; + } + } + + /** + * Searches for a string within a specified string in a case-sensitive + * manner and replaces every match with another string. + * + * @param source The string in which the matching parts will be replaced. + * @param stringToReplace The string that will be searched for. + * @param replacementString The string that will replace each matching + * part. + * @return A new <code>String</code> object containing the replacement + * result. + * @since 1.0 + */ + public static String replace(String source, String stringToReplace, String replacementString) + { + return replace(source, stringToReplace, replacementString, true); + } + + /** + * Searches for a string within a specified string and replaces every + * match with another string. + * + * @param source The string in which the matching parts will be replaced. + * @param stringToReplace The string that will be searched for. + * @param replacementString The string that will replace each matching + * part. + * @param matchCase A <code>boolean</code> indicating if the match is + * going to be performed in a case-sensitive manner or not. + * @return A new <code>String</code> object containing the replacement + * result. + * @since 1.0 + */ + public static String replace(String source, String stringToReplace, String replacementString, boolean matchCase) + { + if (null == source) + { + return null; + } + + if (null == stringToReplace) + { + return source; + } + + if (null == replacementString) + { + return source; + } + + Iterator<String> string_parts = split(source, stringToReplace, matchCase).iterator(); + StringBuilder new_string = new StringBuilder(); + + while (string_parts.hasNext()) + { + String string_part = string_parts.next(); + new_string.append(string_part); + if (string_parts.hasNext()) + { + new_string.append(replacementString); + } + } + + return new_string.toString(); + } + + /** + * Creates a new string that contains the provided string a number of + * times. + * + * @param source The string that will be repeated. + * @param count The number of times that the string will be repeated. + * @return A new <code>String</code> object containing the repeated + * concatenation result. + * @since 1.0 + */ + public static String repeat(String source, int count) + { + if (null == source) + { + return null; + } + + StringBuilder new_string = new StringBuilder(); + while (count > 0) + { + new_string.append(source); + count --; + } + + return new_string.toString(); + } + + /** + * Creates a new array of <code>String</code> objects, containing the + * elements of a supplied <code>Iterator</code>. + * + * @param iterator The iterator containing the elements to create the + * array with. + * @return The new <code>String</code> array. + * @since 1.0 + */ + public static String[] toStringArray(Iterator<String> iterator) + { + if (null == iterator) + { + return new String[0]; + } + + ArrayList<String> strings = new ArrayList<String>(); + + while (iterator.hasNext()) + { + strings.add(iterator.next()); + } + + String[] string_array = new String[strings.size()]; + strings.toArray(string_array); + + return string_array; + } + + /** + * Creates a new <code>ArrayList</code>, containing the elements of a + * supplied array of <code>String</code> objects. + * + * @param stringArray The array of <code>String</code> objects that have + * to be converted. + * @return The new <code>ArrayList</code> with the elements of the + * <code>String</code> array. + * @since 1.0 + */ + public static ArrayList<String> toArrayList(String[] stringArray) + { + ArrayList<String> strings = new ArrayList<String>(); + + if (null == stringArray) + { + return strings; + } + + for (String element : stringArray) + { + strings.add(element); + } + + return strings; + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied <code>Collection</code> of <code>String</code> objects joined + * by a given seperator. + * + * @param collection The <code>Collection</code> containing the elements + * to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(Collection collection, String seperator) + { + if (null == collection) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (0 == collection.size()) + { + return ""; + } + else + { + StringBuilder result = new StringBuilder(); + for (Object element : collection) + { + result.append(String.valueOf(element)); + result.append(seperator); + } + + result.setLength(result.length()-seperator.length()); + return result.toString(); + } + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The object array containing the elements to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(Object[] array, String seperator) + { + return join(array, seperator, null, false); + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The object array containing the elements to join. + * @param seperator The seperator used to join the string elements. + * @param delimiter The delimiter used to surround the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(Object[] array, String seperator, String delimiter) + { + return join(array, seperator, delimiter, false); + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The object array containing the elements to join. + * @param seperator The seperator used to join the string elements. + * @param delimiter The delimiter used to surround the string elements. + * @param encodeStrings Indicates whether the characters of the string + * representation of the Array values should be encoded. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(Object[] array, String seperator, String delimiter, boolean encodeStrings) + { + if (null == array) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (null == delimiter) + { + delimiter = ""; + } + + if (0 == array.length) + { + return ""; + } + else + { + int current_index = 0; + String array_value = null; + StringBuilder result = new StringBuilder(); + while (current_index < array.length - 1) + { + if (null == array[current_index]) + { + result.append("null"); + } + else + { + array_value = String.valueOf(array[current_index]); + if (encodeStrings) + { + array_value = encodeString(array_value); + } + result.append(delimiter); + result.append(array_value); + result.append(delimiter); + } + result.append(seperator); + current_index++; + } + + if (null == array[current_index]) + { + result.append("null"); + } + else + { + array_value = String.valueOf(array[current_index]); + if (encodeStrings) + { + array_value = encodeString(array_value); + } + result.append(delimiter); + result.append(array_value); + result.append(delimiter); + } + return result.toString(); + } + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The boolean array containing the values to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(boolean[] array, String seperator) + { + if (null == array) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (0 == array.length) + { + return ""; + } + else + { + int current_index = 0; + String result = ""; + while (current_index < array.length - 1) + { + result = result + array[current_index] + seperator; + current_index++; + } + + result = result + array[current_index]; + return result; + } + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The byte array containing the values to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(byte[] array, String seperator) + { + if (null == array) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (0 == array.length) + { + return ""; + } + else + { + int current_index = 0; + String result = ""; + while (current_index < array.length - 1) + { + result = result + array[current_index] + seperator; + current_index++; + } + + result = result + array[current_index]; + return result; + } + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The double array containing the values to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(double[] array, String seperator) + { + if (null == array) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (0 == array.length) + { + return ""; + } + else + { + int current_index = 0; + String result = ""; + while (current_index < array.length - 1) + { + result = result + array[current_index] + seperator; + current_index++; + } + + result = result + array[current_index]; + return result; + } + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The float array containing the values to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(float[] array, String seperator) + { + if (null == array) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (0 == array.length) + { + return ""; + } + else + { + int current_index = 0; + String result = ""; + while (current_index < array.length - 1) + { + result = result + array[current_index] + seperator; + current_index++; + } + + result = result + array[current_index]; + return result; + } + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The integer array containing the values to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(int[] array, String seperator) + { + if (null == array) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (0 == array.length) + { + return ""; + } + else + { + int current_index = 0; + String result = ""; + while (current_index < array.length - 1) + { + result = result + array[current_index] + seperator; + current_index++; + } + + result = result + array[current_index]; + return result; + } + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The long array containing the values to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(long[] array, String seperator) + { + if (null == array) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (0 == array.length) + { + return ""; + } + else + { + int current_index = 0; + String result = ""; + while (current_index < array.length - 1) + { + result = result + array[current_index] + seperator; + current_index++; + } + + result = result + array[current_index]; + return result; + } + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The short array containing the values to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(short[] array, String seperator) + { + if (null == array) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (0 == array.length) + { + return ""; + } + else + { + int current_index = 0; + String result = ""; + while (current_index < array.length - 1) + { + result = result + array[current_index] + seperator; + current_index++; + } + + result = result + array[current_index]; + return result; + } + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The char array containing the values to join. + * @param seperator The seperator used to join the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(char[] array, String seperator) + { + return join(array, seperator, null); + } + + /** + * Creates a new <code>String</code> object, containing the elements of a + * supplied array, joined by a given seperator. + * + * @param array The char array containing the values to join. + * @param seperator The seperator used to join the string elements. + * @param delimiter The delimiter used to surround the string elements. + * @return A new <code>String</code> with the join result. + * @since 1.0 + */ + public static String join(char[] array, String seperator, String delimiter) + { + if (null == array) + { + return null; + } + + if (null == seperator) + { + seperator = ""; + } + + if (null == delimiter) + { + delimiter = ""; + } + + if (0 == array.length) + { + return ""; + } + else + { + int current_index = 0; + StringBuilder result = new StringBuilder(); + while (current_index < array.length - 1) + { + result.append(delimiter); + result.append(array[current_index]); + result.append(delimiter); + result.append(seperator); + current_index++; + } + + result.append(delimiter); + result.append(String.valueOf(array[current_index])); + result.append(delimiter); + return result.toString(); + } + } + + /** + * Returns an array that contains all the occurances of a substring in a + * string in the correct order. The search will be performed in a + * case-sensitive manner. + * + * @param source The <code>String</code> object that will be searched in. + * @param substring The string whose occurances will we counted. + * @return An <code>int[]</code> array containing the indices of the + * substring. + * @since 1.0 + */ + public static int[] indicesOf(String source, String substring) + { + return indicesOf(source, substring, true); + } + + /** + * Returns an array that contains all the occurances of a substring in a + * string in the correct order. + * + * @param source The <code>String</code> object that will be searched in. + * @param substring The string whose occurances will we counted. + * @param matchCase A <code>boolean</code> indicating if the match is + * going to be performed in a case-sensitive manner or not. + * @return An <code>int[]</code> array containing the indices of the + * substring. + * @since 1.0 + */ + public static int[] indicesOf(String source, String substring, boolean matchCase) + { + if (null == source || + null == substring) + { + return new int[0]; + } + + String source_lookup_reference = null; + if (!matchCase) + { + source_lookup_reference = source.toLowerCase(); + substring = substring.toLowerCase(); + } + else + { + source_lookup_reference = source; + } + + int current_index = 0; + int substring_index = 0; + int count = count(source_lookup_reference, substring); + int[] indices = new int[count]; + int counter = 0; + + while (current_index < source.length()-1) + { + substring_index = source_lookup_reference.indexOf(substring, current_index); + + if (-1 == substring_index) + { + break; + } + else + { + current_index = substring_index + substring.length(); + indices[counter] = substring_index; + counter++; + } + } + + return indices; + } + + /** + * Matches a collection of regular expressions against a string. + * + * @param value The <code>String</code> that will be checked. + * @param regexps The collection of regular expressions against which the + * match will be performed. + * @return The <code>Matcher</code> instance that corresponds to the + * <code>String</code> that returned a successful match; or + * <p><code>null</code> if no match could be found. + * @since 1.0 + */ + public static Matcher getMatchingRegexp(String value, Collection<Pattern> regexps) + { + if (value != null && + value.length() > 0 && + regexps != null && + regexps.size() > 0) + { + Matcher matcher = null; + for (Pattern regexp : regexps) + { + matcher = regexp.matcher(value); + if (matcher.matches()) + { + return matcher; + } + } + } + + return null; + } + + /** + * Matches a collection of strings against a regular expression. + * + * @param values The <code>Collection</code> of <code>String</code> + * objects that will be checked. + * @param regexp The regular expression <code>Pattern</code> against which + * the matches will be performed. + * @return The <code>Matcher</code> instance that corresponds to the + * <code>String</code> that returned a successful match; or + * <p><code>null</code> if no match could be found. + * @since 1.0 + */ + public static Matcher getRegexpMatch(Collection<String> values, Pattern regexp) + { + if (values != null && + values.size() > 0 && + regexp != null) + { + Matcher matcher = null; + for (String value : values) + { + matcher = regexp.matcher(value); + if (matcher.matches()) + { + return matcher; + } + } + } + + return null; + } + + /** + * Checks if the name filters through an including and an excluding + * regular expression. + * + * @param name The <code>String</code> that will be filtered. + * @param included The regular expressions that needs to succeed + * @param excluded The regular expressions that needs to fail + * @return <code>true</code> if the name filtered through correctly; or + * <p><code>false</code> otherwise. + * @since 1.0 + */ + public static boolean filter(String name, Pattern included, Pattern excluded) + { + Pattern[] included_array = null; + if (included != null) + { + included_array = new Pattern[] {included}; + } + + Pattern[] excluded_array = null; + if (excluded != null) + { + excluded_array = new Pattern[] {excluded}; + } + + return filter(name, included_array, excluded_array); + } + + /** + * Checks if the name filters through a series of including and excluding + * regular expressions. + * + * @param name The <code>String</code> that will be filtered. + * @param included An array of regular expressions that need to succeed + * @param excluded An array of regular expressions that need to fail + * @return <code>true</code> if the name filtered through correctly; or + * <p><code>false</code> otherwise. + * @since 1.0 + */ + public static boolean filter(String name, Pattern[] included, Pattern[] excluded) + { + if (null == name) + { + return false; + } + + boolean accepted = false; + + // retain only the includes + if (null == included) + { + accepted = true; + } + else + { + for (Pattern pattern : included) + { + if (pattern != null && + pattern.matcher(name).matches()) + { + accepted = true; + break; + } + } + } + + // remove the excludes + if (accepted && + excluded != null) + { + for (Pattern pattern : excluded) + { + if (pattern != null && + pattern.matcher(name).matches()) + { + accepted = false; + break; + } + } + } + + return accepted; + } + + /** + * Ensure that the first character of the provided string is upper case. + * + * @param source The <code>String</code> to capitalize. + * @return The capitalized <code>String</code>. + * @since 1.0 + */ + public static String capitalize(String source) + { + if (source == null || source.length() == 0) + { + return source; + } + + if (source.length() > 1 && + Character.isUpperCase(source.charAt(0))) + { + return source; + } + + char chars[] = source.toCharArray(); + chars[0] = Character.toUpperCase(chars[0]); + return new String(chars); + } + + /** + * Ensure that the first character of the provided string lower case. + * + * @param source The <code>String</code> to uncapitalize. + * @return The uncapitalized <code>String</code>. + * @since 1.5 + */ + public static String uncapitalize(String source) + { + if (source == null || source.length() == 0) + { + return source; + } + + if (source.length() > 1 && + Character.isLowerCase(source.charAt(0))) + { + return source; + } + + char chars[] = source.toCharArray(); + chars[0] = Character.toLowerCase(chars[0]); + return new String(chars); + } + + private static String convertUrl(String source, Pattern pattern, boolean shorten, boolean sanitize, boolean no_follow) + { + int max_length = 1024; + + String result = source; + + Matcher url_matcher = pattern.matcher(source); + boolean found = url_matcher.find(); + if (found) + { + String visual_url = null; + String actual_url = null; + int last = 0; + StringBuilder sb = new StringBuilder(); + do + { + actual_url = url_matcher.group(1); + if (url_matcher.groupCount() > 1) + { + visual_url = url_matcher.group(2); + } + else + { + visual_url = actual_url; + } + + if (sanitize) + { + // defang javascript + actual_url = StringUtils.replace(actual_url, "javascript:", ""); + + // fill in http:// for URLs that don't begin with / + if ((actual_url.indexOf("://") == -1) && + (!actual_url.startsWith("/"))) + { + actual_url = "http://"+actual_url; + } + } + + if (pattern.equals(BBCODE_BAREURL)) + { + sb.append(source.substring(last, url_matcher.start(1))); + } + else + { + sb.append(source.substring(last, url_matcher.start(0))); + } + sb.append("<a href=\""); + sb.append(actual_url); + sb.append("\""); + if (actual_url.startsWith("http://") || + actual_url.startsWith("https://")) + { + sb.append(" target=\"_blank\""); + } + if (no_follow) + { + sb.append(" rel=\"nofollow\""); + } + sb.append(">"); + if (visual_url.length() <= max_length || !shorten) + { + sb.append(visual_url); + } + else + { + String ellipsis = "..."; + int query_index = visual_url.indexOf("?"); + + // hack query string off + // keep '?' + if (query_index != -1) + { + visual_url = visual_url.substring(0, query_index + 1) + ellipsis; + } + + if (visual_url.length() >= max_length) + { + int last_slash = visual_url.lastIndexOf("/"); + int start_slash = visual_url.indexOf("/", visual_url.indexOf("://")+3); + + if (last_slash != start_slash) + { + visual_url = visual_url.substring(0, start_slash + 1) + ellipsis + visual_url.substring(last_slash); + } + } + + sb.append(visual_url); + } + sb.append("</a>"); + + if (pattern.equals(BBCODE_BAREURL)) + { + last = url_matcher.end(1); + } + else + { + last = url_matcher.end(0); + } + + found = url_matcher.find(); + } + while (found); + + sb.append(source.substring(last)); + result = sb.toString(); + } + + return result; + } + + private static String parseBBCode(String source, boolean shorten, boolean sanitize, boolean convert_bare, boolean no_follow) + { + String result = source; + + result = StringUtils.replace(result, "[b]", "<b>", false); + result = StringUtils.replace(result, "[/b]", "</b>", false); + result = StringUtils.replace(result, "[u]", "<u>", false); + result = StringUtils.replace(result, "[/u]", "</u>", false); + result = StringUtils.replace(result, "[i]", "<i>", false); + result = StringUtils.replace(result, "[/i]", "</i>", false); + result = StringUtils.replace(result, "[pre]", "<pre>", false); + result = StringUtils.replace(result, "[/pre]", "</pre>", false); + + String resultCopy = result; + String resultLowerCopy = result.toLowerCase(); + StringBuilder buffer = new StringBuilder(); + int startIndex; + int endIndex; + while (-1 != (startIndex = resultLowerCopy.indexOf("[*]"))) + { + int begin = resultLowerCopy.indexOf("[list]", startIndex + 3); + int end = resultLowerCopy.indexOf("[/list]", startIndex + 3); + int next = resultLowerCopy.indexOf("[*]", startIndex + 3); // 3 == sizeof [*] + + if (begin == -1) + { + begin = Integer.MAX_VALUE; + } + + if (end == -1) + { + end = Integer.MAX_VALUE; + } + + if (next == -1) + { + next = Integer.MAX_VALUE; + } + + if (next < begin && next < end) + { + endIndex = next; + } + else if (begin < next && begin < end) + { + endIndex = begin; + } + else if (end < next && end < begin) + { + endIndex = end; + } + else + { + endIndex = resultLowerCopy.length(); + } + + buffer + .append(resultCopy.substring(0, startIndex)) + .append("<li>") + .append(resultCopy.substring(startIndex + 3, endIndex)) // 3 == sizeof [*] + .append("</li>"); + + resultCopy = resultCopy.substring(endIndex); + resultLowerCopy = resultLowerCopy.substring(endIndex); + } + buffer.append(resultCopy.substring(0)); + + result = buffer.toString(); + + result = StringUtils.replace(result, "[list]", "<ul>", false); + result = StringUtils.replace(result, "[/list]", "</ul>", false); + + Matcher color_matcher = BBCODE_COLOR.matcher(result); + result = color_matcher.replaceAll("<font color=\"$1\">"); + result = StringUtils.replace(result, "[/color]", "</font>", false); + + Matcher size_matcher = BBCODE_SIZE.matcher(result); + result = size_matcher.replaceAll("<font size=\"$1\">"); + result = StringUtils.replace(result, "[/size]", "</font>", false); + + result = convertUrl(result, BBCODE_URL_SHORT, shorten, sanitize, no_follow); + result = convertUrl(result, BBCODE_URL_LONG, shorten, sanitize, no_follow); + + if (convert_bare) + { + result = convertUrl(result, BBCODE_BAREURL, shorten, sanitize, no_follow); + } + + Matcher img_matcher = BBCODE_IMG.matcher(result); + result = img_matcher.replaceAll("<div class=\"bbcode_img\"><img src=\"$1\" border=\"0\" alt=\"\" /></div>"); + + Matcher quote_matcher_long = BBCODE_QUOTE_LONG.matcher(result); + result = quote_matcher_long.replaceAll("<div class=\"quoteaccount\">$1:</div><div class=\"quotebody\">"); + result = StringUtils.replace(result, "[quote]", "<div class=\"quotebody\">", false); + result = StringUtils.replace(result, "[/quote]", "</div>", false); + + result = StringUtils.replace(result, "\r\n", "<br />\r"); + result = StringUtils.replace(result, "\n", "<br />\n"); + result = StringUtils.replace(result, "\r", "\r\n"); + + // remove the BR that could be added due to code formatting ppl + // use to format lists + result = StringUtils.replace(result, "ul><br />\r\n", "ul>\r\n"); + result = StringUtils.replace(result, "ul><br />\n", "ul>\n"); + + return result; + } + + /** + * Converts a <code>String</code> to a <code>boolean</code> value. + * + * @param value The <code>String</code> to convert. + * @return The corresponding <code>boolean</code> value. + * @since 1.0 + */ + public static boolean convertToBoolean(String value) + { + if (null == value) + { + return false; + } + + if (value.equals("1") || + value.equalsIgnoreCase("t") || + value.equalsIgnoreCase("true") || + value.equalsIgnoreCase("y") || + value.equalsIgnoreCase("yes") || + value.equalsIgnoreCase("on")) + { + return true; + } + + return false; + } + + /** + * Converts all tabs on a line to spaces according to the provided tab + * width. + * + * @param line The line whose tabs have to be converted. + * @param tabWidth The tab width. + * @return A new <code>String</code> object containing the line with the + * replaced tabs. + * @since 1.0 + */ + public static String convertTabsToSpaces(String line, int tabWidth) + { + StringBuilder result = new StringBuilder(); + int tab_index = -1; + int last_tab_index = 0; + int added_chars = 0; + int tab_size; + while ((tab_index = line.indexOf("\t", last_tab_index)) != -1) + { + tab_size = tabWidth-((tab_index+added_chars)%tabWidth); + if (0 == tab_size) + { + tab_size = tabWidth; + } + added_chars += tab_size-1; + result.append(line.substring(last_tab_index, tab_index)); + result.append(StringUtils.repeat(" ", tab_size)); + last_tab_index = tab_index+1; + } + if (0 == last_tab_index) + { + return line; + } + else + { + result.append(line.substring(last_tab_index)); + } + + return result.toString(); + } + + /** + * Ensures that all whitespace is removed from a <code>String</code>. + * <p>It also works with a <code>null</code> argument. + * + * @param source The <code>String</code> to trim. + * @return The trimmed <code>String</code>. + * @since 1.0 + */ + public static String trim(String source) + { + if (source == null || source.length() == 0) + { + return source; + } + + return source.trim(); + } + + /** + * Reformats a string where lines that are longer than <tt>width</tt> + * are split apart at the earliest wordbreak or at maxLength, whichever is + * sooner. If the width specified is less than 5 or greater than the input + * Strings length the string will be returned as is. + * <p> + * Please note that this method can be lossy - trailing spaces on wrapped + * lines may be trimmed. + * + * @param input the String to reformat. + * @param width the maximum length of any one line. + * @return a new String with reformatted as needed. + */ + public static String wordWrap(String input, int width, Locale locale) + { + // handle invalid input + if (input == null) + { + return ""; + } + else if (width < 5) + { + return input; + } + else if (width >= input.length()) + { + return input; + } + + // default locale + if (locale == null) + { + locale = Locale.US; + } + + StringBuilder buffer = new StringBuilder(input.length()); + int current_index = 0; + int delimiter_index = 0; + String seperator = "\n"; + String line; + + // go over the input string and jump from line to line + while (current_index <= input.length()) + { + // look for the next linebreak + delimiter_index = input.indexOf(seperator, current_index); + + // get the line that corresponds to it + if (-1 == delimiter_index) + { + line = new String(input.substring(current_index, input.length())); + current_index = input.length() + 1; + } + else + { + line = new String(input.substring(current_index, delimiter_index)); + current_index = delimiter_index + seperator.length(); + } + + // handle the wrapping of the line + BreakIterator breaks = BreakIterator.getLineInstance(locale); + breaks.setText(line); + + int line_start = 0; + int start = breaks.first(); + int end = breaks.next(); + while (end != BreakIterator.DONE) + { + // check if the width has been exceeded + if (end - 1 - line_start >= width) + { + boolean break_line = true; + + // first check if the last characters were spaces, + // if they were and by removing them the width is not + // exceeded, just continue + if (Character.isWhitespace(line.charAt(end - 1))) + { + for (int j = end - 1; j >= 0; j--) + { + if (!Character.isWhitespace(line.charAt(j))) + { + if (j - line_start < width) + { + break_line = false; + } + + break; + } + } + } + + if (break_line) + { + String line_breaked = line.substring(line_start, start); + // this can happen with trailing whitespace + if (line_breaked.length() > width) + { + line_breaked = line_breaked.substring(0, width); + } + buffer.append(line_breaked); + + buffer.append("\n"); + + line_start = start; + } + } + + start = end; + end = breaks.next(); + } + + if (line_start < line.length()) + { + buffer.append(line.substring(line_start)); + } + + if (delimiter_index != -1) + { + buffer.append("\n"); + } + } + + return buffer.toString(); + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TPCLIDConverter.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TPCLIDConverter.java new file mode 100644 index 0000000..4bbfd75 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TPCLIDConverter.java @@ -0,0 +1,758 @@ +package com.ximple.eofms.util; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Envelope; + +public abstract class TPCLIDConverter +{ + private final static int SX1200 = 800; + private final static int SY1200 = 500; + + public static String CoordinateToTpclId(Coordinate dp) + { + long orgX, orgY; + int mapX, mapY; + int shiftX, shiftY; + int dx1, dy1; + int dx2, dy2; + + if (dp == null) + { + return null; + } + + double X = dp.x; + double Y = dp.y; + + String CoordToTPCLID = ""; + + char mapID = CoordinateToSingleMapID(dp); + + if (mapID == 'w') + { + return ""; + } + + /* get the origin point of mapID */ + Coordinate Point = getOriginPoint("" + mapID, Integer.MAX_VALUE); + + if (Point == null) + { + return null; + } + + orgX = (long) Point.x; + orgY = (long) Point.y; + + mapX = intDivision((X - orgX), SX1200); + + if (mapID == 'Z' && mapX >= 100) + { + mapX = mapX - 100; + } + mapY = intDivision((Y - orgY), SY1200); + shiftX = (int) (X - orgX) % SX1200; + shiftY = (int) (Y - orgY) % SY1200; + dx1 = intDivision((shiftX % 100), 10); + dy1 = intDivision((shiftY % 100), 10); + dx2 = (shiftX % 100) % 10; + dy2 = (shiftY % 100) % 10; + + + CoordToTPCLID = "" + mapID; + CoordToTPCLID = CoordToTPCLID + dataFormat(mapX); + CoordToTPCLID = CoordToTPCLID + dataFormat(mapY); + CoordToTPCLID = CoordToTPCLID + intToAscii(shiftX / 100 + asciiToInt("A")); + CoordToTPCLID = CoordToTPCLID + intToAscii(shiftY / 100 + asciiToInt("A")); + CoordToTPCLID = CoordToTPCLID + dx1 + dy1 + dx2 + dy2; + + return CoordToTPCLID; + } + + public static char CoordinateToSingleMapID(Coordinate dp) + { + char mapID = 'w'; + + String[] strY = StringUtils.splitToArray(Double.toString(dp.y), "."); + String[] strX = StringUtils.splitToArray(Double.toString(dp.x), "."); + + int intY = Integer.parseInt(strY[0]); + int intX = Integer.parseInt(strX[0]); + + if (intY > 2944000) + { + return mapID; + } + if (intY >= 2894000 && intY <= 2944000 && intX >= 10000 && intX <= 90000) + { + mapID = 'S'; + return mapID; + } + if (intY >= 2614000 && intY <= 2664000 && intX >= 10000 && intX <= 66000) + { + mapID = 'X'; + return mapID; + } + if (intY >= 2564000 && intY <= 2614000 && intX >= 10000 && intX <= 66000) + { + mapID = 'Y'; + return mapID; + } + if (intY >= 2675800 && intY <= 2725800 && intX >= 10000 && intX <= 170000) + { + mapID = 'Z'; + return mapID; + } + if (intY > 2800000) + { + return mapID; + } + if (intY >= 2750000) + { + if (intX < 170000) + { + return mapID; + } + if (intX < 250000) + { + mapID = 'A'; + return mapID; + } + if (intX < 330000) + { + mapID = 'B'; + return mapID; + } + if (intX < 410000) + { + mapID = 'C'; + return mapID; + } + return mapID; + } + if (intY >= 2700000) + { + if (intX < 170000) + { + return mapID; + } + if (intX < 250000) + { + mapID = 'D'; + return mapID; + } + if (intX < 330000) + { + mapID = 'E'; + return mapID; + } + if (intX < 410000) + { + mapID = 'F'; + return mapID; + } + return mapID; + } + if (intY >= 2650000) + { + if (intX < 170000) + { + return mapID; + } + if (intX < 250000) + { + mapID = 'G'; + return mapID; + } + if (intX < 330000) + { + mapID = 'H'; + return mapID; + } + if (intX < 410000) + { + mapID = 'I'; + return mapID; + } + return mapID; + } + if (intY >= 2600000) + { + if (intX < 90000) + { + return mapID; + } + if (intX < 170000) + { + mapID = 'J'; + return mapID; + } + if (intX < 250000) + { + mapID = 'K'; + return mapID; + } + if (intX < 330000) + { + mapID = 'L'; + return mapID; + } + return mapID; + } + if (intY >= 2550000) + { + if (intX < 90000) + { + return mapID; + } + if (intX < 170000) + { + mapID = 'M'; + return mapID; + } + + if (intX < 250000) + { + mapID = 'N'; + return mapID; + } + if (intX < 330000) + { + mapID = 'O'; + return mapID; + } + return mapID; + } + if (intY >= 2500000) + { + if (intX < 90000) + { + return mapID; + } + if (intX < 170000) + { + mapID = 'P'; + return mapID; + } + if (intX < 250000) + { + mapID = 'Q'; + return mapID; + } + if (intX < 330000) + { + mapID = 'R'; + return mapID; + } + return mapID; + } + if (intY >= 2450000) + { + if (intX < 90000) + { + return mapID; + } + if (intX < 170000) + { + mapID = 'S'; + return mapID; + } + if (intX < 250000) + { + mapID = 'T'; + return mapID; + } + if (intX < 330000) + { + mapID = 'U'; + return mapID; + } + return mapID; + } + if (intY >= 2400000) + { + if (intX < 170000) + { + return mapID; + } + if (intX < 250000) + { + mapID = 'V'; + return mapID; + } + if (intX < 330000) + { + mapID = 'W'; + return mapID; + } + return mapID; + } + return mapID; + } + + public static Envelope convertTpclIdToEnvelope(String tpclid) + { + String tempString = ""; + + Coordinate point = null; + Coordinate tempPoint = null; + double width, height; + + if (tpclid.length() < 5) + { + return null; + } + + tempString = tpclid.substring(0, 1); + int xmapid = Integer.parseInt(tpclid.substring(1, 2)); + + // Get the origin point + point = getOriginPoint(tempString, xmapid); + + if (point == null) + { + return null; + } + + + tempString = tpclid.substring(1, 4); + width = SX1200; + height = SY1200; + + tempPoint = twoNumberScale(tempString, 800, 500); + if (tempPoint != null) + { + point.x = (point.x + tempPoint.x); + point.y = (point.y + tempPoint.y); + } + + if (tpclid.length() >= 7) + { + tempString = (asciiToInt(tpclid.substring(5, 1)) - 65) + "" + (asciiToInt(tpclid.substring(6, 1)) - 65); + tempPoint = twoNumberScale(tempString, 100); + if (tempPoint != null) + { + point.x = point.x + tempPoint.x; + point.y = point.y + tempPoint.y; + } + width = 100.0; + height = 100.0; + } + + if (tpclid.length() >= 9) + { + tempString = tpclid.substring(7, 2); + tempPoint = twoNumberScale(tempString, 10); + if (tempPoint != null) + { + point.x = point.x + tempPoint.x; + point.y = point.y + tempPoint.y; + } + width = 10.0; + height = 10.0; + } + + if (tpclid.length() >= 11) + { + tempString = tpclid.substring(9); + tempPoint = twoNumberScale(tempString, 1); + if (tempPoint != null) + { + point.x = point.x + tempPoint.x; + point.y = point.y + tempPoint.y; + } + width = 1.0; + height = 1.0; + } + + Coordinate pt2 = new Coordinate(point); + pt2.x += width; + pt2.y += height; + return new Envelope(point, pt2); + } + + public static Coordinate convertTpclIdToCoordinate(String tpclid) + { + String tempString = ""; + + Coordinate point = null; + Coordinate tempPoint = null; + + if (tpclid.length() < 5) + { + return null; + } + + tempString = tpclid.substring(0, 1); + int xmapid = Integer.parseInt(tpclid.substring(1, 2)); + + // Get the origin point + point = getOriginPoint(tempString, xmapid); + + if (point == null) + { + return null; + } + + + tempString = tpclid.substring(1, 4); + + tempPoint = twoNumberScale(tempString, 800, 500); + if (tempPoint != null) + { + point.x = (point.x + tempPoint.x); + point.y = (point.y + tempPoint.y); + } + + if (tpclid.length() >= 7) + { + tempString = (asciiToInt(tpclid.substring(5, 1)) - 65) + "" + (asciiToInt(tpclid.substring(6, 1)) - 65); + tempPoint = twoNumberScale(tempString, 100); + if (tempPoint != null) + { + point.x = point.x + tempPoint.x; + point.y = point.y + tempPoint.y; + } + } + + if (tpclid.length() >= 9) + { + tempString = tpclid.substring(7, 2); + tempPoint = twoNumberScale(tempString, 10); + if (tempPoint != null) + { + point.x = point.x + tempPoint.x; + point.y = point.y + tempPoint.y; + } + } + + if (tpclid.length() >= 11) + { + tempString = tpclid.substring(9); + tempPoint = twoNumberScale(tempString, 1); + if (tempPoint != null) + { + point.x = point.x + tempPoint.x; + point.y = point.y + tempPoint.y; + } + } + return point; + } + + + private static int intDivision(double p1, int p2) + { + double resultValue = 0.0; + String result; + resultValue = p1 / p2; + result = Double.toString(resultValue); + String[] temp = StringUtils.splitToArray(result, "."); + result = temp[0]; + return Integer.parseInt(result); + } + + + private static Coordinate twoNumberScale(String number, int scaleX, int scaleY) + { + Coordinate tempPoint = new Coordinate(); + + if (number.length() == 2) + { + tempPoint.x = Double.parseDouble(number.substring(0, 1)) * scaleX; + tempPoint.y = Double.parseDouble(number.substring(1, 1)) * scaleY; + } else if (number.length() == 1) + { + tempPoint.x = Double.parseDouble(number.substring(0, 1)) * scaleX; + tempPoint.y = 0; + } else if (number.length() == 4) + { + tempPoint.x = Double.parseDouble(number.substring(0, 2)) * scaleX; + tempPoint.y = Double.parseDouble(number.substring(2, 2)) * scaleY; + } else + { + tempPoint.x = 0; + tempPoint.y = 0; + } + return tempPoint; + } + + + private static int asciiToInt(String p1) + { + if (p1.endsWith("A")) return 65; + if (p1.endsWith("B")) return 66; + if (p1.endsWith("C")) return 67; + if (p1.endsWith("D")) return 68; + if (p1.endsWith("E")) return 69; + if (p1.endsWith("F")) return 70; + if (p1.endsWith("G")) return 71; + if (p1.endsWith("H")) return 72; + if (p1.endsWith("I")) return 73; + if (p1.endsWith("J")) return 74; + if (p1.endsWith("K")) return 75; + if (p1.endsWith("L")) return 76; + if (p1.endsWith("M")) return 77; + if (p1.endsWith("N")) return 78; + if (p1.endsWith("O")) return 79; + if (p1.endsWith("P")) return 80; + if (p1.endsWith("Q")) return 81; + if (p1.endsWith("R")) return 82; + if (p1.endsWith("S")) return 83; + if (p1.endsWith("T")) return 84; + if (p1.endsWith("U")) return 85; + if (p1.endsWith("V")) return 86; + if (p1.endsWith("W")) return 87; + if (p1.endsWith("X")) return 88; + if (p1.endsWith("Y")) return 89; + if (p1.endsWith("Z")) return 90; + return 0; + } + + + private static char intToAscii(int p1) + { + switch (p1) + { + case 65: + return 'A'; + case 66: + return 'B'; + case 67: + return 'C'; + case 68: + return 'D'; + case 69: + return 'E'; + case 70: + return 'F'; + case 71: + return 'G'; + case 72: + return 'H'; + case 73: + return 'I'; + case 74: + return 'J'; + case 75: + return 'K'; + case 76: + return 'L'; + case 77: + return 'M'; + case 78: + return 'N'; + case 79: + return 'O'; + case 80: + return 'P'; + case 81: + return 'Q'; + case 82: + return 'R'; + case 83: + return 'S'; + case 84: + return 'T'; + case 85: + return 'U'; + case 86: + return 'V'; + case 87: + return 'W'; + case 88: + return 'X'; + case 89: + return 'Y'; + case 90: + return 'Z'; + default: + return '1'; + } + } + + + private static Coordinate getOriginPoint(String letter, int xMapId) + { + int aSwitch = asciiToInt(letter); + Coordinate Point = new Coordinate(); + switch (aSwitch) + { + case 65: //A + { + Point.x = 170000; + Point.y = 2750000; + break; + } + case 66: //B + { + Point.x = 250000; + Point.y = 2750000; + break; + } + case 67: //C + { + Point.x = 330000; + Point.y = 2750000; + break; + } + case 68: //D + { + Point.x = 170000; + Point.y = 2700000; + break; + } + case 69: //E + { + Point.x = 250000; + Point.y = 2700000; + break; + } + case 70: //F + { + Point.x = 330000; + Point.y = 2700000; + break; + } + case 71: //G + { + Point.x = 170000; + Point.y = 2650000; + break; + } + case 72: //H + { + Point.x = 250000; + Point.y = 2650000; + break; + } + case 73: //I + { + Point.x = 330000; + Point.y = 2650000; + break; + } + case 74: //J + { + Point.x = 90000; + Point.y = 2600000; + break; + } + case 75: //K + { + Point.x = 170000; + Point.y = 2600000; + break; + } + case 76: //L + { + Point.x = 250000; + Point.y = 2600000; + break; + } + case 77: //M + { + Point.x = 90000; + Point.y = 2550000; + break; + } + case 78: //N + { + Point.x = 170000; + Point.y = 2550000; + break; + } + case 79: //O + { + Point.x = 250000; + Point.y = 2550000; + break; + } + case 80: //P + { + Point.x = 90000; + Point.y = 2500000; + break; + } + case 81: //Q + { + Point.x = 170000; + Point.y = 2500000; + break; + } + case 82: //R + { + Point.x = 250000; + Point.y = 2500000; + break; + } + case 83: //���� S + { + Point.x = 10000; + Point.y = 2894000; + break; + } + case 84: //T + { + Point.x = 170000; + Point.y = 2450000; + break; + } + case 85: //U + { + Point.x = 250000; + Point.y = 2450000; + break; + } + case 86: //V + { + Point.x = 170000; + Point.y = 2400000; + break; + } + case 87: // W + { + Point.x = 250000; + Point.y = 2400000; + break; + } + case 88: //��� X + { + Point.x = 10000; + Point.y = 2614000; + break; + } + case 89: //��� Y + { + Point.x = 10000; + Point.y = 2564000; + break; + } + case 90: //���� ��Z + { + Point.x = (xMapId < 51) ? 90000 : 10000; + Point.y = 2675800; + break; + } + default: + { + return null; + } + } + return Point; + } + + + private static Coordinate twoNumberScale(String number, int scale) + { + return twoNumberScale(number, scale, scale); + } + + + private static String dataFormat(int p1) + { + String s1 = Integer.toString(p1); + if (s1.length() < 2) + s1 = "0" + s1; + return s1; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java index 06428e0..9a13352 100644 --- a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java @@ -9,7 +9,7 @@ * Time: �U�� 01:35:03 * To change this template use File | Settings | File Templates. */ -public class TWDDatumConverter +public abstract class TWDDatumConverter { /* * Definition of math related value @@ -490,8 +490,13 @@ * } */ + /** + * ��TM2�y���ഫ��TWD97�y�� + * @param pt TM2��m + * @return �s��TWD97�y�� + */ public static Coordinate fromTM2ToTWD97(Coordinate pt) { - return fromTM2(TWD97_A,TWD97_ECC,TWD97_ECC2, 0, 121, TWD97_TM2, pt.x, pt.y); + return fromTM2(TWD97_A,TWD97_ECC,TWD97_ECC2, 0, 121, TWD97_TM2, pt.x - 250000.0, pt.y); } } -- Gitblit v0.0.0-SNAPSHOT