1
+ /* Copyright (c) 2024 LibJ
2
+ *
3
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ * of this software and associated documentation files (the "Software"), to deal
5
+ * in the Software without restriction, including without limitation the rights
6
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ * copies of the Software, and to permit persons to whom the Software is
8
+ * furnished to do so, subject to the following conditions:
9
+ *
10
+ * The above copyright notice and this permission notice shall be included in
11
+ * all copies or substantial portions of the Software.
12
+ *
13
+ * You should have received a copy of The MIT License (MIT) along with this
14
+ * program. If not, see <http://opensource.org/licenses/MIT/>.
15
+ */
16
+
17
+ package org .libj .util .zip ;
18
+
19
+ import java .io .IOException ;
20
+ import java .io .InputStream ;
21
+ import java .io .OutputStream ;
22
+ import java .util .zip .DeflaterOutputStream ;
23
+
24
+ /**
25
+ * Compresses an {@link InputStream} in a memory-optimal, on-demand way only compressing enough to fill a buffer.
26
+ */
27
+ public class GZIPCompressingInputStream extends InputStream {
28
+ private final InputStream in ;
29
+ private final DeflaterOutputStream out ;
30
+ private final byte [] readBuf = new byte [8192 ];
31
+
32
+ private byte [] buf = new byte [8192 ];
33
+ private int read = 0 ;
34
+ private int write = 0 ;
35
+
36
+ public GZIPCompressingInputStream (final InputStream in ) {
37
+ this .in = in ;
38
+ this .out = new UnsynchronizedGZIPOutputStream (new OutputStream () {
39
+ private void ensureCapacity (final int len ) {
40
+ final int length = buf .length ;
41
+ if (write + len >= length ) {
42
+ final byte [] newbuf = new byte [(length + len ) * 2 ];
43
+ System .arraycopy (buf , 0 , newbuf , 0 , length );
44
+ buf = newbuf ;
45
+ }
46
+ }
47
+
48
+ @ Override
49
+ public void write (final byte [] b , final int off , final int len ) throws IOException {
50
+ ensureCapacity (len );
51
+ System .arraycopy (b , off , buf , write , len );
52
+ write += len ;
53
+ }
54
+
55
+ @ Override
56
+ public void write (final int b ) throws IOException {
57
+ ensureCapacity (1 );
58
+ buf [write ++] = (byte )b ;
59
+ }
60
+ });
61
+ }
62
+
63
+ private void compressStream () throws IOException {
64
+ // If the reader has caught up with the writer, then zero the positions out.
65
+ if (read == write ) {
66
+ read = 0 ;
67
+ write = 0 ;
68
+ }
69
+
70
+ while (write == 0 ) {
71
+ // Feed the gzip stream data until it spits out a block.
72
+ final int val = in .read (readBuf );
73
+ if (val > 0 ) {
74
+ out .write (readBuf , 0 , val );
75
+ }
76
+ else if (val == -1 ) {
77
+ // Nothing left to do, we've hit the end of the stream, so close and break out.
78
+ out .close ();
79
+ break ;
80
+ }
81
+ }
82
+ }
83
+
84
+ @ Override
85
+ public int read (final byte [] b , final int off , final int len ) throws IOException {
86
+ compressStream ();
87
+ final int noBytes = Math .min (len , write - read );
88
+ if (noBytes > 0 ) {
89
+ System .arraycopy (buf , read , b , off , noBytes );
90
+ read += noBytes ;
91
+ }
92
+ else if (len > 0 ) {
93
+ // If bytes were requested, but we have none, then we're at the end of the stream.
94
+ return -1 ;
95
+ }
96
+
97
+ return noBytes ;
98
+ }
99
+
100
+ @ Override
101
+ public int read () throws IOException {
102
+ compressStream ();
103
+ return write == 0 ? -1 : buf [read ++] & 0xFF ;
104
+ }
105
+ }
0 commit comments