1 package nom.tam.fits.compression.algorithm.gzip2;
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 import java.nio.DoubleBuffer;
38 import java.nio.FloatBuffer;
39 import java.nio.IntBuffer;
40 import java.nio.LongBuffer;
41 import java.nio.ShortBuffer;
42 import java.util.zip.GZIPInputStream;
43 import java.util.zip.GZIPOutputStream;
44
45 import nom.tam.fits.compression.algorithm.gzip.GZipCompressor;
46 import nom.tam.util.type.ElementType;
47
48 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
49
50
51
52
53
54
55 @SuppressWarnings("javadoc")
56 public abstract class GZip2Compressor<T extends Buffer> extends GZipCompressor<T> {
57
58 public static class ByteGZip2Compressor extends ByteGZipCompressor {
59 }
60
61 public static class IntGZip2Compressor extends GZip2Compressor<IntBuffer> {
62
63 public IntGZip2Compressor() {
64 super(ElementType.INT.size());
65 }
66
67 @Override
68 protected void getPixel(IntBuffer pixelData, byte[] pixelBytes) {
69 IntBuffer pixelBuffer = ByteBuffer.wrap(pixelBytes).asIntBuffer();
70 pixelBuffer.put(pixelData);
71 }
72
73 @Override
74 protected void setPixel(IntBuffer pixelData, byte[] pixelBytes) {
75 pixelData.put(ByteBuffer.wrap(pixelBytes).asIntBuffer());
76 }
77 }
78
79 public static class FloatGZip2Compressor extends GZip2Compressor<FloatBuffer> {
80
81 public FloatGZip2Compressor() {
82 super(ElementType.FLOAT.size());
83 }
84
85 @Override
86 protected void getPixel(FloatBuffer pixelData, byte[] pixelBytes) {
87 FloatBuffer pixelBuffer = ByteBuffer.wrap(pixelBytes).asFloatBuffer();
88 pixelBuffer.put(pixelData);
89 }
90
91 @Override
92 protected void setPixel(FloatBuffer pixelData, byte[] pixelBytes) {
93 pixelData.put(ByteBuffer.wrap(pixelBytes).asFloatBuffer());
94 }
95 }
96
97 public static class LongGZip2Compressor extends GZip2Compressor<LongBuffer> {
98
99 public LongGZip2Compressor() {
100 super(ElementType.LONG.size());
101 }
102
103 @Override
104 protected void getPixel(LongBuffer pixelData, byte[] pixelBytes) {
105 LongBuffer pixelBuffer = ByteBuffer.wrap(pixelBytes).asLongBuffer();
106 pixelBuffer.put(pixelData);
107 }
108
109 @Override
110 protected void setPixel(LongBuffer pixelData, byte[] pixelBytes) {
111 pixelData.put(ByteBuffer.wrap(pixelBytes).asLongBuffer());
112 }
113 }
114
115 public static class DoubleGZip2Compressor extends GZip2Compressor<DoubleBuffer> {
116
117 public DoubleGZip2Compressor() {
118 super(ElementType.DOUBLE.size());
119 }
120
121 @Override
122 protected void getPixel(DoubleBuffer pixelData, byte[] pixelBytes) {
123 DoubleBuffer pixelBuffer = ByteBuffer.wrap(pixelBytes).asDoubleBuffer();
124 pixelBuffer.put(pixelData);
125 }
126
127 @Override
128 protected void setPixel(DoubleBuffer pixelData, byte[] pixelBytes) {
129 pixelData.put(ByteBuffer.wrap(pixelBytes).asDoubleBuffer());
130 }
131 }
132
133 public static class ShortGZip2Compressor extends GZip2Compressor<ShortBuffer> {
134
135 public ShortGZip2Compressor() {
136 super(ElementType.SHORT.size());
137 }
138
139 @Override
140 protected void getPixel(ShortBuffer pixelData, byte[] pixelBytes) {
141 ShortBuffer shortBuffer = ByteBuffer.wrap(pixelBytes).asShortBuffer();
142 shortBuffer.put(pixelData);
143 }
144
145 @Override
146 protected void setPixel(ShortBuffer pixelData, byte[] pixelBytes) {
147 pixelData.put(ByteBuffer.wrap(pixelBytes).asShortBuffer());
148 }
149 }
150
151 public GZip2Compressor(int primitiveSize) {
152 super(primitiveSize);
153 }
154
155 private int[] calculateOffsets(byte[] byteArray) {
156 int[] offset = new int[primitiveSize];
157 offset[0] = 0;
158 for (int primitivIndex = 1; primitivIndex < primitiveSize; primitivIndex++) {
159 offset[primitivIndex] = offset[primitivIndex - 1] + byteArray.length / primitiveSize;
160 }
161 return offset;
162 }
163
164 @Override
165 @SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE", justification = "what null check is FB even referring to?")
166 public boolean compress(T pixelData, ByteBuffer compressed) {
167 int pixelDataLimit = pixelData.limit();
168 byte[] pixelBytes = new byte[pixelDataLimit * primitiveSize];
169 getPixel(pixelData, pixelBytes);
170 pixelBytes = shuffle(pixelBytes);
171 try (GZIPOutputStream zip = createGZipOutputStream(pixelDataLimit, compressed)) {
172
173 zip.write(pixelBytes, 0, pixelBytes.length);
174 } catch (IOException e) {
175 throw new IllegalStateException("could not gzip data", e);
176 }
177 return true;
178 }
179
180 @Override
181 public void decompress(ByteBuffer compressed, T pixelData) {
182 int pixelDataLimit = pixelData.limit();
183 byte[] pixelBytes = new byte[pixelDataLimit * primitiveSize];
184 try (GZIPInputStream zip = createGZipInputStream(compressed)) {
185 int count = 0;
186 int offset = 0;
187 while (offset < pixelBytes.length && count >= 0) {
188 count = zip.read(pixelBytes, offset, pixelBytes.length - offset);
189 if (count >= 0) {
190 offset = offset + count;
191 }
192 }
193 } catch (IOException e) {
194 throw new IllegalStateException("could not gunzip data", e);
195 }
196 pixelBytes = unshuffle(pixelBytes);
197 setPixel(pixelData, pixelBytes);
198 }
199
200 public byte[] shuffle(byte[] byteArray) {
201 byte[] result = new byte[byteArray.length];
202 int resultIndex = 0;
203 int[] offset = calculateOffsets(byteArray);
204 for (int index = 0; index < byteArray.length; index += primitiveSize) {
205 for (int primitiveIndex = 0; primitiveIndex < primitiveSize; primitiveIndex++) {
206 result[resultIndex + offset[primitiveIndex]] = byteArray[index + primitiveIndex];
207 }
208 resultIndex++;
209 }
210 return result;
211 }
212
213 public byte[] unshuffle(byte[] byteArray) {
214 byte[] result = new byte[byteArray.length];
215 int resultIndex = 0;
216 int[] offset = calculateOffsets(byteArray);
217 for (int index = 0; index < byteArray.length; index += primitiveSize) {
218 for (int primitiveIndex = 0; primitiveIndex < primitiveSize; primitiveIndex++) {
219 result[index + primitiveIndex] = byteArray[resultIndex + offset[primitiveIndex]];
220 }
221 resultIndex++;
222 }
223 return result;
224 }
225 }