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 }