001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/io/shpapi/MainFile.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.io.shpapi;
038
039 import java.io.File;
040 import java.io.IOException;
041 import java.io.RandomAccessFile;
042
043 import org.deegree.model.spatialschema.ByteUtils;
044
045 /**
046 * Class representing an ESRI Shape File.
047 * <p>
048 * Uses class ByteUtils modified from the original package com.bbn.openmap.layer.shape <br>
049 * Copyright (C) 1998 BBN Corporation 10 Moulton St. Cambridge, MA 02138 <br>
050 *
051 * @version 16.08.2000
052 * @author Andreas Poth
053 *
054 */
055 public class MainFile {
056
057 /*
058 * A buffer for current record's header.
059 */
060 protected byte[] recHdr = new byte[ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH];
061
062 private byte[] envRecBuf = new byte[36];
063
064 private byte[] dataRecBuf = new byte[36];
065
066 /*
067 * instance variables
068 */
069 private FileHeader fh;
070
071 private IndexFile shx;
072
073 /*
074 * file suffixes for shp
075 */
076 private static final String _shp = ".shp";
077
078 /*
079 * references to the main file
080 */
081 private RandomAccessFile raf;
082
083 /**
084 * Construct a MainFile from a file name.
085 *
086 * @param url
087 * @throws IOException
088 */
089 public MainFile( String url ) throws IOException {
090
091 // creates raf
092 raf = new RandomAccessFile( url + _shp, "r" );
093
094 fh = new FileHeader( raf );
095
096 shx = new IndexFile( url );
097
098 }
099
100 /**
101 * Construct a MainFile from a file name.
102 *
103 * @param url
104 * @param rwflag
105 * @throws IOException
106 */
107 public MainFile( String url, String rwflag ) throws IOException {
108
109 // delet file if it exists
110 File file = new File( url + _shp );
111
112 if ( rwflag.indexOf( 'w' ) > -1 && file.exists() )
113 file.delete();
114 file = null;
115
116 // creates raf
117 raf = new RandomAccessFile( url + _shp, rwflag );
118
119 fh = new FileHeader( raf, rwflag.indexOf( 'w' ) > -1 );
120
121 shx = new IndexFile( url, rwflag );
122
123 }
124
125 /**
126 *
127 */
128 public void close() {
129 try {
130 raf.close();
131 } catch ( Exception ex ) {
132 ex.printStackTrace();
133 }
134 try {
135 shx.close();
136 } catch ( Exception ex ) {
137 ex.printStackTrace();
138 }
139 }
140
141 /**
142 * method: getFileMBR()<BR>
143 * returns the minimum bounding rectangle of geometries<BR>
144 * within the shape-file
145 *
146 * @return the minimum bounding rectangle of geometries<BR>
147 */
148 public SHPEnvelope getFileMBR() {
149
150 return fh.getFileMBR();
151
152 }
153
154 /**
155 * method: getRecordNum()<BR>
156 * returns the number of record with in a shape-file<BR>
157 *
158 * @return the number of record with in a shape-file<BR>
159 */
160 public int getRecordNum() {
161
162 return shx.getRecordNum();
163
164 }
165
166 /**
167 * method: getRecordMBR(int RecNo)<BR>
168 * returns the minimum bound rectangle of RecNo's Geometrie of the shape-file<BR>
169 *
170 * @param RecNo
171 * @return the minimum bound rectangle of RecNo's Geometrie of the shape-file<BR>
172 * @throws IOException
173 */
174 public SHPEnvelope getRecordMBR( int RecNo )
175 throws IOException {
176
177 SHPEnvelope recordMBR = null;
178
179 // index in IndexArray (see IndexFile)
180 int iaIndex = RecNo - 1;
181
182 int off = shx.getRecordOffset( iaIndex );
183
184 // off holds the offset of the shape-record in 16-bit words (= 2 byte)
185 // multiply with 2 gets number of bytes to seek
186 long rafPos = off * 2;
187
188 // fetch shape record
189 raf.seek( rafPos + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH );
190
191 if ( raf.read( envRecBuf, 0, envRecBuf.length ) != -1 ) {
192
193 int shpType = ByteUtils.readLEInt( envRecBuf, 0 );
194
195 // only for PolyLines, Polygons and MultiPoints minimum bounding rectangles are defined
196 if ( shpType == ShapeConst.SHAPE_TYPE_POLYLINE || shpType == ShapeConst.SHAPE_TYPE_POLYGON
197 || shpType == ShapeConst.SHAPE_TYPE_MULTIPOINT ) {
198 recordMBR = new SHPEnvelope( envRecBuf );
199 } // end if shpType
200 } // end if result
201
202 return recordMBR;
203 }
204
205 /**
206 * method: getByRecNo (int RecNo)<BR>
207 * retruns a ShapeRecord-Geometry by RecorcNumber<BR>
208 *
209 * @param RecNo
210 * @return a ShapeRecord-Geometry by RecorcNumber<BR>
211 * @throws IOException
212 */
213 public SHPGeometry getByRecNo( int RecNo )
214 throws IOException {
215
216 SHPGeometry shpGeom = null;
217
218 // index in IndexArray (see IndexFile)
219 int iaIndex = RecNo - 1;
220
221 int off = shx.getRecordOffset( iaIndex );
222
223 // calculate length from 16-bit words (= 2 bytes) to lenght in bytes
224 int len = shx.getRecordLength( iaIndex ) * 2;
225
226 // off holds the offset of the shape-record in 16-bit words (= 2 byte)
227 // multiply with 2 gets number of bytes to seek
228 long rafPos = off * 2;
229
230 // fetch record header
231 raf.seek( rafPos );
232
233 // fetch shape record
234 raf.seek( rafPos + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH );
235
236 if ( len > dataRecBuf.length ) {
237 dataRecBuf = new byte[len];
238 }
239
240 if ( raf.read( dataRecBuf, 0, len ) != -1 ) {
241
242 int shpType = ByteUtils.readLEInt( dataRecBuf, 0 );
243
244 // create a geometry out of record buffer with shapetype
245 if ( shpType == ShapeConst.SHAPE_TYPE_POINT ) {
246 shpGeom = new SHPPoint( dataRecBuf, 4 );
247 } else if ( shpType == ShapeConst.SHAPE_TYPE_MULTIPOINT ) {
248 shpGeom = new SHPMultiPoint( dataRecBuf );
249 } else if ( shpType == ShapeConst.SHAPE_TYPE_POLYLINE ) {
250 shpGeom = new SHPPolyLine( dataRecBuf );
251 } else if ( shpType == ShapeConst.SHAPE_TYPE_POLYGON ) {
252 shpGeom = new SHPPolygon( dataRecBuf );
253 } else if ( shpType == ShapeConst.SHAPE_TYPE_POLYGONZ ) {
254 shpGeom = new SHPPolygon3D( dataRecBuf );
255 }
256
257 } // end if result
258
259 return shpGeom;
260
261 }
262
263 /**
264 * method: getShapeType(int RecNo)<BR>
265 * returns the minimum bound rectangle of RecNo's Geometrie of the shape-file<BR>
266 *
267 * @param RecNo
268 * @return the minimum bound rectangle of RecNo's Geometrie of the shape-file<BR>
269 * @throws IOException
270 */
271 public int getShapeTypeByRecNo( int RecNo )
272 throws IOException {
273
274 int shpType = -1;
275
276 // index in IndexArray (see IndexFile)
277 int iaIndex = RecNo - 1;
278
279 int off = shx.getRecordOffset( iaIndex );
280
281 // calculate length from 16-bit words (= 2 bytes) to length in bytes
282 int len = 4;// shx.getRecordLength( iaIndex ) * 2;
283
284 // off holds the offset of the shape-record in 16-bit words (= 2 byte)
285 // multiply with 2 gets number of bytes to seek
286 long rafPos = off * 2;
287
288 // fetch shape record
289 raf.seek( rafPos + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH );
290
291 byte[] recBuf_ = new byte[len];
292
293 if ( raf.read( recBuf_, 0, len ) != -1 ) {
294 shpType = ByteUtils.readLEInt( recBuf_, 0 );
295 } // end if result
296
297 return shpType;
298 }
299
300 /**
301 * method: public void write(byte[] bytearray)<BR>
302 * appends a bytearray to the shape file<BR>
303 *
304 * @param bytearray
305 * @param record
306 * @param mbr
307 * @throws IOException
308 */
309 public void write( byte[] bytearray, IndexRecord record, SHPEnvelope mbr )
310 throws IOException {
311 raf.seek( record.offset * 2 );
312 raf.write( bytearray );
313 shx.appendRecord( record, mbr );
314 }
315
316 /**
317 * method: public void writeHeader(int filelength, byte shptype, SHPEnvelope mbr)<BR>
318 * writes a header to the shape and index file<BR>
319 *
320 * @param filelength
321 * @param shptype
322 * @param mbr
323 * @throws IOException
324 */
325 public void writeHeader( int filelength, byte shptype, SHPEnvelope mbr )
326 throws IOException {
327 fh.writeHeader( filelength, shptype, mbr );
328 shx.writeHeader( shptype, mbr );
329 }
330
331 }