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