001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_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 /*
063 * instance variables
064 */
065 private FileHeader fh;
066
067 private IndexFile shx;
068
069 /*
070 * file suffixes for shp
071 */
072 private static final String _shp = ".shp";
073
074 /*
075 * references to the main file
076 */
077 private RandomAccessFile raf;
078
079 /**
080 * Construct a MainFile from a file name.
081 *
082 * @param url
083 * @throws IOException
084 */
085 public MainFile( String url ) throws IOException {
086
087 /*
088 * creates raf
089 */
090 raf = new RandomAccessFile( url + _shp, "r" );
091
092 fh = new FileHeader( raf );
093
094 shx = new IndexFile( url );
095
096 }
097
098 /**
099 * Construct a MainFile from a file name.
100 *
101 * @param url
102 * @param rwflag
103 * @throws IOException
104 */
105 public MainFile( String url, String rwflag ) throws IOException {
106
107 // delet file if it exists
108 File file = new File( url + _shp );
109
110 if ( rwflag.indexOf( 'w' ) > -1 && file.exists() )
111 file.delete();
112 file = null;
113
114 /*
115 * creates raf
116 */
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 byte[] recBuf = null;
179
180 // index in IndexArray (see IndexFile)
181 int iaIndex = RecNo - 1;
182
183 int off = shx.getRecordOffset( iaIndex );
184
185 // calculate length from 16-bit words (= 2 bytes) to lenght in bytes
186 int len = shx.getRecordLength( iaIndex ) * 2;
187
188 // off holds the offset of the shape-record in 16-bit words (= 2 byte)
189 // multiply with 2 gets number of bytes to seek
190 long rafPos = off * 2;
191
192 // fetch shape record
193 raf.seek( rafPos + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH );
194
195 recBuf = null;
196 recBuf = new byte[len];
197
198 if ( raf.read( recBuf, 0, len ) != -1 ) {
199
200 int shpType = ByteUtils.readLEInt( recBuf, 0 );
201
202 /*
203 * only for PolyLines, Polygons and MultiPoints minimum bounding rectangles are defined
204 */
205 if ( ( shpType == ShapeConst.SHAPE_TYPE_POLYLINE ) || ( shpType == ShapeConst.SHAPE_TYPE_POLYGON )
206 || ( shpType == ShapeConst.SHAPE_TYPE_MULTIPOINT ) ) {
207
208 recordMBR = new SHPEnvelope( recBuf );
209
210 } // end if shpType
211
212 } // end if result
213
214 return recordMBR;
215 }
216
217 /**
218 * method: getByRecNo (int RecNo)<BR>
219 * retruns a ShapeRecord-Geometry by RecorcNumber<BR>
220 *
221 * @param RecNo
222 * @return a ShapeRecord-Geometry by RecorcNumber<BR>
223 * @throws IOException
224 */
225 public SHPGeometry getByRecNo( int RecNo )
226 throws IOException {
227
228 SHPGeometry shpGeom = null;
229 byte[] recBuf = null;
230
231 // index in IndexArray (see IndexFile)
232 int iaIndex = RecNo - 1;
233
234 int off = shx.getRecordOffset( iaIndex );
235
236 // calculate length from 16-bit words (= 2 bytes) to lenght in bytes
237 int len = shx.getRecordLength( iaIndex ) * 2;
238
239 // off holds the offset of the shape-record in 16-bit words (= 2 byte)
240 // multiply with 2 gets number of bytes to seek
241 long rafPos = off * 2;
242
243 // fetch record header
244 raf.seek( rafPos );
245
246 recBuf = null;
247 recBuf = new byte[ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH];
248
249 // fetch shape record
250 raf.seek( rafPos + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH );
251
252 recBuf = null;
253 recBuf = new byte[len];
254
255 if ( raf.read( recBuf, 0, len ) != -1 ) {
256
257 int shpType = ByteUtils.readLEInt( recBuf, 0 );
258
259 // create a geometry out of record buffer with shapetype
260 if ( shpType == ShapeConst.SHAPE_TYPE_POINT ) {
261 shpGeom = new SHPPoint( recBuf, 4 );
262 } else if ( shpType == ShapeConst.SHAPE_TYPE_MULTIPOINT ) {
263 shpGeom = new SHPMultiPoint( recBuf );
264 } else if ( shpType == ShapeConst.SHAPE_TYPE_POLYLINE ) {
265 shpGeom = new SHPPolyLine( recBuf );
266 } else if ( shpType == ShapeConst.SHAPE_TYPE_POLYGON ) {
267 shpGeom = new SHPPolygon( recBuf );
268 } else if ( shpType == ShapeConst.SHAPE_TYPE_POLYGONZ ) {
269 shpGeom = new SHPPolygon3D( recBuf );
270 }
271
272 } // end if result
273
274 return shpGeom;
275
276 }
277
278 /**
279 * method: getShapeType(int RecNo)<BR>
280 * returns the minimum bound rectangle of RecNo's Geometrie of the shape-file<BR>
281 *
282 * @param RecNo
283 * @return the minimum bound rectangle of RecNo's Geometrie of the shape-file<BR>
284 * @throws IOException
285 */
286 public int getShapeTypeByRecNo( int RecNo )
287 throws IOException {
288
289 byte[] recBuf = null;
290 int shpType = -1;
291
292 // index in IndexArray (see IndexFile)
293 int iaIndex = RecNo - 1;
294
295 int off = shx.getRecordOffset( iaIndex );
296
297 // calculate length from 16-bit words (= 2 bytes) to lenght in bytes
298 int len = shx.getRecordLength( iaIndex ) * 2;
299
300 // off holds the offset of the shape-record in 16-bit words (= 2 byte)
301 // multiply with 2 gets number of bytes to seek
302 long rafPos = off * 2;
303
304 // fetch shape record
305 raf.seek( rafPos + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH );
306
307 recBuf = null;
308 recBuf = new byte[len];
309
310 if ( raf.read( recBuf, 0, len ) != -1 ) {
311
312 shpType = ByteUtils.readLEInt( recBuf, 0 );
313
314 } // end if result
315
316 return shpType;
317 }
318
319 /**
320 * method: public void write(byte[] bytearray)<BR>
321 * appends a bytearray to the shape file<BR>
322 *
323 * @param bytearray
324 * @param record
325 * @param mbr
326 * @throws IOException
327 */
328 public void write( byte[] bytearray, IndexRecord record, SHPEnvelope mbr )
329 throws IOException {
330 raf.seek( record.offset * 2 );
331 raf.write( bytearray );
332 shx.appendRecord( record, mbr );
333 }
334
335 /**
336 * method: public void writeHeader(int filelength, byte shptype, SHPEnvelope mbr)<BR>
337 * writes a header to the shape and index file<BR>
338 *
339 * @param filelength
340 * @param shptype
341 * @param mbr
342 * @throws IOException
343 */
344 public void writeHeader( int filelength, byte shptype, SHPEnvelope mbr )
345 throws IOException {
346 fh.writeHeader( filelength, shptype, mbr );
347 shx.writeHeader( shptype, mbr );
348 }
349
350 }