1 package nom.tam.util;
2
3 /*
4 * #%L
5 * nom.tam FITS library
6 * %%
7 * Copyright (C) 2004 - 2024 nom-tam-fits
8 * %%
9 * This is free and unencumbered software released into the public domain.
10 *
11 * Anyone is free to copy, modify, publish, use, compile, sell, or
12 * distribute this software, either in source code form or as a compiled
13 * binary, for any purpose, commercial or non-commercial, and by any
14 * means.
15 *
16 * In jurisdictions that recognize copyright laws, the author or authors
17 * of this software dedicate any and all copyright interest in the
18 * software to the public domain. We make this dedication for the benefit
19 * of the public at large and to the detriment of our heirs and
20 * successors. We intend this dedication to be an overt act of
21 * relinquishment in perpetuity of all present and future rights to this
22 * software under copyright law.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
28 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
29 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
30 * OTHER DEALINGS IN THE SOFTWARE.
31 * #L%
32 */
33
34 /**
35 * This class provides mechanisms for efficiently formatting numbers and Strings. Data is appended to existing byte
36 * arrays. Note that the formatting of real or double values may differ slightly (in the last bit) from the standard
37 * Java packages since this routines are optimized for speed rather than accuracy.
38 * <p>
39 * The methods in this class create no objects.
40 * <p>
41 * If a number cannot fit into the requested space the truncateOnOverlow flag controls whether the formatter will
42 * attempt to append it using the available length in the output (a la C or Perl style formats). If this flag is set, or
43 * if the number cannot fit into space left in the buffer it is 'truncated' and the requested space is filled with a
44 * truncation fill character. A TruncationException may be thrown if the truncationThrow flag is set.
45 * <p>
46 * This class does not explicitly support separate methods for formatting reals in exponential notation. Real numbers
47 * near one are by default formatted in decimal notation while numbers with large (or very negative) exponents are
48 * formatted in exponential notation. By setting the limits at which these transitions take place the user can force
49 * either exponential or decimal notation.
50 *
51 * @deprecated This class should not be exposed in the public API and is intended for internal use only in ASCII tables.
52 * Also, it may have overlapping functionality with other classes, which should probably be eliminated
53 * for simplicity's sake (and thus less chance of nasty bugs).
54 *
55 * @see ByteParser
56 */
57 @Deprecated
58 public final class ByteFormatter {
59
60 /** String representation of NaN values */
61 public static final String NOT_A_NUMBER = "NaN";
62
63 /** String representation of (positive) infinity values */
64 public static final String INFINITY = "Infinity";
65
66 /** String representation of (negative) infinity values */
67 public static final String NEGATIVE_INFINITY = "-Infinity";
68
69 /**
70 * Maximum magnitude to print in non-scientific notation.
71 */
72 private static final double DEFAULT_SIMPLE_MAX = 1.e6;
73
74 /**
75 * Minimum magnitude to print in non-scientific notation.
76 */
77 private static final double DEFAULT_SIMPLE_MIN = 1.e-3;
78
79 /**
80 * Digits. We could handle other bases by extending or truncating this list and changing the division by 10 (and
81 * it's factors) at various locations.
82 */
83 private static final byte[] DIGITS = {(byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5',
84 (byte) '6', (byte) '7', (byte) '8', (byte) '9'};
85
86 private static final long DOUBLE_EXPONENT_BIT_MASK = 0x7FF0000000000000L;
87
88 private static final int DOUBLE_EXPONENT_EXCESS = 52;
89
90 /**
91 * The hidden bit in normalized double numbers.
92 */
93 private static final long DOUBLE_EXPONENT_NORMALIZE_BIT = 0x0010000000000000L;
94
95 /**
96 * Used to check if double is normalized
97 */
98 private static final int DOUBLE_MIN_EXPONENT = -1023;
99
100 private static final int DOUBLE_SHIFT_BASE = 17;
101
102 private static final int DOUBLE_SHIFT_LIMIT = 200;
103
104 private static final long DOUBLE_VALUE_BIT_MASK = 0x000FFFFFFFFFFFFFL;
105
106 private static final int FLOAT_EXPONENT_BIT_MASK = 0x7F800000;
107
108 private static final int FLOAT_EXPONENT_EXCESS = 23;
109
110 /**
111 * The hidden bit in normalized floating point numbers.
112 */
113 private static final int FLOAT_EXPONENT_NORMALIZE_BIT = 0x00800000;
114
115 /**
116 * Used to check if float is normalized
117 */
118 private static final int FLOAT_MIN_EXPONENT = -127;
119
120 private static final int FLOAT_SHIFT_BASE = 8;
121
122 private static final int FLOAT_SHIFT_LIMIT = 30;
123
124 private static final int FLOAT_VALUE_BIT_MASK = 0x007FFFFF;
125
126 private static final double I_LOG_10 = 1. / Math.log(ByteFormatter.NUMBER_BASE);
127
128 private static final long LONG_TO_INT_MODULO = 1000000000L;
129
130 private static final int MAX_LONG_LENGTH = 19;
131
132 /**
133 * The maximum single digit integer. Special case handling when rounding up and when incrementing the exponent.
134 */
135
136 private static final int MAXIMUM_SINGLE_DIGIT_INTEGER = 9;
137
138 /**
139 * The maximum two digit integer. When we increment an exponent of this value, the exponent gets longer. Don't need
140 * to worry about 999 since exponents can't be that big.
141 */
142 private static final int MAXIMUM_TWO_DIGIT_INTEGER = 99;
143
144 private static final int TEMP_BUFFER_SIZE = 32;
145
146 /**
147 * The underlying number base used in this class.
148 */
149 private static final int NUMBER_BASE = 10;
150
151 /**
152 * Powers of 10. We over extend on both sides. These should perhaps be tabulated rather than computed though it may
153 * be faster to calculate them than to read in the extra bytes in the class file.
154 */
155 private static final double[] NUMBER_BASE_POWERS;
156
157 /**
158 * What do we use to fill when we cannot print the number?Default is often used in Fortran.
159 */
160 private static final byte TRUNCATION_FILL = (byte) '*';
161
162 /**
163 * What index of tenpow is 10^0
164 */
165 private static final int ZERO_POW;
166
167 static { // Static initializer
168 int min = (int) Math.floor((int) (Math.log(Double.MIN_VALUE) * ByteFormatter.I_LOG_10));
169 int max = (int) Math.floor((int) (Math.log(Double.MAX_VALUE) * ByteFormatter.I_LOG_10));
170 max++;
171 NUMBER_BASE_POWERS = new double[max - min + 1];
172 for (int i = 0; i < ByteFormatter.NUMBER_BASE_POWERS.length; i++) {
173 ByteFormatter.NUMBER_BASE_POWERS[i] = Math.pow(ByteFormatter.NUMBER_BASE, i + min);
174 }
175 ZERO_POW = -min;
176 }
177
178 /**
179 * Internal buffers used in formatting fields
180 */
181 private final byte[] tbuf1 = new byte[ByteFormatter.TEMP_BUFFER_SIZE];
182
183 private final byte[] tbuf2 = new byte[ByteFormatter.TEMP_BUFFER_SIZE];
184
185 /**
186 * This method formats a double given a decimal mantissa and exponent information.
187 *
188 * @param val The original number
189 * @param buf Output buffer
190 * @param off Offset into buffer
191 * @param len Maximum number of characters to use in buffer.
192 * @param mant A decimal mantissa for the number.
193 * @param lmant The number of characters in the mantissa
194 * @param shift The exponent of the power of 10 that we shifted val to get the given mantissa.
195 *
196 * @return Offset of next available character in buffer.
197 */
198 private int combineReal(double val, byte[] buf, int off, int len, byte[] mant, int lmant, int shift) {
199
200 // First get the minimum size for the number
201
202 double pos = Math.abs(val);
203 boolean simple = false;
204 int minSize;
205 int maxSize;
206
207 if (pos >= ByteFormatter.DEFAULT_SIMPLE_MIN && pos <= ByteFormatter.DEFAULT_SIMPLE_MAX) {
208 simple = true;
209 }
210
211 int exp = lmant - shift - 1;
212 int lexp = 0;
213
214 if (!simple) {
215 lexp = format(exp, tbuf2, 0, ByteFormatter.TEMP_BUFFER_SIZE);
216
217 minSize = lexp + 2; // e.g., 2e-12
218 maxSize = lexp + lmant + 2; // add in "." and e
219 } else if (exp >= 0) {
220 minSize = exp + 1; // e.g. 32
221
222 // Special case. E.g., 99.9 has
223 // minumum size of 3.
224 int i;
225 for (i = 0; i < lmant && i <= exp; i++) {
226 if (mant[i] != (byte) '9') {
227 break;
228 }
229 }
230 if (i > exp && i < lmant && mant[i] >= (byte) '5') {
231 minSize++;
232 }
233
234 maxSize = lmant + 1; // Add in "."
235 if (maxSize <= minSize) { // Very large numbers.
236 maxSize = minSize + 1;
237 }
238 } else {
239 minSize = 2;
240 maxSize = 1 + Math.abs(exp) + lmant;
241 }
242 if (val < 0) {
243 minSize++;
244 }
245
246 // Can the number fit?
247 if (minSize > len || minSize > buf.length - off) {
248 truncationFiller(buf, off, len);
249 return off + len;
250 }
251
252 // Now begin filling in the buffer.
253 if (val < 0) {
254 buf[off] = (byte) '-';
255 off++;
256 len--;
257 }
258
259 if (simple) {
260 return Math.abs(mantissa(mant, lmant, exp, simple, buf, off, len));
261 }
262 off = mantissa(mant, lmant, 0, simple, buf, off, len - lexp - 1);
263 if (off < 0) {
264 off = -off;
265 len -= off;
266 // Handle the expanded exponent by filling
267 if (exp == MAXIMUM_SINGLE_DIGIT_INTEGER || exp == MAXIMUM_TWO_DIGIT_INTEGER) {
268 // Cannot fit...
269 if (off + len == minSize) {
270 truncationFiller(buf, off, len);
271 return off + len;
272 }
273 // Steal a character from the mantissa.
274 off--;
275 }
276 exp++;
277 lexp = format(exp, tbuf2, 0, ByteFormatter.TEMP_BUFFER_SIZE);
278 }
279 buf[off] = (byte) 'E';
280 off++;
281 System.arraycopy(tbuf2, 0, buf, off, lexp);
282 return off + lexp;
283 }
284
285 /**
286 * Format a boolean into an existing array.
287 *
288 * @param val value to write
289 * @param array the array to fill
290 *
291 * @return Offset of next available character in buffer.
292 */
293 public int format(boolean val, byte[] array) {
294 return format(val, array, 0, array.length);
295 }
296
297 /**
298 * Format a boolean into an existing array
299 *
300 * @param val The boolean to be formatted
301 * @param array The buffer in which to format the data.
302 * @param off The starting offset within the buffer.
303 * @param len The maximum number of characters to use use in formatting the number.
304 *
305 * @return Offset of next available character in buffer.
306 */
307 public int format(boolean val, byte[] array, int off, int len) {
308 if (len > 0) {
309 if (val) {
310 array[off] = (byte) 'T';
311 } else {
312 array[off] = (byte) 'F';
313 }
314 off++;
315 }
316 return off;
317 }
318
319 /**
320 * Format a double into an array.
321 *
322 * @param val The double to be formatted.
323 * @param array The array in which to place the result.
324 *
325 * @return The number of characters used. @ * if the value was truncated
326 */
327 public int format(double val, byte[] array) {
328 return format(val, array, 0, array.length);
329 }
330
331 /**
332 * Format a double into an existing character array.
333 * <p>
334 * This is hard to do exactly right... The JDK code does stuff with rational arithmetic and so forth. We use a much
335 * simpler algorithm which may give an answer off in the lowest order bit. Since this is pure Java, it should still
336 * be consistent from machine to machine.
337 * <p>
338 * Recall that the binary representation of the double is of the form <code>d = 0.bbbbbbbb x 2<sup>n</sup></code>
339 * where there are up to 53 binary digits in the binary fraction (including the assumed leading 1 bit for normalized
340 * numbers). We find a value m such that <code>10<sup>m</sup> d</code> is between <code>2<sup>53</sup></code> and
341 * <code>2<sup>63</sup></code>. This product will be exactly convertible to a long with no loss of precision.
342 * Getting the decimal representation for that is trivial (see formatLong). This is a decimal mantissa and we have
343 * an exponent (<code>-m</code>). All we have to do is manipulate the decimal point to where we want to see it.
344 * Errors can arise due to roundoff in the scaling multiplication, but should be no more than a single bit.
345 *
346 * @param val Double to be formatted
347 * @param buf Buffer in which result is to be stored
348 * @param off Offset within buffer
349 * @param len Maximum length of integer
350 *
351 * @return offset of next unused character in input buffer.
352 */
353 public int format(double val, byte[] buf, int off, int len) {
354
355 double pos = Math.abs(val);
356
357 // Special cases -- It is OK if these get truncated.
358 if (pos == 0.) {
359 return format("0.0", buf, off, len);
360 }
361 if (Double.isNaN(val)) {
362 return format(NOT_A_NUMBER, buf, off, len);
363 }
364 if (Double.isInfinite(val)) {
365 if (val > 0) {
366 return format(INFINITY, buf, off, len);
367 }
368 return format(NEGATIVE_INFINITY, buf, off, len);
369 }
370
371 int power = (int) (Math.log(pos) * ByteFormatter.I_LOG_10);
372 int shift = DOUBLE_SHIFT_BASE - power;
373 double scale;
374 double scale2 = 1;
375
376 // Scale the number so that we get a number ~ n x 10^17.
377 if (shift < DOUBLE_SHIFT_LIMIT) {
378 scale = ByteFormatter.NUMBER_BASE_POWERS[shift + ByteFormatter.ZERO_POW];
379 } else {
380 // Can get overflow if the original number is
381 // very small, so we break out the shift
382 // into two multipliers.
383 scale2 = ByteFormatter.NUMBER_BASE_POWERS[DOUBLE_SHIFT_LIMIT + ByteFormatter.ZERO_POW];
384 scale = ByteFormatter.NUMBER_BASE_POWERS[shift - DOUBLE_SHIFT_LIMIT + ByteFormatter.ZERO_POW];
385 }
386
387 pos = pos * scale * scale2;
388
389 // Parse the double bits.
390
391 long bits = Double.doubleToLongBits(pos);
392
393 // The exponent should be a little more than 52.
394 int exp = (int) (((bits & DOUBLE_EXPONENT_BIT_MASK) >> DOUBLE_EXPONENT_EXCESS) + DOUBLE_MIN_EXPONENT);
395
396 long numb = bits & DOUBLE_VALUE_BIT_MASK;
397
398 // this can never be false because the min exponent of a double is -1022
399 // but lets keep it if we need it for big decimals
400 if (exp > DOUBLE_MIN_EXPONENT) {
401 // Normalized....
402 numb |= DOUBLE_EXPONENT_NORMALIZE_BIT;
403 } else {
404 // Denormalized
405 exp++;
406 }
407
408 // Multiple this number by the excess of the exponent
409 // over 52. This completes the conversion of double to long.
410 numb = numb << exp - DOUBLE_EXPONENT_EXCESS;
411
412 // Get a decimal mantissa.
413 int ndig = format(numb, tbuf1, 0, ByteFormatter.TEMP_BUFFER_SIZE);
414
415 // Now format the double.
416
417 return combineReal(val, buf, off, len, tbuf1, ndig, shift);
418 }
419
420 /**
421 * Format a float into an array.
422 *
423 * @param val The float to be formatted.
424 * @param array The array in which to place the result.
425 *
426 * @return The number of characters used. @ * if the value was truncated
427 */
428 public int format(float val, byte[] array) {
429 return format(val, array, 0, array.length);
430 }
431
432 /**
433 * Format a float into an existing byteacter array.
434 * <p>
435 * This is hard to do exactly right... The JDK code does stuff with rational arithmetic and so forth. We use a much
436 * simpler algorithm which may give an answer off in the lowest order bit. Since this is pure Java, it should still
437 * be consistent from machine to machine.
438 * <p>
439 * Recall that the binary representation of the float is of the form <code>d = 0.bbbbbbbb x 2<sup>n</sup></code>
440 * where there are up to 24 binary digits in the binary fraction (including the assumed leading 1 bit for normalized
441 * numbers). We find a value m such that <code>10<sup>m</sup> d</code> is between <code>2<sup>24</sup></code> and
442 * <code>2<sup>32</sup></code>. This product will be exactly convertible to an int with no loss of precision.
443 * Getting the decimal representation for that is trivial (see formatInteger). This is a decimal mantissa and we
444 * have an exponent ( <code>-m</code>). All we have to do is manipulate the decimal point to where we want to see
445 * it. Errors can arise due to roundoff in the scaling multiplication, but should be very small.
446 *
447 * @param val Float to be formatted
448 * @param buf Buffer in which result is to be stored
449 * @param off Offset within buffer
450 * @param len Maximum length of field
451 *
452 * @return Offset of next character in buffer. @ * if the value was truncated
453 */
454 public int format(float val, byte[] buf, int off, int len) {
455
456 float pos = Math.abs(val);
457
458 // Special cases
459 if (pos == 0.) {
460 return format("0.0", buf, off, len);
461 }
462 if (Float.isNaN(val)) {
463 return format(NOT_A_NUMBER, buf, off, len);
464 }
465 if (Float.isInfinite(val)) {
466 if (val > 0) {
467 return format("Infinity", buf, off, len);
468 }
469 return format("-Infinity", buf, off, len);
470 }
471
472 int power = (int) Math.floor(Math.log(pos) * ByteFormatter.I_LOG_10);
473 int shift = FLOAT_SHIFT_BASE - power;
474 float scale;
475 float scale2 = 1;
476
477 // Scale the number so that we get a number ~ n x 10^8.
478 if (shift < FLOAT_SHIFT_LIMIT) {
479 scale = (float) ByteFormatter.NUMBER_BASE_POWERS[shift + ByteFormatter.ZERO_POW];
480 } else {
481 // Can get overflow if the original number is
482 // very small, so we break out the shift
483 // into two multipliers.
484 scale2 = (float) ByteFormatter.NUMBER_BASE_POWERS[FLOAT_SHIFT_LIMIT + ByteFormatter.ZERO_POW];
485 scale = (float) ByteFormatter.NUMBER_BASE_POWERS[shift - FLOAT_SHIFT_LIMIT + ByteFormatter.ZERO_POW];
486 }
487
488 pos = pos * scale * scale2;
489
490 // Parse the float bits.
491
492 int bits = Float.floatToIntBits(pos);
493
494 // The exponent should be a little more than 23
495 int exp = ((bits & FLOAT_EXPONENT_BIT_MASK) >> FLOAT_EXPONENT_EXCESS) + FLOAT_MIN_EXPONENT;
496
497 int numb = bits & FLOAT_VALUE_BIT_MASK;
498
499 if (exp > FLOAT_MIN_EXPONENT) {
500 // Normalized....
501 numb |= FLOAT_EXPONENT_NORMALIZE_BIT;
502 } else {
503 // Denormalized
504 exp++;
505 }
506
507 // Multiple this number by the excess of the exponent
508 // over 24. This completes the conversion of float to int
509 // (<<= did not work on Alpha TruUnix)
510
511 numb = numb << exp - FLOAT_EXPONENT_EXCESS;
512
513 // Get a decimal mantissa.
514 int ndig = format(numb, tbuf1, 0, ByteFormatter.TEMP_BUFFER_SIZE);
515
516 // Now format the float.
517
518 return combineReal(val, buf, off, len, tbuf1, ndig, shift);
519 }
520
521 /**
522 * Format an int into an array.
523 *
524 * @param val The int to be formatted.
525 * @param array The array in which to place the result.
526 *
527 * @return The number of characters used. @ * if the value was truncated
528 */
529 public int format(int val, byte[] array) {
530 return format(val, array, 0, array.length);
531 }
532
533 /**
534 * Format an int into an existing array.
535 *
536 * @param val Integer to be formatted
537 * @param buf Buffer in which result is to be stored
538 * @param off Offset within buffer
539 * @param len Maximum length of integer
540 *
541 * @return offset of next unused character in input buffer.
542 */
543 public int format(int val, byte[] buf, int off, int len) {
544
545 // Special case
546 if (val == Integer.MIN_VALUE) {
547 if (len > ByteFormatter.NUMBER_BASE) {
548 return format("-2147483648", buf, off, len);
549 }
550 truncationFiller(buf, off, len);
551 return off + len;
552 }
553
554 int pos = Math.abs(val);
555
556 // First count the number of characters in the result.
557 // Otherwise we need to use an intermediary buffer.
558
559 int ndig = 1;
560 int dmax = ByteFormatter.NUMBER_BASE;
561
562 while (ndig < ByteFormatter.NUMBER_BASE && pos >= dmax) {
563 ndig++;
564 dmax *= ByteFormatter.NUMBER_BASE;
565 }
566
567 if (val < 0) {
568 ndig++;
569 }
570
571 // Truncate if necessary.
572 if (ndig > len || ndig > buf.length - off) {
573 truncationFiller(buf, off, len);
574 return off + len;
575 }
576
577 // Now insert the actual characters we want -- backwards
578 // We use a do{} while() to handle the caByteFormatterse of 0.
579
580 off += ndig;
581
582 int xoff = off - 1;
583 do {
584 buf[xoff] = ByteFormatter.DIGITS[pos % ByteFormatter.NUMBER_BASE];
585 xoff--;
586 pos /= ByteFormatter.NUMBER_BASE;
587 } while (pos > 0);
588
589 if (val < 0) {
590 buf[xoff] = (byte) '-';
591 }
592
593 return off;
594 }
595
596 /**
597 * Format a long into an array.
598 *
599 * @param val The long to be formatted.
600 * @param array The array in which to place the result.
601 *
602 * @return The number of characters used. @ * if the value was truncated
603 */
604 public int format(long val, byte[] array) {
605 return format(val, array, 0, array.length);
606 }
607
608 /**
609 * Format a long into an existing array.
610 *
611 * @param val Long to be formatted
612 * @param buf Buffer in which result is to be stored
613 * @param off Offset within buffer
614 * @param len Maximum length of integer
615 *
616 * @return offset of next unused character in input buffer. @ * if the value was truncated
617 */
618 public int format(long val, byte[] buf, int off, int len) {
619 // Special case
620 if (val == Long.MIN_VALUE) {
621 if (len > MAX_LONG_LENGTH) {
622 return format("-9223372036854775808", buf, off, len);
623 }
624 truncationFiller(buf, off, len);
625 return off + len;
626 }
627 long pos = Math.abs(val);
628 // First count the number of characters in the result.
629 // Otherwise we need to use an intermediary buffer.
630 int ndig = 1;
631 long dmax = ByteFormatter.NUMBER_BASE;
632 // Might be faster to try to do this partially in ints
633 while (ndig < MAX_LONG_LENGTH && pos >= dmax) {
634 ndig++;
635 dmax *= ByteFormatter.NUMBER_BASE;
636 }
637 if (val < 0) {
638 ndig++;
639 }
640 // Truncate if necessary.
641 if (ndig > len || ndig > buf.length - off) {
642 truncationFiller(buf, off, len);
643 return off + len;
644 }
645 // Now insert the actual characters we want -- backwards.
646 off += ndig;
647 int xoff = off - 1;
648 buf[xoff] = (byte) '0';
649 boolean last = pos == 0;
650 while (!last) {
651 // Work on ints rather than longs.
652 int giga = (int) (pos % LONG_TO_INT_MODULO);
653 pos /= LONG_TO_INT_MODULO;
654 last = pos == 0;
655 for (int i = 0; i < MAXIMUM_SINGLE_DIGIT_INTEGER; i++) {
656
657 buf[xoff] = ByteFormatter.DIGITS[giga % ByteFormatter.NUMBER_BASE];
658 xoff--;
659 giga /= ByteFormatter.NUMBER_BASE;
660 if (last && giga == 0) {
661 break;
662 }
663 }
664 }
665
666 if (val < 0) {
667 buf[xoff] = (byte) '-';
668 }
669
670 return off;
671 }
672
673 /**
674 * Insert a string at the beginning of an array. * @return Offset of next available character in buffer.
675 *
676 * @param val The string to be inserted. A null string will insert len spaces.
677 * @param array The buffer in which to insert the string.
678 *
679 * @return Offset of next available character in buffer.
680 */
681 public int format(String val, byte[] array) {
682 return format(val, array, 0, array.length);
683 }
684
685 /**
686 * Insert a String into an existing character array. If the String is longer than len, then only the the initial len
687 * characters will be inserted.
688 *
689 * @param val The string to be inserted. A null string will insert len spaces.
690 * @param array The buffer in which to insert the string.
691 * @param off The starting offset to insert the string.
692 * @param len The maximum number of characters to insert.
693 *
694 * @return Offset of next available character in buffer.
695 */
696 public int format(String val, byte[] array, int off, int len) {
697
698 if (val == null) {
699 for (int i = 0; i < len; i++) {
700 array[off + i] = (byte) ' ';
701 }
702 return off + len;
703 }
704
705 int slen = val.length();
706
707 if (slen > len || slen > array.length - off) {
708 val = val.substring(0, len);
709 slen = len;
710 }
711
712 System.arraycopy(AsciiFuncs.getBytes(val), 0, array, off, slen);
713 return off + slen;
714 }
715
716 /**
717 * Write the mantissa of the number. This method addresses the subtleties involved in rounding numbers.
718 */
719 private int mantissa(byte[] mant, int lmant, int exp, boolean simple, byte[] buf, int off, int len) {
720
721 // Save in case we need to extend the number.
722 int off0 = off;
723 int pos = 0;
724
725 if (exp < 0) {
726 buf[off] = (byte) '0';
727 len--;
728 off++;
729 if (len > 0) {
730 buf[off] = (byte) '.';
731 off++;
732 len--;
733 }
734 // Leading 0s in small numbers.
735 int cexp = exp;
736 while (cexp < -1 && len > 0) {
737 buf[off] = (byte) '0';
738 cexp++;
739 off++;
740 len--;
741 }
742
743 } else {
744
745 // Print out all digits to the left of the decimal.
746 while (exp >= 0 && pos < lmant) {
747 buf[off] = mant[pos];
748 off++;
749 pos++;
750 len--;
751 exp--;
752 }
753 // Trust we have enough space for this.
754 for (int i = 0; i <= exp; i++) {
755 buf[off] = (byte) '0';
756 off++;
757 len--;
758 }
759
760 // Add in a decimal if we have space.
761 if (len > 0) {
762 buf[off] = (byte) '.';
763 len--;
764 off++;
765 }
766 }
767
768 // Now handle the digits to the right of the decimal.
769 while (len > 0 && pos < lmant) {
770 buf[off] = mant[pos];
771 off++;
772 exp--;
773 len--;
774 pos++;
775 }
776
777 // Now handle rounding.
778
779 if (pos < lmant && mant[pos] >= (byte) '5') {
780 int i;
781
782 // Increment to the left until we find a non-9
783 for (i = off - 1; i >= off0; i--) {
784
785 if (buf[i] == (byte) '.' || buf[i] == (byte) '-') {
786 continue;
787 }
788 if (buf[i] != (byte) '9') {
789 buf[i]++;
790 break;
791 }
792 buf[i] = (byte) '0';
793 }
794
795 // Now we handle 99.99 case. This can cause problems
796 // in two cases. If we are not using scientific notation
797 // then we may want to convert 99.9 to 100., i.e.,
798 // we need to move the decimal point. If there is no
799 // decimal point, then we must not be truncating on overflow
800 // but we should be allowed to write it to the
801 // next character (i.e., we are not at the end of buf).
802 //
803 // If we are printing in scientific notation, then we want
804 // to convert 9.99 to 1.00, i.e. we do not move the decimal.
805 // However we need to signal that the exponent should be
806 // incremented by one.
807 //
808 // We cannot have aligned the number, since that requires
809 // the full precision number to fit within the requested
810 // length, and we would have printed out the entire
811 // mantissa (i.e., pos >= lmant)
812
813 if (i < off0) {
814
815 buf[off0] = (byte) '1';
816 boolean foundDecimal = false;
817 for (i = off0 + 1; i < off; i++) {
818 if (buf[i] == (byte) '.') {
819 foundDecimal = true;
820 if (simple) {
821 buf[i] = (byte) '0';
822 i++;
823 if (i < off) {
824 buf[i] = (byte) '.';
825 }
826 }
827 break;
828 }
829 }
830 if (simple && !foundDecimal) {
831 buf[off + 1] = (byte) '0'; // 99 went to 100
832 off++;
833 }
834
835 off = -off; // Signal to change exponent if necessary.
836 }
837
838 }
839
840 return off;
841 }
842
843 /**
844 * Fill the buffer with truncation characters. After filling the buffer, a TruncationException will be thrown if the
845 * appropriate flag is set.
846 */
847 private void truncationFiller(byte[] buffer, int offset, int length) {
848 for (int i = offset; i < offset + length; i++) {
849 buffer[i] = ByteFormatter.TRUNCATION_FILL;
850 }
851 }
852
853 }