001 //$HeadURL: http://svn.wald.intevation.org/svn/deegree/base/trunk/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: 31147 $, $Date: 2011-06-29 13:18:11 +0200 (Mi, 29 Jun 2011) $
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 // TODO
143 // Maybe skip this and and trim to b.length
144 if ( b.length > fddata[16] ) {
145 throw new DBaseException( "string contains too many characters " + (String) recData.get( i ) );
146 }
147 for ( int j = 0; j < b.length; j++ )
148 datasec.data[offset + j] = b[j];
149 for ( int j = b.length; j < fddata[16]; j++ )
150 datasec.data[offset + j] = 0x20;
151 break;
152 case (byte) 'N':
153 if ( recData.get( i ) != null && !( recData.get( i ) instanceof Number ) )
154 throw new DBaseException( "invalid data type at field: " + i );
155 if ( recData.get( i ) == null ) {
156 b = new byte[0];
157 } else {
158 b = ( (Number) recData.get( i ) ).toString().getBytes();
159 }
160 if ( b.length > fddata[16] )
161 throw new DBaseException( "string contains too many characters " + (String) recData.get( i ) );
162 for ( int j = 0; j < b.length; j++ )
163 datasec.data[offset + j] = b[j];
164 for ( int j = b.length; j < fddata[16]; j++ )
165 datasec.data[offset + j] = 0x0;
166 break;
167 case (byte) 'D':
168 if ( recData.get( i ) != null && !( recData.get( i ) instanceof Date ) )
169 throw new DBaseException( "invalid data type at field: " + i );
170 if ( recData.get( i ) == null ) {
171 b = new byte[0];
172 } else {
173 SimpleDateFormat sdf_ = new SimpleDateFormat( "yyyy-MM-dd", Locale.getDefault() );
174 b = sdf_.format( (Date) recData.get( i ) ).getBytes();
175 }
176 if ( b.length > fddata[16] )
177 throw new DBaseException( "string contains too many characters " + (Date) recData.get( i ) );
178 for ( int j = 0; j < b.length; j++ )
179 datasec.data[offset + j] = b[j];
180 for ( int j = b.length; j < fddata[16]; j++ )
181 datasec.data[offset + j] = 0x0;
182 break;
183 default: {
184 System.out.println("TTTT" + (char)fddata[11] );
185 throw new DBaseException( "data type not supported" );
186 }
187
188 }
189
190 offset += fddata[16];
191
192 }
193
194 // puts the record to the ArrayList (container)
195 data.add( index, datasec );
196
197 }
198
199 /**
200 * method: public byte[] getDataSection() returns the data section as a byte array.
201 */
202 public byte[] getDataSection() {
203
204 // allocate memory for all datarecords on one array + 1 byte
205 byte[] outdata = new byte[data.size() * recordlength + 1];
206
207 // set the file terminating byte
208 outdata[outdata.length - 1] = 0x1A;
209
210 // get all records from the ArrayList and put it
211 // on a single array
212 int j = 0;
213 for ( int i = 0; i < data.size(); i++ ) {
214 ByteContainer bc = data.get( i );
215 for ( int k = 0; k < recordlength; k++ ) {
216 outdata[j++] = bc.data[k];
217 }
218 }
219 return outdata;
220 }
221
222 public void getDataSection( OutputStream os )
223 throws IOException {
224
225 // get all records from the ArrayList and write it into a stream
226 for ( int i = 0; i < data.size(); i++ ) {
227 ByteContainer bc = data.get( i );
228 for ( int k = 0; k < recordlength; k++ ) {
229 os.write( bc.data[k] );
230 }
231
232 }
233 // set the file terminating byte
234 os.write( 0x1A );
235 }
236
237 /**
238 * method: public int getNoOfRecords() returns the number of records within the container
239 */
240 public int getNoOfRecords() {
241 return data.size();
242 }
243
244 }
245
246 class ByteContainer {
247
248 public byte[] data = null;
249
250 public ByteContainer( int size ) {
251
252 data = new byte[size];
253
254 }
255
256 }