1 package nom.tam.image.compression.bintable;
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.nio.Buffer;
36 import java.nio.ByteBuffer;
37
38 import nom.tam.fits.BinaryTable;
39 import nom.tam.fits.FitsException;
40 import nom.tam.fits.compression.algorithm.api.ICompressorControl;
41 import nom.tam.image.compression.hdu.CompressedTableData;
42 import nom.tam.image.compression.hdu.CompressedTableHDU;
43 import nom.tam.util.ByteBufferInputStream;
44 import nom.tam.util.ColumnTable;
45 import nom.tam.util.FitsInputStream;
46 import nom.tam.util.type.ElementType;
47
48
49
50
51 @SuppressWarnings("javadoc")
52 public class BinaryTableTileDecompressor extends BinaryTableTile {
53
54 private BinaryTable orig;
55
56 private final CompressedTableData compressed;
57
58 private int targetColumn = column;
59
60
61
62
63
64
65 public BinaryTableTileDecompressor(CompressedTableData compressedTable, ColumnTable<?> columnTable,
66 BinaryTableTileDescription description) throws FitsException {
67 super(columnTable, description);
68 compressed = compressedTable;
69 }
70
71 public BinaryTableTileDecompressor(CompressedTableData compressedTable, BinaryTable table,
72 BinaryTableTileDescription description) throws FitsException {
73 this(compressedTable, table.getData(), description);
74 orig = table;
75 }
76
77 private void decompressVariable() throws IOException {
78 int nRows = rowEnd - rowStart;
79 boolean longPointers = orig.getDescriptor(targetColumn).hasLongPointers();
80
81
82 ByteBuffer pdata = ByteBuffer.wrap((byte[]) compressed.getElement(getTileIndex(), column));
83 ByteBuffer pointers = ByteBuffer
84 .allocateDirect((2 * nRows) * (Long.BYTES + (longPointers ? Long.BYTES : Integer.BYTES)));
85
86 getGZipCompressorControl().decompress(pdata, pointers, null);
87 pointers.flip();
88
89 long[][] cdesc = new long[nRows][2];
90 Object p = longPointers ? new long[nRows][2] : new int[nRows][2];
91
92 try (FitsInputStream ips = new FitsInputStream(new ByteBufferInputStream(pointers))) {
93 if (CompressedTableHDU.hasOldStandardVLAIndexing()) {
94
95
96 ips.readLArray(cdesc);
97
98 ips.readLArray(p);
99 } else {
100
101
102 ips.readLArray(p);
103
104 ips.readLArray(cdesc);
105 }
106 }
107
108 ElementType<?> dataType = ElementType.forClass(orig.getDescriptor(column).getElementClass());
109
110 ICompressorControl compressor = getCompressorControl(dataType.primitiveClass());
111
112
113 final Object bak = compressed.getData().getElement(getTileIndex(), column);
114
115 try {
116 for (int r = 0; r < nRows; r++) {
117 long csize = cdesc[r][0];
118 long coffset = cdesc[r][1];
119
120 if (csize < 0 || csize > Integer.MAX_VALUE || coffset < 0 || coffset > Integer.MAX_VALUE) {
121 throw new FitsException(
122 "Illegal or unsupported compressed heap pointer (offset=" + coffset + ", size=" + csize);
123 }
124
125 long dcount = longPointers ? ((long[][]) p)[r][0] : ((int[][]) p)[r][0];
126 long doffset = longPointers ? ((long[][]) p)[r][1] : ((int[][]) p)[r][1];
127
128 if (dcount < 0 || dcount > Integer.MAX_VALUE || doffset < 0 || doffset > Integer.MAX_VALUE) {
129 throw new FitsException(
130 "Illegal or unsupported uncompressed heap pointer (offset=" + doffset + ", size=" + dcount);
131 }
132
133
134
135 Object temp = bak instanceof long[] ? new long[] {csize, coffset} : new int[] {(int) csize, (int) coffset};
136 compressed.getData().setElement(getTileIndex(), column, temp);
137
138
139 ByteBuffer zip = ByteBuffer.wrap((byte[]) compressed.getElement(getTileIndex(), column));
140 Buffer buf = dataType.newBuffer(dcount);
141 compressor.decompress(zip, buf, null);
142 buf.flip();
143
144
145 data.setElement(rowStart + r, targetColumn, longPointers ? ((long[][]) p)[r] : ((int[][]) p)[r]);
146
147
148 orig.setElement(rowStart + r, targetColumn, buf.array());
149 }
150 } finally {
151
152 compressed.getData().setElement(getTileIndex(), column, bak);
153 }
154 }
155
156 private void decompressTableTile() throws IOException {
157 ByteBuffer zip = ByteBuffer.wrap((byte[]) compressed.getElement(getTileIndex(), column));
158 ByteBuffer buf = ByteBuffer.allocateDirect(getUncompressedSizeInBytes());
159
160 getCompressorControl().decompress(zip, type.asTypedBuffer(buf), null);
161 buf.rewind();
162
163 try (FitsInputStream is = new FitsInputStream(new ByteBufferInputStream(buf))) {
164 data.read(is, rowStart, rowEnd, targetColumn);
165 }
166 }
167
168 @Override
169 public void run() {
170 try {
171 if (orig != null && orig.getDescriptor(targetColumn).isVariableSize()) {
172
173 decompressVariable();
174 } else {
175
176 decompressTableTile();
177 }
178 } catch (IOException e) {
179 throw new IllegalStateException(e.getMessage(), e);
180 }
181 }
182
183
184
185
186
187
188
189
190
191
192
193
194
195 public BinaryTableTileDecompressor decompressToColumn(int col) {
196 targetColumn = col;
197 return this;
198 }
199
200 }