001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_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 }