Statistics
| Revision:

root / branches / Mobile_Compatible_Hito_1 / libFMap_mobile_shp_driver / src-file / org / gvsig / data / datastores / vectorial / file / shp_mem / DbaseFileHeaderNIO.java @ 22037

History | View | Annotate | Download (22.3 KB)

1 21865 jldominguez
/*
2
 *    Geotools - OpenSource mapping toolkit
3
 *    (C) 2002, Centre for Computational Geography
4
 *
5
 *    This library is free software; you can redistribute it and/or
6
 *    modify it under the terms of the GNU Lesser General Public
7
 *    License as published by the Free Software Foundation;
8
 *    version 2.1 of the License.
9
 *
10
 *    This library is distributed in the hope that it will be useful,
11
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 *    Lesser General Public License for more details.
14
 *
15
 *    You should have received a copy of the GNU Lesser General Public
16
 *    License along with this library; if not, write to the Free Software
17
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 *
19
 *    This file is based on an origional contained in the GISToolkit project:
20
 *    http://gistoolkit.sourceforge.net/
21
 *
22
 */
23
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
24
 *
25
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
26
 *
27
 * This program is free software; you can redistribute it and/or
28
 * modify it under the terms of the GNU General Public License
29
 * as published by the Free Software Foundation; either version 2
30
 * of the License, or (at your option) any later version.
31
 *
32
 * This program is distributed in the hope that it will be useful,
33
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
35
 * GNU General Public License for more details.
36
 *
37
 * You should have received a copy of the GNU General Public License
38
 * along with this program; if not, write to the Free Software
39
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
40
 *
41
 * For more information, contact:
42
 *
43
 *  Generalitat Valenciana
44
 *   Conselleria d'Infraestructures i Transport
45
 *   Av. Blasco Ib??ez, 50
46
 *   46010 VALENCIA
47
 *   SPAIN
48
 *
49
 *      +34 963862235
50
 *   gvsig@gva.es
51
 *      www.gvsig.gva.es
52
 *
53
 *    or
54
 *
55
 *   IVER T.I. S.A
56
 *   Salamanca 50
57
 *   46005 Valencia
58
 *   Spain
59
 *
60
 *   +34 963163400
61
 *   dac@iver.es
62
 */
63
/************************************************
64
 *                                                                                                *
65
 *   Modfied By:                                                                *
66
 *   Prodevelop Integraci?n de Tecnolog?as SL        *
67
 *   Conde Salvatierra de ?lava , 34-10                        *
68
 *   46004 Valencia                                                                *
69
 *   Spain                                                                                *
70
 *                                                                                                *
71
 *   +34 963 510 612                                                        *
72
 *   +34 963 510 968                                                        *
73
 *   gis@prodevelop.es                                                        *
74
 *   http://www.prodevelop.es                                        *
75
 *                                                                                                *
76
 *   gvSIG Mobile Team 2006                                         *
77
 *                                                                                          *
78
 ************************************************/
79
80
package org.gvsig.data.datastores.vectorial.file.shp_mem;
81
82
import java.io.IOException;
83
import java.nio.ByteOrder;
84
import java.sql.Types;
85
import java.util.Calendar;
86
import java.util.Date;
87
88
import org.apache.log4j.Logger;
89 22037 jldominguez
import org.gvsig.data.datastores.vectorial.file.shp_util.FalseByteBuffer;
90 21865 jldominguez
91
import com.vividsolutions.jts.geom.Geometry;
92
93
/**
94
 * Class to represent the header of a Dbase III file. Creation date: (5/15/2001
95
 * 5:15:30 PM)
96
 */
97
public class DbaseFileHeaderNIO {
98
99
        private static Logger logger = Logger.getLogger(DbaseFileHeaderNIO.class);
100
        // Constant for the size of a record
101
        private static final int FILE_DESCRIPTOR_SIZE = 32;
102
103
        // type of the file, must be 03h
104
        private static final byte MAGIC = 0x03;
105
106
        private static final int MINIMUM_HEADER = 33;
107
108
        // Date the file was last updated.
109
        private Date date = new Date();
110
111
        private int recordCnt = 0;
112
113
        private int fieldCnt = 0;
114
115
        private int myFileType = 0;
116
117
        // set this to a default length of 1, which is enough for one "space"
118
        // character which signifies an empty record
119
        private int recordLength = 1;
120
121
        // set this to a flagged value so if no fields are added before the write,
122
        // we know to adjust the headerLength to MINIMUM_HEADER
123
        private int headerLength = -1;
124
125
        private int largestFieldSize = 0;
126
127
        // collection of header records.
128
        // lets start out with a zero-length array, just in case
129
        private DbaseField[] fields = null; // new DbaseField[0];
130
131
        /**
132
         * Lee del buffer.
133
         *
134
         * @param buffer .
135
         * @param channel .
136
         *
137
         * @throws IOException .
138
         * @throws EOFException .
139
         */
140
//        private void readg(ByteBuffer buffer, ReadableByteChannel channel)
141
//                        throws IOException {
142
//                while (buffer.remaining() > 0) {
143
//                        if (channel.read(buffer) == -1) {
144
//                                throw new EOFException("Premature end of file");
145
//                        }
146
//                }
147
//        }
148
149
        /**
150
         * Determine the most appropriate Java Class for representing the data in
151
         * the field.
152
         *
153
         * <PRE>
154
         *
155
         * All packages are java.lang unless otherwise specified. C (Character) ->
156
         * String N (Numeric) -> Integer or Double (depends on field's decimal
157
         * count) F (Floating) -> Double L (Logical) -> Boolean D (Date) ->
158
         * java.util.Date Unknown -> String
159
         *
160
         * </PRE>
161
         *
162
         * @param i
163
         *            The index of the field, from 0 to <CODE>getNumFields() - 1</CODE> .
164
         *
165
         * @return A Class which closely represents the dbase field type.
166
         */
167
        public Class getFieldClass(int i) {
168
                Class typeClass = null;
169
170
                switch (fields[i].fieldType) {
171
                case 'C':
172
                        typeClass = String.class;
173
174
                        break;
175
176
                case 'N':
177
178
                        if (fields[i].decimalCount == 0) {
179
                                typeClass = Integer.class;
180
                        } else {
181
                                typeClass = Double.class;
182
                        }
183
184
                        break;
185
186
                case 'F':
187
                        typeClass = Double.class;
188
189
                        break;
190
191
                case 'L':
192
                        typeClass = Boolean.class;
193
194
                        break;
195
196
                case 'D':
197
                        typeClass = Date.class;
198
199
                        break;
200
201
                default:
202
                        typeClass = String.class;
203
204
                        break;
205
                }
206
207
                return typeClass;
208
        }
209
210
        /**
211
         * Add a column to this DbaseFileHeader. The type is one of (C N L or D)
212
         * character, number, logical(true/false), or date. The Field length is the
213
         * total length in bytes reserved for this column. The decimal count only
214
         * applies to numbers(N), and floating point values (F), and refers to the
215
         * number of characters to reserve after the decimal point. <B>Don't expect
216
         * miracles from this...</B>
217
         *
218
         * <PRE>
219
         *
220
         * Field Type MaxLength ---------- --------- C 254 D 8 F 20 N 18
221
         *
222
         * </PRE>
223
         *
224
         * @param inFieldName
225
         *            The name of the new field, must be less than 10 characters or
226
         *            it gets truncated.
227
         * @param inFieldType
228
         *            A character representing the dBase field, ( see above ). Case
229
         *            insensitive.
230
         * @param inFieldLength
231
         *            The length of the field, in bytes ( see above )
232
         * @param inDecimalCount
233
         *            For numeric fields, the number of decimal places to track.
234
         */
235
        public void addColumn(String inFieldName, char inFieldType,
236
                        int inFieldLength, int inDecimalCount) {
237
                /*
238
                 * if (inFieldLength <=0) { throw new DbaseFileException("field length <=
239
                 * 0"); }
240
                 */
241
                if (fields == null) {
242
                        fields = new DbaseField[0];
243
                }
244
245
                int tempLength = 1; // the length is used for the offset, and there is a
246
                // * for deleted as the first byte
247
                DbaseField[] tempFieldDescriptors = new DbaseField[fields.length + 1];
248
249
                for (int i = 0; i < fields.length; i++) {
250
                        fields[i].fieldDataAddress = tempLength;
251
                        tempLength = tempLength + fields[i].fieldLength;
252
                        tempFieldDescriptors[i] = fields[i];
253
                }
254
255
                tempFieldDescriptors[fields.length] = new DbaseField();
256
                tempFieldDescriptors[fields.length].fieldLength = inFieldLength;
257
                tempFieldDescriptors[fields.length].decimalCount = inDecimalCount;
258
                tempFieldDescriptors[fields.length].fieldDataAddress = tempLength;
259
260
                // set the field name
261
                String tempFieldName = inFieldName;
262
263
                if (tempFieldName == null) {
264
                        tempFieldName = "NoName";
265
                }
266
267
                // Fix for GEOT-42, ArcExplorer will not handle field names > 10 chars
268
                // Sorry folks.
269
                if (tempFieldName.length() > 10) {
270
                        tempFieldName = tempFieldName.substring(0, 10);
271
                        warn("FieldName " + inFieldName
272
                                        + " is longer than 10 characters, truncating to "
273
                                        + tempFieldName);
274
                }
275
276
                tempFieldDescriptors[fields.length].fieldName = tempFieldName;
277
278
                // the field type
279
                if ((inFieldType == 'C') || (inFieldType == 'c')) {
280
                        tempFieldDescriptors[fields.length].fieldType = 'C';
281
282
                        if (inFieldLength > 254) {
283
                                warn("Field Length for "
284
                                                + inFieldName
285
                                                + " set to "
286
                                                + inFieldLength
287
                                                + " Which is longer than 254, not consistent with dbase III");
288
                        }
289
                } else if ((inFieldType == 'S') || (inFieldType == 's')) {
290
                        tempFieldDescriptors[fields.length].fieldType = 'C';
291
                        warn("Field type for "
292
                                        + inFieldName
293
                                        + " set to S which is flat out wrong people!, I am setting this to C, in the hopes you meant character.");
294
295
                        if (inFieldLength > 254) {
296
                                warn("Field Length for "
297
                                                + inFieldName
298
                                                + " set to "
299
                                                + inFieldLength
300
                                                + " Which is longer than 254, not consistent with dbase III");
301
                        }
302
303
                        tempFieldDescriptors[fields.length].fieldLength = 8;
304
                } else if ((inFieldType == 'D') || (inFieldType == 'd')) {
305
                        tempFieldDescriptors[fields.length].fieldType = 'D';
306
307
                        if (inFieldLength != 8) {
308
                                warn("Field Length for " + inFieldName + " set to "
309
                                                + inFieldLength + " Setting to 8 digets YYYYMMDD");
310
                        }
311
312
                        tempFieldDescriptors[fields.length].fieldLength = 8;
313
                } else if ((inFieldType == 'F') || (inFieldType == 'f')) {
314
                        tempFieldDescriptors[fields.length].fieldType = 'F';
315
316
                        if (inFieldLength > 20) {
317
                                warn("Field Length for "
318
                                                + inFieldName
319
                                                + " set to "
320
                                                + inFieldLength
321
                                                + " Preserving length, but should be set to Max of 20 not valid for dbase IV, and UP specification, not present in dbaseIII.");
322
                        }
323
                } else if ((inFieldType == 'N') || (inFieldType == 'n')) {
324
                        tempFieldDescriptors[fields.length].fieldType = 'N';
325
326
                        if (inFieldLength > 18) {
327
                                warn("Field Length for "
328
                                                + inFieldName
329
                                                + " set to "
330
                                                + inFieldLength
331
                                                + " Preserving length, but should be set to Max of 18 for dbase III specification.");
332
                        }
333
334
                        if (inDecimalCount < 0) {
335
                                warn("Field Decimal Position for " + inFieldName + " set to "
336
                                                + inDecimalCount
337
                                                + " Setting to 0 no decimal data will be saved.");
338
                                tempFieldDescriptors[fields.length].decimalCount = 0;
339
                        }
340
341
                        if (inDecimalCount > (inFieldLength - 1)) {
342
                                warn("Field Decimal Position for " + inFieldName + " set to "
343
                                                + inDecimalCount + " Setting to " + (inFieldLength - 1)
344
                                                + " no non decimal data will be saved.");
345
                                tempFieldDescriptors[fields.length].decimalCount = inFieldLength - 1;
346
                        }
347
                } else if ((inFieldType == 'L') || (inFieldType == 'l')) {
348
                        tempFieldDescriptors[fields.length].fieldType = 'L';
349
350
                        if (inFieldLength != 1) {
351
                                warn("Field Length for " + inFieldName + " set to "
352
                                                + inFieldLength
353
                                                + " Setting to length of 1 for logical fields.");
354
                        }
355
356
                        tempFieldDescriptors[fields.length].fieldLength = 1;
357
                } else {
358
                        // throw new DbaseFileException("Undefined field type "+inFieldType
359
                        // + " For column "+inFieldName);
360
                }
361
362
                // the length of a record
363
                tempLength = tempLength
364
                                + tempFieldDescriptors[fields.length].fieldLength;
365
366
                // set the new fields.
367
                fields = tempFieldDescriptors;
368
                fieldCnt = fields.length;
369
                headerLength = MINIMUM_HEADER + (32 * fields.length);
370
                recordLength = tempLength;
371
        }
372
373
        /**
374
         * Remove a column from this DbaseFileHeader.
375
         *
376
         * @param inFieldName
377
         *            The name of the field, will ignore case and trim.
378
         *
379
         * @return index of the removed column, -1 if no found
380
         *
381
         */
382
        public int removeColumn(String inFieldName) {
383
                int retCol = -1;
384
                int tempLength = 1;
385
                DbaseField[] tempFieldDescriptors = new DbaseField[fields.length - 1];
386
387
                for (int i = 0, j = 0; i < fields.length; i++) {
388
                        if (!inFieldName.equalsIgnoreCase(fields[i].fieldName.trim())) {
389
                                // if this is the last field and we still haven't found the
390
                                // named field
391
                                if ((i == j) && (i == (fields.length - 1))) {
392
//                                        System.err.println("Could not find a field named '"
393
//                                                        + inFieldName + "' for removal");
394
395
                                        return retCol;
396
                                }
397
398
                                tempFieldDescriptors[j] = fields[i];
399
                                tempFieldDescriptors[j].fieldDataAddress = tempLength;
400
                                tempLength += tempFieldDescriptors[j].fieldLength;
401
402
                                // only increment j on non-matching fields
403
                                j++;
404
                        } else {
405
                                retCol = i;
406
                        }
407
                }
408
409
                // set the new fields.
410
                fields = tempFieldDescriptors;
411
                headerLength = 33 + (32 * fields.length);
412
                recordLength = tempLength;
413
414
                return retCol;
415
        }
416
417
        /**
418
         *
419
         *
420
         * @param inWarn
421
         *
422
         *
423
         * @todo addProgessListener handling
424
         */
425
        private void warn(String inWarn) {
426
                logger.error(inWarn);
427
        }
428
429
        // Retrieve the length of the field at the given index
430
431
        /**
432
         * Returns the field length in bytes.
433
         *
434
         * @param inIndex
435
         *            The field index.
436
         *
437
         * @return The length in bytes.
438
         */
439
        public int getFieldLength(int inIndex) {
440
                return fields[inIndex].fieldLength;
441
        }
442
443
        // Retrieve the location of the decimal point within the field.
444
445
        /**
446
         * Get the decimal count of this field.
447
         *
448
         * @param inIndex
449
         *            The field index.
450
         *
451
         * @return The decimal count.
452
         */
453
        public int getFieldDecimalCount(int inIndex) {
454
                return fields[inIndex].decimalCount;
455
        }
456
457
        // Retrieve the Name of the field at the given index
458
459
        /**
460
         * Get the field name.
461
         *
462
         * @param inIndex
463
         *            The field index.
464
         *
465
         * @return The name of the field.
466
         */
467
        public String getFieldName(int inIndex) {
468
                return fields[inIndex].fieldName;
469
        }
470
471
        // Retrieve the type of field at the given index
472
473
        /**
474
         * Get the character class of the field.
475
         *
476
         * @param inIndex
477
         *            The field index.
478
         *
479
         * @return The dbase character representing this field.
480
         */
481
        public char getFieldType(int inIndex) {
482
                return fields[inIndex].fieldType;
483
        }
484
485
        public int getFieldIntType(int inIndex) {
486
                return charTypeToIntType(fields[inIndex].fieldType);
487
        }
488
489
        public static int charTypeToIntType(char c) {
490
                if (c == 'N') return Types.DOUBLE;
491
                if (c == 'C') return Types.VARCHAR;
492
                if (c == 'D') return Types.DATE;
493
                if (c == 'L') return Types.BOOLEAN;
494
                return Types.VARCHAR;
495
        }
496
497
        /**
498
         * Get the date this file was last updated.
499
         *
500
         * @return The Date last modified.
501
         */
502
        public Date getLastUpdateDate() {
503
                return date;
504
        }
505
506
        /**
507
         * Return the number of fields in the records.
508
         *
509
         * @return The number of fields in this table.
510
         */
511
        public int getNumFields() {
512
                if (fields == null)
513
                        return 0;
514
                return fields.length;
515
        }
516
517
        /**
518
         * Return the number of records in the file
519
         *
520
         * @return The number of records in this table.
521
         */
522
        public int getNumRecords() {
523
                return recordCnt;
524
        }
525
526
        /**
527
         * Get the length of the records in bytes.
528
         *
529
         * @return The number of bytes per record.
530
         */
531
        public int getRecordLength() {
532
                return recordLength;
533
        }
534
535
        /**
536
         * Get the length of the header
537
         *
538
         * @return The length of the header in bytes.
539
         */
540
        public int getHeaderLength() {
541
                return headerLength;
542
        }
543
544
        /**
545
         * Read the header data from the DBF file.
546
         *
547
         * @param in
548
         *
549
         *
550
         * @throws IOException
551
         *
552
         */
553
        public void readHeader(FalseByteBuffer in) throws IOException {
554
                // type of file.
555
                myFileType = in.getByte();
556
557
                if (myFileType != 0x03) {
558
                        throw new IOException("Unsupported DBF file Type "
559
                                        + Integer.toHexString(myFileType));
560
                }
561
562
                // parse the update date information.
563
                int tempUpdateYear = (int) in.getByte();
564
                int tempUpdateMonth = (int) in.getByte();
565
                int tempUpdateDay = (int) in.getByte();
566
                tempUpdateYear = tempUpdateYear + 2000;
567
568
                Calendar c = Calendar.getInstance();
569
                c.set(Calendar.YEAR, tempUpdateYear);
570
                c.set(Calendar.MONTH, tempUpdateMonth - 1);
571
                c.set(Calendar.DATE, tempUpdateDay);
572
                date = c.getTime();
573
574
                // read the number of records.
575
                in.setByteOrder(ByteOrder.LITTLE_ENDIAN);
576
                recordCnt = in.getInt();
577
578
                // read the length of the header structure.
579
                headerLength = in.getShort();
580
581
                // read the length of a record
582
                recordLength = in.getShort();
583
584
                in.setByteOrder(ByteOrder.BIG_ENDIAN);
585
586
                // skip the reserved bytes in the header.
587
                in.position(in.getPosition() + 20);
588
589
                // calculate the number of Fields in the header
590
                fieldCnt = (headerLength - FILE_DESCRIPTOR_SIZE - 1)
591
                                / FILE_DESCRIPTOR_SIZE;
592
593
                // read all of the header records
594
                fields = new DbaseField[fieldCnt];
595
596
                for (int i = 0; i < fieldCnt; i++) {
597
                        fields[i] = new DbaseField();
598
599
                        // read the field name
600
                        byte[] buffer = new byte[11];
601
                        in.getBytes(buffer);
602
                        fields[i].fieldName = new String(buffer);
603
604
                        // read the field type
605
                        fields[i].fieldType = (char) in.getByte();
606
607
                        // read the field data address, offset from the start of the record.
608
                        fields[i].fieldDataAddress = in.getInt();
609
610
                        // read the field length in bytes
611
                        int tempLength = (int) in.getByte();
612
613
                        if (tempLength < 0) {
614
                                tempLength = tempLength + 256;
615
                        }
616
617
                        fields[i].fieldLength = tempLength;
618
619
                        // read the field decimal count in bytes
620
                        fields[i].decimalCount = (int) in.getByte();
621
622
                        // read the reserved bytes.
623
                        in.position(in.getPosition() + 14);
624
                }
625
626
                // Last byte is a marker for the end of the field definitions.
627
                in.getByte();
628
        }
629
630
        /**
631
         * Get the largest field size of this table.
632
         *
633
         * @return The largt field size iiin bytes.
634
         */
635
        public int getLargestFieldSize() {
636
                return largestFieldSize;
637
        }
638
639
        /**
640
         * Set the number of records in the file
641
         *
642
         * @param inNumRecords
643
         *            The number of records.
644
         */
645
        public void setNumRecords(int inNumRecords) {
646
                recordCnt = inNumRecords;
647
        }
648
649
        /**
650
         * Write the header data to the DBF file.
651
         *
652
         * @param out
653
         *            A channel to write to. If you have an OutputStream you can
654
         *            obtain the correct channel by using
655
         *            java.nio.Channels.newChannel(OutputStream out).
656
         *
657
         * @throws IOException
658
         *             If errors occur.
659
         */
660
661
662
        /**
663
         * Get a simple representation of this header.
664
         *
665
         * @return A String representing the state of the header.
666
         */
667
        public String toString() {
668
                StringBuffer fs = new StringBuffer();
669
670
                for (int i = 0, ii = fields.length; i < ii; i++) {
671
                        DbaseField f = fields[i];
672
                        fs.append(f.fieldName + " " + f.fieldType + " " + f.fieldLength
673
                                        + " " + f.decimalCount + " " + f.fieldDataAddress + "\n");
674
                }
675
676
                return "DB3 Header\n" + "Date : " + date + "\n" + "Records : "
677
                                + recordCnt + "\n" + "Fields : " + fieldCnt + "\n" + fs;
678
        }
679
680
        /**
681
         * Crea un DbaseFile.
682
         *
683
         * @return DbaseFileHeaderNIO
684
         *
685
         * @throws IOException .
686
         */
687
        public static DbaseFileHeaderNIO createNewDbaseHeader() throws IOException {
688
                DbaseFileHeaderNIO header = new DbaseFileHeaderNIO();
689
690
                for (int i = 0, ii = 1; i < ii; i++) {
691
                        // AttributeType type = featureType.getAttributeType(i);
692
                        Class colType = Integer.class;
693
                        String colName = "ID";
694
                        int fieldLen = 10;
695
696
                        if (fieldLen <= 0) {
697
                                fieldLen = 255;
698
                        }
699
700
                        // @todo respect field length
701
                        if ((colType == Integer.class) || (colType == Short.class)
702
                                        || (colType == Byte.class)) {
703
                                header.addColumn(colName, 'N', Math.min(fieldLen, 10), 0);
704
                        } else if (colType == Long.class) {
705
                                header.addColumn(colName, 'N', Math.min(fieldLen, 19), 0);
706
                        } else if ((colType == Double.class) || (colType == Float.class)
707
                                        || (colType == Number.class)) {
708
                                int l = Math.min(fieldLen, 33);
709
                                int d = Math.max(l - 2, 0);
710
                                header.addColumn(colName, 'N', l, d);
711
                        } else if (java.util.Date.class.isAssignableFrom(colType)) {
712
                                header.addColumn(colName, 'D', fieldLen, 0);
713
                        } else if (colType == Boolean.class) {
714
                                header.addColumn(colName, 'L', 1, 0);
715
                        } else if (CharSequence.class.isAssignableFrom(colType)) {
716
                                // Possible fix for GEOT-42 : ArcExplorer doesn't like 0 length
717
                                // ensure that maxLength is at least 1
718
                                header.addColumn(colName, 'C', Math.min(254, fieldLen), 0);
719
                        } else if (Geometry.class.isAssignableFrom(colType)) {
720
                                continue;
721
                        } else {
722
                                throw new IOException("Unable to write : " + colType.getName());
723
                        }
724
                }
725
726
                return header;
727
        }
728
729
        /**
730
         * Creates DbaseHeader
731
         * @param fieldNames
732
         * @param fieldTypes
733
         * @param fieldLength
734
         * @return
735
         * @throws IOException
736
         */
737
        public static DbaseFileHeaderNIO createDbaseHeader(String[] fieldNames,
738
                        int[] fieldTypes, int[] fieldLength) throws IOException {
739
                DbaseFileHeaderNIO header = new DbaseFileHeaderNIO();
740
741
                for (int i = 0, ii = fieldNames.length; i < ii; i++) {
742
743
                        int type = fieldTypes[i];
744
                        String colName = fieldNames[i];
745
746
                        // /int fieldLen = ((DBFDriver)sds.getDriver()).getFieldLength(i);
747
                        int fieldLen = fieldLength[i]; // TODO aqu? el tama?o no es
748
                        // correcto hay que calcularlo,
749
                        // ahora mismo est? puesto a pi??n.
750
                        int decimales = 5;
751
752
                        // if (fieldLen <= 0) {
753
                        // fieldLen = 255;
754
                        // }
755
                        // TODO [AZABALA] HE INTENTADO CREAR UN TIPO Types.BIGINT y
756
                        // ha petado (por eso lo a?ado)
757
                        if ((type == Types.DOUBLE) || (type == Types.FLOAT)
758
                                        || (type == Types.INTEGER) || (type == Types.BIGINT))
759
760
                                header.addColumn(colName, 'N', Math.min(fieldLen, 18),
761
                                                decimales);
762
                        if (type == Types.DATE)
763
                                header.addColumn(colName, 'D', fieldLen, 0);
764
                        if ((type == Types.BIT) || (type == Types.BOOLEAN))
765
                                header.addColumn(colName, 'L', 1, 0);
766
                        if ((type == Types.VARCHAR) || (type == Types.CHAR)
767
                                        || (type == Types.LONGVARCHAR))
768
                                header.addColumn(colName, 'C', Math.min(254, fieldLen), 0);
769
                }
770
771
                return header;
772
        }
773
774
        /**
775
         * Class for holding the information assicated with a record.
776
         */
777
        class DbaseField {
778
                // Field Name
779
                String fieldName;
780
781
                // Field Type (C N L D or M)
782
                char fieldType;
783
784
                // Field Data Address offset from the start of the record.
785
                int fieldDataAddress;
786
787
                // Length of the data in bytes
788
                int fieldLength;
789
790
                // Field decimal count in Binary, indicating where the decimal is
791
                int decimalCount;
792
        }
793
794
        public static DbaseFileHeaderNIO createDbaseHeader(
795
                        FieldDescription[] fieldsDesc) {
796
                DbaseFileHeaderNIO header = new DbaseFileHeaderNIO();
797
798
                for (int i = 0, ii = fieldsDesc.length; i < ii; i++) {
799
800
                        int type = fieldsDesc[i].getFieldType();
801
                        String colName = fieldsDesc[i].getFieldName();
802
803
                        int fieldLen = fieldsDesc[i].getFieldLength(); // TODO aqu? el
804
                        // tama?o no es
805
                        // correcto hay que
806
                        // calcularlo, ahora
807
                        // mismo est? puesto
808
                        // a pi??n.
809
                        int decimales = fieldsDesc[i].getFieldDecimalCount();
810
811
                        switch (type) {
812
                        case Types.DOUBLE:
813
                        case Types.FLOAT:
814
                        case Types.INTEGER:
815
                        case Types.BIGINT:
816
                        case Types.SMALLINT:
817
                                header.addColumn(colName, 'N', Math.min(fieldLen, 18),
818
                                                decimales);
819
                                break;
820
                        case Types.DATE:
821
                                header.addColumn(colName, 'D', fieldLen, 0);
822
                                break;
823
                        case Types.BIT:
824
                        case Types.BOOLEAN:
825
                                header.addColumn(colName, 'L', 1, 0);
826
                                break;
827
                        case Types.VARCHAR:
828
                        case Types.CHAR:
829
                        case Types.LONGVARCHAR:
830
                                header.addColumn(colName, 'C', Math.min(254, fieldLen), 0);
831
                                break;
832
                        default:
833
                                throw new RuntimeException("Field type " + type + " not supported in DBF writer");
834
835
                        }
836
                } // for
837
838
                return header;
839
840
        }
841
842
        public void setFieldName(int j, String newName) {
843
                fields[j].fieldName = newName;
844
        }
845
}