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 }