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