40 |
class CompressedOutputStream extends DTPOutputStream |
class CompressedOutputStream extends DTPOutputStream |
41 |
{ |
{ |
42 |
|
|
43 |
static final byte RECORD = -128; // 0x80 |
static final byte RECORD = -128; // 0x80 |
44 |
static final byte EOF = 64; // 0x40 |
static final byte EOF = 64; // 0x40 |
45 |
|
|
46 |
CompressedOutputStream(DTP dtp, OutputStream out) |
CompressedOutputStream(DTP dtp, OutputStream out) |
47 |
{ |
{ |
48 |
super(dtp, out); |
super(dtp, out); |
49 |
} |
} |
50 |
|
|
51 |
/** |
/** |
52 |
* Just one byte cannot be compressed. |
* Just one byte cannot be compressed. |
53 |
* It takes 5 bytes to transmit - hardly very compressed! |
* It takes 5 bytes to transmit - hardly very compressed! |
54 |
*/ |
*/ |
55 |
public void write(int c) throws IOException |
public void write(int c) throws IOException |
56 |
{ |
{ |
57 |
if (transferComplete) |
if (transferComplete) |
58 |
return; |
return; |
59 |
byte[] buf = new byte[] |
byte[] buf = new byte[] |
60 |
{ |
{ |
61 |
RECORD, /* record descriptor */ |
RECORD, /* record descriptor */ |
62 |
0x00, 0x01, /* one byte */ |
0x00, 0x01, /* one byte */ |
63 |
0x01, /* one uncompressed byte */ |
0x01, /* one uncompressed byte */ |
64 |
(byte) c /* the byte */ |
(byte) c /* the byte */ |
65 |
}; |
}; |
66 |
super.write(buf, 0, 5); |
out.write(buf, 0, 5); |
67 |
} |
} |
68 |
|
|
69 |
public void write(byte[]b) throws IOException |
public void write(byte[] b) throws IOException |
70 |
{ |
{ |
71 |
write(b, 0, b.length); |
write(b, 0, b.length); |
72 |
} |
} |
|
|
|
|
/** |
|
|
* The larger len is, the better. |
|
|
*/ |
|
|
public void write(byte[]b, int off, int len) throws IOException |
|
|
{ |
|
|
if (transferComplete) |
|
|
return; |
|
|
byte[] buf = compress(b, off, len); |
|
|
len = buf.length; |
|
|
buf[0] = RECORD; /* record descriptor */ |
|
|
buf[1] = (byte) ((len & 0x00ff) >> 8); /* high byte of bytecount */ |
|
|
buf[2] = (byte) (len & 0xff00); /* low byte of bytecount */ |
|
|
super.write(buf, 0, len); |
|
|
} |
|
73 |
|
|
74 |
/** |
/** |
75 |
* Returns the compressed form of the given byte array. |
* The larger len is, the better. |
76 |
* The first 3 bytes are left free for header information. |
*/ |
77 |
*/ |
public void write(byte[] b, int off, int len) throws IOException |
78 |
byte[] compress(byte[]b, int off, int len) |
{ |
79 |
{ |
if (transferComplete) |
80 |
byte[]buf = new byte[len]; |
return; |
81 |
byte last = 0; |
byte[] buf = compress(b, off, len); |
82 |
int pos = 0, raw_count = 0, rep_count = 1; |
len = buf.length; |
83 |
for (int i = off; i < len; i++) |
buf[0] = RECORD; /* record descriptor */ |
84 |
{ |
buf[1] = (byte) ((len & 0x00ff) >> 8); /* high byte of bytecount */ |
85 |
byte c = b[i]; |
buf[2] = (byte) (len & 0xff00); /* low byte of bytecount */ |
86 |
if (i > off && c == last) // compress |
out.write(buf, 0, len); |
87 |
{ |
} |
88 |
if (raw_count > 0) // flush raw bytes to buf |
|
89 |
|
/** |
90 |
|
* Returns the compressed form of the given byte array. |
91 |
|
* The first 3 bytes are left free for header information. |
92 |
|
*/ |
93 |
|
byte[] compress(byte[] b, int off, int len) |
94 |
|
{ |
95 |
|
byte[] buf = new byte[len]; |
96 |
|
byte last = 0; |
97 |
|
int pos = 0, raw_count = 0, rep_count = 1; |
98 |
|
for (int i = off; i < len; i++) |
99 |
{ |
{ |
100 |
// need to add raw_count+1 bytes |
byte c = b[i]; |
101 |
if (pos + (raw_count + 1) > buf.length) |
if (i > off && c == last) // compress |
102 |
buf = realloc(buf, len); |
{ |
103 |
pos = flush_raw(buf, pos, b, (i - raw_count) - 1, raw_count); |
if (raw_count > 0) // flush raw bytes to buf |
104 |
raw_count = 0; |
{ |
105 |
|
// need to add raw_count+1 bytes |
106 |
|
if (pos + (raw_count + 1) > buf.length) |
107 |
|
buf = realloc(buf, len); |
108 |
|
pos = flush_raw(buf, pos, b, (i - raw_count) - 1, raw_count); |
109 |
|
raw_count = 0; |
110 |
|
} |
111 |
|
rep_count++; // keep looking for same byte |
112 |
|
} |
113 |
|
else |
114 |
|
{ |
115 |
|
if (rep_count > 1) // flush compressed bytes to buf |
116 |
|
{ |
117 |
|
// need to add 2 bytes |
118 |
|
if (pos + 2 > buf.length) |
119 |
|
buf = realloc(buf, len); |
120 |
|
pos = flush_compressed(buf, pos, rep_count, last); |
121 |
|
rep_count = 1; |
122 |
|
} |
123 |
|
raw_count++; // keep looking for raw bytes |
124 |
|
} |
125 |
|
if (rep_count == 127) // flush compressed bytes |
126 |
|
{ |
127 |
|
// need to add 2 bytes |
128 |
|
if (pos + 2 > buf.length) |
129 |
|
buf = realloc(buf, len); |
130 |
|
pos = flush_compressed(buf, pos, rep_count, last); |
131 |
|
rep_count = 1; |
132 |
|
} |
133 |
|
if (raw_count == 127) // flush raw bytes |
134 |
|
{ |
135 |
|
// need to add raw_count+1 bytes |
136 |
|
if (pos + (raw_count + 1) > buf.length) |
137 |
|
buf = realloc(buf, len); |
138 |
|
pos = flush_raw(buf, pos, b, (i - raw_count), raw_count); |
139 |
|
raw_count = 0; |
140 |
|
} |
141 |
|
last = c; |
142 |
} |
} |
143 |
rep_count++; // keep looking for same byte |
if (rep_count > 1) // flush compressed bytes |
|
} |
|
|
else |
|
|
{ |
|
|
if (rep_count > 1) // flush compressed bytes to buf |
|
144 |
{ |
{ |
145 |
// need to add 2 bytes |
// need to add 2 bytes |
146 |
if (pos + 2 > buf.length) |
if (pos + 2 > buf.length) |
147 |
buf = realloc(buf, len); |
buf = realloc(buf, len); |
148 |
pos = flush_compressed(buf, pos, rep_count, last); |
pos = flush_compressed(buf, pos, rep_count, last); |
149 |
rep_count = 1; |
rep_count = 1; |
150 |
} |
} |
151 |
raw_count++; // keep looking for raw bytes |
if (raw_count > 0) // flush raw bytes |
152 |
} |
{ |
153 |
if (rep_count == 127) // flush compressed bytes |
// need to add raw_count+1 bytes |
154 |
{ |
if (pos + (raw_count + 1) > buf.length) |
155 |
// need to add 2 bytes |
buf = realloc(buf, len); |
156 |
if (pos + 2 > buf.length) |
pos = flush_raw(buf, pos, b, (len - raw_count), raw_count); |
157 |
buf = realloc(buf, len); |
raw_count = 0; |
158 |
pos = flush_compressed(buf, pos, rep_count, last); |
} |
159 |
rep_count = 1; |
byte[] ret = new byte[pos + 3]; |
160 |
} |
System.arraycopy(buf, 0, ret, 3, pos); |
161 |
if (raw_count == 127) // flush raw bytes |
return ret; |
162 |
{ |
} |
|
// need to add raw_count+1 bytes |
|
|
if (pos + (raw_count + 1) > buf.length) |
|
|
buf = realloc(buf, len); |
|
|
pos = flush_raw(buf, pos, b, (i - raw_count), raw_count); |
|
|
raw_count = 0; |
|
|
} |
|
|
last = c; |
|
|
} |
|
|
if (rep_count > 1) // flush compressed bytes |
|
|
{ |
|
|
// need to add 2 bytes |
|
|
if (pos + 2 > buf.length) |
|
|
buf = realloc(buf, len); |
|
|
pos = flush_compressed(buf, pos, rep_count, last); |
|
|
rep_count = 1; |
|
|
} |
|
|
if (raw_count > 0) // flush raw bytes |
|
|
{ |
|
|
// need to add raw_count+1 bytes |
|
|
if (pos + (raw_count + 1) > buf.length) |
|
|
buf = realloc(buf, len); |
|
|
pos = flush_raw(buf, pos, b, (len - raw_count), raw_count); |
|
|
raw_count = 0; |
|
|
} |
|
|
byte[]ret = new byte[pos + 3]; |
|
|
System.arraycopy(buf, 0, ret, 3, pos); |
|
|
return ret; |
|
|
} |
|
|
|
|
|
int flush_compressed(byte[]buf, int pos, int count, byte c) |
|
|
{ |
|
|
buf[pos++] = (byte) (0x80 | count); |
|
|
buf[pos++] = c; |
|
|
return pos; |
|
|
} |
|
|
|
|
|
int flush_raw(byte[]buf, int pos, byte[]src, int off, int len) |
|
|
{ |
|
|
buf[pos++] = (byte) len; |
|
|
System.arraycopy(src, off, buf, pos, len); |
|
|
return pos + len; |
|
|
} |
|
|
|
|
|
byte[]realloc(byte[]buf, int len) |
|
|
{ |
|
|
byte[]ret = new byte[buf.length + len]; |
|
|
System.arraycopy(buf, 0, ret, 0, buf.length); |
|
|
return ret; |
|
|
} |
|
163 |
|
|
164 |
public void close() throws IOException |
int flush_compressed(byte[] buf, int pos, int count, byte c) |
165 |
{ |
{ |
166 |
byte[] buf = new byte[] |
buf[pos++] = (byte) (0x80 | count); |
167 |
{ |
buf[pos++] = c; |
168 |
EOF, /* eof descriptor */ |
return pos; |
169 |
0x00, 0x00 /* no bytes */ |
} |
170 |
}; |
|
171 |
super.write(buf, 0, 3); |
int flush_raw(byte[] buf, int pos, byte[] src, int off, int len) |
172 |
super.close(); |
{ |
173 |
} |
buf[pos++] = (byte) len; |
174 |
|
System.arraycopy(src, off, buf, pos, len); |
175 |
|
return pos + len; |
176 |
|
} |
177 |
|
|
178 |
|
byte[] realloc(byte[] buf, int len) |
179 |
|
{ |
180 |
|
byte[] ret = new byte[buf.length + len]; |
181 |
|
System.arraycopy(buf, 0, ret, 0, buf.length); |
182 |
|
return ret; |
183 |
|
} |
184 |
|
|
185 |
|
public void close() throws IOException |
186 |
|
{ |
187 |
|
byte[] buf = new byte[] |
188 |
|
{ |
189 |
|
EOF, /* eof descriptor */ |
190 |
|
0x00, 0x00 /* no bytes */ |
191 |
|
}; |
192 |
|
out.write(buf, 0, 3); |
193 |
|
out.close(); |
194 |
|
} |
195 |
|
|
196 |
} |
} |