Skip to content

Commit 75432fa

Browse files
committed
Add gzip c
1 parent 472d743 commit 75432fa

File tree

5 files changed

+122
-6
lines changed

5 files changed

+122
-6
lines changed

CHANGELOG

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* add bitAt() utility
66
* add hash feature
77
* add checksum transformer
8+
* add gzip transformer
89

910
## v0.4.0
1011

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,15 @@ Bytes.wrap(array).transform(checksumCrc32());
211211
Bytes.wrap(array).transform(checksum(new Adler32(), ChecksumTransformer.Mode.TRANSFORM, 4));
212212
```
213213

214+
**GZip compression**:
215+
216+
```java
217+
import static at.favre.lib.bytes.BytesTransformers.*;
218+
219+
Bytes compressed = Bytes.wrap(array).transform(compressGzip());
220+
Bytes decompressed = compressed.transform(decompressGzip());
221+
```
222+
214223
Other transformers:
215224

216225
```java

src/main/java/at/favre/lib/bytes/BytesTransformers.java

Lines changed: 81 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
package at.favre.lib.bytes;
22

3+
import java.io.ByteArrayInputStream;
4+
import java.io.ByteArrayOutputStream;
35
import java.util.Objects;
46
import java.util.zip.CRC32;
57
import java.util.zip.Checksum;
8+
import java.util.zip.GZIPInputStream;
9+
import java.util.zip.GZIPOutputStream;
610

711
/**
812
* Collection of additional {@link BytesTransformer} for more specific use cases
@@ -30,10 +34,6 @@ public static BytesTransformer checksumCrc32() {
3034
return new ChecksumTransformer(new CRC32(), ChecksumTransformer.Mode.TRANSFORM, 4);
3135
}
3236

33-
/**
34-
* Create a {@link BytesTransformer} which transforms to 4 byte Crc32 checksum of given bytes
35-
* @return transformer
36-
*/
3737
/**
3838
* Create a {@link BytesTransformer} which transforms to 4 byte Crc32 checksum of given bytes
3939
*
@@ -47,6 +47,28 @@ public static BytesTransformer checksum(Checksum checksum, ChecksumTransformer.M
4747
return new ChecksumTransformer(checksum, mode, checksumLengthByte);
4848
}
4949

50+
/**
51+
* Create a {@link BytesTransformer} which gzip compresses the internal byte array
52+
*
53+
* @return transformer
54+
* @throws IllegalStateException if compression was not possible (i.e. wrapped {@link java.io.IOException})
55+
* @see <a href="https://en.wikipedia.org/wiki/Gzip">Gzip</a>
56+
*/
57+
public static BytesTransformer compressGzip() {
58+
return new GzipCompressor(true);
59+
}
60+
61+
/**
62+
* Create a {@link BytesTransformer} which gzip decompresses the internal byte array
63+
*
64+
* @return transformer
65+
* @throws IllegalStateException if compression was not possible (i.e. wrapped {@link java.io.IOException})
66+
* @see <a href="https://en.wikipedia.org/wiki/Gzip">Gzip</a>
67+
*/
68+
public static BytesTransformer decompressGzip() {
69+
return new GzipCompressor(false);
70+
}
71+
5072
/**
5173
* Adds or converts to arbitrary checksum
5274
*/
@@ -67,7 +89,7 @@ enum Mode {
6789
private final int checksumLengthByte;
6890

6991
public ChecksumTransformer(Checksum checksum, Mode mode, int checksumLengthByte) {
70-
if (checksumLengthByte < 0 || checksumLengthByte > 8)
92+
if (checksumLengthByte <= 0 || checksumLengthByte > 8)
7193
throw new IllegalArgumentException("checksumlength must be between 1 and 8 bytes");
7294

7395
Objects.requireNonNull(checksum, "checksum instance must not be null");
@@ -88,4 +110,58 @@ public byte[] transform(byte[] currentArray, boolean inPlace) {
88110
}
89111
}
90112
}
113+
114+
/**
115+
* Byte compression with gzip
116+
*/
117+
final static class GzipCompressor implements BytesTransformer {
118+
private final boolean compress;
119+
120+
public GzipCompressor(boolean compress) {
121+
this.compress = compress;
122+
}
123+
124+
@Override
125+
public byte[] transform(byte[] currentArray, boolean inPlace) {
126+
return compress ? compress(currentArray) : decompress(currentArray);
127+
}
128+
129+
private byte[] decompress(byte[] compressedContent) {
130+
ByteArrayOutputStream bos = new ByteArrayOutputStream();
131+
GZIPInputStream gzipInputStream = null;
132+
byte[] returnBuffer;
133+
try {
134+
int len;
135+
byte buffer[] = new byte[4 * 1024];
136+
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedContent));
137+
138+
while ((len = gzipInputStream.read(buffer)) > 0) {
139+
bos.write(buffer, 0, len);
140+
}
141+
142+
gzipInputStream.close();
143+
returnBuffer = bos.toByteArray();
144+
bos.close();
145+
return returnBuffer;
146+
} catch (Exception e) {
147+
throw new IllegalStateException("could not decompress gzip", e);
148+
}
149+
}
150+
151+
private byte[] compress(byte[] content) {
152+
ByteArrayOutputStream bos = new ByteArrayOutputStream(content.length);
153+
GZIPOutputStream gzipOutputStream = null;
154+
byte[] returnBuffer;
155+
try {
156+
gzipOutputStream = new GZIPOutputStream(bos);
157+
gzipOutputStream.write(content);
158+
gzipOutputStream.close();
159+
returnBuffer = bos.toByteArray();
160+
bos.close();
161+
return returnBuffer;
162+
} catch (Exception e) {
163+
throw new IllegalStateException("could not compress gzip", e);
164+
}
165+
}
166+
}
91167
}

src/main/java/at/favre/lib/bytes/BytesValidators.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
/**
2828
* Util and easy access for {@link BytesValidators}
2929
*/
30-
public class BytesValidators {
30+
public final class BytesValidators {
3131

3232
private BytesValidators() {
3333
}

src/test/java/at/favre/lib/bytes/BytesTransformTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,11 @@ public void bitSwitchOutOfBounds() throws Exception {
273273
@Test
274274
public void hash() throws Exception {
275275
assertEquals(Bytes.parseHex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"), Bytes.from("").hashSha256());
276+
assertEquals(Bytes.parseHex("e362eea626386c93a54c9b82e6b896c0350fbff0ee12f284660253aac0908cfb"), Bytes.from("ö9h%6Ghh1\"").hashSha256());
276277
assertEquals(Bytes.parseHex("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"), Bytes.from("").hashSha512());
278+
assertEquals(Bytes.parseHex("106747C3DDC117091BEF8D21AEBAA8D314656D3AE1135AB36F4C0B07A264127CF625FE616751BEC66B43032B904E2D3B6C21BF14E078F6BB775A72503F48111D"), Bytes.from("ö9h%6Ghh1\"").hashSha512());
279+
assertEquals(Bytes.parseHex("d41d8cd98f00b204e9800998ecf8427e"), Bytes.from("").hash("MD5"));
280+
assertEquals(Bytes.parseHex("ff38205f1cb22f588d8bc9ae21f22092"), Bytes.from("ö9h%6Ghh1\"").hash("MD5"));
277281
}
278282

279283
@Test
@@ -289,6 +293,32 @@ public void checksumTest() throws Exception {
289293
Bytes.from(example2_bytes_seven).transform(checksum(new Adler32(), ChecksumTransformer.Mode.TRANSFORM, 4)));
290294
}
291295

296+
@Test(expected = IllegalArgumentException.class)
297+
public void checksumTestIllegalByteLengthTooShort() throws Exception {
298+
Bytes.from(example2_bytes_seven).transform(checksum(new CRC32(), ChecksumTransformer.Mode.TRANSFORM, 0));
299+
}
300+
301+
@Test(expected = IllegalArgumentException.class)
302+
public void checksumTestIllegalByteLengthTooLong() throws Exception {
303+
Bytes.from(example2_bytes_seven).transform(checksum(new CRC32(), ChecksumTransformer.Mode.TRANSFORM, 9));
304+
}
305+
306+
@Test
307+
public void testCompress() throws Exception {
308+
for (int i = 1; i < 10; i++) {
309+
testCompressInternal(256 * i);
310+
}
311+
}
312+
313+
private void testCompressInternal(int length) {
314+
Bytes emptyArray = Bytes.allocate(length);
315+
byte[] compressed = Bytes.from(emptyArray).transform(compressGzip()).array();
316+
byte[] uncompressed = Bytes.wrap(compressed).transform(decompressGzip()).array();
317+
assertArrayEquals(emptyArray.array(), uncompressed);
318+
assertArrayNotEquals(compressed, uncompressed);
319+
assertTrue("compressed is not smaller " + compressed.length + " vs " + uncompressed.length, compressed.length < uncompressed.length);
320+
}
321+
292322
@Test
293323
public void transform() throws Exception {
294324
assertArrayEquals(example_bytes_two, Bytes.from(example_bytes_two).transform(new BytesTransformer() {

0 commit comments

Comments
 (0)