Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.file / org.gvsig.fmap.dal.file.dbf / src / main / java / org / gvsig / fmap / dal / store / dbf / utils / DbaseFileHeader.java @ 40559

History | View | Annotate | Download (26.1 KB)

1 40559 jjdelcerro
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24 40435 jjdelcerro
/*
25
 * Created on 16-feb-2004
26
 *
27
 * To change the template for this generated file go to
28
 * Window>Preferences>Java>Code Generation>Code and Comments
29
 */
30
package org.gvsig.fmap.dal.store.dbf.utils;
31
32
import java.io.IOException;
33
import java.io.UnsupportedEncodingException;
34
import java.nio.ByteBuffer;
35
import java.nio.ByteOrder;
36
import java.nio.channels.FileChannel;
37
import java.nio.charset.Charset;
38
import java.util.ArrayList;
39
import java.util.Calendar;
40
import java.util.Date;
41
import java.util.Iterator;
42
import java.util.List;
43
import java.util.Set;
44
import java.util.SortedMap;
45
46
import org.gvsig.fmap.dal.DataTypes;
47
import org.gvsig.fmap.dal.exception.UnsupportedVersionException;
48
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
49
import org.gvsig.fmap.dal.feature.FeatureType;
50
import org.gvsig.fmap.dal.feature.exception.AttributeFeatureTypeNotSuportedException;
51
import org.gvsig.tools.ToolsLocator;
52
import org.gvsig.utils.bigfile.BigByteBuffer2;
53
54
55
56
/**
57
 * Class to represent the header of a Dbase III file. Creation date: (5/15/2001
58
 * 5:15:30 PM)
59
 */
60
public class DbaseFileHeader {
61
    // Constant for the size of a record
62
    private int FILE_DESCRIPTOR_SIZE = 32;
63
64
        // type of the file, must be 03h
65
        private static final byte MAGIC = 0x03;
66
67
        private static final int MINIMUM_HEADER = 33;
68
69
    // type of the file, must be 03h
70
    private int myFileType = 0x03;
71
72
    // Date the file was last updated.
73
    private Date myUpdateDate = new Date();
74
75
    // Number of records in the datafile
76
        private int myNumRecords = 0;
77
78
    // Length of the header structure
79
    private int myHeaderLength;
80
81
    /**
82
     * Length of the records. Set to 1 as the default value as if there is
83
     * not any defined column, at least the deleted status initial byte
84
     * is taken into account.
85
     */
86
    private int myRecordLength = 1;
87
88
    // Number of fields in the record.
89
    private int myNumFields;
90
91
    // collection of header records.
92
    private DbaseFieldDescriptor[] myFieldDescriptions;
93
94
        private byte myLanguageID;
95
96
        private List<String>   encodingSupportedByString = null;
97
98
    /**
99
     * DbaseFileHreader constructor comment.
100
     */
101
    public DbaseFileHeader() {
102
        super();
103
104
        encodingSupportedByString = new ArrayList<String>();
105
                SortedMap<String, Charset> m = Charset.availableCharsets();
106
                Set<String> k = m.keySet();
107
                Iterator<String> it = k.iterator();
108
                while(it.hasNext()) {
109
                        encodingSupportedByString.add(it.next());
110
                }
111
    }
112
113
    /**
114
     * Add a column to this DbaseFileHeader. The type is one of (C N L or D)
115
     * character, number, logical(true/false), or date. The Field length is
116
     * the total length in bytes reserved for this column. The decimal count
117
     * only applies to numbers(N), and floating point values (F), and refers
118
     * to the number of characters to reserve after the decimal point.
119
     *
120
     * @param inFieldName DOCUMENT ME!
121
     * @param inFieldType DOCUMENT ME!
122
     * @param inFieldLength DOCUMENT ME!
123
     * @param inDecimalCount DOCUMENT ME!
124
     * @throws BadFieldDriverException
125
     *
126
     * @throws Exception DOCUMENT ME!
127
     */
128
    public void addColumn(String inFieldName, char inFieldType,
129
        int inFieldLength, int inDecimalCount)
130
                        throws AttributeFeatureTypeNotSuportedException {
131
        if (inFieldLength <= 0) {
132
            inFieldLength = 1;
133
        }
134
135
        if (myFieldDescriptions == null) {
136
            myFieldDescriptions = new DbaseFieldDescriptor[0];
137
        }
138
139
        int tempLength = 1; // the length is used for the offset, and there is a * for deleted as the first byte
140
        DbaseFieldDescriptor[] tempFieldDescriptors = new DbaseFieldDescriptor[myFieldDescriptions.length +
141
            1];
142
143
        for (int i = 0; i < myFieldDescriptions.length; i++) {
144
            myFieldDescriptions[i].myFieldDataAddress = tempLength;
145
            tempLength = tempLength + myFieldDescriptions[i].myFieldLength;
146
            tempFieldDescriptors[i] = myFieldDescriptions[i];
147
        }
148
149
        tempFieldDescriptors[myFieldDescriptions.length] = new DbaseFieldDescriptor();
150
        tempFieldDescriptors[myFieldDescriptions.length].myFieldLength = inFieldLength;
151
        tempFieldDescriptors[myFieldDescriptions.length].myDecimalCount = inDecimalCount;
152
        tempFieldDescriptors[myFieldDescriptions.length].myFieldDataAddress = tempLength;
153
154
        // set the field name
155
        String tempFieldName = inFieldName;
156
157
        if (tempFieldName == null) {
158
            tempFieldName = "NoName";
159
        }
160
161
        if (tempFieldName.length() > 11) {
162
            tempFieldName = tempFieldName.substring(0, 11);
163
            warn("FieldName " + inFieldName +
164
                " is longer than 11 characters, truncating to " +
165
                tempFieldName);
166
        }
167
168
        tempFieldDescriptors[myFieldDescriptions.length].myFieldName = tempFieldName;
169
        tempFieldDescriptors[myFieldDescriptions.length].myFieldName_trim = tempFieldName
170
                                .trim();
171
172
        // the field type
173
        if ((inFieldType == 'C') || (inFieldType == 'c')) {
174
            tempFieldDescriptors[myFieldDescriptions.length].myFieldType = 'C';
175
176
            if (inFieldLength > 254) {
177
                warn("Field Length for " + inFieldName + " set to " +
178
                    inFieldLength +
179
                    " Which is longer than 254, not consistent with dbase III");
180
            }
181
        } else if ((inFieldType == 'S') || (inFieldType == 's')) {
182
            tempFieldDescriptors[myFieldDescriptions.length].myFieldType = 'C';
183
            warn("Field type for " + inFieldName +
184
                " set to S which is flat out wrong people!, I am setting this to C, in the hopes you meant character.");
185
186
            if (inFieldLength > 254) {
187
                warn("Field Length for " + inFieldName + " set to " +
188
                    inFieldLength +
189
                    " Which is longer than 254, not consistent with dbase III");
190
            }
191
192
            tempFieldDescriptors[myFieldDescriptions.length].myFieldLength = 8;
193
        } else if ((inFieldType == 'D') || (inFieldType == 'd')) {
194
            tempFieldDescriptors[myFieldDescriptions.length].myFieldType = 'D';
195
196
            if (inFieldLength != 8) {
197
                warn("Field Length for " + inFieldName + " set to " +
198
                    inFieldLength + " Setting to 8 digets YYYYMMDD");
199
            }
200
201
            tempFieldDescriptors[myFieldDescriptions.length].myFieldLength = 8;
202
        } else if ((inFieldType == 'F') || (inFieldType == 'f')) {
203
            tempFieldDescriptors[myFieldDescriptions.length].myFieldType = 'F';
204
205
            if (inFieldLength > 20) {
206
                warn("Field Length for " + inFieldName + " set to " +
207
                    inFieldLength +
208
                    " Preserving length, but should be set to Max of 20 not valid for dbase IV, and UP specification, not present in dbaseIII.");
209
            }
210
        } else if ((inFieldType == 'N') || (inFieldType == 'n')) {
211
            tempFieldDescriptors[myFieldDescriptions.length].myFieldType = 'N';
212
213
            if (inFieldLength > 18) {
214
                warn("Field Length for " + inFieldName + " set to " +
215
                    inFieldLength +
216
                    " Preserving length, but should be set to Max of 18 for dbase III specification.");
217
            }
218
219
            if (inDecimalCount < 0) {
220
                warn("Field Decimal Position for " + inFieldName + " set to " +
221
                    inDecimalCount +
222
                    " Setting to 0 no decimal data will be saved.");
223
                tempFieldDescriptors[myFieldDescriptions.length].myDecimalCount = 0;
224
            }
225
//
226
//            if (inDecimalCount > (inFieldLength - 1)) {
227
//                warn("Field Decimal Position for " + inFieldName + " set to " +
228
//                    inDecimalCount + " Setting to " + (inFieldLength - 1) +
229
//                    " no non decimal data will be saved.");
230
//                tempFieldDescriptors[myFieldDescriptions.length].myDecimalCount = inFieldLength -
231
//                    1;
232
//            }
233
        } else if ((inFieldType == 'L') || (inFieldType == 'l')) {
234
            tempFieldDescriptors[myFieldDescriptions.length].myFieldType = 'L';
235
236
            if (inFieldLength != 1) {
237
                warn("Field Length for " + inFieldName + " set to " +
238
                    inFieldLength +
239
                    " Setting to length of 1 for logical fields.");
240
            }
241
242
            tempFieldDescriptors[myFieldDescriptions.length].myFieldLength = 1;
243
        } else {
244
            throw new AttributeFeatureTypeNotSuportedException(tempFieldName,
245
                                        inFieldType, ToolsLocator.getDataTypesManager().getTypeName(inFieldType), "DBF");
246
        }
247
248
        // the length of a record
249
        tempLength = tempLength +
250
            tempFieldDescriptors[myFieldDescriptions.length].myFieldLength;
251
252
        // set the new fields.
253
        myFieldDescriptions = tempFieldDescriptors;
254
        myHeaderLength = 33 + (32 * myFieldDescriptions.length);
255
        myNumFields = myFieldDescriptions.length;
256
        myRecordLength = tempLength;
257
    }
258
259
    /**
260
     * Remove a column from this DbaseFileHeader.
261
     *
262
     * @param inFieldName DOCUMENT ME!
263
     *
264
     * @return index of the removed column, -1 if no found
265
     */
266
    public int removeColumn(String inFieldName) {
267
        int retCol = -1;
268
        int tempLength = 1;
269
        DbaseFieldDescriptor[] tempFieldDescriptors = new DbaseFieldDescriptor[myFieldDescriptions.length -
270
            1];
271
272
        for (int i = 0, j = 0; i < myFieldDescriptions.length; i++) {
273
            if (!inFieldName.equalsIgnoreCase(
274
                        myFieldDescriptions[i].myFieldName.trim())) {
275
                // if this is the last field and we still haven't found the
276
                // named field
277
                if ((i == j) && (i == (myFieldDescriptions.length - 1))) {
278
                    System.err.println("Could not find a field named '" +
279
                        inFieldName + "' for removal");
280
281
                    return retCol;
282
                }
283
284
                tempFieldDescriptors[j] = myFieldDescriptions[i];
285
                tempFieldDescriptors[j].myFieldDataAddress = tempLength;
286
                tempLength += tempFieldDescriptors[j].myFieldLength;
287
288
                // only increment j on non-matching fields
289
                j++;
290
            } else {
291
                retCol = i;
292
            }
293
        }
294
295
        // set the new fields.
296
        myFieldDescriptions = tempFieldDescriptors;
297
        myHeaderLength = 33 + (32 * myFieldDescriptions.length);
298
        myNumFields = myFieldDescriptions.length;
299
        myRecordLength = tempLength;
300
301
        return retCol;
302
    }
303
304
    /**
305
     * DOCUMENT ME!
306
     *
307
     * @param inWarn DOCUMENT ME!
308
     */
309
    private void warn(String inWarn) {
310
        //TODO Descomentar esto cuando tenga la clase warning support
311
        //            warnings.warn(inWarn);
312
    }
313
314
    /**
315
     * Return the Field Descriptor for the given field.
316
     *
317
     * @param inIndex DOCUMENT ME!
318
     *
319
     * @return DOCUMENT ME!
320
     */
321
    public DbaseFieldDescriptor getFieldDescription(int inIndex) {
322
        return myFieldDescriptions[inIndex];
323
    }
324
325
    // Retrieve the length of the field at the given index
326
    public int getFieldLength(int inIndex) {
327
        return myFieldDescriptions[inIndex].myFieldLength;
328
    }
329
330
    // Retrieve the location of the decimal point within the field.
331
    public int getFieldDecimalCount(int inIndex) {
332
        return myFieldDescriptions[inIndex].myDecimalCount;
333
    }
334
335
    // Retrieve the Name of the field at the given index
336
    public String getFieldName(int inIndex) {
337
        return myFieldDescriptions[inIndex].myFieldName;
338
    }
339
340
    public int getFieldIndex(String name) {
341
                for (int i = 0; i < myFieldDescriptions.length; i++) {
342
                        if (myFieldDescriptions[i].myFieldName_trim
343
                                        .equalsIgnoreCase(name)) {
344
                                return i;
345
                        }
346
                }
347
                return -1;
348
        }
349
350
    // Retrieve the type of field at the given index
351
    public char getFieldType(int inIndex) {
352
        return myFieldDescriptions[inIndex].myFieldType;
353
    }
354
355
    /**
356
     * Return the date this file was last updated.
357
     *
358
     * @return DOCUMENT ME!
359
     */
360
    public Date getLastUpdateDate() {
361
        return myUpdateDate;
362
    }
363
364
     /**
365
     * Return the number of fields in the records.
366
     *
367
     * @return DOCUMENT ME!
368
     */
369
    public int getNumFields() {
370
        return myNumFields;
371
    }
372
373
    /**
374
     * Return the number of records in the file
375
     *
376
     * @return DOCUMENT ME!
377
     */
378
    public int getNumRecords() {
379
        return myNumRecords;
380
    }
381
382
    /**
383
     * Return the length of the records in bytes.
384
     *
385
     * @return DOCUMENT ME!
386
     */
387
    public int getRecordLength() {
388
        return myRecordLength;
389
    }
390
391
    /**
392
     * Return the length of the header
393
     *
394
     * @return DOCUMENT ME!
395
     */
396
    public int getHeaderLength() {
397
        return myHeaderLength;
398
    }
399
400
        /**
401
         * Read the header data from the DBF file.
402
         *
403
         * @param in
404
         *            DOCUMENT ME!
405
         * @throws UnsupportedVersionException
406
         * @throws UnsupportedEncodingException
407
         *
408
         * @throws IOException
409
         *             DOCUMENT ME!
410
         */
411
    public void readHeader(BigByteBuffer2 in, String charsName)
412
                        throws UnsupportedVersionException, UnsupportedEncodingException {
413
        // type of file.
414
        myFileType = in.get();
415
416
        if (myFileType != 0x03) {
417
            throw new UnsupportedVersionException("DBF", Integer
418
                                        .toHexString(myFileType));
419
        }
420
421
        // parse the update date information.
422
        int tempUpdateYear = in.get();
423
        int tempUpdateMonth = in.get();
424
        int tempUpdateDay = in.get();
425
        tempUpdateYear = tempUpdateYear + 1900;
426
427
        Calendar c = Calendar.getInstance();
428
        c.set(Calendar.YEAR, tempUpdateYear);
429
        c.set(Calendar.MONTH, tempUpdateMonth - 1);
430
        c.set(Calendar.DATE, tempUpdateDay);
431
        myUpdateDate = c.getTime();
432
433
        // read the number of records.
434
        in.order(ByteOrder.LITTLE_ENDIAN);
435
        myNumRecords = in.getInt();
436
437
        // read the length of the header structure.
438
        myHeaderLength = in.getShort();
439
440
        // read the length of a record
441
        myRecordLength = in.getShort(); //posicon 0h
442
443
        in.order(ByteOrder.BIG_ENDIAN);
444
445
        // skip the reserved bytes in the header.
446
        // in.position(in.position() + 20);
447
448
        // Leemos el byte de language
449
        in.position(29);
450
        myLanguageID = in.get();
451
        if (charsName == null) {
452
                charsName = getCharsetName();
453
                charsName = mappingEncoding(charsName);
454
                }
455
456
457
        // Posicionamos para empezar a leer los campos.
458
        in.position(32);
459
460
        // calculate the number of Fields in the header
461
        myNumFields = (myHeaderLength - FILE_DESCRIPTOR_SIZE - 1) / FILE_DESCRIPTOR_SIZE;
462
463
        // read all of the header records
464
        myFieldDescriptions = new DbaseFieldDescriptor[myNumFields];
465
        int fieldOffset = 0;
466
467
        for (int i = 0; i < myNumFields; i++) {
468
            myFieldDescriptions[i] = new DbaseFieldDescriptor();
469
470
            // read the field name
471
            byte[] buffer = new byte[11];
472
            in.get(buffer);
473
            if (charsName != null) {
474
                                myFieldDescriptions[i].myFieldName = new String(buffer,
475
                                                charsName);
476
                        } else {
477
                                myFieldDescriptions[i].myFieldName = new String(buffer);
478
                        }
479
            myFieldDescriptions[i].myFieldName_trim = myFieldDescriptions[i].myFieldName
480
                                        .trim();
481
482
            // read the field type
483
            myFieldDescriptions[i].myFieldType = (char) in.get();
484
485
            // read the field data address, offset from the start of the record.
486
            myFieldDescriptions[i].myFieldDataAddress = in.getInt();
487
488
            // read the field length in bytes
489
            int tempLength = in.get();
490
491
            if (tempLength < 0) {
492
                tempLength = tempLength + 256;
493
            }
494
495
            myFieldDescriptions[i].myFieldLength = tempLength;
496
497
            // read the field decimal count in bytes
498
            myFieldDescriptions[i].myDecimalCount = in.get();
499
500
            // NUEVO: Calculamos los offsets aqu? para no
501
            // tener que recalcular cada vez que nos piden
502
            // algo.
503
            myFieldDescriptions[i].myFieldDataAddress = fieldOffset;
504
            fieldOffset += tempLength;
505
            // Fin NUEVO
506
            // read the reserved bytes.
507
            in.position(in.position() + 14);
508
        }
509
510
        // Last byte is a marker for the end of the field definitions.
511
        in.get();
512
    }
513
514
    /**
515
     * Set the number of records in the file
516
     *
517
     * @param inNumRecords DOCUMENT ME!
518
     */
519
    public void setNumRecords(int inNumRecords) {
520
        myNumRecords = inNumRecords;
521
    }
522
523
    /*
524
     * Write the header data to the DBF file.
525
     *
526
     * @param out DOCUMENT ME!
527
     *
528
     * @throws Exception DOCUMENT ME!
529
     *
530
           public void writeHeader(LEDataOutputStream out) throws Exception {
531
               // write the output file type.
532
               out.writeByte(myFileType);
533
               // write the date stuff
534
               Calendar c = Calendar.getInstance();
535
               c.setTime(new Date());
536
               out.writeByte(c.get(Calendar.YEAR) - 1900);
537
               out.writeByte(c.get(Calendar.MONTH) + 1);
538
               out.writeByte(c.get(Calendar.DAY_OF_MONTH));
539
               // write the number of records in the datafile.
540
               out.writeInt(myNumRecords);
541
               // write the length of the header structure.
542
               out.writeShort(myHeaderLength);
543
               // write the length of a record
544
               out.writeShort(myRecordLength);
545
               // write the reserved bytes in the header
546
               for (int i = 0; i < 20; i++)
547
                   out.writeByte(0);
548
               // write all of the header records
549
               int tempOffset = 0;
550
               for (int i = 0; i < myFieldDescriptions.length; i++) {
551
                   // write the field name
552
                   for (int j = 0; j < 11; j++) {
553
                       if (myFieldDescriptions[i].myFieldName.length() > j) {
554
                           out.writeByte((int) myFieldDescriptions[i].myFieldName.charAt(
555
                                   j));
556
                       } else {
557
                           out.writeByte(0);
558
                       }
559
                   }
560
                   // write the field type
561
                   out.writeByte(myFieldDescriptions[i].myFieldType);
562
                   // write the field data address, offset from the start of the record.
563
                   out.writeInt(tempOffset);
564
                   tempOffset += myFieldDescriptions[i].myFieldLength;
565
                   // write the length of the field.
566
                   out.writeByte(myFieldDescriptions[i].myFieldLength);
567
                   // write the decimal count.
568
                   out.writeByte(myFieldDescriptions[i].myDecimalCount);
569
                   // write the reserved bytes.
570
                   for (int j = 0; j < 14; j++)
571
                       out.writeByte(0);
572
               }
573
               // write the end of the field definitions marker
574
               out.writeByte(0x0D);
575
           }
576
     */
577
578
    /**
579
     * Class for holding the information assicated with a record.
580
     */
581
    class DbaseFieldDescriptor {
582
        // Field Name
583
        String myFieldName;
584
585
        String myFieldName_trim;
586
587
        // Field Type (C N L D F or M)
588
        char myFieldType;
589
590
        // Field Data Address offset from the start of the record.
591
        int myFieldDataAddress;
592
593
        // Length of the data in bytes
594
        int myFieldLength;
595
596
        // Field decimal count in Binary, indicating where the decimal is
597
        int myDecimalCount;
598
    }
599
600
        public byte getLanguageID() {
601
                return myLanguageID;
602
        }
603
604
605
606
        public static DbaseFileHeader createDbaseHeader(FeatureType featureType)
607
                        throws AttributeFeatureTypeNotSuportedException {
608
                DbaseFileHeader header = new DbaseFileHeader();
609
                Iterator iterator=featureType.iterator();
610
                // TODO header.myLanguageID = langId;
611
                while (iterator.hasNext()) {
612
                        FeatureAttributeDescriptor descriptor = (FeatureAttributeDescriptor) iterator.next();
613
614
615
                        int type = descriptor.getType();
616
                        String colName = descriptor.getName();
617
618
                        int fieldLen = descriptor.getSize(); // TODO aqu? el
619
                        // tama?o no es
620
                        // correcto hay que
621
                        // calcularlo, ahora
622
                        // mismo est? puesto
623
                        // a pi??n.
624
                        int decimales = descriptor.getPrecision();
625
                        if ((type==DataTypes.DOUBLE || type==DataTypes.FLOAT) && decimales==0){
626
                                decimales=1;
627
                        }
628
629
                        if (DataTypes.DOUBLE == type || DataTypes.FLOAT == type
630
                                        || DataTypes.INT == type || DataTypes.LONG == type) {
631
                                header.addColumn(colName, 'N', Math.min(fieldLen, 18),
632
                                                decimales);
633
                        } else if (DataTypes.DATE == type) {
634
                                header.addColumn(colName, 'D', fieldLen, 0);
635
                        } else if (DataTypes.BOOLEAN == type) {
636
                                header.addColumn(colName, 'L', 1, 0);
637
                        } else if (DataTypes.STRING == type) {
638
                                header.addColumn(colName, 'C', Math.min(254, fieldLen), 0);
639
                        }
640
641
642
                }
643
                return header;
644
        }
645
        /**
646
         * Write the header data to the DBF file.
647
         *
648
         * @param out
649
         *            A channel to write to. If you have an OutputStream you can
650
         *            obtain the correct channel by using
651
         *            java.nio.Channels.newChannel(OutputStream out).
652
         *
653
         * @throws IOException
654
         *             If errors occur.
655
         */
656
        public void writeHeader(FileChannel out) throws IOException {
657
                // take care of the annoying case where no records have been added...
658
                if (myHeaderLength <= 0) {
659
                        myHeaderLength = MINIMUM_HEADER;
660
                }
661
662
                // Desde el principio
663
                out.position(0);
664
665
                ByteBuffer buffer = ByteBuffer.allocateDirect(myHeaderLength);
666
                buffer.order(ByteOrder.LITTLE_ENDIAN);
667
668
                // write the output file type.
669
                buffer.put(MAGIC);
670
671
                // write the date stuff
672
                Calendar c = Calendar.getInstance();
673
                c.setTime(new Date());
674
                buffer.put((byte) (c.get(Calendar.YEAR) % 100));
675
                buffer.put((byte) (c.get(Calendar.MONTH) + 1));
676
                buffer.put((byte) (c.get(Calendar.DAY_OF_MONTH)));
677
678
                // write the number of records in the datafile.
679
                buffer.putInt(myNumRecords);
680
681
                // write the length of the header structure.
682
                buffer.putShort((short) myHeaderLength);
683
684
                // write the length of a record
685
                buffer.putShort((short) myRecordLength);
686
687
                // // write the reserved bytes in the header
688
                // for (int i=0; i<20; i++) out.writeByteLE(0);
689
                buffer.position(buffer.position() + 20);
690
691
                // write all of the header records
692
                int tempOffset = 0;
693
694
                if (myFieldDescriptions != null) {
695
                        for (int i = 0; i < myFieldDescriptions.length; i++) {
696
                                // write the field name
697
                                for (int j = 0; j < 11; j++) {
698
                                        if (myFieldDescriptions[i].myFieldName.length() > j) {
699
                                                buffer.put((byte) myFieldDescriptions[i].myFieldName.charAt(j));
700
                                        } else {
701
                                                buffer.put((byte) 0);
702
                                        }
703
                                }
704
705
                                // write the field type
706
                                buffer.put((byte) myFieldDescriptions[i].myFieldType);
707
708
                                // // write the field data address, offset from the start of the
709
                                // record.
710
                                buffer.putInt(tempOffset);
711
                                tempOffset += myFieldDescriptions[i].myFieldLength;
712
713
                                // write the length of the field.
714
                                buffer.put((byte) myFieldDescriptions[i].myFieldLength);
715
716
                                // write the decimal count.
717
                                buffer.put((byte) myFieldDescriptions[i].myDecimalCount);
718
719
                                // write the reserved bytes.
720
                                // for (in j=0; jj<14; j++) out.writeByteLE(0);
721
                                buffer.position(buffer.position() + 14);
722
                        }
723
                }
724
                // write the end of the field definitions marker
725
                buffer.put((byte) 0x0D);
726
727
                buffer.position(0);
728
729
                int r = buffer.remaining();
730
731
                while ((r -= out.write(buffer)) > 0) {
732
                        ; // do nothing
733
                }
734
        }
735
736
        /**
737
         *         01h                DOS USA        code page 437
738
                02h                DOS Multilingual code page 850
739
                03h                Windows ANSI code page 1252
740
                04h                Standard Macintosh
741
                64h                EE MS-DOS code page 852
742
                65h                Nordic MS-DOS code page 865
743
                66h                Russian MS-DOS code page 866
744
                67h                Icelandic MS-DOS
745
                68h                Kamenicky (Czech) MS-DOS
746
                69h                Mazovia (Polish) MS-DOS
747
                6Ah                Greek MS-DOS (437G)
748
                6Bh                Turkish MS-DOS
749
                96h                Russian Macintosh
750
                97h                Eastern European Macintosh
751
                98h                Greek Macintosh
752
                C8h                Windows EE        code page 1250
753
                C9h                Russian Windows
754
                CAh                Turkish Windows
755
                CBh                Greek Windows
756
         * @return
757
         */
758
        public String getCharsetName() {
759
                switch (getLanguageID()) {
760
                case 0x01:
761
                        return "US-ASCII";
762
                case 0x02:
763
                        return "ISO-8859-1";
764
                case 0x03:
765
                        return "windows-1252";
766
                case 0x04:
767
                        return "mac";
768
                case 0x64:
769
                        return "ISO-8859-1";
770
                case 0x65:
771
                        return "ISO-8859-1";
772
                case 0x66:
773
                        return "ISO-8859-1";
774
                case 0x67:
775
                        return "ISO-8859-1";
776
                case 0x68:
777
                        return "greek";
778
                case 0x69:
779
                        return "ISO-8859-1";
780
                case 0x6A:
781
                        return "greek";
782
                case 0x6B:
783
                        return "ISO-8859-1";
784
785
                default:
786
                        return "ISO-8859-1";
787
                }
788
        }
789
790
        public String mappingEncoding(String dbfEnconding) {
791
                if(encodingSupportedByString.contains(dbfEnconding))
792
                        return dbfEnconding;
793
                else
794
                        return "UTF-8";
795
        }
796
797
}