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
/**
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
/*
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
}