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    }