    001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/io/dbaseapi/DBFDataSection.java $
    002
    003    /*----------------------------------------------------------------------------
    004     This file is part of deegree, http://deegree.org/
    005     Copyright (C) 2001-2009 by:
    006     Department of Geography, University of Bonn
    007     and
    008     lat/lon GmbH
    009
    010     This library is free software; you can redistribute it and/or modify it under
    011     the terms of the GNU Lesser General Public License as published by the Free
    012     Software Foundation; either version 2.1 of the License, or (at your option)
    013     any later version.
    014     This library is distributed in the hope that it will be useful, but WITHOUT
    015     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    016     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
    017     details.
    018     You should have received a copy of the GNU Lesser General Public License
    019     along with this library; if not, write to the Free Software Foundation, Inc.,
    020     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    021
    022     Contact information:
    023
    024     lat/lon GmbH
    025     Aennchenstr. 19, 53177 Bonn
    026     Germany
    027     http://lat-lon.de/
    028
    029     Department of Geography, University of Bonn
    030     Prof. Dr. Klaus Greve
    031     Postfach 1147, 53001 Bonn
    032     Germany
    033     http://www.geographie.uni-bonn.de/deegree/
    034
    035     e-mail: info@deegree.org
    036     ----------------------------------------------------------------------------*/
    037
    038    package org.deegree.io.dbaseapi;
    039
    040    import java.io.IOException;
    041    import java.io.OutputStream;
    042    import java.text.SimpleDateFormat;
    043    import java.util.ArrayList;
    044    import java.util.Date;
    045    import java.util.List;
    046    import java.util.Locale;
    047
    048    /**
    049     * Class representing a record of the data section of a dBase III/IV file<BR>
    050     * at the moment only the daata types character ("C") and numeric ("N") are supported
    051     *
    052     *
    053     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
    054     * @author last edited by: $Author: apoth $
    055     *
    056     * @version $Revision: 24277 $, $Date: 2010-05-10 16:41:12 +0200 (Mo, 10. Mai 2010) $
    057     */
    058    public class DBFDataSection {
    059
    060        /**
    061         * length of one record in bytes
    062         */
    063        private int recordlength = 0;
    064
    065        private FieldDescriptor[] fieldDesc = null;
    066
    067        private List<ByteContainer> data = new ArrayList<ByteContainer>();
    068
    069        /**
    070         * constructor
    071         */
    072        public DBFDataSection( FieldDescriptor[] fieldDesc ) {
    073
    074            this.fieldDesc = fieldDesc;
    075
    076            // calculate length of the data section
    077            recordlength = 0;
    078            for ( int i = 0; i < this.fieldDesc.length; i++ ) {
    079
    080                byte[] fddata = this.fieldDesc[i].getFieldDescriptor();
    081
    082                recordlength += fddata[16];
    083
    084                fddata = null;
    085
    086            }
    087
    088            recordlength++;
    089
    090        }
    091
    092        /**
    093         * method: public setRecord(ArrayList recData) writes a data record to byte array representing the data section of
    094         * the dBase file. The method gets the data type of each field in recData from fieldDesc wich has been set at the
    095         * constructor.
    096         */
    097        public void setRecord( List<?> recData )
    098                                throws DBaseException {
    099
    100            setRecord( data.size(), recData );
    101
    102        }
    103
    104        /**
    105         * method: public setRecord(int index, ArrayList recData) writes a data record to byte array representing the data
    106         * section of the dBase file. The method gets the data type of each field in recData from fieldDesc wich has been
    107         * set at the constructor. index specifies the location of the retrieved record in the datasection. if an invalid
    108         * index is used an exception will be thrown
    109         */
    110        public void setRecord( int index, List<?> recData )
    111                                throws DBaseException {
    112
    113            ByteContainer datasec = new ByteContainer( recordlength );
    114
    115            if ( ( index < 0 ) || ( index > data.size() ) )
    116                throw new DBaseException( "invalid index: " + index );
    117
    118            if ( recData.size() != this.fieldDesc.length )
    119                throw new DBaseException( "invalid size of recData" );
    120
    121            int offset = 0;
    122
    123            datasec.data[offset] = 0x20;
    124
    125            offset++;
    126
    127            byte[] b = null;
    128
    129            // write every field on the ArrayList to the data byte array
    130            for ( int i = 0; i < recData.size(); i++ ) {
    131                byte[] fddata = this.fieldDesc[i].getFieldDescriptor();
    132                switch ( fddata[11] ) {
    133
    134                // if data type is character
    135                case (byte) 'C':
    136
    137                    if ( recData.get( i ) == null ) {
    138                        b = new byte[0];
    139                    } else {
    140                        b = recData.get( i ).toString().getBytes();
    141                    }
    142                    if ( b.length > fddata[16] )
    143                        throw new DBaseException( "string contains too many characters " + (String) recData.get( i ) );
    144                    for ( int j = 0; j < b.length; j++ )
    145                        datasec.data[offset + j] = b[j];
    146                    for ( int j = b.length; j < fddata[16]; j++ )
    147                        datasec.data[offset + j] = 0x20;
    148                    break;
    149                case (byte) 'N':
    150                    if ( recData.get( i ) != null && !( recData.get( i ) instanceof Number ) )
    151                        throw new DBaseException( "invalid data type at field: " + i );
    152                    if ( recData.get( i ) == null ) {
    153                        b = new byte[0];
    154                    } else {
    155                        b = ( (Number) recData.get( i ) ).toString().getBytes();
    156                    }
    157                    if ( b.length > fddata[16] )
    158                        throw new DBaseException( "string contains too many characters " + (String) recData.get( i ) );
    159                    for ( int j = 0; j < b.length; j++ )
    160                        datasec.data[offset + j] = b[j];
    161                    for ( int j = b.length; j < fddata[16]; j++ )
    162                        datasec.data[offset + j] = 0x0;
    163                    break;
    164                case (byte) 'D':
    165                    if ( recData.get( i ) != null && !( recData.get( i ) instanceof Date ) )
    166                        throw new DBaseException( "invalid data type at field: " + i );
    167                    if ( recData.get( i ) == null ) {
    168                        b = new byte[0];
    169                    } else {
    170                        SimpleDateFormat sdf_ = new SimpleDateFormat( "yyyy-MM-dd", Locale.getDefault() );
    171                        b = sdf_.format( (Date) recData.get( i )  ).getBytes();
    172                    }
    173                    if ( b.length > fddata[16] )
    174                        throw new DBaseException( "string contains too many characters " + (Date) recData.get( i ) );
    175                    for ( int j = 0; j < b.length; j++ )
    176                        datasec.data[offset + j] = b[j];
    177                    for ( int j = b.length; j < fddata[16]; j++ )
    178                        datasec.data[offset + j] = 0x0;
    179                    break;
    180                  default: {
    181                    System.out.println("TTTT" + (char)fddata[11] );
    182                    throw new DBaseException( "data type not supported" );
    183                }
    184
    185                }
    186
    187                offset += fddata[16];
    188
    189            }
    190
    191            // puts the record to the ArrayList (container)
    192            data.add( index, datasec );
    193
    194        }
    195
    196        /**
    197         * method: public byte[] getDataSection() returns the data section as a byte array.
    198         */
    199        public byte[] getDataSection() {
    200
    201            // allocate memory for all datarecords on one array + 1 byte
    202            byte[] outdata = new byte[data.size() * recordlength + 1];
    203
    204            // set the file terminating byte
    205            outdata[outdata.length - 1] = 0x1A;
    206
    207            // get all records from the ArrayList and put it
    208            // on a single array
    209            int j = 0;
    210            for ( int i = 0; i < data.size(); i++ ) {
    211                ByteContainer bc = data.get( i );
    212                for ( int k = 0; k < recordlength; k++ ) {
    213                    outdata[j++] = bc.data[k];
    214                }
    215            }
    216            return outdata;
    217        }
    218
    219        public void getDataSection( OutputStream os )
    220                                throws IOException {
    221
    222            // get all records from the ArrayList and write it into a stream
    223            for ( int i = 0; i < data.size(); i++ ) {
    224                ByteContainer bc = data.get( i );
    225                for ( int k = 0; k < recordlength; k++ ) {
    226                    os.write( bc.data[k] );
    227                }
    228
    229            }
    230            // set the file terminating byte
    231            os.write( 0x1A );
    232        }
    233
    234        /**
    235         * method: public int getNoOfRecords() returns the number of records within the container
    236         */
    237        public int getNoOfRecords() {
    238            return data.size();
    239        }
    240
    241    }
    242
    243    class ByteContainer {
    244
    245        public byte[] data = null;
    246
    247        public ByteContainer( int size ) {
    248
    249            data = new byte[size];
    250
    251        }
    252
    253    }