    001    //$$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/tools/shape/AVL2SLD.java $$
    002    /*----------------------------------------------------------------------------
    003     This file is part of deegree, http://deegree.org/
    004     Copyright (C) 2001-2009 by:
    005       Department of Geography, University of Bonn
    006     and
    007       lat/lon GmbH
    008
    009     This library is free software; you can redistribute it and/or modify it under
    010     the terms of the GNU Lesser General Public License as published by the Free
    011     Software Foundation; either version 2.1 of the License, or (at your option)
    012     any later version.
    013     This library is distributed in the hope that it will be useful, but WITHOUT
    014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
    016     details.
    017     You should have received a copy of the GNU Lesser General Public License
    018     along with this library; if not, write to the Free Software Foundation, Inc.,
    019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    020
    021     Contact information:
    022
    023     lat/lon GmbH
    024     Aennchenstr. 19, 53177 Bonn
    025     Germany
    026     http://lat-lon.de/
    027
    028     Department of Geography, University of Bonn
    029     Prof. Dr. Klaus Greve
    030     Postfach 1147, 53001 Bonn
    031     Germany
    032     http://www.geographie.uni-bonn.de/deegree/
    033
    034     e-mail: info@deegree.org
    035    ----------------------------------------------------------------------------*/
    036
    037    package org.deegree.tools.shape;
    038
    039    import java.awt.Color;
    040    import java.awt.image.BufferedImage;
    041    import java.io.File;
    042    import java.io.FileOutputStream;
    043    import java.io.FileReader;
    044    import java.io.FileWriter;
    045    import java.io.FilenameFilter;
    046    import java.io.IOException;
    047    import java.io.Reader;
    048    import java.util.ArrayList;
    049    import java.util.HashMap;
    050    import java.util.List;
    051    import java.util.Map;
    052    import java.util.regex.Matcher;
    053    import java.util.regex.Pattern;
    054
    055    import org.deegree.datatypes.QualifiedName;
    056    import org.deegree.framework.util.ImageUtils;
    057    import org.deegree.framework.util.StringTools;
    058    import org.deegree.framework.xml.Marshallable;
    059    import org.deegree.graphics.sld.AbstractLayer;
    060    import org.deegree.graphics.sld.AbstractStyle;
    061    import org.deegree.graphics.sld.ExternalGraphic;
    062    import org.deegree.graphics.sld.FeatureTypeStyle;
    063    import org.deegree.graphics.sld.Fill;
    064    import org.deegree.graphics.sld.Font;
    065    import org.deegree.graphics.sld.Graphic;
    066    import org.deegree.graphics.sld.GraphicFill;
    067    import org.deegree.graphics.sld.LabelPlacement;
    068    import org.deegree.graphics.sld.LineSymbolizer;
    069    import org.deegree.graphics.sld.Mark;
    070    import org.deegree.graphics.sld.NamedLayer;
    071    import org.deegree.graphics.sld.PointPlacement;
    072    import org.deegree.graphics.sld.PointSymbolizer;
    073    import org.deegree.graphics.sld.PolygonSymbolizer;
    074    import org.deegree.graphics.sld.Rule;
    075    import org.deegree.graphics.sld.Stroke;
    076    import org.deegree.graphics.sld.StyleFactory;
    077    import org.deegree.graphics.sld.StyledLayerDescriptor;
    078    import org.deegree.graphics.sld.Symbolizer;
    079    import org.deegree.graphics.sld.TextSymbolizer;
    080    import org.deegree.io.shpapi.MainFile;
    081    import org.deegree.io.shpapi.ShapeConst;
    082    import org.deegree.model.filterencoding.ComplexFilter;
    083    import org.deegree.model.filterencoding.Filter;
    084    import org.deegree.model.filterencoding.FilterConstructionException;
    085    import org.deegree.model.filterencoding.Literal;
    086    import org.deegree.model.filterencoding.LogicalOperation;
    087    import org.deegree.model.filterencoding.Operation;
    088    import org.deegree.model.filterencoding.OperationDefines;
    089    import org.deegree.model.filterencoding.PropertyIsCOMPOperation;
    090    import org.deegree.model.filterencoding.PropertyName;
    091
    092    /**
    093     * <p>
    094     * This class converts ESRI *.avl files to OGC SLD documents. The current version of this tool isn't
    095     * able to convert each and every construction that is possible with an *.avl file. But most of the
    096     * common expressions will be mapped.
    097     * </p>
    098     * <p>
    099     * Because SLD (version 1.0.0) does not know inline bitmap or fill pattern definition directly
    100     * (maybe it is possible using some SVG tags) all polygon fill patterns must be converted to images
    101     * that are written to the file system and referenced as external graphic by the created SLD style.
    102     * The similar is true for symbol definitions. SLD just 'knowns' a few predefined symbols that are
    103     * not able to capture all symbols known by ArcView. In this context deegree also will extend the
    104     * well known symbol by using ASCII codes to references symbols defined in an available font. This
    105     * will enable deegree to transform the ArcView option defining a symbol by using an ACSII character
    106     * directly. At least even if the synthax for this is SLD compliant most SLD implementation probably
    107     * won't be able to evaluate this.
    108     * </p>
    109     *
    110     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
    111     * @author last edited by: $Author: mschneider $
    112     *
    113     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
    114     */
    115    public class AVL2SLD {
    116
    117        private String fileRootName = null;
    118
    119        private String targetDir = null;
    120
    121        private Map<String, Map<String, Object>> blocks = new HashMap<String, Map<String, Object>>();
    122
    123        private static AVLPointSymbolCodeList cl = null;
    124
    125        /**
    126         * @param fileRootName
    127         * @param targetDir
    128         */
    129        public AVL2SLD( String fileRootName, String targetDir ) {
    130            this.fileRootName = fileRootName;
    131            this.targetDir = targetDir;
    132            if ( !this.targetDir.endsWith( "/" ) ) {
    133                this.targetDir = this.targetDir + "/";
    134            }
    135        }
    136
    137        /**
    138         * reads the avl file assigned to a class instance
    139         *
    140         * @throws IOException
    141         */
    142        public void read()
    143                                throws IOException {
    144            Reader reader = new FileReader( fileRootName + ".avl" );
    145            StringBuffer sb = new StringBuffer( 50000 );
    146            int c = 0;
    147            while ( ( c = reader.read() ) > -1 ) {
    148                if ( c == 9 )
    149                    c = ' ';
    150                // if ( c != 10 && c != 13) {
    151                sb.append( (char) c );
    152                // }
    153            }
    154            reader.close();
    155
    156            // create a entry in 'blocks' for each '(' ... ')'
    157            // enclosed section
    158            String[] s1 = splitavl( sb.toString() );
    159
    160            for ( int i = 1; i < s1.length; i++ ) {
    161                // write each KVP of section to a map and store it
    162                // in the blocks map.
    163                // the Class, Pattern and he Child key will be treated
    164                // as array because it isn't unique
    165                int pos = s1[i].indexOf( ' ' );
    166                if ( pos < 0 )
    167                    continue;
    168                String section = s1[i].substring( 0, pos ).trim();
    169                String[] s2 = StringTools.toArray( s1[i].substring( pos, s1[i].length() ), ":\n", false );
    170                Map<String, Object> block = new HashMap<String, Object>();
    171                for ( int j = 0; j < s2.length; j = j + 2 ) {
    172                    if ( s2[j].trim().equals( "Class" ) ) {
    173                        List<String> list = (List<String>) block.get( "Class" );
    174                        if ( list == null ) {
    175                            list = new ArrayList<String>();
    176                        }
    177                        list.add( s2[j + 1] );
    178                        block.put( s2[j], list );
    179                    } else if ( s2[j].trim().equals( "Child" ) ) {
    180                        List<String> list = (List<String>) block.get( "Child" );
    181                        if ( list == null ) {
    182                            list = new ArrayList<String>();
    183                        }
    184                        list.add( s2[j + 1] );
    185                        block.put( s2[j], list );
    186                    } else if ( s2[j].trim().equals( "Pattern" ) ) {
    187                        List<String> list = (List<String>) block.get( "Pattern" );
    188                        if ( list == null ) {
    189                            list = new ArrayList<String>();
    190                        }
    191                        list.add( s2[j + 1] );
    192                        block.put( s2[j], list );
    193                    } else if ( s2[j].trim().equals( "Bits" ) ) {
    194                        List<String> list = (List<String>) block.get( "Bits" );
    195                        if ( list == null ) {
    196                            list = new ArrayList<String>();
    197                        }
    198                        list.add( s2[j + 1] );
    199                        block.put( s2[j], list );
    200                    } else {
    201                        block.put( s2[j], s2[j + 1].trim() );
    202                    }
    203                }
    204                blocks.put( section, block );
    205            }
    206
    207        }
    208
    209        /**
    210         * returns a <tt>Style</tt>. For each class/child contained in a avl file one <tt>Rule</tt>
    211         * will be created
    212         *
    213         * @return a <tt>Style</tt>. For each class/child contained in a avl file one <tt>Rule</tt>
    214         *         will be created
    215         * @throws IOException
    216         * @throws Exception
    217         */
    218        public AbstractStyle getStyle()
    219                                throws IOException, Exception {
    220            Map odb = blocks.get( "ODB.1" );
    221            String roots = (String) odb.get( "Roots" );
    222            Map legend = blocks.get( "Legend." + roots );
    223            String filterCol = null;
    224            if ( legend.get( "FieldNames" ) != null ) {
    225                Map block = blocks.get( "AVStr." + legend.get( "FieldNames" ) );
    226                filterCol = (String) block.get( "S" );
    227                filterCol = StringTools.validateString( filterCol, "\"" ).toUpperCase();
    228            }
    229
    230            int geoType = getGeometryType();
    231
    232            AbstractStyle style = null;
    233            switch ( geoType ) {
    234            case ShapeConst.SHAPE_TYPE_POINT:
    235                style = createPointStyle( legend, filterCol );
    236                break;
    237            case ShapeConst.SHAPE_TYPE_POLYLINE:
    238                style = createLinesStyle( legend, filterCol );
    239                break;
    240            case ShapeConst.SHAPE_TYPE_POLYGON:
    241                style = createPolygonStyle( legend, filterCol );
    242                break;
    243            case ShapeConst.SHAPE_TYPE_MULTIPOINT:
    244                style = createPointStyle( legend, filterCol );
    245                break;
    246            default:
    247                throw new Exception( "unknown geometry type: " + geoType );
    248            }
    249            return style;
    250        }
    251
    252        /**
    253         * creates a <tt>StyledLayerDescriptor</tt> from the avl file assigned to the instace of a
    254         * <tt>AVLReader</tt>. The returned instance of a <tt>StyledLayerDescriptor</tt> just
    255         * contains one style that may containes several <tt>Rule</tt>s
    256         *
    257         * @return a <tt>StyledLayerDescriptor</tt> created from the avl file assigned to the instace
    258         *         of a <tt>AVLReader</tt>. The returned instance of a <tt>StyledLayerDescriptor</tt>
    259         *         just contains one style that may containes several <tt>Rule</tt>s
    260         * @throws IOException
    261         * @throws Exception
    262         */
    263        public StyledLayerDescriptor getStyledLayerDescriptor()
    264                                throws IOException, Exception {
    265            AbstractStyle style = getStyle();
    266            String[] t = StringTools.toArray( fileRootName, "/", false );
    267            String name = "default:" + t[t.length - 1];
    268            AbstractLayer layer = new NamedLayer( name, null, new AbstractStyle[] { style } );
    269            return new StyledLayerDescriptor( new AbstractLayer[] { layer }, "1.0.0" );
    270        }
    271
    272        /**
    273         * @return parse a string and return array of blocks between braces "(" and ")". It accounts for
    274         *         braces in quoted strings.
    275         *
    276         * @param s
    277         *            string to parse
    278         */
    279        public static String[] splitavl( String s ) {
    280            if ( s == null || s.equals( "" ) ) {
    281                return new String[0];
    282            }
    283
    284            Pattern pat = Pattern.compile( "\\(([^)\"]|\"[^\"]*\")*\\)" );
    285            Matcher mat = pat.matcher( s );
    286            int prevend = 0;
    287            ArrayList<String> vec = new ArrayList<String>();
    288            while ( mat.find() ) {
    289                int start = mat.start();
    290                int end = mat.end();
    291                if ( prevend < start - 1 ) {
    292                    String str = s.substring( prevend, start ).trim();
    293                    if ( str.length() > 0 ) {
    294                        vec.add( str );
    295                    }
    296                }
    297                String str = s.substring( start + 1, end - 1 ).trim();
    298                if ( str.length() > 0 ) {
    299                    vec.add( str );
    300                }
    301                prevend = end;
    302            }
    303            if ( prevend < s.length() - 1 ) {
    304                String str = s.substring( prevend ).trim();
    305                if ( str.length() > 0 ) {
    306                    vec.add( str );
    307                }
    308            }
    309
    310            // no value selected
    311            if ( vec.size() == 0 ) {
    312                return new String[0];
    313            }
    314
    315            return vec.toArray( new String[vec.size()] );
    316        }
    317
    318        private int getGeometryType()
    319                                throws IOException {
    320            MainFile mf = new MainFile( fileRootName );
    321            int type = mf.getShapeTypeByRecNo( 1 );
    322            mf.close();
    323            return type;
    324        }
    325
    326        /**
    327         * creates a <tt>Style</tt>. For each class/child contained in a avl file one <tt>Rule</tt>
    328         * will be created
    329         *
    330         * @param legend
    331         * @param filterCol
    332         * @return a <tt>Style</tt>.
    333         */
    334        // private AbstractStyle[] createPointStyles( Map legend, String filterCol ) {
    335        // AbstractStyle[] styles = null;
    336        // return styles;
    337        // }
    338        /**
    339         * creates a <tt>Style</tt>. For each class/child contained in a avl file one <tt>Rule</tt>
    340         * will be created
    341         *
    342         * @param legend
    343         * @param filterCol
    344         * @return a <tt>Style</tt>.
    345         */
    346        private AbstractStyle createPointStyle( Map legend, String filterCol )
    347                                throws FilterConstructionException {
    348            try {
    349                cl = new AVLPointSymbolCodeList();
    350            } catch ( Exception e ) {
    351                e.printStackTrace();
    352            }
    353            String tmp = (String) legend.get( "Symbols" );
    354            Map block = blocks.get( "SymList." + tmp );
    355            List classes = (List) legend.get( "Class" );
    356            List children = (List) block.get( "Child" );
    357
    358            List<Rule> list = new ArrayList<Rule>( classes.size() );
    359            for ( int i = 0; i < classes.size(); i++ ) {
    360                String clNo = (String) classes.get( i );
    361                Map clss = blocks.get( "LClass." + clNo );
    362                String childNo = (String) children.get( i );
    363                Map<String, Object> child = blocks.get( "CMkSym." + childNo );
    364                Rule rule = null;
    365                if ( child == null ) {
    366                    child = blocks.remove( "BMkSym." + childNo );
    367                    rule = createSimplePointRule( clss, child, filterCol );
    368                } else {
    369                    rule = createComplexPointRule( clss, child, filterCol );
    370                }
    371                if ( rule != null ) {
    372                    list.add( rule );
    373                }
    374            }
    375            Rule[] rules = list.toArray( new Rule[list.size()] );
    376            FeatureTypeStyle fts = StyleFactory.createFeatureTypeStyle( rules );
    377
    378            String[] t = StringTools.toArray( fileRootName, "/", false );
    379            String name = "default:" + t[t.length - 1];
    380            return StyleFactory.createStyle( name, null, null, fts );
    381        }
    382
    383        /**
    384         * creates a Style for a line symbol
    385         *
    386         * @param clss
    387         * @param child
    388         * @return a Style for a line symbol
    389         */
    390        private Rule createSimplePointRule( Map clss, Map<String, Object> child, String filterCol ) {
    391
    392            if ( clss.get( "IsNoData" ) != null ) {
    393                return null;
    394            }
    395
    396            String label = (String) clss.get( "Label" );
    397            label = StringTools.validateString( label, "\"" );
    398            Filter filter = createFilter( clss, filterCol );
    399            // get foreground color
    400            String clrIdx = (String) child.get( "Color" );
    401            Map<String, Object> color = blocks.get( "TClr." + clrIdx );
    402            double fgOpacity = 1f;
    403            if ( color != null && "\"Transparent\"".equals( color.get( "Name" ) ) ) {
    404                fgOpacity = 0f;
    405            }
    406            Color fgColor = createColor( color );
    407            if ( fgColor == null ) {
    408                fgColor = Color.BLACK;
    409            }
    410            // get background color (what ever this means)
    411            clrIdx = (String) child.get( "BgColor" );
    412            color = blocks.get( "TClr." + clrIdx );
    413            double bgOpacity = 1f;
    414            if ( color != null && "\"Transparent\"".equals( color.get( "Name" ) ) ) {
    415                bgOpacity = 0f;
    416            }
    417            Color bgColor = createColor( color );
    418            if ( bgColor == null ) {
    419                bgColor = Color.BLACK;
    420            }
    421
    422            double size = Double.parseDouble( (String) child.get( "Size" ) );
    423            double rotation = Double.parseDouble( (String) child.get( "Angle" ) );
    424
    425            // creation of a font from a avl file is a triky thing because
    426            // esri uses their own font names and codes
    427            // --> don' know if this works
    428            String fntIdx = (String) child.get( "Font" );
    429            Map fntMap = blocks.get( "NFont." + fntIdx );
    430            Font font = createFont( fntMap );
    431            PointPlacement pp = StyleFactory.createPointPlacement();
    432            LabelPlacement labelPlacement = StyleFactory.createLabelPlacement( pp );
    433            TextSymbolizer textSym = StyleFactory.createTextSymbolizer( fgColor, font, filterCol, labelPlacement );
    434
    435            String patternIdx = (String) ( (ArrayList) child.get( "Pattern" ) ).get( 0 );
    436            String symbol = cl.getSymbol( patternIdx );
    437
    438            // create a Mark with a stroke and fill to controll both
    439            // opacities
    440            Stroke stroke = StyleFactory.createStroke( fgColor, 1, fgOpacity, null, "mitre", "butt" );
    441            Fill fill = StyleFactory.createFill( bgColor, bgOpacity );
    442            Mark mark = StyleFactory.createMark( symbol, fill, stroke );
    443
    444            Graphic graphic = StyleFactory.createGraphic( null, mark, 1, size, rotation );
    445            PointSymbolizer pointSym = StyleFactory.createPointSymbolizer( graphic );
    446
    447            return StyleFactory.createRule( new Symbolizer[] { pointSym, textSym }, label, label, "", null, filter, false,
    448                                            0, 9E99 );
    449        }
    450
    451        private Rule createComplexPointRule( Map clss, Map<String, Object> child, String filterCol )
    452                                throws FilterConstructionException {
    453
    454            if ( clss.get( "IsNoData" ) != null ) {
    455                return null;
    456            }
    457
    458            String tmp = (String) child.get( "Symbols" );
    459            Map block = blocks.get( "SymList." + tmp );
    460            List children = (List) block.get( "Child" );
    461
    462            List<Symbolizer> smbls = new ArrayList<Symbolizer>();
    463            for ( int i = 0; i < children.size(); i++ ) {
    464                String childNo = (String) children.get( i );
    465                Map child_ = blocks.get( "CMkSym." + childNo );
    466                Rule rule = null;
    467                if ( child_ == null ) {
    468                    child = blocks.remove( "BMkSym." + childNo );
    469                    rule = createSimplePointRule( clss, child, filterCol );
    470                } else {
    471                    rule = createComplexPointRule( clss, child, filterCol );
    472                }
    473                Symbolizer[] sym = rule.getSymbolizers();
    474                for ( int j = 0; j < sym.length; j++ ) {
    475                    smbls.add( sym[j] );
    476                }
    477            }
    478            Symbolizer[] sym = new Symbolizer[smbls.size()];
    479            sym = smbls.toArray( sym );
    480
    481            String label = (String) clss.get( "Label" );
    482            label = StringTools.validateString( label, "\"" );
    483            Filter filter = createFilter( clss, filterCol );
    484
    485            return StyleFactory.createRule( sym, label, label, "", null, filter, false, 0, 9E99 );
    486        }
    487
    488        private Font createFont( Map fntMap ) {
    489            String idx = (String) fntMap.get( "Family" );
    490            String family = (String) blocks.get( "AVStr." + idx ).get( "S" );
    491            idx = (String) fntMap.get( "Name" );
    492            String name = (String) blocks.get( "AVStr." + idx ).get( "S" );
    493            idx = (String) fntMap.get( "Style" );
    494            String style = (String) blocks.get( "AVStr." + idx ).get( "S" );
    495            String weight = (String) fntMap.get( "Weight" );
    496            String wideness = (String) fntMap.get( "Wideness" );
    497
    498            boolean italic = style.equals( "Italic" );
    499            boolean bold = Integer.parseInt( weight ) > 1;
    500
    501            return StyleFactory.createFont( family, italic, bold, 12 );
    502        }
    503
    504        /**
    505         * creates a <tt>Style</tt>. For each class/child contained in a avl file one <tt>Rule</tt>
    506         * will be created
    507         *
    508         * @param legend
    509         * @param filterCol
    510         * @return a <tt>Style</tt>.
    511         */
    512        private AbstractStyle createLinesStyle( Map legend, String filterCol ) {
    513            String tmp = (String) legend.get( "Symbols" );
    514            Map block = blocks.get( "SymList." + tmp );
    515            List classes = (List) legend.get( "Class" );
    516            List children = (List) block.get( "Child" );
    517            List<Rule> list = new ArrayList<Rule>( classes.size() );
    518            for ( int i = 0; i < classes.size(); i++ ) {
    519                String clNo = (String) classes.get( i );
    520                Map clss = blocks.get( "LClass." + clNo );
    521                String childNo = (String) children.get( i );
    522                Map<String, Object> child = blocks.get( "BLnSym." + childNo );
    523
    524                if ( child == null ) {
    525                    // won't be treated correctly because we can't transform
    526                    // lines with sambols at the moment
    527                    child = blocks.get( "CLnSym." + childNo );
    528                }
    529                Rule rule = createLineRule( clss, child, filterCol );
    530                if ( rule != null ) {
    531                    list.add( rule );
    532                }
    533            }
    534            Rule[] rules = list.toArray( new Rule[list.size()] );
    535            FeatureTypeStyle fts = StyleFactory.createFeatureTypeStyle( rules );
    536
    537            String[] t = StringTools.toArray( fileRootName, "/", false );
    538            String name = "default:" + t[t.length - 1];
    539            return StyleFactory.createStyle( name, null, null, fts );
    540        }
    541
    542        /**
    543         * creates a Style for a line symbol
    544         *
    545         * @param clss
    546         * @param child
    547         * @return a Style for a line symbol
    548         */
    549        private Rule createLineRule( Map clss, Map<String, Object> child, String filterCol ) {
    550
    551            if ( clss.get( "IsNoData" ) != null ) {
    552                return null;
    553            }
    554
    555            String label = (String) clss.get( "Label" );
    556            label = StringTools.validateString( label, "\"" );
    557            Filter filter = createFilter( clss, filterCol );
    558
    559            String clrIdx = (String) child.get( "Color" );
    560            Map<String, Object> color = blocks.get( "TClr." + clrIdx );
    561            double opacity = 1f;
    562            if ( color != null && "\"Transparent\"".equals( color.get( "Name" ) ) && color.size() > 0 ) {
    563                opacity = 0f;
    564            }
    565            Color colour = createColor( color );
    566            if ( colour == null ) {
    567                colour = Color.BLACK;
    568            }
    569
    570            double width = 1.0; // default Width
    571            if ( child.get( "Width" ) != null ) {
    572                width = Double.parseDouble( (String) child.get( "Width" ) ) + width;
    573            }
    574            // double width = Double.parseDouble( (String)child.get("Width") ) + 1;
    575            List<String> pl = (List<String>) child.get( "Pattern" );
    576
    577            if ( child.get( "Pattern" ) == null ) { // create a default pattern List if
    578                // it is null
    579                pl = new ArrayList<String>();
    580                for ( int i = 0; i < 16; i++ ) { // Fill the default List with
    581                    // default values "0.00000000000000"
    582                    pl.add( "0.00000000000000" );
    583                }
    584            }
    585
    586            // List pl = (List)child.get("Pattern");
    587            float[] dashArray = createDashArray( pl );
    588            Stroke stroke = StyleFactory.createStroke( colour, width, opacity, dashArray, "mitre", "butt" );
    589            LineSymbolizer lineSym = StyleFactory.createLineSymbolizer( stroke );
    590
    591            return StyleFactory.createRule( new Symbolizer[] { lineSym }, label, label, "", null, filter, false, 0, 9E99 );
    592        }
    593
    594        /**
    595         * creates a <tt>Style</tt>. For each class/child contained in a avl file one <tt>Rule</tt>
    596         * will be created
    597         *
    598         * @param legend
    599         * @param filterCol
    600         * @return a <tt>Style</tt>.
    601         */
    602        private AbstractStyle createPolygonStyle( Map legend, String filterCol )
    603                                throws Exception {
    604            String tmp = (String) legend.get( "Symbols" );
    605            Map block = blocks.get( "SymList." + tmp );
    606            List classes = (List) legend.get( "Class" );
    607            List children = (List) block.get( "Child" );
    608            List<Rule> list = new ArrayList<Rule>( classes.size() );
    609            for ( int i = 0; i < classes.size(); i++ ) {
    610                String clNo = (String) classes.get( i );
    611                Map clss = blocks.get( "LClass." + clNo );
    612                String childNo = (String) children.get( i );
    613                Map<String, Object> child = blocks.get( "BShSym." + childNo );
    614                Rule rule = null;
    615                if ( child == null ) {
    616                    // VShSym is a vector polygon fill
    617                    child = blocks.get( "VShSym." + childNo );
    618                    rule = createPolygonVecRule( clss, child, filterCol );
    619                } else {
    620                    rule = createPolygonBMPRule( clss, child, filterCol );
    621                }
    622                if ( rule != null ) {
    623                    list.add( rule );
    624                }
    625                // TODO
    626                // write special method for vector polygon fill
    627            }
    628            Rule[] rules = list.toArray( new Rule[list.size()] );
    629            FeatureTypeStyle fts = StyleFactory.createFeatureTypeStyle( rules );
    630
    631            String[] t = StringTools.toArray( fileRootName, "/", false );
    632            String name = "default:" + t[t.length - 1];
    633            return StyleFactory.createStyle( name, null, null, fts );
    634        }
    635
    636        /**
    637         * creates a Style for a line symbol
    638         *
    639         * @param clss
    640         * @param child
    641         * @return a Style for a line symbol
    642         */
    643        private Rule createPolygonBMPRule( Map clss, Map<String, Object> child, String filterCol )
    644                                throws Exception {
    645
    646            if ( clss.get( "IsNoData" ) != null ) {
    647                return null;
    648            }
    649
    650            String label = (String) clss.get( "Label" );
    651            label = StringTools.validateString( label, "\"" );
    652
    653            Filter filter = null;
    654            if ( filterCol != null ) {
    655                filter = createFilter( clss, filterCol );
    656            }
    657            // get foreground color
    658            String clrIdx = (String) child.get( "Color" );
    659            Map<String, Object> color = blocks.get( "TClr." + clrIdx );
    660            double opacity = 1f;
    661            if ( color != null && "\"Transparent\"".equals( color.get( "Name" ) ) ) {
    662                opacity = 0f;
    663            }
    664
    665            Color fgColor = createColor( color );
    666            if ( fgColor == null ) {
    667                fgColor = Color.BLACK;
    668            }
    669            // get color of the outlining stroke
    670            clrIdx = (String) child.get( "OutlineColor" );
    671            color = blocks.get( "TClr." + clrIdx );
    672            double outLOpacity = 1f;
    673            if ( color != null && "\"Transparent\"".equals( color.get( "Name" ) ) ) {
    674                outLOpacity = 0f;
    675            }
    676            Color outLColor = createColor( color );
    677            if ( outLColor == null ) {
    678                outLColor = Color.BLACK;
    679            }
    680            // get background color
    681            clrIdx = (String) child.get( "BgColor" );
    682            color = blocks.get( "TClr." + clrIdx );
    683            double bgOpacity = 1f;
    684            if ( color != null && "\"Transparent\"".equals( color.get( "Name" ) ) ) {
    685                bgOpacity = 0f;
    686            }
    687            Color bgColor = createColor( color );
    688
    689            // create fill pattern as an image that will be referenced as
    690            // external graphic
    691            String stippleIdx = (String) child.get( "Stipple" );
    692            String src = null;
    693            if ( stippleIdx != null ) {
    694                Map stipple = blocks.get( "Stipple." + stippleIdx );
    695                src = createExternalGraphicFromStipple( stipple, label, fgColor, bgColor );
    696            }
    697
    698            double width = Double.parseDouble( (String) child.get( "OutlineWidth" ) ) + 1;
    699            Stroke stroke = StyleFactory.createStroke( outLColor, width, outLOpacity, null, "mitre", "butt" );
    700            Fill fill = null;
    701            if ( stippleIdx != null ) {
    702                ExternalGraphic eg = StyleFactory.createExternalGraphic( "file:///" + src, "image/gif" );
    703                Graphic graph = StyleFactory.createGraphic( eg, null, opacity, 10, 0 );
    704                GraphicFill gf = StyleFactory.createGraphicFill( graph );
    705                fill = StyleFactory.createFill( fgColor, opacity, gf );
    706            } else {
    707                fill = StyleFactory.createFill( fgColor, opacity );
    708            }
    709            PolygonSymbolizer polySym = StyleFactory.createPolygonSymbolizer( stroke, fill );
    710            return StyleFactory.createRule( new Symbolizer[] { polySym }, label, label, "", null, filter, false, 0, 9E99 );
    711        }
    712
    713        /**
    714         * creates a Style for a line symbol
    715         *
    716         * @param clss
    717         * @param child
    718         * @return a Style for a line symbol
    719         */
    720        private Rule createPolygonVecRule( Map clss, Map<String, Object> child, String filterCol )
    721                                throws Exception {
    722
    723            if ( clss.get( "IsNoData" ) != null ) {
    724                return null;
    725            }
    726
    727            String label = (String) clss.get( "Label" );
    728            label = StringTools.validateString( label, "\"" );
    729
    730            Filter filter = null;
    731            if ( filterCol != null ) {
    732                filter = createFilter( clss, filterCol );
    733            }
    734            // get foreground color
    735            String clrIdx = (String) child.get( "Color" );
    736            Map<String, Object> color = blocks.get( "TClr." + clrIdx );
    737            double opacity = 1f;
    738            if ( color != null && "\"Transparent\"".equals( color.get( "Name" ) ) ) {
    739                opacity = 0f;
    740            }
    741            Color fgColor = createColor( color );
    742            if ( fgColor == null ) {
    743                fgColor = Color.BLACK;
    744            }
    745            // get color of the outlining stroke
    746            clrIdx = (String) child.get( "OutlineColor" );
    747            color = blocks.get( "TClr." + clrIdx );
    748            double outLOpacity = 1f;
    749            if ( color != null && "\"Transparent\"".equals( color.get( "Name" ) ) ) {
    750                outLOpacity = 0f;
    751            }
    752            Color outLColor = createColor( color );
    753            if ( outLColor == null ) {
    754                outLColor = Color.BLACK;
    755            }
    756            // get background color
    757            clrIdx = (String) child.get( "BgColor" );
    758            color = blocks.get( "TClr." + clrIdx );
    759            double bgOpacity = 1f;
    760            if ( color != null && "\"Transparent\"".equals( color.get( "Name" ) ) ) {
    761                bgOpacity = 0f;
    762            }
    763            Color bgColor = createColor( color );
    764
    765            // create fill pattern as an image that will be referenced as
    766            // external graphic
    767            String stippleIdx = (String) child.get( "Stipple" );
    768            String src = null;
    769            if ( stippleIdx != null ) {
    770                Map stipple = blocks.get( "Stipple." + stippleIdx );
    771                src = createExternalGraphicFromStipple( stipple, label, fgColor, bgColor );
    772            }
    773
    774            double width = Double.parseDouble( (String) child.get( "OutlineWidth" ) ) + 1;
    775            Stroke stroke = StyleFactory.createStroke( outLColor, width, outLOpacity, null, "mitre", "butt" );
    776            Fill fill = null;
    777            if ( stippleIdx != null ) {
    778                ExternalGraphic eg = StyleFactory.createExternalGraphic( "file:///" + src, "image/gif" );
    779                Graphic graph = StyleFactory.createGraphic( eg, null, opacity, 10, 0 );
    780                GraphicFill gf = StyleFactory.createGraphicFill( graph );
    781                fill = StyleFactory.createFill( fgColor, opacity, gf );
    782            } else {
    783                fill = StyleFactory.createFill( fgColor, opacity );
    784            }
    785            PolygonSymbolizer polySym = StyleFactory.createPolygonSymbolizer( stroke, fill );
    786            return StyleFactory.createRule( new Symbolizer[] { polySym }, label, label, "", null, filter, false, 0, 9E99 );
    787        }
    788
    789        /**
    790         * creates an image from a stipple and stores it as a gif image. The method returns the full
    791         * name of the stored image.
    792         *
    793         * @param stipple
    794         * @return an image from a stipple and stores it as a gif image. The method returns the full
    795         *         name of the stored image.
    796         */
    797        private String createExternalGraphicFromStipple( Map stipple, String label, Color fg, Color bg )
    798                                throws Exception {
    799
    800            if ( label != null ) {
    801                label = label.replace( ' ', '_' );
    802                label = label.replace( '.', '_' );
    803                label = label.replace( ';', '_' );
    804                label = label.replace( ',', '_' );
    805                label = label.replace( '-', '_' );
    806                label = label.replace( ':', '_' );
    807            }
    808            String tmp = (String) stipple.get( "Columns" );
    809            int cols = Integer.parseInt( tmp );
    810            tmp = (String) stipple.get( "Rows" );
    811            int rows = Integer.parseInt( tmp );
    812
    813            List bList = (List) stipple.get( "Bits" );
    814            StringBuffer bStr = new StringBuffer( 1000 );
    815            for ( int i = 0; i < bList.size(); i++ ) {
    816                String[] t = StringTools.toArray( ( (String) bList.get( i ) ).trim(), " ", false );
    817                for ( int j = 0; j < t.length; j++ ) {
    818                    bStr.append( t[j] );
    819                }
    820            }
    821
    822            char[] ch = bStr.toString().toCharArray();
    823
    824            BufferedImage bi = createFillPattern( cols, rows, ch, fg, bg );
    825
    826            final String format = "gif";
    827
    828            String[] t = StringTools.toArray( fileRootName, "/", false );
    829            String base = t[t.length - 1];
    830            StringBuffer fileName = new StringBuffer();
    831            fileName.append( targetDir ).append( base );
    832            if ( label != null ) {
    833                fileName.append( "_" ).append( label ).append( "." ).append( format );
    834            } else {
    835                fileName.append( "." ).append( format );
    836            }
    837
    838            // FileOutputStream fos = new FileOutputStream( targetDir + base + '_' + label + "." +
    839            // format );
    840            FileOutputStream fos = new FileOutputStream( fileName.toString() );
    841            ImageUtils.saveImage( bi, fos, format, 1.0f );
    842            // Encoders.encodeGif(fos,bi);
    843            fos.close();
    844
    845            if ( targetDir.startsWith( "/" ) ) {
    846                if ( label != null ) {
    847                    return targetDir.substring( 1, targetDir.length() ) + base + '_' + label + "." + format;
    848                } else {
    849                    return targetDir.substring( 1, targetDir.length() ) + base + "." + format;
    850                }
    851            } else {
    852                if ( label != null ) {
    853                    return targetDir + base + '_' + label + "." + format;
    854                } else {
    855                    return targetDir + base + "." + format;
    856                }
    857
    858            }
    859
    860        }
    861
    862        /**
    863         * creates a <tt>BufferedImage</tt> using the stipple contained in the passed char array.
    864         *
    865         * @param cols
    866         * @param rows
    867         * @param ch
    868         * @return a <tt>BufferedImage</tt> using the stipple contained in the passed char array.
    869         */
    870        private BufferedImage createFillPattern( int cols, int rows, char[] ch, Color fg, Color bg ) {
    871            BufferedImage bi = new BufferedImage( cols, rows, BufferedImage.TYPE_INT_ARGB );
    872            int cntChar = 0;
    873            byte[] bTmp = null;
    874            char chr = ' ';
    875            int hexCnt = 0;
    876            if ( cols % 8 != 0 ) {
    877                hexCnt = ( cols / 8 + 1 ) * 8;
    878            } else {
    879                hexCnt = cols;
    880            }
    881            for ( int i = 0; i < rows; i++ ) {
    882                for ( int j = 0; j < hexCnt; j++ ) {
    883                    if ( j % 4 == 0 ) {
    884                        chr = ch[cntChar++];
    885                        bTmp = getBits( chr );
    886                    }
    887                    if ( j < cols ) {
    888                        if ( bTmp[j % 4] == 0 ) {
    889                            if ( bg != null ) {
    890                                bi.setRGB( j, i, bg.getRGB() );
    891                            }
    892                        } else {
    893                            bi.setRGB( j, i, fg.getRGB() );
    894                        }
    895                    }
    896                }
    897            }
    898            return bi;
    899        }
    900
    901        private byte[] getBits( int ch ) {
    902            switch ( ch ) {
    903            case '0':
    904                return new byte[] { 0, 0, 0, 0 };
    905            case '1':
    906                return new byte[] { 0, 0, 0, 1 };
    907            case '2':
    908                return new byte[] { 0, 0, 1, 0 };
    909            case '3':
    910                return new byte[] { 0, 0, 1, 1 };
    911            case '4':
    912                return new byte[] { 0, 1, 0, 0 };
    913            case '5':
    914                return new byte[] { 0, 1, 0, 1 };
    915            case '6':
    916                return new byte[] { 0, 1, 1, 0 };
    917            case '7':
    918                return new byte[] { 0, 1, 1, 1 };
    919            case '8':
    920                return new byte[] { 1, 0, 0, 0 };
    921            case '9':
    922                return new byte[] { 1, 0, 0, 1 };
    923            case 'a':
    924                return new byte[] { 1, 0, 1, 0 };
    925            case 'b':
    926                return new byte[] { 1, 0, 1, 1 };
    927            case 'c':
    928                return new byte[] { 1, 1, 0, 0 };
    929            case 'd':
    930                return new byte[] { 1, 1, 0, 1 };
    931            case 'e':
    932                return new byte[] { 1, 1, 1, 0 };
    933            case 'f':
    934                return new byte[] { 1, 1, 1, 1 };
    935            default:
    936                return new byte[] { 0, 0, 0, 0 };
    937            }
    938        }
    939
    940        /**
    941         * @return creates a dasharray for constructing a stroke from the pattern entries of a avl
    942         *         xxxSym. block
    943         *
    944         * @param pl
    945         */
    946        private float[] createDashArray( List<String> pl ) {
    947            int cnt = 0;
    948            for ( int i = 0; i < pl.size(); i++ ) {
    949                if ( Float.parseFloat( pl.get( i ) ) > 0 ) {
    950                    cnt++;
    951                } else {
    952                    break;
    953                }
    954            }
    955            float[] pattern = null;
    956            if ( cnt > 0 ) {
    957                pattern = new float[cnt];
    958                for ( int i = 0; i < pattern.length; i++ ) {
    959                    pattern[i] = Float.parseFloat( pl.get( i ) );
    960                }
    961            }
    962            return pattern;
    963        }
    964
    965        /**
    966         * creates a AWT color from a val color block
    967         *
    968         * @param color
    969         * @return a AWT color from a val color block
    970         */
    971        private Color createColor( Map<String, Object> color ) {
    972            StringBuffer hex = new StringBuffer( "0x" );
    973            if ( color != null && !"\"Transparent\"".equals( color.get( "Name" ) ) ) {
    974                String red = (String) color.get( "Red" );
    975                if ( red == null )
    976                    red = "0x0000";
    977                int c = (int) ( ( Integer.decode( red ).intValue() / 65535f ) * 255 );
    978                if ( c < 15 ) {
    979                    hex.append( 0 );
    980                }
    981                hex.append( Integer.toHexString( c ) );
    982                String green = (String) color.get( "Green" );
    983                if ( green == null )
    984                    green = "0x0000";
    985                c = (int) ( ( Integer.decode( green ).intValue() / 65535f ) * 255 );
    986                if ( c < 15 ) {
    987                    hex.append( 0 );
    988                }
    989                hex.append( Integer.toHexString( c ) );
    990                String blue = (String) color.get( "Blue" );
    991                if ( blue == null )
    992                    blue = "0x0000";
    993                c = (int) ( ( Integer.decode( blue ).intValue() / 65535f ) * 255 );
    994                if ( c < 15 ) {
    995                    hex.append( 0 );
    996                }
    997                hex.append( Integer.toHexString( c ) );
    998            } else {
    999                // hex.append("000000");
    1000                return null;
    1001            }
    1002            return Color.decode( hex.toString() );
    1003        }
    1004
    1005        private Filter createFilter( Map clss, String filterCol ) {
    1006
    1007            if ( clss.get( "Label" ) == null ) {
    1008                return null;
    1009            }
    1010            Filter filter = null;
    1011
    1012            String maxN = (String) clss.get( "MaxStr" );
    1013            String minN = (String) clss.get( "MinStr" );
    1014            if ( maxN != null && minN != null ) {
    1015                filter = createStringFilter( clss, filterCol );
    1016            } else {
    1017                filter = createNumberFilter( clss, filterCol );
    1018            }
    1019
    1020            return filter;
    1021        }
    1022
    1023        private Filter createStringFilter( Map clss, String filterCol ) {
    1024            Filter filter;
    1025            Operation oper = null;
    1026            String maxN = (String) clss.get( "MaxStr" );
    1027            String minN = (String) clss.get( "MinStr" );
    1028            maxN = maxN.substring( 1, maxN.length() - 1 );
    1029            minN = minN.substring( 1, minN.length() - 1 );
    1030            if ( maxN.equals( minN ) ) {
    1031                oper = new PropertyIsCOMPOperation( OperationDefines.PROPERTYISEQUALTO,
    1032                                                    new PropertyName( new QualifiedName( filterCol ) ), new Literal( minN ) );
    1033            } else {
    1034                ArrayList<Operation> list = new ArrayList<Operation>();
    1035                Operation op = new PropertyIsCOMPOperation( OperationDefines.PROPERTYISLESSTHANOREQUALTO,
    1036                                                            new PropertyName( new QualifiedName( filterCol ) ),
    1037                                                            new Literal( maxN ) );
    1038                list.add( op );
    1039                op = new PropertyIsCOMPOperation( OperationDefines.PROPERTYISGREATERTHANOREQUALTO,
    1040                                                  new PropertyName( new QualifiedName( filterCol ) ), new Literal( minN ) );
    1041                list.add( op );
    1042
    1043                oper = new LogicalOperation( OperationDefines.AND, list );
    1044            }
    1045            filter = new ComplexFilter( oper );
    1046            return filter;
    1047        }
    1048
    1049        private Filter createNumberFilter( Map clss, String filterCol ) {
    1050
    1051            String maxN = (String) clss.get( "MaxNum" );
    1052            String minN = (String) clss.get( "MinNum" );
    1053            if ( maxN == null ) {
    1054                maxN = "9E99";
    1055            }
    1056            if ( minN == null ) {
    1057                minN = "-9E99";
    1058            }
    1059            double t1 = Double.parseDouble( minN );
    1060            double t2 = Double.parseDouble( maxN );
    1061            Operation oper = null;
    1062            if ( t1 == t2 ) {
    1063                // if t1 == t2 no range is defined and so an 'is equal to'
    1064                // opertaion must be used
    1065                if ( ( (int) t1 ) == t1 ) {
    1066                    // if no significant fraction values are present
    1067                    // cast the value to int
    1068                    oper = new PropertyIsCOMPOperation( OperationDefines.PROPERTYISEQUALTO,
    1069                                                        new PropertyName( new QualifiedName( filterCol ) ),
    1070                                                        new Literal( "" + ( (int) t1 ) ) );
    1071                } else {
    1072                    oper = new PropertyIsCOMPOperation( OperationDefines.PROPERTYISEQUALTO,
    1073                                                        new PropertyName( new QualifiedName( filterCol ) ),
    1074                                                        new Literal( "" + t1 ) );
    1075                }
    1076            } else {
    1077                // if t1 != t2 range of valid values is defined and so an so two
    1078                // operation (one for each border of the range) are used
    1079                ArrayList<Operation> list = new ArrayList<Operation>();
    1080                Operation op = new PropertyIsCOMPOperation( OperationDefines.PROPERTYISLESSTHANOREQUALTO,
    1081                                                            new PropertyName( new QualifiedName( filterCol ) ),
    1082                                                            new Literal( maxN ) );
    1083                list.add( op );
    1084                op = new PropertyIsCOMPOperation( OperationDefines.PROPERTYISGREATERTHANOREQUALTO,
    1085                                                  new PropertyName( new QualifiedName( filterCol ) ), new Literal( minN ) );
    1086                list.add( op );
    1087
    1088                oper = new LogicalOperation( OperationDefines.AND, list );
    1089
    1090            }
    1091
    1092            return new ComplexFilter( oper );
    1093
    1094        }
    1095
    1096        private static String[] getAVLFiles( String dir ) {
    1097            File file = new File( dir );
    1098            return file.list( new DFileFilter() );
    1099
    1100        }
    1101
    1102        private static void printHelp() {
    1103
    1104            System.out.println( "Converts ESRI *.avl files to OGC SLD documents. The current version of " );
    1105            System.out.println( "this tool isn't able to convert each and every construction that is " );
    1106            System.out.println( "possible with an *.avl file. But most of the common expressions will be mapped." );
    1107            System.out.println( "Supported are *.avl files for point, lines and polygons." );
    1108            System.out.println( "" );
    1109            System.out.println( "-sourceFile -> full path to the *.avl file to be converted. " );
    1110            System.out.println( "           in the same directory a shapefile with the same name as the *.avl" );
    1111            System.out.println( "               file must exist! (conditional, -sourceFile or -sourceDir must " );
    1112            System.out.println( "               be defined)" );
    1113            System.out.println( "-sourceDir  -> directory containing one or more *.avl files. for each existing" );
    1114            System.out.println( "               *.avl file a shapefile with the same base name must exist. " );
    1115            System.out.println( "               (conditional, -sourceFile or -sourceDir must be defined)" );
    1116            System.out.println( "-targetDir  -> directory where the created SLD document(s) will be stored. (optional)" );
    1117            System.out.println( "-h  -> print this help" );
    1118        }
    1119
    1120        /**
    1121         *
    1122         * @param args
    1123         * @throws Exception
    1124         */
    1125        public static void main( String[] args )
    1126                                throws Exception {
    1127
    1128            Map<String, String> map = new HashMap<String, String>();
    1129
    1130            for ( int i = 0; i < args.length; i += 2 ) {
    1131                map.put( args[i], args[i + 1] );
    1132            }
    1133
    1134            if ( map.get( "-sourceFile" ) == null && map.get( "-sourceDir" ) == null && map.get( "-h" ) == null ) {
    1135                System.out.println( "-sourceFile or -sourceDir must be defined!" );
    1136                System.out.println();
    1137                printHelp();
    1138                System.exit( 1 );
    1139            }
    1140
    1141            if ( map.get( "-h" ) != null ) {
    1142                printHelp();
    1143                System.exit( 0 );
    1144            }
    1145
    1146            String targetDir = ".";
    1147            String[] sourceFiles = null;
    1148            if ( map.get( "-sourceFile" ) != null ) {
    1149                sourceFiles = new String[] { map.get( "-sourceFile" ) };
    1150                // set the default target directory to the sourceFile's directory
    1151                targetDir = sourceFiles[0].substring( 0, sourceFiles[0].lastIndexOf( "/" ) );
    1152            }
    1153
    1154            if ( sourceFiles == null ) {
    1155                String sourceDir = map.get( "-sourceDir" );
    1156                sourceFiles = getAVLFiles( sourceDir );
    1157                for ( int i = 0; i < sourceFiles.length; i++ ) {
    1158                    sourceFiles[i] = sourceDir + '/' + sourceFiles[i];
    1159                }
    1160                // set the default target directory to the source directory
    1161                targetDir = sourceDir;
    1162
    1163            }
    1164
    1165            // String targetDir = ".";
    1166            if ( map.get( "-targetDir" ) != null ) {
    1167                targetDir = map.get( "-targetDir" );
    1168            }
    1169
    1170            for ( int i = 0; i < sourceFiles.length; i++ ) {
    1171                System.out.println( "processing: " + sourceFiles[i] );
    1172                int pos = sourceFiles[i].lastIndexOf( '.' );
    1173                String file = sourceFiles[i].substring( 0, pos );
    1174                AVL2SLD avl = new AVL2SLD( file, targetDir );
    1175                avl.read();
    1176                StyledLayerDescriptor sld = avl.getStyledLayerDescriptor();
    1177                String[] t = StringTools.toArray( file, "/", false );
    1178                FileWriter fos = new FileWriter( targetDir + '/' + t[t.length - 1] + ".xml" );
    1179                fos.write( ( (Marshallable) sld ).exportAsXML() );
    1180                fos.close();
    1181            }
    1182        }
    1183
    1184        /**
    1185         *
    1186         *
    1187         * @version $Revision: 18195 $
    1188         * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
    1189         */
    1190        private static class DFileFilter implements FilenameFilter {
    1191            /**
    1192             * @param f
    1193             * @return true if accepted
    1194             */
    1195            public boolean accept( File f, String name ) {
    1196                int pos = name.lastIndexOf( "." );
    1197                String ext = name.substring( pos + 1 );
    1198                return ext.toUpperCase().equals( "AVL" );
    1199            }
    1200        }
    1201
    1202    }