001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/io/shpapi/shape_new/ShapeFileWriter.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    package org.deegree.io.shpapi.shape_new;
037    
038    import java.io.BufferedOutputStream;
039    import java.io.File;
040    import java.io.FileOutputStream;
041    import java.io.IOException;
042    import java.io.OutputStream;
043    
044    import org.deegree.framework.log.ILogger;
045    import org.deegree.framework.log.LoggerFactory;
046    import org.deegree.io.dbaseapi.DBaseException;
047    import org.deegree.model.spatialschema.ByteUtils;
048    
049    /**
050     * <code>ShapeFileWriter</code> is a class to write shapefiles.
051     *
052     * @author <a href="mailto:schmitz@lat-lon.de">Andreas Schmitz</a>
053     * @author last edited by: $Author: mschneider $
054     *
055     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
056     */
057    public class ShapeFileWriter {
058    
059        private ShapeFile shapeFile;
060    
061        private static final ILogger LOG = LoggerFactory.getLogger( ShapeFileWriter.class );
062    
063        /**
064         * @param shapes
065         */
066        public ShapeFileWriter( ShapeFile shapes ) {
067            shapeFile = shapes;
068        }
069    
070        private void writeHeader( OutputStream out, int length )
071                                throws IOException {
072    
073            // what's funny about shapefiles:
074            // 1) in the headers, they use big endian for some values, little endian for others
075            // (the rest of the file is little endian)
076            // 2) Only 4 byte ints and 8 byte doubles are used in the file, however,
077            // the size is measured in 16 bit words...
078    
079            byte[] header = new byte[100];
080    
081            ByteUtils.writeBEInt( header, 0, ShapeFile.FILETYPE );
082            ByteUtils.writeBEInt( header, 24, length );
083            ByteUtils.writeLEInt( header, 28, ShapeFile.VERSION );
084            ByteUtils.writeLEInt( header, 32, shapeFile.getShapeType() );
085    
086            ShapeEnvelope envelope = shapeFile.getEnvelope();
087            envelope.write( header, 36 );
088    
089            // it shouldn't hurt to write these values as doubles default to 0.0 anyway
090            ByteUtils.writeLEDouble( header, 68, envelope.zmin );
091            ByteUtils.writeLEDouble( header, 76, envelope.zmax );
092            ByteUtils.writeLEDouble( header, 84, envelope.mmin );
093            ByteUtils.writeLEDouble( header, 92, envelope.mmax );
094    
095            out.write( header, 0, 100 );
096        }
097    
098        private void writeShapes( OutputStream mainOut, OutputStream indexOut )
099                                throws IOException {
100            // allocate the WHOLE shape file
101            byte[] bytes = new byte[shapeFile.getSize()];
102            byte[] indexBytes = new byte[8 * shapeFile.getShapes().size()];
103    
104            int recordNum = 1;
105            int offset = 0;
106            int indexOffset = 0;
107    
108            for ( Shape s : shapeFile.getShapes() ) {
109                ByteUtils.writeBEInt( indexBytes, indexOffset, ( 100 + offset ) / 2 );
110                indexOffset += 4;
111                ByteUtils.writeBEInt( indexBytes, indexOffset, s.getByteLength() / 2 );
112                indexOffset += 4;
113    
114                ByteUtils.writeBEInt( bytes, offset, recordNum++ );
115                offset += 4;
116                ByteUtils.writeBEInt( bytes, offset, s.getByteLength() / 2 ); // again 16-bit words
117                offset += 4;
118    
119                LOG.logDebug( "Writing a " + s.getClass().getSimpleName() + ", size " + s.getByteLength() + " from offset "
120                              + offset );
121                offset = s.write( bytes, offset );
122            }
123    
124            mainOut.write( bytes, 0, bytes.length );
125            indexOut.write( indexBytes, 0, indexBytes.length );
126        }
127    
128        /**
129         * Writes the shapes to the files with the given base name.
130         *
131         * @param baseName
132         * @throws IOException
133         * @throws DBaseException
134         * @deprecated
135         */
136        @Deprecated
137        public void write( String baseName )
138                                throws IOException, DBaseException {
139            LOG.logWarning( "Base name parameter " + baseName + " is ignored! Base name of " + shapeFile.getBaseName()
140                            + " is used instead." );
141            write();
142        }
143    
144        /**
145         * Writes the shapes to file.
146         *
147         * @throws IOException
148         * @throws DBaseException
149         */
150        public void write()
151                                throws IOException, DBaseException {
152            String baseName = shapeFile.getBaseName();
153            File mainFile = new File( baseName + ".shp" );
154            BufferedOutputStream mainOut = new BufferedOutputStream( new FileOutputStream( mainFile ) );
155            writeHeader( mainOut, ( shapeFile.getSize() + 100 ) / 2 );
156    
157            File indexFile = new File( baseName + ".shx" );
158            BufferedOutputStream indexOut = new BufferedOutputStream( new FileOutputStream( indexFile ) );
159            writeHeader( indexOut, ( shapeFile.getShapes().size() * 8 + 100 ) / 2 );
160    
161            writeShapes( mainOut, indexOut );
162    
163            mainOut.close();
164            indexOut.close();
165    
166            shapeFile.writeDBF();
167        }
168    
169    }