001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/io/shpapi/MainFile.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004    This file is part of deegree.
005    Copyright (C) 2001-2008 by:
006    EXSE, Department of Geography, University of Bonn
007    http://www.giub.uni-bonn.de/deegree/
008    lat/lon GmbH
009    http://www.lat-lon.de
010    
011    This library is free software; you can redistribute it and/or
012    modify it under the terms of the GNU Lesser General Public
013    License as published by the Free Software Foundation; either
014    version 2.1 of the License, or (at your option) any later version.
015    
016    This library is distributed in the hope that it will be useful,
017    but WITHOUT ANY WARRANTY; without even the implied warranty of
018    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019    Lesser General Public License for more details.
020    
021    You should have received a copy of the GNU Lesser General Public
022    License along with this library; if not, write to the Free Software
023    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025    Contact:
026    
027    Andreas Poth
028    lat/lon GmbH
029    Aennchenstr. 19
030    53177 Bonn
031    Germany
032    E-Mail: poth@lat-lon.de
033    
034    Prof. Dr. Klaus Greve
035    Department of Geography
036    University of Bonn
037    Meckenheimer Allee 166
038    53115 Bonn
039    Germany
040    E-Mail: greve@giub.uni-bonn.de
041    
042                     
043     ---------------------------------------------------------------------------*/
044    
045    package org.deegree.io.shpapi;
046    
047    import java.io.File;
048    import java.io.IOException;
049    import java.io.RandomAccessFile;
050    
051    import org.deegree.model.spatialschema.ByteUtils;
052    
053    
054    /**
055     * Class representing an ESRI Shape File. 
056     * <p>
057     * Uses class ByteUtils modified 
058     * from the original package com.bbn.openmap.layer.shape
059     * <br>
060     * Copyright (C) 1998 BBN Corporation 10 Moulton St. Cambridge, MA 02138
061     * <br>
062     * 
063     * @version 16.08.2000
064     * @author Andreas Poth
065     *
066     */
067    public class MainFile {
068    
069       /* 
070        * A buffer for current record's header. 
071        */
072        protected byte[] recHdr = new byte[ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH];
073        
074       /*
075        * instance variables
076        */
077        private FileHeader fh;
078        private IndexFile shx;
079        
080       /* 
081        * file suffixes for shp
082        */
083        private static final String _shp = ".shp";    
084    
085       /*
086        * references to the main file 
087        */ 
088        private RandomAccessFile raf;    
089        
090    
091       /**
092        * Construct a MainFile from a file name.
093        */
094        public MainFile(String url) throws IOException {
095           
096           /* 
097            * creates raf 
098            */
099            raf= new RandomAccessFile(url + _shp,"r"); 
100    
101            fh = new FileHeader(raf);        
102    
103            shx = new IndexFile(url);        
104    
105        }
106    
107       /**
108        * Construct a MainFile from a file name.
109        */
110        public MainFile(String url, String rwflag) throws IOException {
111           
112            // delet file if it exists
113            File file = new File(url + _shp);
114            
115            if (rwflag.indexOf('w') > -1 && file.exists()) file.delete();
116            file = null;
117    
118           /* 
119            * creates raf 
120            */
121            raf= new RandomAccessFile(url + _shp,rwflag); 
122    
123            fh = new FileHeader(raf, rwflag.indexOf('w') > -1);
124    
125            shx = new IndexFile(url,rwflag);   
126    
127        }
128        
129        public void close()
130        {
131            try {
132                    raf.close();                    
133                } catch (Exception ex) { 
134                ex.printStackTrace();
135            }
136            try {
137                shx.close();            
138            } catch (Exception ex) { 
139                ex.printStackTrace();
140            }          
141        }
142    
143    
144       
145       /**
146        * method: getFileMBR()<BR>
147        * returns the minimum bounding rectangle of geometries<BR>
148        * within the shape-file
149        */
150        public SHPEnvelope getFileMBR() {
151    
152            return fh.getFileMBR();
153    
154        }
155    
156       /**
157        * method: getRecordNum()<BR>
158        * returns 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 
169        * of the shape-file<BR>
170        */
171        public SHPEnvelope getRecordMBR(int RecNo) throws IOException{
172    
173            SHPEnvelope recordMBR = null;
174            byte[] recBuf= null; 
175    
176            // index in IndexArray (see IndexFile) 
177            int iaIndex = RecNo-1; 
178    
179            int off = shx.getRecordOffset(iaIndex);
180    
181            // calculate length from 16-bit words (= 2 bytes) to lenght in bytes
182            int len = shx.getRecordLength(iaIndex) * 2;
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            recBuf = null;
192            recBuf = new byte[len];
193    
194            if ( raf.read(recBuf, 0, len) != -1 ) {
195    
196                int shpType = ByteUtils.readLEInt(recBuf, 0);
197    
198               /*
199                * only for PolyLines, Polygons and MultiPoints 
200                * minimum bounding rectangles are defined
201                */
202                if ( (shpType == ShapeConst.SHAPE_TYPE_POLYLINE) || 
203                     (shpType == ShapeConst.SHAPE_TYPE_POLYGON) ||
204                     (shpType == ShapeConst.SHAPE_TYPE_MULTIPOINT) ) {
205    
206                    recordMBR = new SHPEnvelope(recBuf);
207    
208                } // end if shpType
209    
210            } // end if result
211    
212            return recordMBR;
213        } 
214    
215    
216       /**
217        * method: getByRecNo (int RecNo)<BR>
218        * retruns a ShapeRecord-Geometry by RecorcNumber<BR>
219        */
220        public SHPGeometry getByRecNo (int RecNo) throws IOException {
221    
222            SHPGeometry  shpGeom = null;
223            byte[] recBuf= null;
224    
225            // index in IndexArray (see IndexFile) 
226            int iaIndex = RecNo-1; 
227    
228            int off = shx.getRecordOffset(iaIndex);
229    
230            // calculate length from 16-bit words (= 2 bytes) to lenght in bytes
231            int len = shx.getRecordLength(iaIndex) * 2;        
232    
233            // off holds the offset of the shape-record in 16-bit words (= 2 byte)
234            // multiply with 2 gets number of bytes to seek
235            long rafPos= off*2;
236    
237            //fetch record header
238            raf.seek(rafPos);
239    
240            recBuf = null;
241            recBuf = new byte[ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH];        
242    
243            // fetch shape record 
244            raf.seek(rafPos + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH);
245    
246            recBuf = null;
247            recBuf = new byte[len];
248    
249            if ( raf.read(recBuf, 0, len) != -1 ) {
250    
251                int shpType = ByteUtils.readLEInt(recBuf, 0);            
252    
253                // create a geometry out of record buffer with shapetype
254                if (shpType == ShapeConst.SHAPE_TYPE_POINT) {
255                    shpGeom = new SHPPoint(recBuf,4);
256                } else if (shpType == ShapeConst.SHAPE_TYPE_MULTIPOINT) {
257                    shpGeom = new SHPMultiPoint(recBuf);
258                } else if (shpType == ShapeConst.SHAPE_TYPE_POLYLINE) {
259                    shpGeom = new SHPPolyLine(recBuf);
260                } else if (shpType == ShapeConst.SHAPE_TYPE_POLYGON) {
261                    shpGeom = new SHPPolygon(recBuf);
262                } else if( shpType == ShapeConst.SHAPE_TYPE_POLYGONZ ){
263                    shpGeom = new SHPPolygon3D(recBuf);
264                }   
265             
266            } // end if result
267       
268            return shpGeom;
269    
270        }
271    
272       /**
273        * method: getShapeType(int RecNo)<BR>
274        * returns the minimum bound rectangle of RecNo's Geometrie 
275        * of the shape-file<BR>
276        */
277        public int getShapeTypeByRecNo(int RecNo) throws IOException {
278    
279            byte[] recBuf = null;
280            int shpType = -1;
281    
282            // index in IndexArray (see IndexFile) 
283            int iaIndex = RecNo-1; 
284    
285            int off = shx.getRecordOffset(iaIndex);
286    
287            // calculate length from 16-bit words (= 2 bytes) to lenght in bytes
288            int len = shx.getRecordLength(iaIndex) * 2;
289    
290            // off holds the offset of the shape-record in 16-bit words (= 2 byte)
291            // multiply with 2 gets number of bytes to seek
292            long rafPos= off*2;
293    
294            // fetch shape record 
295            raf.seek(rafPos + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH);
296    
297            recBuf = null;
298            recBuf = new byte[len];
299    
300            if ( raf.read(recBuf, 0, len) != -1 ) {
301    
302                shpType = ByteUtils.readLEInt(recBuf, 0);
303    
304            } // end if result
305    
306            return shpType;
307        } 
308    
309       /**
310        * method: public void write(byte[] bytearray)<BR>
311        * appends a bytearray to the shape file<BR>
312        */
313        public void write(byte[] bytearray, IndexRecord record, SHPEnvelope mbr) throws IOException {
314            raf.seek(record.offset*2);
315            raf.write(bytearray);
316            shx.appendRecord(record,mbr);
317        }
318    
319       /**
320        * method: public void writeHeader(int filelength, byte shptype, SHPEnvelope mbr)<BR>
321        * writes a header to the shape and index file<BR>
322        */
323        public void writeHeader(int filelength, byte shptype, SHPEnvelope mbr) throws IOException {
324            fh.writeHeader(filelength, shptype,mbr);
325            shx.writeHeader(shptype,mbr);
326        }
327       
328    }