1 package nom.tam.fits;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 import java.io.IOException;
35 import java.lang.reflect.Array;
36 import java.util.Arrays;
37
38 import nom.tam.fits.header.Bitpix;
39 import nom.tam.fits.header.IFitsHeader;
40 import nom.tam.fits.header.Standard;
41 import nom.tam.util.ArrayDataInput;
42 import nom.tam.util.ArrayDataOutput;
43 import nom.tam.util.ArrayFuncs;
44 import nom.tam.util.ByteFormatter;
45 import nom.tam.util.ByteParser;
46 import nom.tam.util.Cursor;
47 import nom.tam.util.FormatException;
48
49 import static nom.tam.fits.header.Standard.NAXIS1;
50 import static nom.tam.fits.header.Standard.NAXIS2;
51 import static nom.tam.fits.header.Standard.TBCOLn;
52 import static nom.tam.fits.header.Standard.TDMAXn;
53 import static nom.tam.fits.header.Standard.TDMINn;
54 import static nom.tam.fits.header.Standard.TFIELDS;
55 import static nom.tam.fits.header.Standard.TFORMn;
56 import static nom.tam.fits.header.Standard.TLMAXn;
57 import static nom.tam.fits.header.Standard.TLMINn;
58 import static nom.tam.fits.header.Standard.TNULLn;
59
60
61
62
63
64
65
66
67
68
69 @SuppressWarnings("deprecation")
70 public class AsciiTable extends AbstractTableData {
71
72 private static final int MAX_INTEGER_LENGTH = 10;
73
74 private static final int FLOAT_MAX_LENGTH = 16;
75
76 private static final int LONG_MAX_LENGTH = 20;
77
78 private static final int INT_MAX_LENGTH = 10;
79
80 private static final int DOUBLE_MAX_LENGTH = 24;
81
82
83 private static boolean isI10PreferInt = true;
84
85
86
87
88 private int nRows;
89
90
91 private int nFields;
92
93
94 private int rowLen;
95
96
97 private String[] nulls;
98
99
100 private Class<?>[] types;
101
102
103 private int[] offsets;
104
105
106 private int[] lengths;
107
108
109 private byte[] buffer;
110
111
112 private boolean[] isNull;
113
114
115 private String[] names;
116
117
118
119
120 private Object[] data;
121
122
123
124
125 private ByteParser bp;
126
127
128 private ArrayDataInput currInput;
129
130
131 public AsciiTable() {
132 data = new Object[0];
133 buffer = null;
134 nFields = 0;
135 nRows = 0;
136 rowLen = 0;
137 types = new Class[0];
138 lengths = new int[0];
139 offsets = new int[0];
140 nulls = new String[0];
141 names = new String[0];
142 }
143
144
145
146
147
148
149
150
151
152
153
154
155 public AsciiTable(Header hdr) throws FitsException {
156 this(hdr, isI10PreferInt);
157 }
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180 public AsciiTable(Header hdr, boolean preferInt) throws FitsException {
181 String ext = hdr.getStringValue(Standard.XTENSION, Standard.XTENSION_IMAGE);
182
183 if (!ext.equalsIgnoreCase(Standard.XTENSION_ASCIITABLE)) {
184 throw new FitsException("Not an ASCII table header (XTENSION = " + hdr.getStringValue(Standard.XTENSION) + ")");
185 }
186
187 nRows = hdr.getIntValue(NAXIS2);
188 nFields = hdr.getIntValue(TFIELDS);
189 rowLen = hdr.getIntValue(NAXIS1);
190
191 types = new Class[nFields];
192 offsets = new int[nFields];
193 lengths = new int[nFields];
194 nulls = new String[nFields];
195 names = new String[nFields];
196
197 for (int i = 0; i < nFields; i++) {
198 names[i] = hdr.getStringValue(Standard.TTYPEn.n(i + 1), TableHDU.getDefaultColumnName(i));
199 offsets[i] = hdr.getIntValue(TBCOLn.n(i + 1)) - 1;
200 String s = hdr.getStringValue(TFORMn.n(i + 1));
201 if (offsets[i] < 0 || s == null) {
202 throw new FitsException("Invalid Specification for column:" + (i + 1));
203 }
204 s = s.trim();
205 char c = s.charAt(0);
206 s = s.substring(1);
207 if (s.indexOf('.') > 0) {
208 s = s.substring(0, s.indexOf('.'));
209 }
210 lengths[i] = Integer.parseInt(s);
211
212 switch (c) {
213 case 'A':
214 types[i] = String.class;
215 break;
216 case 'I':
217 if (lengths[i] == MAX_INTEGER_LENGTH) {
218 types[i] = guessI10Type(i, hdr, preferInt);
219 } else {
220 types[i] = lengths[i] > MAX_INTEGER_LENGTH ? long.class : int.class;
221 }
222 break;
223 case 'F':
224 case 'E':
225 types[i] = float.class;
226 break;
227 case 'D':
228 types[i] = double.class;
229 break;
230 default:
231 throw new FitsException("could not parse column type of ascii table");
232 }
233
234 nulls[i] = hdr.getStringValue(TNULLn.n(i + 1));
235 if (nulls[i] != null) {
236 nulls[i] = nulls[i].trim();
237 }
238 }
239 }
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260 public static AsciiTable fromColumnMajor(Object[] columns) throws FitsException {
261 AsciiTable t = new AsciiTable();
262 for (int i = 0; i < columns.length; i++) {
263 try {
264 t.addColumn(columns[i]);
265 } catch (Exception e) {
266 throw new FitsException("col[" + i + "]: " + e.getMessage(), e);
267 }
268 }
269 return t;
270 }
271
272 void setColumnName(int col, String value)
273 throws IllegalArgumentException, IndexOutOfBoundsException, HeaderCardException {
274 HeaderCard.validateChars(value);
275 names[col] = value;
276 }
277
278
279
280
281
282
283
284
285
286
287
288
289 private boolean requiresLong(Header h, IFitsHeader key, Long dft) {
290 long l = h.getLongValue(key, dft);
291 if (l == dft) {
292 return false;
293 }
294
295 return (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE);
296 }
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316 private Class<?> guessI10Type(int col, Header h, boolean preferInt) {
317 col++;
318
319 if (requiresLong(h, TLMINn.n(col), Long.MAX_VALUE) || requiresLong(h, TLMAXn.n(col), Long.MIN_VALUE)
320 || requiresLong(h, TDMINn.n(col), Long.MAX_VALUE) || requiresLong(h, TDMAXn.n(col), Long.MIN_VALUE)) {
321 return long.class;
322 }
323
324 if ((h.containsKey(TLMINn.n(col)) || h.containsKey(TDMINn.n(col)))
325 && (h.containsKey(TLMAXn.n(col)) || h.containsKey(TDMAXn.n(col)))) {
326
327 return int.class;
328 }
329
330 return preferInt ? int.class : long.class;
331 }
332
333
334
335
336
337
338
339
340
341
342 public final Class<?> getColumnType(int col) {
343 return types[col];
344 }
345
346 int addColInfo(int col, Cursor<String, HeaderCard> iter) {
347 String tform = null;
348 if (types[col] == String.class) {
349 tform = "A" + lengths[col];
350 } else if (types[col] == int.class || types[col] == long.class) {
351 tform = "I" + lengths[col];
352 } else if (types[col] == float.class) {
353 tform = "E" + lengths[col] + ".0";
354 } else if (types[col] == double.class) {
355 tform = "D" + lengths[col] + ".0";
356 }
357
358 Standard.context(AsciiTable.class);
359 if (names[col] != null) {
360 iter.add(HeaderCard.create(Standard.TTYPEn.n(col + 1), names[col]));
361 }
362 iter.add(HeaderCard.create(Standard.TFORMn.n(col + 1), tform));
363 iter.add(HeaderCard.create(Standard.TBCOLn.n(col + 1), offsets[col] + 1));
364 Standard.context(null);
365 return lengths[col];
366 }
367
368 @Override
369 public int addColumn(Object newCol) throws FitsException, IllegalArgumentException {
370 if (newCol == null) {
371 throw new FitsException("data is null");
372 }
373
374 if (!newCol.getClass().isArray()) {
375 throw new IllegalArgumentException("Not an array: " + newCol.getClass().getName());
376 }
377
378 int maxLen = 1;
379 if (newCol instanceof String[]) {
380 String[] sa = (String[]) newCol;
381 for (String element : sa) {
382 if (element != null && element.length() > maxLen) {
383 maxLen = element.length();
384 }
385 }
386 } else if (newCol instanceof double[]) {
387 maxLen = DOUBLE_MAX_LENGTH;
388 } else if (newCol instanceof int[]) {
389 maxLen = INT_MAX_LENGTH;
390 } else if (newCol instanceof long[]) {
391 maxLen = LONG_MAX_LENGTH;
392 } else if (newCol instanceof float[]) {
393 maxLen = FLOAT_MAX_LENGTH;
394 } else {
395 throw new FitsException(
396 "No AsciiTable support for elements of " + newCol.getClass().getComponentType().getName());
397 }
398 addColumn(newCol, maxLen);
399
400
401 buffer = null;
402
403 return nFields;
404 }
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425 public int addColumn(Object newCol, int width) throws FitsException, IllegalArgumentException {
426 if (width < 1) {
427 throw new IllegalArgumentException("Illegal ASCII column width: " + width);
428 }
429
430 if (!newCol.getClass().isArray()) {
431 throw new IllegalArgumentException("Not an array: " + newCol.getClass().getName());
432 }
433
434 if (nFields > 0 && Array.getLength(newCol) != nRows) {
435 throw new FitsException(
436 "Mismatched number of rows: expected " + nRows + ", got " + Array.getLength(newCol) + "rows.");
437 }
438
439 if (nFields == 0) {
440 nRows = Array.getLength(newCol);
441 }
442
443 Class<?> type = ArrayFuncs.getBaseClass(newCol);
444 if (type != int.class && type != long.class && type != float.class && type != double.class
445 && type != String.class) {
446 throw new FitsException("No AsciiTable support for elements of " + type.getName());
447 }
448
449 data = Arrays.copyOf(data, nFields + 1);
450 offsets = Arrays.copyOf(offsets, nFields + 1);
451 lengths = Arrays.copyOf(lengths, nFields + 1);
452 types = Arrays.copyOf(types, nFields + 1);
453 nulls = Arrays.copyOf(nulls, nFields + 1);
454 names = Arrays.copyOf(names, nFields + 1);
455
456 data[nFields] = newCol;
457 offsets[nFields] = rowLen + 1;
458 lengths[nFields] = width;
459 types[nFields] = ArrayFuncs.getBaseClass(newCol);
460 names[nFields] = TableHDU.getDefaultColumnName(nFields);
461
462 rowLen += width + 1;
463 if (isNull != null) {
464 boolean[] newIsNull = new boolean[nRows * (nFields + 1)];
465
466 int add = 0;
467 for (int i = 0; i < isNull.length; i++) {
468 if (i % nFields == 0) {
469 add++;
470 }
471 if (isNull[i]) {
472 newIsNull[i + add] = true;
473 }
474 }
475 isNull = newIsNull;
476 }
477 nFields++;
478
479
480 buffer = null;
481
482 return nFields;
483 }
484
485
486
487
488 @Override
489 public int addRow(Object[] newRow) throws FitsException {
490 try {
491
492
493
494 if (nFields == 0) {
495 for (Object element : newRow) {
496 addColumn(element);
497 }
498 } else {
499 for (int i = 0; i < nFields; i++) {
500 Object o = ArrayFuncs.newInstance(types[i], nRows + 1);
501 System.arraycopy(data[i], 0, o, 0, nRows);
502 System.arraycopy(newRow[i], 0, o, nRows, 1);
503 data[i] = o;
504 }
505 nRows++;
506 }
507
508 buffer = null;
509 return nRows;
510 } catch (Exception e) {
511 throw new FitsException("Error adding row:" + e.getMessage(), e);
512 }
513 }
514
515 @Override
516 public void deleteColumns(int start, int len) throws FitsException {
517 ensureData();
518
519 Object[] newData = new Object[nFields - len];
520 int[] newOffsets = new int[nFields - len];
521 int[] newLengths = new int[nFields - len];
522 Class<?>[] newTypes = new Class[nFields - len];
523 String[] newNulls = new String[nFields - len];
524
525
526 System.arraycopy(data, 0, newData, 0, start);
527
528 System.arraycopy(lengths, 0, newLengths, 0, start);
529 System.arraycopy(types, 0, newTypes, 0, start);
530 System.arraycopy(nulls, 0, newNulls, 0, start);
531
532
533 System.arraycopy(data, start + len, newData, start, nFields - start - len);
534
535 System.arraycopy(lengths, start + len, newLengths, start, nFields - start - len);
536 System.arraycopy(types, start + len, newTypes, start, nFields - start - len);
537 System.arraycopy(nulls, start + len, newNulls, start, nFields - start - len);
538
539 for (int i = start; i < start + len; i++) {
540 rowLen -= lengths[i] + 1;
541 }
542
543 data = newData;
544 offsets = newOffsets;
545 lengths = newLengths;
546 types = newTypes;
547 nulls = newNulls;
548
549 if (isNull != null) {
550 boolean found = false;
551
552 boolean[] newIsNull = new boolean[nRows * (nFields - len)];
553 for (int i = 0; i < nRows; i++) {
554 int oldOff = nFields * i;
555 int newOff = (nFields - len) * i;
556 for (int col = 0; col < start; col++) {
557 newIsNull[newOff + col] = isNull[oldOff + col];
558 found = found || isNull[oldOff + col];
559 }
560 for (int col = start + len; col < nFields; col++) {
561 newIsNull[newOff + col - len] = isNull[oldOff + col];
562 found = found || isNull[oldOff + col];
563 }
564 }
565 if (found) {
566 isNull = newIsNull;
567 } else {
568 isNull = null;
569 }
570 }
571
572
573 buffer = null;
574
575 nFields -= len;
576 }
577
578
579
580
581
582 @Override
583 public void deleteRows(int start, int len) throws FitsException {
584 if (nRows == 0 || start < 0 || start >= nRows || len <= 0) {
585 return;
586 }
587 if (start + len > nRows) {
588 len = nRows - start;
589 }
590
591 ensureData();
592
593 for (int i = 0; i < nFields; i++) {
594 try {
595 Object o = ArrayFuncs.newInstance(types[i], nRows - len);
596 System.arraycopy(data[i], 0, o, 0, start);
597 System.arraycopy(data[i], start + len, o, start, nRows - len - start);
598 data[i] = o;
599 } catch (Exception e) {
600 throw new FitsException("Error deleting row: " + e.getMessage(), e);
601 }
602
603 }
604 nRows -= len;
605 }
606
607 @Override
608 protected void loadData(ArrayDataInput in) throws IOException, FitsException {
609 currInput = in;
610
611 if (buffer == null) {
612 getBuffer((long) nRows * rowLen, 0);
613 }
614
615 data = new Object[nFields];
616 for (int i = 0; i < nFields; i++) {
617 data[i] = ArrayFuncs.newInstance(types[i], nRows);
618 }
619
620 bp.setOffset(0);
621
622 int rowOffset;
623 for (int i = 0; i < nRows; i++) {
624 rowOffset = rowLen * i;
625 for (int j = 0; j < nFields; j++) {
626 try {
627 if (!extractElement(rowOffset + offsets[j], lengths[j], data, j, i, nulls[j])) {
628 if (isNull == null) {
629 isNull = new boolean[nRows * nFields];
630 }
631
632 isNull[j + i * nFields] = true;
633 }
634 } catch (ArrayIndexOutOfBoundsException e) {
635 throw new FitsException("not enough data: " + e, e);
636 }
637 }
638 }
639 }
640
641 @Override
642 public void read(ArrayDataInput in) throws FitsException {
643 currInput = in;
644 super.read(in);
645 }
646
647
648
649
650
651
652
653
654
655
656
657
658
659 private boolean extractElement(int offset, int length, Object[] array, int col, int row, String nullFld)
660 throws FitsException {
661
662 bp.setOffset(offset);
663
664 if (nullFld != null) {
665 String s = bp.getString(length);
666 if (s.trim().equals(nullFld)) {
667 return false;
668 }
669 bp.skip(-length);
670 }
671 try {
672 if (array[col] instanceof String[]) {
673 ((String[]) array[col])[row] = bp.getString(length);
674 } else if (array[col] instanceof int[]) {
675 ((int[]) array[col])[row] = bp.getInt(length);
676 } else if (array[col] instanceof float[]) {
677 ((float[]) array[col])[row] = bp.getFloat(length);
678 } else if (array[col] instanceof double[]) {
679 ((double[]) array[col])[row] = bp.getDouble(length);
680 } else if (array[col] instanceof long[]) {
681 ((long[]) array[col])[row] = bp.getLong(length);
682 } else {
683 throw new FitsException("Invalid type for ASCII table conversion:" + array[col]);
684 }
685 } catch (FormatException e) {
686 throw new FitsException("Error parsing data at row,col:" + row + "," + col + " ", e);
687 }
688 return true;
689 }
690
691 @Override
692 protected void fillHeader(Header h) {
693 h.deleteKey(Standard.SIMPLE);
694 h.deleteKey(Standard.EXTEND);
695
696 Standard.context(AsciiTable.class);
697
698 Cursor<String, HeaderCard> c = h.iterator();
699 c.add(HeaderCard.create(Standard.XTENSION, Standard.XTENSION_ASCIITABLE));
700 c.add(HeaderCard.create(Standard.BITPIX, Bitpix.BYTE.getHeaderValue()));
701 c.add(HeaderCard.create(Standard.NAXIS, 2));
702 c.add(HeaderCard.create(Standard.NAXIS1, rowLen));
703 c.add(HeaderCard.create(Standard.NAXIS2, nRows));
704 c.add(HeaderCard.create(Standard.PCOUNT, 0));
705 c.add(HeaderCard.create(Standard.GCOUNT, 1));
706 c.add(HeaderCard.create(Standard.TFIELDS, nFields));
707
708 for (int i = 0; i < nFields; i++) {
709 addColInfo(i, c);
710 }
711
712 Standard.context(null);
713 }
714
715
716
717
718 private void getBuffer(long size, long offset) throws IOException, FitsException {
719
720 if (currInput == null) {
721 throw new IOException("No stream open to read");
722 }
723
724 if (size > Integer.MAX_VALUE) {
725 throw new FitsException("Cannot read ASCII table > 2 GB");
726 }
727
728 buffer = new byte[(int) size];
729 if (offset != 0) {
730 FitsUtil.reposition(currInput, offset);
731 }
732 currInput.readFully(buffer);
733 bp = new ByteParser(buffer);
734 }
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752 @Override
753 public Object getColumn(int col) throws FitsException {
754 ensureData();
755 return data[col];
756 }
757
758 @Override
759 protected Object[] getCurrentData() {
760 return data;
761 }
762
763 @Override
764 public Object[] getData() throws FitsException {
765 return (Object[]) super.getData();
766 }
767
768 @Override
769 public Object getElement(int row, int col) throws FitsException {
770 if (data != null) {
771 return singleElement(row, col);
772 }
773 return parseSingleElement(row, col);
774 }
775
776 @Override
777 public int getNCols() {
778 return nFields;
779 }
780
781 @Override
782 public int getNRows() {
783 return nRows;
784 }
785
786 @Override
787 public Object[] getRow(int row) throws FitsException {
788
789 if (data != null) {
790 return singleRow(row);
791 }
792 return parseSingleRow(row);
793 }
794
795
796
797
798
799
800 public int getRowLen() {
801 return rowLen;
802 }
803
804 @Override
805 protected long getTrueSize() {
806 return (long) nRows * rowLen;
807 }
808
809
810
811
812
813
814
815
816
817 public boolean isNull(int row, int col) {
818 if (isNull != null) {
819 return isNull[row * nFields + col];
820 }
821 return false;
822 }
823
824
825
826
827
828
829 private Object parseSingleElement(int row, int col) throws FitsException {
830
831 Object[] res = new Object[1];
832 try {
833 getBuffer(lengths[col], getFileOffset() + (long) row * (long) rowLen + offsets[col]);
834 } catch (IOException e) {
835 buffer = null;
836 throw new FitsException("Unable to read element", e);
837 }
838 res[0] = ArrayFuncs.newInstance(types[col], 1);
839
840 boolean success = extractElement(0, lengths[col], res, 0, 0, nulls[col]);
841 buffer = null;
842
843 return success ? res[0] : null;
844 }
845
846
847
848
849
850
851 private Object[] parseSingleRow(int row) throws FitsException {
852
853 Object[] res = new Object[nFields];
854
855 try {
856 getBuffer(rowLen, getFileOffset() + (long) row * (long) rowLen);
857 } catch (IOException e) {
858 throw new FitsException("Unable to read row", e);
859 }
860
861 for (int i = 0; i < nFields; i++) {
862 res[i] = ArrayFuncs.newInstance(types[i], 1);
863 if (!extractElement(offsets[i], lengths[i], res, i, 0, nulls[i])) {
864 res[i] = null;
865 }
866 }
867
868
869 buffer = null;
870 return res;
871 }
872
873 @Override
874 public void setColumn(int col, Object newData) throws FitsException {
875 ensureData();
876 if (col < 0 || col >= nFields || newData.getClass() != data[col].getClass()
877 || Array.getLength(newData) != Array.getLength(data[col])) {
878 throw new FitsException("Invalid column/column mismatch:" + col);
879 }
880 data[col] = newData;
881
882
883 buffer = null;
884 }
885
886 @Override
887 public void setElement(int row, int col, Object newData) throws FitsException {
888 ensureData();
889 try {
890 System.arraycopy(newData, 0, data[col], row, 1);
891 } catch (Exception e) {
892 throw new FitsException("Incompatible element:" + row + "," + col, e);
893 }
894 setNull(row, col, false);
895
896
897 buffer = null;
898
899 }
900
901
902
903
904
905
906
907
908
909 public void setNull(int row, int col, boolean flag) {
910 if (flag) {
911 if (isNull == null) {
912 isNull = new boolean[nRows * nFields];
913 }
914 isNull[col + row * nFields] = true;
915 } else if (isNull != null) {
916 isNull[col + row * nFields] = false;
917 }
918
919
920 buffer = null;
921 }
922
923
924
925
926
927 void setNullString(int col, String newNull) {
928 if (col >= 0 && col < nulls.length) {
929 nulls[col] = newNull;
930 }
931 }
932
933 @Override
934 public void setRow(int row, Object[] newData) throws FitsException {
935 if (row < 0 || row > nRows) {
936 throw new FitsException("Invalid row in setRow");
937 }
938 ensureData();
939 for (int i = 0; i < nFields; i++) {
940 try {
941 System.arraycopy(newData[i], 0, data[i], row, 1);
942 } catch (Exception e) {
943 throw new FitsException("Unable to modify row: incompatible data:" + row, e);
944 }
945 setNull(row, i, false);
946 }
947
948
949 buffer = null;
950
951 }
952
953
954
955
956 private Object singleElement(int row, int col) {
957
958 Object res = null;
959 if (isNull == null || !isNull[row * nFields + col]) {
960 res = ArrayFuncs.newInstance(types[col], 1);
961 System.arraycopy(data[col], row, res, 0, 1);
962 }
963 return res;
964 }
965
966
967
968
969 private Object[] singleRow(int row) {
970
971 Object[] res = new Object[nFields];
972 for (int i = 0; i < nFields; i++) {
973 if (isNull == null || !isNull[row * nFields + i]) {
974 res[i] = ArrayFuncs.newInstance(types[i], 1);
975 System.arraycopy(data[i], row, res[i], 0, 1);
976 }
977 }
978 return res;
979 }
980
981
982
983
984
985
986 @Override
987 public void updateAfterDelete(int oldNCol, Header hdr) throws FitsException {
988
989 int offset = 0;
990 for (int i = 0; i < nFields; i++) {
991 offsets[i] = offset;
992 hdr.addValue(TBCOLn.n(i + 1), offset + 1);
993 offset += lengths[i] + 1;
994 }
995 for (int i = nFields; i < oldNCol; i++) {
996 hdr.deleteKey(TBCOLn.n(i + 1));
997 }
998
999 hdr.addValue(NAXIS1, rowLen);
1000 }
1001
1002 @Override
1003 public void write(ArrayDataOutput str) throws FitsException {
1004
1005 if (str != currInput) {
1006 ensureData();
1007 }
1008
1009
1010
1011 if (data == null) {
1012 throw new FitsException("Attempt to write undefined ASCII Table");
1013 }
1014
1015 if ((long) nRows * rowLen > Integer.MAX_VALUE) {
1016 throw new FitsException("Cannot write ASCII table > 2 GB");
1017 }
1018
1019 buffer = new byte[nRows * rowLen];
1020
1021 bp = new ByteParser(buffer);
1022 for (int i = 0; i < buffer.length; i++) {
1023 buffer[i] = (byte) ' ';
1024 }
1025
1026 ByteFormatter bf = new ByteFormatter();
1027
1028 for (int i = 0; i < nRows; i++) {
1029
1030 for (int j = 0; j < nFields; j++) {
1031 int offset = i * rowLen + offsets[j];
1032 int len = lengths[j];
1033 if (isNull != null && isNull[i * nFields + j]) {
1034 if (nulls[j] == null) {
1035 throw new FitsException("No null value set when needed");
1036 }
1037 bf.format(nulls[j], buffer, offset, len);
1038 } else if (types[j] == String.class) {
1039 String[] s = (String[]) data[j];
1040 bf.format(s[i], buffer, offset, len);
1041 } else if (types[j] == int.class) {
1042 int[] ia = (int[]) data[j];
1043 bf.format(ia[i], buffer, offset, len);
1044 } else if (types[j] == float.class) {
1045 float[] fa = (float[]) data[j];
1046 bf.format(fa[i], buffer, offset, len);
1047 } else if (types[j] == double.class) {
1048 double[] da = (double[]) data[j];
1049 bf.format(da[i], buffer, offset, len);
1050 } else if (types[j] == long.class) {
1051 long[] la = (long[]) data[j];
1052 bf.format(la[i], buffer, offset, len);
1053 }
1054 }
1055 }
1056
1057
1058 try {
1059 str.write(buffer);
1060 FitsUtil.pad(str, buffer.length, (byte) ' ');
1061 } catch (IOException e) {
1062 throw new FitsException("Error writing ASCII Table data", e);
1063 }
1064 }
1065
1066 @Override
1067 public AsciiTableHDU toHDU() {
1068 Header h = new Header();
1069 fillHeader(h);
1070 return new AsciiTableHDU(h, this);
1071 }
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090 public static void setI10PreferInt(boolean value) {
1091 isI10PreferInt = value;
1092 }
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105 public static boolean isI10PreferInt() {
1106 return isI10PreferInt;
1107 }
1108 }