Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / drivers / shp / DbaseFileHeaderNIO.java @ 4430

History | View | Annotate | Download (24.2 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 java.io.EOFException;
66
import java.io.IOException;
67
import java.nio.ByteBuffer;
68
import java.nio.ByteOrder;
69
import java.nio.channels.FileChannel;
70
import java.nio.channels.ReadableByteChannel;
71
import java.sql.Types;
72
import java.util.Calendar;
73
import java.util.Date;
74
import java.util.logging.Level;
75
import java.util.logging.Logger;
76

    
77
import com.hardcode.gdbms.engine.data.DataSource;
78
import com.hardcode.gdbms.engine.data.driver.DriverException;
79
import com.iver.cit.gvsig.fmap.drivers.FieldDescription;
80
import com.iver.utiles.bigfile.BigByteBuffer2;
81
import com.vividsolutions.jts.geom.Geometry;
82

    
83

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

    
92
        // type of the file, must be 03h
93
        private static final byte MAGIC = 0x03;
94
        private static final int MINIMUM_HEADER = 33;
95

    
96
        // Date the file was last updated.
97
        private Date date = new Date();
98
        private int recordCnt = 0;
99
        private int fieldCnt = 0;
100
        private int myFileType = 0;
101

    
102
        // set this to a default length of 1, which is enough for one "space"
103
        // character which signifies an empty record
104
        private int recordLength = 1;
105

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

    
112
        // collection of header records.
113
        // lets start out with a zero-length array, just in case
114
        private DbaseField[] fields = null; // new DbaseField[0];
115

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

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

    
155
                switch (fields[i].fieldType) {
156
                        case 'C':
157
                                typeClass = String.class;
158

    
159
                                break;
160

    
161
                        case 'N':
162

    
163
                                if (fields[i].decimalCount == 0) {
164
                                        typeClass = Integer.class;
165
                                } else {
166
                                        typeClass = Double.class;
167
                                }
168

    
169
                                break;
170

    
171
                        case 'F':
172
                                typeClass = Double.class;
173

    
174
                                break;
175

    
176
                        case 'L':
177
                                typeClass = Boolean.class;
178

    
179
                                break;
180

    
181
                        case 'D':
182
                                typeClass = Date.class;
183

    
184
                                break;
185

    
186
                        default:
187
                                typeClass = String.class;
188

    
189
                                break;
190
                }
191

    
192
                return typeClass;
193
        }
194

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

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

    
232
                for (int i = 0; i < fields.length; i++) {
233
                        fields[i].fieldDataAddress = tempLength;
234
                        tempLength = tempLength + fields[i].fieldLength;
235
                        tempFieldDescriptors[i] = fields[i];
236
                }
237

    
238
                tempFieldDescriptors[fields.length] = new DbaseField();
239
                tempFieldDescriptors[fields.length].fieldLength = inFieldLength;
240
                tempFieldDescriptors[fields.length].decimalCount = inDecimalCount;
241
                tempFieldDescriptors[fields.length].fieldDataAddress = tempLength;
242

    
243
                // set the field name
244
                String tempFieldName = inFieldName;
245

    
246
                if (tempFieldName == null) {
247
                        tempFieldName = "NoName";
248
                }
249

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

    
259
                tempFieldDescriptors[fields.length].fieldName = tempFieldName;
260

    
261
                // the field type
262
                if ((inFieldType == 'C') || (inFieldType == 'c')) {
263
                        tempFieldDescriptors[fields.length].fieldType = 'C';
264

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

    
275
                        if (inFieldLength > 254) {
276
                                warn("Field Length for " + inFieldName + " set to " +
277
                                        inFieldLength +
278
                                        " Which is longer than 254, not consistent with dbase III");
279
                        }
280

    
281
                        tempFieldDescriptors[fields.length].fieldLength = 8;
282
                } else if ((inFieldType == 'D') || (inFieldType == 'd')) {
283
                        tempFieldDescriptors[fields.length].fieldType = 'D';
284

    
285
                        if (inFieldLength != 8) {
286
                                warn("Field Length for " + inFieldName + " set to " +
287
                                        inFieldLength + " Setting to 8 digets YYYYMMDD");
288
                        }
289

    
290
                        tempFieldDescriptors[fields.length].fieldLength = 8;
291
                } else if ((inFieldType == 'F') || (inFieldType == 'f')) {
292
                        tempFieldDescriptors[fields.length].fieldType = 'F';
293

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

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

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

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

    
325
                        if (inFieldLength != 1) {
326
                                warn("Field Length for " + inFieldName + " set to " +
327
                                        inFieldLength +
328
                                        " Setting to length of 1 for logical fields.");
329
                        }
330

    
331
                        tempFieldDescriptors[fields.length].fieldLength = 1;
332
                } else {
333
                        //throw new DbaseFileException("Undefined field type "+inFieldType + " For column "+inFieldName);
334
                }
335

    
336
                // the length of a record
337
                tempLength = tempLength +
338
                        tempFieldDescriptors[fields.length].fieldLength;
339

    
340
                // set the new fields.
341
                fields = tempFieldDescriptors;
342
                fieldCnt = fields.length;
343
                headerLength = MINIMUM_HEADER + (32 * fields.length);
344
                recordLength = tempLength;
345
        }
346

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

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

    
370
                                        return retCol;
371
                                }
372

    
373
                                tempFieldDescriptors[j] = fields[i];
374
                                tempFieldDescriptors[j].fieldDataAddress = tempLength;
375
                                tempLength += tempFieldDescriptors[j].fieldLength;
376

    
377
                                // only increment j on non-matching fields
378
                                j++;
379
                        } else {
380
                                retCol = i;
381
                        }
382
                }
383

    
384
                // set the new fields.
385
                fields = tempFieldDescriptors;
386
                headerLength = 33 + (32 * fields.length);
387
                recordLength = tempLength;
388

    
389
                return retCol;
390
        }
391

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

    
405
        // Retrieve the length of the field at the given index
406

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

    
418
        // Retrieve the location of the decimal point within the field.
419

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

    
431
        // Retrieve the Name of the field at the given index
432

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

    
444
        // Retrieve the type of field at the given index
445

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

    
457
        /**
458
         * Get the date this file was last updated.
459
         *
460
         * @return The Date last modified.
461
         */
462
        public Date getLastUpdateDate() {
463
                return date;
464
        }
465

    
466
        /**
467
         * Return the number of fields in the records.
468
         *
469
         * @return The number of fields in this table.
470
         */
471
        public int getNumFields() {
472
                if (fields == null)
473
                        return 0;
474
                return fields.length;
475
        }
476

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

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

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

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

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

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

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

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

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

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

    
542
                in.order(ByteOrder.BIG_ENDIAN);
543

    
544
                // skip the reserved bytes in the header.
545
                in.position(in.position() + 20);
546

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

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

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

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

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

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

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

    
570
                        if (tempLength < 0) {
571
                                tempLength = tempLength + 256;
572
                        }
573

    
574
                        fields[i].fieldLength = tempLength;
575

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

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

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

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

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

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

    
620
                // Desde el principio
621
                out.position(0);
622
                
623
                ByteBuffer buffer = ByteBuffer.allocateDirect(headerLength);
624
                buffer.order(ByteOrder.LITTLE_ENDIAN);
625

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

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

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

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

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

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

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

    
652
                if (fields != null)
653
                {
654
                        for (int i = 0; i < fields.length; i++) {
655
                                // write the field name
656
                                for (int j = 0; j < 11; j++) {
657
                                        if (fields[i].fieldName.length() > j) {
658
                                                buffer.put((byte) fields[i].fieldName.charAt(j));
659
                                        } else {
660
                                                buffer.put((byte) 0);
661
                                        }
662
                                }
663
        
664
                                // write the field type
665
                                buffer.put((byte) fields[i].fieldType);
666
        
667
                                //    // write the field data address, offset from the start of the record.
668
                                buffer.putInt(tempOffset);
669
                                tempOffset += fields[i].fieldLength;
670
        
671
                                // write the length of the field.
672
                                buffer.put((byte) fields[i].fieldLength);
673
        
674
                                // write the decimal count.
675
                                buffer.put((byte) fields[i].decimalCount);
676
        
677
                                // write the reserved bytes.
678
                                //for (in j=0; jj<14; j++) out.writeByteLE(0);
679
                                buffer.position(buffer.position() + 14);
680
                        }
681
                }
682
                // write the end of the field definitions marker
683
                buffer.put((byte) 0x0D);
684

    
685
                buffer.position(0);
686

    
687
                int r = buffer.remaining();
688

    
689
                while ((r -= out.write(buffer)) > 0) {
690
                        ; // do nothing
691
                }
692
        }
693

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

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

    
708
                return "DB3 Header\n" + "Date : " + date + "\n" + "Records : " +
709
                recordCnt + "\n" + "Fields : " + fieldCnt + "\n" + fs;
710
        }
711

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

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

    
729
                        if (fieldLen <= 0) {
730
                                fieldLen = 255;
731
                        }
732

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

    
759
                return header;
760
        }
761

    
762
    public static DbaseFileHeaderNIO createDbaseHeader(DataSource ds)
763
    throws IOException {
764
        try {
765
            int[] fieldTypes = new int[ds.getFieldCount()];
766
            int[] fieldLength = new int[fieldTypes.length];
767
            for (int i = 0; i < fieldTypes.length; i++) {
768
                fieldTypes[i] = ds.getFieldType(i);
769
                fieldLength[i] = 100;
770
            }
771
            
772
            return createDbaseHeader(ds.getFieldNames(), fieldTypes, fieldLength);
773
        } catch (DriverException e) {
774
            // TODO Auto-generated catch block
775
            e.printStackTrace();
776
            return null;
777
        }
778
    }
779

    
780
        /**
781
         * DOCUMENT ME!
782
         *
783
         * @param sds DOCUMENT ME!
784
         *
785
         * @return DOCUMENT ME!
786
         *
787
         * @throws IOException DOCUMENT ME!
788
         */
789
        public static DbaseFileHeaderNIO createDbaseHeader(String[] fieldNames, int[] fieldTypes, int[] fieldLength)
790
                throws IOException {
791
                DbaseFileHeaderNIO header = new DbaseFileHeaderNIO();
792

    
793
                        for (int i = 0, ii = fieldNames.length; i < ii; i++) {
794

    
795
                                int type = fieldTypes[i];
796
                                String colName = fieldNames[i];
797

    
798
                                ///int fieldLen = ((DBFDriver)sds.getDriver()).getFieldLength(i);
799
                                int fieldLen = fieldLength[i]; //TODO aqu? el tama?o no es correcto hay que calcularlo, ahora mismo est? puesto a pi??n.
800
                                int decimales = 5;
801

    
802
                                //  if (fieldLen <= 0) {
803
                                //       fieldLen = 255;
804
                                //   }
805
                                //TODO [AZABALA] HE INTENTADO CREAR UN TIPO Types.BIGINT y
806
                                //ha petado (por eso lo a?ado)
807
                                if ((type == Types.DOUBLE) ||
808
                                    (type == Types.FLOAT) || 
809
                                    (type == Types.INTEGER) ||
810
                                    (type == Types.BIGINT))
811
                                    
812
                                                header.addColumn(colName, 'N', Math.min(fieldLen, 10),
813
                                                        decimales);
814
                                if (type == Types.DATE)
815
                                                header.addColumn(colName, 'D', fieldLen, 0);
816
                                if ((type == Types.BIT) ||
817
                        (type == Types.BOOLEAN))
818
                                                header.addColumn(colName, 'L', 1, 0);
819
                                if ((type == Types.VARCHAR) ||
820
                                            (type == Types.CHAR) || 
821
                                            (type == Types.LONGVARCHAR))
822
                                    header.addColumn(colName, 'C', Math.min(254, fieldLen),
823
                                                        0);
824
                                }
825

    
826
                return header;
827
        }
828

    
829

    
830
        /**
831
         * Class for holding the information assicated with a record.
832
         */
833
        class DbaseField {
834
                // Field Name
835
                String fieldName;
836

    
837
                // Field Type (C N L D or M)
838
                char fieldType;
839

    
840
                // Field Data Address offset from the start of the record.
841
                int fieldDataAddress;
842

    
843
                // Length of the data in bytes
844
                int fieldLength;
845

    
846
                // Field decimal count in Binary, indicating where the decimal is
847
                int decimalCount;
848
        }
849

    
850

    
851
        public static DbaseFileHeaderNIO createDbaseHeader(FieldDescription[] fieldsDesc) {
852
                DbaseFileHeaderNIO header = new DbaseFileHeaderNIO();
853

    
854
                for (int i = 0, ii = fieldsDesc.length; i < ii; i++) {
855

    
856
                        int type = fieldsDesc[i].getFieldType();
857
                        String colName = fieldsDesc[i].getFieldName();
858

    
859
                        int fieldLen = fieldsDesc[i].getFieldLength(); //TODO aqu? el tama?o no es correcto hay que calcularlo, ahora mismo est? puesto a pi??n.
860
                        int decimales = fieldsDesc[i].getFieldDecimalCount();
861

    
862
                        if ((type == Types.DOUBLE) ||
863
                            (type == Types.FLOAT) || 
864
                            (type == Types.INTEGER)||
865
                            (type == Types.BIGINT))
866
                            
867
                                        header.addColumn(colName, 'N', Math.min(fieldLen, 10),
868
                                                decimales);
869
                        if (type == Types.DATE)
870
                                        header.addColumn(colName, 'D', fieldLen, 0);
871
                        if ((type == Types.BIT) ||
872
                    (type == Types.BOOLEAN))
873
                                        header.addColumn(colName, 'L', 1, 0);
874
                        if ((type == Types.VARCHAR) ||
875
                                    (type == Types.CHAR) || 
876
                                    (type == Types.LONGVARCHAR))
877
                            header.addColumn(colName, 'C', Math.min(254, fieldLen),
878
                                                0);
879
                        }
880

    
881
        return header;
882

    
883
        }
884
}