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 }