Revision 44669 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/DbaseFileWriter.java

View differences:

DbaseFileWriter.java
24 24
package org.gvsig.fmap.dal.store.dbf.utils;
25 25

  
26 26
import java.io.IOException;
27
import java.math.BigDecimal;
27 28
import java.nio.Buffer;
28 29
import java.nio.BufferOverflowException;
29 30
import java.nio.ByteBuffer;
30 31
import java.nio.MappedByteBuffer;
31 32
import java.nio.channels.FileChannel;
32 33
import java.nio.charset.Charset;
33
import java.text.FieldPosition;
34
import java.text.NumberFormat;
35
import java.util.Arrays;
36
import java.util.Calendar;
37 34
import java.util.Date;
38 35
import java.util.Iterator;
39
import java.util.Locale;
40 36
import org.apache.commons.lang3.StringUtils;
41 37

  
42 38
import org.gvsig.fmap.dal.DataTypes;
......
60 56
 * w.close();
61 57
 * </PRE></CODE> You must supply the <CODE>moreRecords</CODE> and
62 58
 * <CODE>getMyRecord()</CODE> logic...
63
 * 
59
 *
64 60
 * @author Ian Schneider
65 61
 */
66 62
public class DbaseFileWriter {
67 63

  
68
    private DbaseFileHeader header;
69
    private DbaseFileWriter.FieldFormatter formatter =
70
        new DbaseFileWriter.FieldFormatter();
71
    FileChannel channel;
64
    private final DbaseFileHeader header;
65
    private FieldFormatter formatter = new FieldFormatter();
66
    private FileChannel channel;
72 67
    private ByteBuffer buffer;
73 68
    private boolean headDrity = false;
74 69
    private ByteBuffer blank;
75 70
    private int blankSize;
76
    
77
    //private Charset charset = Charset.forName("ISO-8859-1");
71

  
78 72
    private Charset charset;
79 73

  
80 74
    /**
81 75
     * Create a DbaseFileWriter using the specified header and writing to the
82 76
     * given channel.
83
     * 
84
     * @param header
85
     *            The DbaseFileHeader to write.
86
     * @param out
87
     *            The Channel to write to.
88
     * 
89
     * 
90
     * @throws InitializeWriterException
91
     * @throws IOException
92
     *             If errors occur while initializing.
77
     *
78
     * @param header The DbaseFileHeader to write.
79
     * @param out The Channel to write to.
80
     * @param isNew
81
     * @throws org.gvsig.fmap.dal.exception.InitializeException
82
     *
83
     *
93 84
     */
94 85
    public DbaseFileWriter(DbaseFileHeader header, FileChannel out,
95
        boolean isNew) throws InitializeException {
86
            boolean isNew) throws InitializeException {
96 87
        this.header = header;
97 88
        this.channel = out;
98 89
        this.headDrity = isNew;
99 90
        this.setCharset(Charset.forName(header.mappingEncoding(header.getCharsetName())));
100
        
91

  
101 92
        init();
102 93
    }
103 94

  
......
113 104
    }
114 105

  
115 106
    private void write() throws WriteException {
116
        ((Buffer)buffer).position(0);
107
        ((Buffer) buffer).position(0);
117 108
        int r = buffer.remaining();
118 109
        try {
119 110
            while ((r -= channel.write(buffer)) > 0) {
120
                ; // do nothing
111
                // do nothing
121 112
            }
122 113
        } catch (IOException e) {
123 114
            throw new WriteException("DBF Writer", e);
......
127 118
    private void writeHeader() throws WriteException {
128 119
        try {
129 120
            channel.position(0);
130
            header.writeHeader(channel);
121
            header.write(channel);
131 122
        } catch (IOException e) {
132 123
            throw new WriteException("DBF Writer", e);
133 124
        }
......
135 126

  
136 127
    /**
137 128
     * Write a single dbase record.
138
     * 
139
     * @param record
140
     *            The entries to write.
129
     *
130
     * @param feature
141 131
     * @throws UnsupportedEncodingException
142 132
     * @throws WriteException
143 133
     */
144 134
    public void append(Feature feature) throws WriteException,
145
        UnsupportedEncodingException {
135
            UnsupportedEncodingException {
146 136
        this.fillBuffer(feature);
147 137
        try {
148 138
            this.moveToEOF();
......
156 146
    }
157 147

  
158 148
    private void fillBuffer(Feature feature)
159
        throws UnsupportedEncodingException, WriteException {
149
            throws UnsupportedEncodingException, WriteException {
160 150
        FeatureType featureType = feature.getType();
161 151
        try {
162
            ((Buffer)buffer).position(0);
152
            ((Buffer) buffer).position(0);
163 153

  
164 154
            // put the 'not-deleted' marker
165 155
            buffer.put((byte) ' ');
166 156

  
167 157
            @SuppressWarnings("unchecked")
168
            Iterator<FeatureAttributeDescriptor> iterator =
169
                featureType.iterator();
170
            
158
            Iterator<FeatureAttributeDescriptor> iterator
159
                    = featureType.iterator();
160

  
171 161
            while (iterator.hasNext()) {
172 162
                FeatureAttributeDescriptor fad = iterator.next();
173 163
                if (fad.isComputed()) {
174 164
                    continue;
175 165
                }
176
                
166

  
177 167
                if (fad.getName().length() > DbaseFile.MAX_FIELD_NAME_LENGTH) {
178 168
                    throw new FieldNameTooLongException(
179
                        "DBF file", fad.getName());
169
                            "DBF file", fad.getName());
180 170
                }
181
                
171

  
182 172
                int type = fad.getType();
183 173
                if (type == DataTypes.GEOMETRY) {
184 174
                    continue;
......
189 179
            throw new WriteException("DbaseFileWriter", e);
190 180
        }
191 181
    }
192
    
182

  
193 183
    private void moveToEOF() throws IOException {
194 184
        this.moveTo(this.header.getNumRecords());
195 185
    }
......
200 190
        // "DbaseFileWriterNIO: channel is not a FileChannel. Cannot position properly");
201 191
        // }
202 192

  
203
        long newPos =
204
            header.getHeaderLength() + numReg * header.getRecordLength();
193
        long newPos
194
                = header.getHeaderLength() + numReg * header.getRecordLength();
205 195
        if (this.channel.position() != newPos) {
206 196
            this.channel.position(newPos);
207 197
        }
......
209 199

  
210 200
    /**
211 201
     * Write a single dbase record. Useful to update a dbf.
212
     * 
213
     * @param record
214
     *            The entries to write.
202
     *
203
     * @param feature
204
     * @param numReg
215 205
     * @throws WriteException
216 206
     * @throws UnsupportedEncodingException
217 207
     */
218 208
    public void update(Feature feature, long numReg) throws WriteException,
219
        UnsupportedEncodingException {
209
            UnsupportedEncodingException {
220 210
        this.fillBuffer(feature);
221 211

  
222 212
        try {
......
228 218
        write();
229 219
    }
230 220

  
231
    private String fieldString(FeatureAttributeDescriptor attr, Feature feature) throws java.io.UnsupportedEncodingException {
221
    private void encodeField(FeatureAttributeDescriptor attr, Feature feature) throws java.io.UnsupportedEncodingException, UnsupportedEncodingException {
222
        DbaseFieldDescriptor descriptor = this.header.getFieldDescription(attr.getName());
223

  
232 224
        int type = attr.getType();
233
        int dbfFieldIndex = this.header.getFieldIndex(attr.getName());
234
        final int fieldLen = header.getFieldLength(dbfFieldIndex);
235
        String fieldString = "";
236
        //
237
        // https://www.dbase.com/Knowledgebase/INT/db7_file_fmt.htm
238
        //
225
        final int fieldLen = descriptor.getSize();
226
        String fieldString;
227

  
228
//        if( buffer.position()!=descriptor.getOffsetInRecord() ) {
229
//            throw new RuntimeException("Encoding field '"+descriptor.getName()+"' found an incorrect offset.");
230
//        }
231
        if( feature.isNull(attr.getIndex()) ) {
232
            safeEncode(" ", fieldLen, false);
233
            return;
234
        }
239 235
        if (DataTypes.BOOLEAN == type) {
240 236
            boolean b = feature.getBoolean(attr.getIndex());
241
            if (b) {
242
                fieldString = "T";
243
            } else {
244
                fieldString = "F";
245
            }
246
        } else
247
            if (DataTypes.BYTE == type) {
248
                fieldString = String.valueOf(feature.getByte(attr.getIndex()));
249
            } else
250
                if (DataTypes.DATE == type) {
251
                    Date date = feature.getDate(attr.getIndex());
252
                    fieldString = formatter.getFieldString(date);
253
                } else
254
                    if (DataTypes.DOUBLE == type) {
255
                        double d = feature.getDouble(attr.getIndex());
256
                        fieldString =
257
                            formatter.getFieldString(fieldLen,
258
                                header.getFieldDecimalCount(dbfFieldIndex), d);
259
                    } else
260
                        if (DataTypes.FLOAT == type) {
261
                            float f = feature.getFloat(attr.getIndex());
262
                            fieldString =
263
                                formatter.getFieldString(fieldLen,
264
                                    header.getFieldDecimalCount(dbfFieldIndex),
265
                                    f);
266
                        } else
267
                            if (DataTypes.INT == type) {
268
                                int integer = feature.getInt(attr.getIndex());
269
                                fieldString =
270
                                    formatter.getFieldString(fieldLen, header
271
                                        .getFieldDecimalCount(dbfFieldIndex),
272
                                        integer);
273
                            } else
274
                                if (DataTypes.LONG == type) {
275
                                    long l = feature.getLong(attr.getIndex());
276
                                    fieldString =
277
                                        formatter
278
                                            .getFieldString(
279
                                                fieldLen,
280
                                                header
281
                                                    .getFieldDecimalCount(dbfFieldIndex),
282
                                                l);
283
                                } else
284
                                    if (DataTypes.STRING == type) {
285
                                        String s =
286
                                            feature.getString(attr.getIndex());
287
                                        return s;
288
                                    }
289
        return fieldString;
237
            safeEncode(b? "T":"F", 1, true);
290 238

  
291
    }
239
        } else if (DataTypes.TIME == type) {
240
            Date date = feature.getDate(attr.getIndex());
241
            fieldString = formatter.formatTime(date);
242
            safeEncode(fieldString, fieldLen, false);
292 243

  
293
    private void encodeField(FeatureAttributeDescriptor attr, Feature feature) throws java.io.UnsupportedEncodingException, UnsupportedEncodingException {
294
        int type = attr.getType();
295
        int dbfFieldIndex = this.header.getFieldIndex(attr.getName());
296
        final int fieldLen = header.getFieldLength(dbfFieldIndex);
297
        String fieldString = "";
298
        
299
        if( DataTypes.BOOLEAN == type ) {
300
            boolean b = feature.getBoolean(attr.getIndex());
301
            if( b ) {
302
                safeEncode("T", 1, true);
303
            } else {
304
                safeEncode("F", 1, true);
305
            }
306
        
307
        } else if( DataTypes.BYTE == type ) {
308
            fieldString = String.valueOf(feature.getByte(attr.getIndex()));
309
            safeEncode(fieldString, 8, false);
310
        
311
        } else if( DataTypes.DATE == type ) {
244
        } else if (DataTypes.TIMESTAMP == type) {
312 245
            Date date = feature.getDate(attr.getIndex());
313
            fieldString = formatter.getFieldString(date);
314
            safeEncode(fieldString, 8, false);
315
        
316
        } else if( DataTypes.DOUBLE == type ) {
317
            double d = feature.getDouble(attr.getIndex());
318
            fieldString  = formatter.getFieldString(
319
                fieldLen, header.getFieldDecimalCount(dbfFieldIndex), d
320
            );
246
            fieldString = formatter.formatTimestamp(date);
321 247
            safeEncode(fieldString, fieldLen, false);
322
        
323
        } else if( DataTypes.FLOAT == type ) {
324
            float f = feature.getFloat(attr.getIndex());
325
            fieldString = formatter.getFieldString(
326
                fieldLen, header.getFieldDecimalCount(dbfFieldIndex), f
327
            );
248

  
249
        } else if (DataTypes.DATE == type) {
250
            Date date = feature.getDate(attr.getIndex());
251
            fieldString = formatter.formatDate(date);
328 252
            safeEncode(fieldString, fieldLen, false);
329
        
330
        } else if( DataTypes.INT == type ) {
331
            int integer = feature.getInt(attr.getIndex());
332
            fieldString = formatter.getFieldString(
333
                fieldLen, header.getFieldDecimalCount(dbfFieldIndex), integer
334
            );
253

  
254
        } else if (DataTypes.DECIMAL == type) {
255
            BigDecimal n = feature.getDecimal(attr.getIndex());
256
            fieldString = formatter.format(n, fieldLen);
335 257
            safeEncode(fieldString, fieldLen, false);
336
        
337
        } else if( DataTypes.LONG == type ) {
258

  
259
        } else if (DataTypes.DOUBLE == type) {
260
            double n = feature.getDouble(attr.getIndex());
261
            fieldString = formatter.format(n, fieldLen, descriptor.getScale());
262
            safeEncode(fieldString, fieldLen, false);
263

  
264
        } else if (DataTypes.FLOAT == type) {
265
            float n = feature.getFloat(attr.getIndex());
266
            fieldString = formatter.format(n, fieldLen, descriptor.getScale());
267
            safeEncode(fieldString, fieldLen, false);
268

  
269
        } else if (DataTypes.LONG == type) {
338 270
            long l = feature.getLong(attr.getIndex());
339
            fieldString = formatter.getFieldString(
340
                fieldLen, header.getFieldDecimalCount(dbfFieldIndex),l
341
            );
271
            fieldString = formatter.format(l, fieldLen, descriptor.getScale());
342 272
            safeEncode(fieldString, fieldLen, false);
343
        
344
        } else if( DataTypes.STRING == type ) {
273

  
274
        } else if (DataTypes.INT == type) {
275
            int n = feature.getInt(attr.getIndex());
276
            fieldString = formatter.format(n, fieldLen, descriptor.getScale());
277
            safeEncode(fieldString, fieldLen, false);
278

  
279
        } else if (DataTypes.BYTE == type) {
280
            int n = feature.getInt(attr.getIndex());
281
            fieldString = formatter.format(n, fieldLen);
282
            safeEncode(fieldString, fieldLen, false);
283

  
284
        } else if (DataTypes.STRING == type) {
345 285
            String s = feature.getString(attr.getIndex());
346 286
            safeEncode(StringUtils.defaultIfEmpty(s, ""), fieldLen, true);
347
        
287

  
348 288
        } else {
349 289
            // Si no conocemos el tipo intentamos guardarlo como un string
350 290
            String s = feature.getString(attr.getIndex());
......
355 295
    }
356 296

  
357 297
    /**
358
     * Returns a safely padded (and potentially truncated) string 
359
     * 
360
     * This may truncate some record, but it is required to ensure
361
     * that the field limit is not overflowed when using 
362
     * variable-length charsets such as UTF-8.
363
     * @throws UnsupportedEncodingException 
298
     * Returns a safely padded (and potentially truncated) string
299
     *
300
     * This may truncate some record, but it is required to ensure that the
301
     * field limit is not overflowed when using variable-length charsets such as
302
     * UTF-8.
303
     *
304
     * @throws UnsupportedEncodingException
364 305
     */
365 306
    private void safeEncode(String in, int limit, boolean rightPadding) throws UnsupportedEncodingException {
366
    	try {
367
    		byte[] encodedString = in.getBytes(this.charset);
368
    		if (encodedString.length>limit) {
369
    			// too long, truncating
370
    			/*
307
        try {
308
            byte[] encodedString = in.getBytes(this.charset);
309
            if (encodedString.length > limit) {
310
                // too long, truncating
311
                /*
371 312
    			 * The block code bellow is equivalent to this simple code
372 313
    			 * fragment:
373 314

  
......
400 341
    		Finally, as we should be close enough to the right truncation position,
401 342
    		we increment/decrement the truncated string by only 1 character, to
402 343
    		ensure we truncate in the exact position. 
403
    			 */
404
    			String str = in;
405
    			int estimatedDiff, deviation;
406
    			int deviationPrev;
407
    			double ratio;
408
    			byte[] encodedChar;
409
    			int truncatePos = 0;
410
    			deviation = encodedString.length - limit;
411
    			deviationPrev = deviation - 1;
412
    			while(Math.abs(deviation)>Math.abs(deviationPrev) && str.length()>0) {
413
    				ratio = ((double)encodedString.length) / ((double)str.length());
414
    				// apply the estimated diff, ensuring it is at least >= 1.0 in absolute value
415
    				estimatedDiff = Math.max((int)(((double)deviation)/ratio), (int)(Math.signum(deviation)*1));
416
    				// too long, truncating
417
    				if (rightPadding) {
418
    					truncatePos = Math.max(str.length()-estimatedDiff, 0);
419
    					str = in.substring(0, truncatePos);
420
    				}
421
    				else {
422
    					truncatePos = Math.max(truncatePos + estimatedDiff, 0);
423
    					str = in.substring(truncatePos);				  
424
    				}
425
    				encodedString = str.getBytes(charset);
426
    				deviationPrev = deviation;
427
    				deviation = encodedString.length - limit;
428
    			}
429
    			// now we are close enough, get the exact position for truncating
430
    			while (encodedString.length>limit) {
431
    				// too long, truncating
432
    				//    				  System.out.println("truncating");
433
    				if (rightPadding) {
434
    					str = in.substring(0, str.length()-1);
435
    				}
436
    				else {
437
    					truncatePos = truncatePos + 1;
438
    					str = in.substring(truncatePos);
439
    				}
440
    				encodedString = str.getBytes(charset);
441
    			}
442
    			while (encodedString.length<limit && str.length()<in.length()) {
443
    				// Extend if necessary:
444
    				// 1 - Get the length in bytes of the next char
445
    				// 2 - Add the char to the substring if we are still within the limits 
446
    				//    				  System.out.println("extending");
447
    				if (rightPadding) {
448
    					encodedChar = in.substring(str.length(), str.length()+1).getBytes(charset);
449
    				}
450
    				else {
451
    					encodedChar = in.substring(truncatePos-1, truncatePos).getBytes(charset);
452
    					//    					  System.out.println(encodedChar);
453
    					//    					  System.out.println(encodedChar.length);
454
    					//    					  System.out.println(testStrings[i].substring(truncatePos-1, truncatePos));
455
    				}
456
    				//    				  System.out.println(testStrings[i].substring(in.length(), in.length()+1));
457
    				if ((encodedString.length + encodedChar.length)>limit) {
458
    					// one more char would overflow the limit
459
    					break;
460
    				}
461
    				// too short, extending
462
    				if (rightPadding) {
463
    					str = in.substring(0, str.length()+1);
464
    				}
465
    				else {
466
    					truncatePos = truncatePos - 1;
467
    					str = in.substring(truncatePos);
468
    				}
469
    				encodedString = str.getBytes(charset);
470
    			}
471
    		}
472
    		if (rightPadding) {
473
    			buffer.put(encodedString);
474
    		}
475
    		if (encodedString.length<limit) {
476
    			// too short, padding
477
    			int i = encodedString.length;
478
    			while (i<limit) {
479
    				((Buffer)blank).position(0);
480
    				buffer.put(blank);
481
    				i=i+blankSize;
482
    			}
483
    			if (i>limit) {
484
    				// Might happen for instance if charset is UTF16 and the
485
    				// limit of characters in the field is an odd number
486
    				throw new UnsupportedEncodingException(new Exception("Impossible to encode this DBF using the selected charset"));
487
    			}
488
    		}
489
    		if (!rightPadding) {
490
    			buffer.put(encodedString);
491
    		}
492
    	}
493
		catch(BufferOverflowException exc) {
494
			// Might happen for instance if charset is UTF16 and the
495
			// limit of characters in the field is an odd number
496
			throw new UnsupportedEncodingException(exc);
497
		}
344
                 */
345
                String str = in;
346
                int estimatedDiff, deviation;
347
                int deviationPrev;
348
                double ratio;
349
                byte[] encodedChar;
350
                int truncatePos = 0;
351
                deviation = encodedString.length - limit;
352
                deviationPrev = deviation - 1;
353
                while (Math.abs(deviation) > Math.abs(deviationPrev) && str.length() > 0) {
354
                    ratio = ((double) encodedString.length) / ((double) str.length());
355
                    // apply the estimated diff, ensuring it is at least >= 1.0 in absolute value
356
                    estimatedDiff = Math.max((int) (((double) deviation) / ratio), (int) (Math.signum(deviation) * 1));
357
                    // too long, truncating
358
                    if (rightPadding) {
359
                        truncatePos = Math.max(str.length() - estimatedDiff, 0);
360
                        str = in.substring(0, truncatePos);
361
                    } else {
362
                        truncatePos = Math.max(truncatePos + estimatedDiff, 0);
363
                        str = in.substring(truncatePos);
364
                    }
365
                    encodedString = str.getBytes(charset);
366
                    deviationPrev = deviation;
367
                    deviation = encodedString.length - limit;
368
                }
369
                // now we are close enough, get the exact position for truncating
370
                while (encodedString.length > limit) {
371
                    // too long, truncating
372
                    //    				  System.out.println("truncating");
373
                    if (rightPadding) {
374
                        str = in.substring(0, str.length() - 1);
375
                    } else {
376
                        truncatePos = truncatePos + 1;
377
                        str = in.substring(truncatePos);
378
                    }
379
                    encodedString = str.getBytes(charset);
380
                }
381
                while (encodedString.length < limit && str.length() < in.length()) {
382
                    // Extend if necessary:
383
                    // 1 - Get the length in bytes of the next char
384
                    // 2 - Add the char to the substring if we are still within the limits 
385
                    //    				  System.out.println("extending");
386
                    if (rightPadding) {
387
                        encodedChar = in.substring(str.length(), str.length() + 1).getBytes(charset);
388
                    } else {
389
                        encodedChar = in.substring(truncatePos - 1, truncatePos).getBytes(charset);
390
                        //    					  System.out.println(encodedChar);
391
                        //    					  System.out.println(encodedChar.length);
392
                        //    					  System.out.println(testStrings[i].substring(truncatePos-1, truncatePos));
393
                    }
394
                    //    				  System.out.println(testStrings[i].substring(in.length(), in.length()+1));
395
                    if ((encodedString.length + encodedChar.length) > limit) {
396
                        // one more char would overflow the limit
397
                        break;
398
                    }
399
                    // too short, extending
400
                    if (rightPadding) {
401
                        str = in.substring(0, str.length() + 1);
402
                    } else {
403
                        truncatePos = truncatePos - 1;
404
                        str = in.substring(truncatePos);
405
                    }
406
                    encodedString = str.getBytes(charset);
407
                }
408
            }
409
            if (rightPadding) {
410
                buffer.put(encodedString);
411
            }
412
            if (encodedString.length < limit) {
413
                // too short, padding
414
                int i = encodedString.length;
415
                while (i < limit) {
416
                    ((Buffer) blank).position(0);
417
                    buffer.put(blank);
418
                    i = i + blankSize;
419
                }
420
                if (i > limit) {
421
                    // Might happen for instance if charset is UTF16 and the
422
                    // limit of characters in the field is an odd number
423
                    throw new UnsupportedEncodingException(new Exception("Impossible to encode this DBF using the selected charset"));
424
                }
425
            }
426
            if (!rightPadding) {
427
                buffer.put(encodedString);
428
            }
429
        } catch (BufferOverflowException exc) {
430
            // Might happen for instance if charset is UTF16 and the
431
            // limit of characters in the field is an odd number
432
            throw new UnsupportedEncodingException(exc);
433
        }
498 434
    }
499
    
500
    /**
501
     * Returns a safely padded (and potentially truncated) string 
502
     * 
503
     * This may truncate some record, but it is required to ensure
504
     * that the field limit is not overflowed when using 
505
     * variable-length charsets such as UTF-8.
506
     * 
507
     * This implementation is not used but it is kept here for reference.
508
     * It is fully equivalent to the {@link #safeEncode(String, int, boolean)}
509
     * method and easier to understand, but this implementation is much
510
     * slower for any multibyte charset (such as UTF-8).
511
     *  
512
     * @throws UnsupportedEncodingException 
513
     */
514
    private void safeEncodeSlow(String in, int limit, boolean rightPadding) throws UnsupportedEncodingException {
515
    	try {
516
    		byte[] encodedString = in.getBytes(this.charset);
517
    		while (encodedString.length>limit) {
518
    			// too long, truncating
519
    			if (rightPadding) {
520
    				in = in.substring(0, in.length()-1);
521
    				encodedString = in.getBytes(charset);
522
    			}
523
    			else {
524
    				in.substring(1, in.length());
525
    				encodedString = in.getBytes(charset);
526
    			}
527
    		}
528
    		if (rightPadding) {
529
    			buffer.put(encodedString);
530
    		}
531
    		if (encodedString.length<limit) {
532
    			// too short, padding
533
    			int i = encodedString.length;
534
    			while (i<limit) {
535
    				((Buffer)blank).position(0);
536
    				buffer.put(blank);
537
    				i=i+blankSize;
538
    			}
539
    			if (i>limit) {
540
    				throw new UnsupportedEncodingException(new Exception("Impossible to encode this DBF using the selected charset"));
541
    			}
542
    		}
543
    		if (!rightPadding) {
544
    			buffer.put(encodedString);
545
    		}
546
    	}
547
    	catch(BufferOverflowException exc) {
548
    		// Might happen for instance if charset is UTF16 and the
549
    		// limit of characters in the field is an odd number
550
    		throw new UnsupportedEncodingException(exc);
551
    	}
552
    }
553 435

  
554 436

  
555 437
    /**
556 438
     * Release resources associated with this writer. <B>Highly recommended</B>
557
     * 
439
     *
558 440
     * @throws CloseException
559
     * @throws IOException
560
     *             If errors occur.
561 441
     */
562 442
    public void close() throws CloseException {
563 443
        // IANS - GEOT 193, bogus 0x00 written. According to dbf spec, optional
......
591 471
        formatter = null;
592 472
    }
593 473

  
594
    /** Utility for formatting Dbase fields. */
595
    public static class FieldFormatter {
596

  
597
        private StringBuffer buffer = new StringBuffer(255);
598
        private NumberFormat numFormat = NumberFormat
599
            .getNumberInstance(Locale.US);
600
        private Calendar calendar = Calendar.getInstance(Locale.US);
601
        private String emtpyString;
602
        private static final int MAXCHARS = 255;
603

  
604
        public FieldFormatter() {
605
            // Avoid grouping on number format
606
            numFormat.setGroupingUsed(false);
607

  
608
            // build a 255 white spaces string
609
            StringBuffer sb = new StringBuffer(MAXCHARS);
610
            sb.setLength(MAXCHARS);
611
            for (int i = 0; i < MAXCHARS; i++) {
612
                sb.setCharAt(i, ' ');
613
            }
614

  
615
            emtpyString = sb.toString();
616
        }
617

  
618
        public String getFieldString(int size, String s) {
619
            buffer.replace(0, size, emtpyString);
620
            buffer.setLength(size);
621

  
622
            if (s != null) {
623
                buffer.replace(0, size, s);
624
                if (s.length() <= size) {
625
                    for (int i = s.length(); i < size; i++) {
626
                        buffer.append(' ');
627
                    }
628
                }
629
            }
630

  
631
            buffer.setLength(size);
632
            return buffer.toString();
633
        }
634

  
635
        public String getFieldString(Date d) {
636

  
637
            if (d != null) {
638
                buffer.delete(0, buffer.length());
639

  
640
                calendar.setTime(d);
641
                int year = calendar.get(Calendar.YEAR);
642
                int month = calendar.get(Calendar.MONTH) + 1; // returns 0 based
643
                                                              // month?
644
                int day = calendar.get(Calendar.DAY_OF_MONTH);
645

  
646
                if (year < 1000) {
647
                    if (year >= 100) {
648
                        buffer.append("0");
649
                    } else
650
                        if (year >= 10) {
651
                            buffer.append("00");
652
                        } else {
653
                            buffer.append("000");
654
                        }
655
                }
656
                buffer.append(year);
657

  
658
                if (month < 10) {
659
                    buffer.append("0");
660
                }
661
                buffer.append(month);
662

  
663
                if (day < 10) {
664
                    buffer.append("0");
665
                }
666
                buffer.append(day);
667
            } else {
668
                buffer.setLength(8);
669
                buffer.replace(0, 8, emtpyString);
670
            }
671

  
672
            buffer.setLength(8);
673
            return buffer.toString();
674
        }
675

  
676
        public String getFieldString(int size, int decimalPlaces, double n) {
677
            buffer.delete(0, buffer.length());
678

  
679
            numFormat.setMaximumFractionDigits(decimalPlaces);
680
            numFormat.setMinimumFractionDigits(decimalPlaces);
681
            numFormat.format(n, buffer, new FieldPosition(
682
                NumberFormat.INTEGER_FIELD));
683
            return buffer.toString();
684
        }
685
    }
686

  
687 474
    public void setCharset(Charset charset) {
688 475
        this.charset = charset;
689
    	blank = charset.encode(" ");
690
    	blankSize = blank.limit();
476
        blank = charset.encode(" ");
477
        blankSize = blank.limit();
691 478
    }
692 479

  
693 480
}

Also available in: Unified diff