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 }