001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/io/shpapi/shape_new/ShapeFileWriter.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003     This file is part of deegree.
004     Copyright (C) 2001-2008 by:
005     Department of Geography, University of Bonn
006     http://www.giub.uni-bonn.de/deegree/
007     lat/lon GmbH
008     http://www.lat-lon.de
009    
010     This library is free software; you can redistribute it and/or
011     modify it under the terms of the GNU Lesser General Public
012     License as published by the Free Software Foundation; either
013     version 2.1 of the License, or (at your option) any later version.
014    
015     This library is distributed in the hope that it will be useful,
016     but WITHOUT ANY WARRANTY; without even the implied warranty of
017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
018     Lesser General Public License for more details.
019    
020     You should have received a copy of the GNU Lesser General Public
021     License along with this library; if not, write to the Free Software
022     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
023    
024     Contact:
025    
026     Andreas Poth
027     lat/lon GmbH
028     Aennchenstr. 19
029     53177 Bonn
030     Germany
031     E-Mail: poth@lat-lon.de
032    
033     Prof. Dr. Klaus Greve
034     Department of Geography
035     University of Bonn
036     Meckenheimer Allee 166
037     53115 Bonn
038     Germany
039     E-Mail: greve@giub.uni-bonn.de
040    
041     ---------------------------------------------------------------------------*/
042    package org.deegree.io.shpapi.shape_new;
043    
044    import java.io.BufferedOutputStream;
045    import java.io.File;
046    import java.io.FileOutputStream;
047    import java.io.IOException;
048    import java.io.OutputStream;
049    
050    import org.deegree.framework.log.ILogger;
051    import org.deegree.framework.log.LoggerFactory;
052    import org.deegree.io.dbaseapi.DBaseException;
053    import org.deegree.model.spatialschema.ByteUtils;
054    
055    /**
056     * <code>ShapeFileWriter</code> is a class to write shapefiles.
057     * 
058     * @author <a href="mailto:schmitz@lat-lon.de">Andreas Schmitz</a>
059     * @author last edited by: $Author: apoth $
060     * 
061     * @version $Revision: 9342 $, $Date: 2007-12-27 13:32:57 +0100 (Do, 27 Dez 2007) $
062     */
063    public class ShapeFileWriter {
064    
065        private ShapeFile shapeFile;
066    
067        private static final ILogger LOG = LoggerFactory.getLogger( ShapeFileWriter.class );
068    
069        /**
070         * @param shapes
071         */
072        public ShapeFileWriter( ShapeFile shapes ) {
073            shapeFile = shapes;
074        }
075    
076        private void writeHeader( OutputStream out, int length )
077                                throws IOException {
078    
079            // what's funny about shapefiles:
080            // 1) in the headers, they use big endian for some values, little endian for others
081            // (the rest of the file is little endian)
082            // 2) Only 4 byte ints and 8 byte doubles are used in the file, however,
083            // the size is measured in 16 bit words...
084    
085            byte[] header = new byte[100];
086    
087            ByteUtils.writeBEInt( header, 0, ShapeFile.FILETYPE );
088            ByteUtils.writeBEInt( header, 24, length );
089            ByteUtils.writeLEInt( header, 28, ShapeFile.VERSION );
090            ByteUtils.writeLEInt( header, 32, shapeFile.getShapeType() );
091    
092            ShapeEnvelope envelope = shapeFile.getEnvelope();
093            envelope.write( header, 36 );
094    
095            // it shouldn't hurt to write these values as doubles default to 0.0 anyway
096            ByteUtils.writeLEDouble( header, 68, envelope.zmin );
097            ByteUtils.writeLEDouble( header, 76, envelope.zmax );
098            ByteUtils.writeLEDouble( header, 84, envelope.mmin );
099            ByteUtils.writeLEDouble( header, 92, envelope.mmax );
100    
101            out.write( header, 0, 100 );
102        }
103    
104        private void writeShapes( OutputStream mainOut, OutputStream indexOut )
105                                throws IOException {
106            // allocate the WHOLE shape file
107            byte[] bytes = new byte[shapeFile.getSize()];
108            byte[] indexBytes = new byte[8 * shapeFile.getShapes().size()];
109    
110            int recordNum = 1;
111            int offset = 0;
112            int indexOffset = 0;
113    
114            for ( Shape s : shapeFile.getShapes() ) {
115                ByteUtils.writeBEInt( indexBytes, indexOffset, ( 100 + offset ) / 2 );
116                indexOffset += 4;
117                ByteUtils.writeBEInt( indexBytes, indexOffset, s.getByteLength() / 2 );
118                indexOffset += 4;
119    
120                ByteUtils.writeBEInt( bytes, offset, recordNum++ );
121                offset += 4;
122                ByteUtils.writeBEInt( bytes, offset, s.getByteLength() / 2 ); // again 16-bit words
123                offset += 4;
124    
125                LOG.logDebug( "Writing a " + s.getClass().getSimpleName() + ", size " + s.getByteLength() + " from offset " + offset );
126                offset = s.write( bytes, offset );
127            }
128    
129            mainOut.write( bytes, 0, bytes.length );
130            indexOut.write( indexBytes, 0, indexBytes.length );
131        }
132    
133        /**
134         * Writes the shapes to the files with the given base name.
135         * 
136         * @param baseName
137         * @throws IOException
138         * @throws DBaseException
139         */
140        public void write( String baseName )
141                                throws IOException, DBaseException {
142            File mainFile = new File( baseName + ".shp" );
143            BufferedOutputStream mainOut = new BufferedOutputStream( new FileOutputStream( mainFile ) );
144            writeHeader( mainOut, ( shapeFile.getSize() + 100 ) / 2 );
145    
146            File indexFile = new File( baseName + ".shx" );
147            BufferedOutputStream indexOut = new BufferedOutputStream( new FileOutputStream( indexFile ) );
148            writeHeader( indexOut, ( shapeFile.getShapes().size() * 8 + 100 ) / 2 );
149    
150            writeShapes( mainOut, indexOut );
151    
152            mainOut.close();
153            indexOut.close();
154    
155            shapeFile.writeDBF();
156        }
157    
158    }