Statistics
| Revision:

root / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / drivers / shp / DbaseFileHeaderNIO.java @ 1773

History | View | Annotate | Download (22.3 KB)

1
/*
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
package com.iver.cit.gvsig.fmap.drivers.shp;
64

    
65
import com.hardcode.gdbms.engine.data.DriverException;
66
import com.hardcode.gdbms.engine.instruction.SemanticException;
67
import com.hardcode.gdbms.engine.values.Value;
68

    
69
import com.iver.cit.gvsig.fmap.layers.SelectableDataSource;
70

    
71
import com.vividsolutions.jts.geom.Geometry;
72

    
73
import java.io.EOFException;
74
import java.io.IOException;
75

    
76
import java.nio.ByteBuffer;
77
import java.nio.ByteOrder;
78
import java.nio.channels.ReadableByteChannel;
79
import java.nio.channels.WritableByteChannel;
80

    
81
import java.sql.Types;
82
import java.util.Calendar;
83
import java.util.Date;
84
import java.util.logging.Level;
85
import java.util.logging.Logger;
86

    
87

    
88
/**
89
 * Class to represent the header of a Dbase III file. Creation date: (5/15/2001
90
 * 5:15:30 PM)
91
 */
92
public class DbaseFileHeaderNIO {
93
        // Constant for the size of a record
94
        private static final int FILE_DESCRIPTOR_SIZE = 32;
95

    
96
        // type of the file, must be 03h
97
        private static final byte MAGIC = 0x03;
98
        private static final int MINIMUM_HEADER = 33;
99

    
100
        // Date the file was last updated.
101
        private Date date = new Date();
102
        private int recordCnt = 0;
103
        private int fieldCnt = 0;
104
        private int myFileType = 0;
105

    
106
        // set this to a default length of 1, which is enough for one "space"
107
        // character which signifies an empty record
108
        private int recordLength = 1;
109

    
110
        // set this to a flagged value so if no fields are added before the write,
111
        // we know to adjust the headerLength to MINIMUM_HEADER
112
        private int headerLength = -1;
113
        private int largestFieldSize = 0;
114
        private Logger logger = Logger.getLogger("org.geotools.data.shapefile");
115

    
116
        // collection of header records.
117
        // lets start out with a zero-length array, just in case
118
        private DbaseField[] fields = null; // new DbaseField[0];
119

    
120
        /**
121
         * Lee del buffer.
122
         *
123
         * @param buffer .
124
         * @param channel .
125
         *
126
         * @throws IOException .
127
         * @throws EOFException .
128
         */
129
        private void read(ByteBuffer buffer, ReadableByteChannel channel)
130
                throws IOException {
131
                while (buffer.remaining() > 0) {
132
                        if (channel.read(buffer) == -1) {
133
                                throw new EOFException("Premature end of file");
134
                        }
135
                }
136
        }
137

    
138
        /**
139
         * Determine the most appropriate Java Class for representing the data in
140
         * the field.
141
         * <PRE>
142
         * All packages are java.lang unless otherwise specified.
143
         * C (Character) -> String
144
         * N (Numeric)   -> Integer or Double (depends on field's decimal count)
145
         * F (Floating)  -> Double
146
         * L (Logical)   -> Boolean
147
         * D (Date)      -> java.util.Date
148
         * Unknown       -> String
149
         * </PRE>
150
         *
151
         * @param i The index of the field, from 0 to <CODE>getNumFields() -
152
         *                   1</CODE> .
153
         *
154
         * @return A Class which closely represents the dbase field type.
155
         */
156
        public Class getFieldClass(int i) {
157
                Class typeClass = null;
158

    
159
                switch (fields[i].fieldType) {
160
                        case 'C':
161
                                typeClass = String.class;
162

    
163
                                break;
164

    
165
                        case 'N':
166

    
167
                                if (fields[i].decimalCount == 0) {
168
                                        typeClass = Integer.class;
169
                                } else {
170
                                        typeClass = Double.class;
171
                                }
172

    
173
                                break;
174

    
175
                        case 'F':
176
                                typeClass = Double.class;
177

    
178
                                break;
179

    
180
                        case 'L':
181
                                typeClass = Boolean.class;
182

    
183
                                break;
184

    
185
                        case 'D':
186
                                typeClass = Date.class;
187

    
188
                                break;
189

    
190
                        default:
191
                                typeClass = String.class;
192

    
193
                                break;
194
                }
195

    
196
                return typeClass;
197
        }
198

    
199
        /**
200
         * Add a column to this DbaseFileHeader. The type is one of (C N L or D)
201
         * character, number, logical(true/false), or date. The Field length is
202
         * the total length in bytes reserved for this column. The decimal count
203
         * only applies to numbers(N), and floating point values (F), and refers
204
         * to the number of characters to reserve after the decimal point.
205
         * <B>Don't expect miracles from this...</B>
206
         * <PRE>
207
         * Field Type MaxLength
208
         * ---------- ---------
209
         * C          254
210
         * D          8
211
         * F          20
212
         * N          18
213
         * </PRE>
214
         *
215
         * @param inFieldName The name of the new field, must be less than 10
216
         *                   characters or it gets truncated.
217
         * @param inFieldType A character representing the dBase field, ( see above
218
         *                   ). Case insensitive.
219
         * @param inFieldLength The length of the field, in bytes ( see above )
220
         * @param inDecimalCount For numeric fields, the number of decimal places
221
         *                   to track.
222
         */
223
        public void addColumn(String inFieldName, char inFieldType,
224
                int inFieldLength, int inDecimalCount) {
225
                /*if (inFieldLength <=0) {
226
                   throw new DbaseFileException("field length <= 0");
227
                   }
228
                 */
229
                if (fields == null) {
230
                        fields = new DbaseField[0];
231
                }
232

    
233
                int tempLength = 1; // the length is used for the offset, and there is a * for deleted as the first byte
234
                DbaseField[] tempFieldDescriptors = new DbaseField[fields.length + 1];
235

    
236
                for (int i = 0; i < fields.length; i++) {
237
                        fields[i].fieldDataAddress = tempLength;
238
                        tempLength = tempLength + fields[i].fieldLength;
239
                        tempFieldDescriptors[i] = fields[i];
240
                }
241

    
242
                tempFieldDescriptors[fields.length] = new DbaseField();
243
                tempFieldDescriptors[fields.length].fieldLength = inFieldLength;
244
                tempFieldDescriptors[fields.length].decimalCount = inDecimalCount;
245
                tempFieldDescriptors[fields.length].fieldDataAddress = tempLength;
246

    
247
                // set the field name
248
                String tempFieldName = inFieldName;
249

    
250
                if (tempFieldName == null) {
251
                        tempFieldName = "NoName";
252
                }
253

    
254
                // Fix for GEOT-42, ArcExplorer will not handle field names > 10 chars
255
                // Sorry folks.
256
                if (tempFieldName.length() > 10) {
257
                        tempFieldName = tempFieldName.substring(0, 10);
258
                        warn("FieldName " + inFieldName +
259
                                " is longer than 10 characters, truncating to " +
260
                                tempFieldName);
261
                }
262

    
263
                tempFieldDescriptors[fields.length].fieldName = tempFieldName;
264

    
265
                // the field type
266
                if ((inFieldType == 'C') || (inFieldType == 'c')) {
267
                        tempFieldDescriptors[fields.length].fieldType = 'C';
268

    
269
                        if (inFieldLength > 254) {
270
                                warn("Field Length for " + inFieldName + " set to " +
271
                                        inFieldLength +
272
                                        " Which is longer than 254, not consistent with dbase III");
273
                        }
274
                } else if ((inFieldType == 'S') || (inFieldType == 's')) {
275
                        tempFieldDescriptors[fields.length].fieldType = 'C';
276
                        warn("Field type for " + inFieldName +
277
                                " set to S which is flat out wrong people!, I am setting this to C, in the hopes you meant character.");
278

    
279
                        if (inFieldLength > 254) {
280
                                warn("Field Length for " + inFieldName + " set to " +
281
                                        inFieldLength +
282
                                        " Which is longer than 254, not consistent with dbase III");
283
                        }
284

    
285
                        tempFieldDescriptors[fields.length].fieldLength = 8;
286
                } else if ((inFieldType == 'D') || (inFieldType == 'd')) {
287
                        tempFieldDescriptors[fields.length].fieldType = 'D';
288

    
289
                        if (inFieldLength != 8) {
290
                                warn("Field Length for " + inFieldName + " set to " +
291
                                        inFieldLength + " Setting to 8 digets YYYYMMDD");
292
                        }
293

    
294
                        tempFieldDescriptors[fields.length].fieldLength = 8;
295
                } else if ((inFieldType == 'F') || (inFieldType == 'f')) {
296
                        tempFieldDescriptors[fields.length].fieldType = 'F';
297

    
298
                        if (inFieldLength > 20) {
299
                                warn("Field Length for " + inFieldName + " set to " +
300
                                        inFieldLength +
301
                                        " Preserving length, but should be set to Max of 20 not valid for dbase IV, and UP specification, not present in dbaseIII.");
302
                        }
303
                } else if ((inFieldType == 'N') || (inFieldType == 'n')) {
304
                        tempFieldDescriptors[fields.length].fieldType = 'N';
305

    
306
                        if (inFieldLength > 18) {
307
                                warn("Field Length for " + inFieldName + " set to " +
308
                                        inFieldLength +
309
                                        " Preserving length, but should be set to Max of 18 for dbase III specification.");
310
                        }
311

    
312
                        if (inDecimalCount < 0) {
313
                                warn("Field Decimal Position for " + inFieldName + " set to " +
314
                                        inDecimalCount +
315
                                        " Setting to 0 no decimal data will be saved.");
316
                                tempFieldDescriptors[fields.length].decimalCount = 0;
317
                        }
318

    
319
                        if (inDecimalCount > (inFieldLength - 1)) {
320
                                warn("Field Decimal Position for " + inFieldName + " set to " +
321
                                        inDecimalCount + " Setting to " + (inFieldLength - 1) +
322
                                        " no non decimal data will be saved.");
323
                                tempFieldDescriptors[fields.length].decimalCount = inFieldLength -
324
                                        1;
325
                        }
326
                } else if ((inFieldType == 'L') || (inFieldType == 'l')) {
327
                        tempFieldDescriptors[fields.length].fieldType = 'L';
328

    
329
                        if (inFieldLength != 1) {
330
                                warn("Field Length for " + inFieldName + " set to " +
331
                                        inFieldLength +
332
                                        " Setting to length of 1 for logical fields.");
333
                        }
334

    
335
                        tempFieldDescriptors[fields.length].fieldLength = 1;
336
                } else {
337
                        //throw new DbaseFileException("Undefined field type "+inFieldType + " For column "+inFieldName);
338
                }
339

    
340
                // the length of a record
341
                tempLength = tempLength +
342
                        tempFieldDescriptors[fields.length].fieldLength;
343

    
344
                // set the new fields.
345
                fields = tempFieldDescriptors;
346
                fieldCnt = fields.length;
347
                headerLength = MINIMUM_HEADER + (32 * fields.length);
348
                recordLength = tempLength;
349
        }
350

    
351
        /**
352
         * Remove a column from this DbaseFileHeader.
353
         *
354
         * @param inFieldName The name of the field, will ignore case and trim.
355
         *
356
         * @return index of the removed column, -1 if no found
357
         *
358
         * @todo This is really ugly, don't know who wrote it, but it needs
359
         *                  fixin...
360
         */
361
        public int removeColumn(String inFieldName) {
362
                int retCol = -1;
363
                int tempLength = 1;
364
                DbaseField[] tempFieldDescriptors = new DbaseField[fields.length - 1];
365

    
366
                for (int i = 0, j = 0; i < fields.length; i++) {
367
                        if (!inFieldName.equalsIgnoreCase(fields[i].fieldName.trim())) {
368
                                // if this is the last field and we still haven't found the
369
                                // named field
370
                                if ((i == j) && (i == (fields.length - 1))) {
371
                                        System.err.println("Could not find a field named '" +
372
                                                inFieldName + "' for removal");
373

    
374
                                        return retCol;
375
                                }
376

    
377
                                tempFieldDescriptors[j] = fields[i];
378
                                tempFieldDescriptors[j].fieldDataAddress = tempLength;
379
                                tempLength += tempFieldDescriptors[j].fieldLength;
380

    
381
                                // only increment j on non-matching fields
382
                                j++;
383
                        } else {
384
                                retCol = i;
385
                        }
386
                }
387

    
388
                // set the new fields.
389
                fields = tempFieldDescriptors;
390
                headerLength = 33 + (32 * fields.length);
391
                recordLength = tempLength;
392

    
393
                return retCol;
394
        }
395

    
396
        /**
397
         * DOCUMENT ME!
398
         *
399
         * @param inWarn DOCUMENT ME!
400
         *
401
         * @todo addProgessListener handling
402
         */
403
        private void warn(String inWarn) {
404
                if (logger.isLoggable(Level.WARNING)) {
405
                        logger.warning(inWarn);
406
                }
407
        }
408

    
409
        // Retrieve the length of the field at the given index
410

    
411
        /**
412
         * Returns the field length in bytes.
413
         *
414
         * @param inIndex The field index.
415
         *
416
         * @return The length in bytes.
417
         */
418
        public int getFieldLength(int inIndex) {
419
                return fields[inIndex].fieldLength;
420
        }
421

    
422
        // Retrieve the location of the decimal point within the field.
423

    
424
        /**
425
         * Get the decimal count of this field.
426
         *
427
         * @param inIndex The field index.
428
         *
429
         * @return The decimal count.
430
         */
431
        public int getFieldDecimalCount(int inIndex) {
432
                return fields[inIndex].decimalCount;
433
        }
434

    
435
        // Retrieve the Name of the field at the given index
436

    
437
        /**
438
         * Get the field name.
439
         *
440
         * @param inIndex The field index.
441
         *
442
         * @return The name of the field.
443
         */
444
        public String getFieldName(int inIndex) {
445
                return fields[inIndex].fieldName;
446
        }
447

    
448
        // Retrieve the type of field at the given index
449

    
450
        /**
451
         * Get the character class of the field.
452
         *
453
         * @param inIndex The field index.
454
         *
455
         * @return The dbase character representing this field.
456
         */
457
        public char getFieldType(int inIndex) {
458
                return fields[inIndex].fieldType;
459
        }
460

    
461
        /**
462
         * Get the date this file was last updated.
463
         *
464
         * @return The Date last modified.
465
         */
466
        public Date getLastUpdateDate() {
467
                return date;
468
        }
469

    
470
        /**
471
         * Return the number of fields in the records.
472
         *
473
         * @return The number of fields in this table.
474
         */
475
        public int getNumFields() {
476
                return fields.length;
477
        }
478

    
479
        /**
480
         * Return the number of records in the file
481
         *
482
         * @return The number of records in this table.
483
         */
484
        public int getNumRecords() {
485
                return recordCnt;
486
        }
487

    
488
        /**
489
         * Get the length of the records in bytes.
490
         *
491
         * @return The number of bytes per record.
492
         */
493
        public int getRecordLength() {
494
                return recordLength;
495
        }
496

    
497
        /**
498
         * Get the length of the header
499
         *
500
         * @return The length of the header in bytes.
501
         */
502
        public int getHeaderLength() {
503
                return headerLength;
504
        }
505

    
506
        /**
507
         * Read the header data from the DBF file.
508
         *
509
         * @param in DOCUMENT ME!
510
         *
511
         * @throws IOException DOCUMENT ME!
512
         */
513
        public void readHeader(ByteBuffer in) throws IOException {
514
                // type of file.
515
                myFileType = in.get();
516

    
517
                if (myFileType != 0x03) {
518
                        throw new IOException("Unsupported DBF file Type " +
519
                                Integer.toHexString(myFileType));
520
                }
521

    
522
                // parse the update date information.
523
                int tempUpdateYear = (int) in.get();
524
                int tempUpdateMonth = (int) in.get();
525
                int tempUpdateDay = (int) in.get();
526
                tempUpdateYear = tempUpdateYear + 1900;
527

    
528
                Calendar c = Calendar.getInstance();
529
                c.set(Calendar.YEAR, tempUpdateYear);
530
                c.set(Calendar.MONTH, tempUpdateMonth - 1);
531
                c.set(Calendar.DATE, tempUpdateDay);
532
                date = c.getTime();
533

    
534
                // read the number of records.
535
                in.order(ByteOrder.LITTLE_ENDIAN);
536
                recordCnt = in.getInt();
537

    
538
                // read the length of the header structure.
539
                headerLength = in.getShort();
540

    
541
                // read the length of a record
542
                recordLength = in.getShort();
543

    
544
                in.order(ByteOrder.BIG_ENDIAN);
545

    
546
                // skip the reserved bytes in the header.
547
                in.position(in.position() + 20);
548

    
549
                // calculate the number of Fields in the header
550
                fieldCnt = (headerLength - FILE_DESCRIPTOR_SIZE - 1) / FILE_DESCRIPTOR_SIZE;
551

    
552
                // read all of the header records
553
                fields = new DbaseField[fieldCnt];
554

    
555
                for (int i = 0; i < fieldCnt; i++) {
556
                        fields[i] = new DbaseField();
557

    
558
                        // read the field name
559
                        byte[] buffer = new byte[11];
560
                        in.get(buffer);
561
                        fields[i].fieldName = new String(buffer);
562

    
563
                        // read the field type
564
                        fields[i].fieldType = (char) in.get();
565

    
566
                        // read the field data address, offset from the start of the record.
567
                        fields[i].fieldDataAddress = in.getInt();
568

    
569
                        // read the field length in bytes
570
                        int tempLength = (int) in.get();
571

    
572
                        if (tempLength < 0) {
573
                                tempLength = tempLength + 256;
574
                        }
575

    
576
                        fields[i].fieldLength = tempLength;
577

    
578
                        // read the field decimal count in bytes
579
                        fields[i].decimalCount = (int) in.get();
580

    
581
                        // read the reserved bytes.
582
                        in.position(in.position() + 14);
583
                }
584

    
585
                // Last byte is a marker for the end of the field definitions.
586
                in.get();
587
        }
588

    
589
        /**
590
         * Get the largest field size of this table.
591
         *
592
         * @return The largt field size iiin bytes.
593
         */
594
        public int getLargestFieldSize() {
595
                return largestFieldSize;
596
        }
597

    
598
        /**
599
         * Set the number of records in the file
600
         *
601
         * @param inNumRecords The number of records.
602
         */
603
        public void setNumRecords(int inNumRecords) {
604
                recordCnt = inNumRecords;
605
        }
606

    
607
        /**
608
         * Write the header data to the DBF file.
609
         *
610
         * @param out A channel to write to. If you have an OutputStream you can
611
         *                   obtain the correct channel by using
612
         *                   java.nio.Channels.newChannel(OutputStream out).
613
         *
614
         * @throws IOException If errors occur.
615
         */
616
        public void writeHeader(WritableByteChannel out) throws IOException {
617
                // take care of the annoying case where no records have been added...
618
                if (headerLength == -1) {
619
                        headerLength = MINIMUM_HEADER;
620
                }
621

    
622
                ByteBuffer buffer = ByteBuffer.allocateDirect(headerLength);
623
                buffer.order(ByteOrder.LITTLE_ENDIAN);
624

    
625
                // write the output file type.
626
                buffer.put((byte) MAGIC);
627

    
628
                // write the date stuff
629
                Calendar c = Calendar.getInstance();
630
                c.setTime(new Date());
631
                buffer.put((byte) (c.get(Calendar.YEAR) % 100));
632
                buffer.put((byte) (c.get(Calendar.MONTH) + 1));
633
                buffer.put((byte) (c.get(Calendar.DAY_OF_MONTH)));
634

    
635
                // write the number of records in the datafile.
636
                buffer.putInt(recordCnt);
637

    
638
                // write the length of the header structure.
639
                buffer.putShort((short) headerLength);
640

    
641
                // write the length of a record
642
                buffer.putShort((short) recordLength);
643

    
644
                //    // write the reserved bytes in the header
645
                //    for (int i=0; i<20; i++) out.writeByteLE(0);
646
                buffer.position(buffer.position() + 20);
647

    
648
                // write all of the header records
649
                int tempOffset = 0;
650

    
651
                for (int i = 0; i < fields.length; i++) {
652
                        // write the field name
653
                        for (int j = 0; j < 11; j++) {
654
                                if (fields[i].fieldName.length() > j) {
655
                                        buffer.put((byte) fields[i].fieldName.charAt(j));
656
                                } else {
657
                                        buffer.put((byte) 0);
658
                                }
659
                        }
660

    
661
                        // write the field type
662
                        buffer.put((byte) fields[i].fieldType);
663

    
664
                        //    // write the field data address, offset from the start of the record.
665
                        buffer.putInt(tempOffset);
666
                        tempOffset += fields[i].fieldLength;
667

    
668
                        // write the length of the field.
669
                        buffer.put((byte) fields[i].fieldLength);
670

    
671
                        // write the decimal count.
672
                        buffer.put((byte) fields[i].decimalCount);
673

    
674
                        // write the reserved bytes.
675
                        //for (in j=0; jj<14; j++) out.writeByteLE(0);
676
                        buffer.position(buffer.position() + 14);
677
                }
678

    
679
                // write the end of the field definitions marker
680
                buffer.put((byte) 0x0D);
681

    
682
                buffer.position(0);
683

    
684
                int r = buffer.remaining();
685

    
686
                while ((r -= out.write(buffer)) > 0) {
687
                        ; // do nothing
688
                }
689
        }
690

    
691
        /**
692
         * Get a simple representation of this header.
693
         *
694
         * @return A String representing the state of the header.
695
         */
696
        public String toString() {
697
                StringBuffer fs = new StringBuffer();
698

    
699
                for (int i = 0, ii = fields.length; i < ii; i++) {
700
                        DbaseField f = fields[i];
701
                        fs.append(f.fieldName + " " + f.fieldType + " " + f.fieldLength +
702
                                " " + f.decimalCount + " " + f.fieldDataAddress + "\n");
703
                }
704

    
705
                return "DB3 Header\n" + "Date : " + date + "\n" + "Records : " +
706
                recordCnt + "\n" + "Fields : " + fieldCnt + "\n" + fs;
707
        }
708

    
709
        /**
710
         * Crea un DbaseFile.
711
         *
712
         * @return DbaseFileHeaderNIO
713
         *
714
         * @throws IOException .
715
         */
716
        public static DbaseFileHeaderNIO createNewDbaseHeader()
717
                throws IOException {
718
                DbaseFileHeaderNIO header = new DbaseFileHeaderNIO();
719

    
720
                for (int i = 0, ii = 1; i < ii; i++) {
721
                        //AttributeType type = featureType.getAttributeType(i);
722
                        Class colType = Integer.class;
723
                        String colName = "ID";
724
                        int fieldLen = 10;
725

    
726
                        if (fieldLen <= 0) {
727
                                fieldLen = 255;
728
                        }
729

    
730
                        // @todo respect field length
731
                        if ((colType == Integer.class) || (colType == Short.class) ||
732
                                        (colType == Byte.class)) {
733
                                header.addColumn(colName, 'N', Math.min(fieldLen, 10), 0);
734
                        } else if (colType == Long.class) {
735
                                header.addColumn(colName, 'N', Math.min(fieldLen, 19), 0);
736
                        } else if ((colType == Double.class) || (colType == Float.class) ||
737
                                        (colType == Number.class)) {
738
                                int l = Math.min(fieldLen, 33);
739
                                int d = Math.max(l - 2, 0);
740
                                header.addColumn(colName, 'N', l, d);
741
                        } else if (java.util.Date.class.isAssignableFrom(colType)) {
742
                                header.addColumn(colName, 'D', fieldLen, 0);
743
                        } else if (colType == Boolean.class) {
744
                                header.addColumn(colName, 'L', 1, 0);
745
                        } else if (CharSequence.class.isAssignableFrom(colType)) {
746
                                // Possible fix for GEOT-42 : ArcExplorer doesn't like 0 length
747
                                // ensure that maxLength is at least 1
748
                                header.addColumn(colName, 'C', Math.min(254, fieldLen), 0);
749
                        } else if (Geometry.class.isAssignableFrom(colType)) {
750
                                continue;
751
                        } else {
752
                                throw new IOException("Unable to write : " + colType.getName());
753
                        }
754
                }
755

    
756
                return header;
757
        }
758

    
759
        /**
760
         * DOCUMENT ME!
761
         *
762
         * @param sds DOCUMENT ME!
763
         *
764
         * @return DOCUMENT ME!
765
         *
766
         * @throws IOException DOCUMENT ME!
767
         */
768
        public static DbaseFileHeaderNIO createDbaseHeader(SelectableDataSource sds)
769
                throws IOException {
770
                DbaseFileHeaderNIO header = new DbaseFileHeaderNIO();
771

    
772
                try {
773
                        for (int i = 0, ii = sds.getFieldCount(); i < ii; i++) {
774

    
775
                                int type = sds.getFieldType(i);
776
                                String colName = sds.getFieldName(i);
777

    
778
                                ///int fieldLen = ((DBFDriver)sds.getDriver()).getFieldLength(i);
779
                                int fieldLen = 100; //TODO aqu? el tama?o no es correcto hay que calcularlo, ahora mismo est? puesto a pi??n.
780
                                int decimales = 5;
781

    
782
                                //  if (fieldLen <= 0) {
783
                                //       fieldLen = 255;
784
                                //   }
785
                                // @todo respect field length
786
                                if ((type == Types.DOUBLE) ||
787
                                    (type == Types.FLOAT) || 
788
                                    (type == Types.INTEGER))
789
                                    
790
                                                header.addColumn(colName, 'N', Math.min(fieldLen, 10),
791
                                                        decimales);
792
                                if (type == Types.DATE)
793
                                                header.addColumn(colName, 'D', fieldLen, 0);
794
                                if (type == Types.BIT)
795
                                                header.addColumn(colName, 'L', 1, 0);
796
                                if ((type == Types.VARCHAR) ||
797
                                            (type == Types.CHAR) || 
798
                                            (type == Types.LONGVARCHAR))
799
                                    header.addColumn(colName, 'C', Math.min(254, fieldLen),
800
                                                        0);
801
                                }
802
                } catch (DriverException e) {
803
                        e.printStackTrace();
804
                }
805

    
806
                return header;
807
        }
808

    
809

    
810
        /**
811
         * Class for holding the information assicated with a record.
812
         */
813
        class DbaseField {
814
                // Field Name
815
                String fieldName;
816

    
817
                // Field Type (C N L D or M)
818
                char fieldType;
819

    
820
                // Field Data Address offset from the start of the record.
821
                int fieldDataAddress;
822

    
823
                // Length of the data in bytes
824
                int fieldLength;
825

    
826
                // Field decimal count in Binary, indicating where the decimal is
827
                int decimalCount;
828
        }
829
}