1 // 2 // Copyright (c) ZeroC, Inc. All rights reserved. 3 // 4 5 package IceInternal; 6 7 public class BZip2 8 { compress(Buffer buf, int headerSize, int compressionLevel)9 public static Buffer compress(Buffer buf, int headerSize, int compressionLevel) 10 { 11 assert(supported()); 12 13 int uncompressedLen = buf.size() - headerSize; 14 int compressedLen = (int)(uncompressedLen * 1.01 + 600); 15 byte[] compressed = new byte[compressedLen]; 16 17 byte[] data = null; 18 int offset = 0; 19 try 20 { 21 // 22 // If the ByteBuffer is backed by an array then we can avoid 23 // an extra copy by using the array directly. 24 // 25 data = buf.b.array(); 26 offset = buf.b.arrayOffset(); 27 } 28 catch(Exception ex) 29 { 30 // 31 // Otherwise, allocate an array to hold a copy of the uncompressed data. 32 // 33 data = new byte[buf.size()]; 34 buf.position(0); 35 buf.b.get(data); 36 } 37 38 try 39 { 40 // 41 // Compress the data using the class org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream. 42 // Its constructor requires an OutputStream argument, therefore we pass the 43 // compressed buffer in an OutputStream wrapper. 44 // 45 BufferedOutputStream bos = new BufferedOutputStream(compressed); 46 java.lang.Object[] args = new java.lang.Object[]{ bos, Integer.valueOf(compressionLevel) }; 47 java.io.OutputStream os = (java.io.OutputStream)_bzOutputStreamCtor.newInstance(args); 48 os.write(data, offset + headerSize, uncompressedLen); 49 os.close(); 50 compressedLen = bos.pos(); 51 } 52 catch(Exception ex) 53 { 54 throw new Ice.CompressionException("bzip2 compression failure", ex); 55 } 56 57 // 58 // Don't bother if the compressed data is larger than the 59 // uncompressed data. 60 // 61 if(compressedLen >= uncompressedLen) 62 { 63 return null; 64 } 65 66 Buffer r = new Buffer(false); 67 r.resize(headerSize + 4 + compressedLen, false); 68 r.position(0); 69 70 // 71 // Copy the header from the uncompressed stream to the compressed one. 72 // 73 r.b.put(data, offset, headerSize); 74 75 // 76 // Add the size of the uncompressed stream before the message body. 77 // 78 r.b.putInt(buf.size()); 79 80 // 81 // Add the compressed message body. 82 // 83 r.b.put(compressed, 0, compressedLen); 84 85 return r; 86 } 87 uncompress(Buffer buf, int headerSize, int messageSizeMax)88 public static Buffer uncompress(Buffer buf, int headerSize, int messageSizeMax) 89 { 90 assert(supported()); 91 92 buf.position(headerSize); 93 int uncompressedSize = buf.b.getInt(); 94 if(uncompressedSize <= headerSize) 95 { 96 throw new Ice.IllegalMessageSizeException(); 97 } 98 if(uncompressedSize > messageSizeMax) 99 { 100 IceInternal.Ex.throwMemoryLimitException(uncompressedSize, messageSizeMax); 101 } 102 103 int compressedLen = buf.size() - headerSize - 4; 104 105 byte[] compressed = null; 106 int offset = 0; 107 try 108 { 109 // 110 // If the ByteBuffer is backed by an array then we can avoid 111 // an extra copy by using the array directly. 112 // 113 compressed = buf.b.array(); 114 offset = buf.b.arrayOffset(); 115 } 116 catch(Exception ex) 117 { 118 // 119 // Otherwise, allocate an array to hold a copy of the compressed data. 120 // 121 compressed = new byte[buf.size()]; 122 buf.position(0); 123 buf.b.get(compressed); 124 } 125 126 Buffer r = new Buffer(false); 127 r.resize(uncompressedSize, false); 128 129 try 130 { 131 // 132 // Uncompress the data using the class org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream. 133 // Its constructor requires an InputStream argument, therefore we pass the 134 // compressed data in a ByteArrayInputStream. 135 // 136 java.io.ByteArrayInputStream bais = 137 new java.io.ByteArrayInputStream(compressed, offset + headerSize + 4, compressedLen); 138 java.lang.Object[] args = new java.lang.Object[]{ bais }; 139 java.io.InputStream is = (java.io.InputStream)_bzInputStreamCtor.newInstance(args); 140 r.position(headerSize); 141 byte[] arr = new byte[8 * 1024]; 142 int n; 143 while((n = is.read(arr)) != -1) 144 { 145 r.b.put(arr, 0, n); 146 } 147 is.close(); 148 } 149 catch(Exception ex) 150 { 151 throw new Ice.CompressionException("bzip2 uncompression failure", ex); 152 } 153 154 // 155 // Copy the header from the compressed stream to the uncompressed one. 156 // 157 r.position(0); 158 r.b.put(compressed, offset, headerSize); 159 160 return r; 161 } 162 163 private static boolean _checked = false; 164 private static java.lang.reflect.Constructor<?> _bzInputStreamCtor; 165 private static java.lang.reflect.Constructor<?> _bzOutputStreamCtor; 166 supported()167 public synchronized static boolean supported() 168 { 169 // 170 // Use lazy initialization when determining whether support for bzip2 compression is available. 171 // 172 if(!_checked) 173 { 174 _checked = true; 175 try 176 { 177 Class<?> cls; 178 Class<?>[] types = new Class<?>[1]; 179 cls = IceInternal.Util.findClass("org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream", null); 180 if(cls != null) 181 { 182 types[0] = java.io.InputStream.class; 183 _bzInputStreamCtor = cls.getDeclaredConstructor(types); 184 } 185 cls = IceInternal.Util.findClass("org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream", null); 186 if(cls != null) 187 { 188 types = new Class[2]; 189 types[0] = java.io.OutputStream.class; 190 types[1] = Integer.TYPE; 191 _bzOutputStreamCtor = cls.getDeclaredConstructor(types); 192 } 193 } 194 catch(Exception ex) 195 { 196 // Ignore - bzip2 compression not available. 197 } 198 } 199 return _bzInputStreamCtor != null && _bzOutputStreamCtor != null; 200 } 201 202 private static class BufferedOutputStream extends java.io.OutputStream 203 { BufferedOutputStream(byte[] data)204 BufferedOutputStream(byte[] data) 205 { 206 _data = data; 207 } 208 209 @Override close()210 public void close() 211 throws java.io.IOException 212 { 213 } 214 215 @Override flush()216 public void flush() 217 throws java.io.IOException 218 { 219 } 220 221 @Override write(byte[] b)222 public void write(byte[] b) 223 throws java.io.IOException 224 { 225 assert(_data.length - _pos >= b.length); 226 System.arraycopy(b, 0, _data, _pos, b.length); 227 _pos += b.length; 228 } 229 230 @Override write(byte[] b, int off, int len)231 public void write(byte[] b, int off, int len) 232 throws java.io.IOException 233 { 234 assert(_data.length - _pos >= len); 235 System.arraycopy(b, off, _data, _pos, len); 236 _pos += len; 237 } 238 239 @Override write(int b)240 public void write(int b) 241 throws java.io.IOException 242 { 243 assert(_data.length - _pos >= 1); 244 _data[_pos] = (byte)b; 245 ++_pos; 246 } 247 248 int pos()249 pos() 250 { 251 return _pos; 252 } 253 254 private byte[] _data; 255 private int _pos; 256 } 257 } 258