    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    }