1 5 package org.h2.tools; 6 7 import java.io.IOException ; 8 import java.io.InputStream ; 9 import java.io.OutputStream ; 10 import java.sql.SQLException ; 11 import java.util.zip.DeflaterOutputStream ; 12 import java.util.zip.GZIPInputStream ; 13 import java.util.zip.GZIPOutputStream ; 14 import java.util.zip.InflaterInputStream ; 15 import java.util.zip.ZipEntry ; 16 import java.util.zip.ZipInputStream ; 17 import java.util.zip.ZipOutputStream ; 18 19 import org.h2.compress.CompressDeflate; 20 import org.h2.compress.CompressLZF; 21 import org.h2.compress.CompressNo; 22 import org.h2.compress.Compresser; 23 import org.h2.compress.LZFInputStream; 24 import org.h2.compress.LZFOutputStream; 25 import org.h2.message.Message; 26 import org.h2.util.StringUtils; 27 28 31 public class CompressTool { 32 33 private static CompressTool instance = new CompressTool(); 34 private static byte[] buffer; 35 private static int MAX_BUFFER_SIZE = 64 * 1024 * 1024; 36 37 private static byte[] getBuffer(int min) { 38 if(min > MAX_BUFFER_SIZE) { 39 return new byte[min]; 40 } 41 if(buffer == null || buffer.length < min) { 42 buffer = new byte[min]; 43 } 44 return buffer; 45 } 46 47 private CompressTool() { 48 } 49 50 55 public static CompressTool getInstance() { 56 return instance; 57 } 58 59 67 public byte[] compress(byte[] in, String algorithm) throws SQLException { 68 int len = in.length; 69 if(in.length < 5) { 70 algorithm = "NO"; 71 } 72 Compresser compress = getCompresser(algorithm); 73 byte[] buff = getBuffer((len < 100 ? len + 100 : len) * 2); 74 int newLen = compress(in, in.length, compress, buff); 75 byte[] out = new byte[newLen]; 76 System.arraycopy(buff, 0, out, 0, newLen); 77 return out; 78 } 79 80 83 public synchronized int compress(byte[] in, int len, Compresser compress, byte[] out) { 84 int newLen = 0; 85 out[0] = (byte)compress.getAlgorithm(); 86 int start = 1 + writeInt(out, 1, len); 87 newLen = compress.compress(in, len, out, start); 88 if(newLen > len + start || newLen <= 0) { 89 out[0] = Compresser.NO; 90 System.arraycopy(in, 0, out, start, len); 91 newLen = len + start; 92 } 93 return newLen; 94 } 95 96 103 public byte[] expand(byte[] in) throws SQLException { 104 int algorithm = in[0]; 105 Compresser compress = getCompresser(algorithm); 106 try { 107 int len = readInt(in, 1); 108 int start = 1 + getLength(len); 109 byte[] buff = new byte[len]; 110 compress.expand(in, start, in.length-start, buff, 0, len); 111 return buff; 112 } catch(Throwable e) { 113 throw Message.getSQLException(Message.COMPRESSION_ERROR, null, e); 114 } 115 } 116 117 120 public void expand(byte[] in, byte[] out, int outPos) throws SQLException { 121 int algorithm = in[0]; 122 Compresser compress = getCompresser(algorithm); 123 try { 124 int len = readInt(in, 1); 125 int start = 1 + getLength(len); 126 compress.expand(in, start, in.length-start, out, outPos, len); 127 } catch(Throwable e) { 128 throw Message.getSQLException(Message.COMPRESSION_ERROR, null, e); 129 } 130 } 131 132 private int readInt(byte[] buff, int pos) { 133 int x = buff[pos++] & 0xff; 134 if (x < 0x80) { 135 return x; 136 } 137 if (x < 0xc0) { 138 return ((x & 0x3f) << 8) + (buff[pos++] & 0xff); 139 } 140 if (x < 0xe0) { 141 return ((x & 0x1f) << 16) + ((buff[pos++] & 0xff) << 8) + (buff[pos++] & 0xff); 142 } 143 if (x < 0xf0) { 144 return ((x & 0xf) << 24) + ((buff[pos++] & 0xff) << 16) + ((buff[pos++] & 0xff) << 8) + (buff[pos++] & 0xff); 145 } 146 return ((buff[pos++] & 0xff) << 24) + ((buff[pos++] & 0xff) << 16) + ((buff[pos++] & 0xff) << 8) + (buff[pos++] & 0xff); 147 } 148 149 private int writeInt(byte[] buff, int pos, int x) { 150 if (x < 0) { 151 buff[pos++] = (byte) 0xf0; 152 buff[pos++] = (byte) (x >> 24); 153 buff[pos++] = (byte) (x >> 16); 154 buff[pos++] = (byte) (x >> 8); 155 buff[pos++] = (byte) x; 156 return 5; 157 } else if (x < 0x80) { 158 buff[pos++] = (byte) x; 159 return 1; 160 } else if (x < 0x4000) { 161 buff[pos++] = (byte) (0x80 | (x >> 8)); 162 buff[pos++] = (byte) x; 163 return 2; 164 } else if (x < 0x200000) { 165 buff[pos++] = (byte) (0xc0 | (x >> 16)); 166 buff[pos++] = (byte) (x >> 8); 167 buff[pos++] = (byte) x; 168 return 3; 169 } else if (x < 0x10000000) { 170 buff[pos++] = (byte) (0xe0 | (x >> 24)); 171 buff[pos++] = (byte) (x >> 16); 172 buff[pos++] = (byte) (x >> 8); 173 buff[pos++] = (byte) x; 174 return 4; 175 } else { 176 buff[pos++] = (byte) 0xf0; 177 buff[pos++] = (byte) (x >> 24); 178 buff[pos++] = (byte) (x >> 16); 179 buff[pos++] = (byte) (x >> 8); 180 buff[pos++] = (byte) x; 181 return 5; 182 } 183 } 184 185 private int getLength(int x) { 186 if(x<0) { 187 return 5; 188 } else if(x< 0x80) { 189 return 1; 190 } else if(x < 0x4000) { 191 return 2; 192 } else if(x < 0x200000) { 193 return 3; 194 } else if(x < 0x10000000) { 195 return 4; 196 } else { 197 return 5; 198 } 199 } 200 201 private Compresser getCompresser(String algorithm) throws SQLException { 202 if(algorithm == null) { 203 algorithm = "LZF"; 204 } 205 int idx = algorithm.indexOf(' '); 206 String options = null; 207 if(idx > 0) { 208 options = algorithm.substring(idx+1); 209 algorithm = algorithm.substring(0, idx); 210 } 211 int a = getCompressAlgorithm(algorithm); 212 Compresser compress = getCompresser(a); 213 compress.setOptions(options); 214 return compress; 215 } 216 217 220 public int getCompressAlgorithm(String algorithm) throws SQLException { 221 algorithm = StringUtils.toUpperEnglish(algorithm); 222 if("NO".equals(algorithm)) { 223 return Compresser.NO; 224 } else if("LZF".equals(algorithm)) { 225 return Compresser.LZF; 226 } else if("DEFLATE".equals(algorithm)) { 227 return Compresser.DEFLATE; 228 } else { 229 throw Message.getSQLException(Message.UNSUPPORTED_COMPRESSION_ALGORITHM_1, algorithm); 230 } 231 } 232 233 private Compresser getCompresser(int algorithm) throws SQLException { 234 switch(algorithm) { 235 case Compresser.NO: 236 return new CompressNo(); 237 case Compresser.LZF: 238 return new CompressLZF(); 239 case Compresser.DEFLATE: 240 return new CompressDeflate(); 241 default: 242 throw Message.getSQLException(Message.UNSUPPORTED_COMPRESSION_ALGORITHM_1, ""+algorithm); 243 } 244 } 245 246 249 public static OutputStream wrapOutputStream(OutputStream out, String compressionAlgorithm, String entryName) throws SQLException { 250 try { 251 if("GZIP".equals(compressionAlgorithm)) { 252 out = new GZIPOutputStream (out); 253 } else if("ZIP".equals(compressionAlgorithm)) { 254 ZipOutputStream z = new ZipOutputStream (out); 255 z.putNextEntry(new ZipEntry (entryName)); 256 out = z; 257 } else if("DEFLATE".equals(compressionAlgorithm)) { 258 out = new DeflaterOutputStream (out); 259 } else if("LZF".equals(compressionAlgorithm)) { 260 out = new LZFOutputStream(out); 261 } else if(compressionAlgorithm != null) { 262 throw Message.getSQLException(Message.UNSUPPORTED_COMPRESSION_ALGORITHM_1, compressionAlgorithm); 263 } 264 return out; 265 } catch (IOException e) { 266 throw Message.convert(e); 267 } 268 } 269 270 273 public static InputStream wrapInputStream(InputStream in, String compressionAlgorithm, String entryName) throws SQLException { 274 try { 275 if("GZIP".equals(compressionAlgorithm)) { 276 in = new GZIPInputStream (in); 277 } else if("ZIP".equals(compressionAlgorithm)) { 278 ZipInputStream z = new ZipInputStream (in); 279 while(true) { 280 ZipEntry entry = z.getNextEntry(); 281 if(entry == null) { 282 return null; 283 } 284 if(entryName.equals(entry.getName())) { 285 break; 286 } 287 } 288 in = z; 289 } else if("DEFLATE".equals(compressionAlgorithm)) { 290 in = new InflaterInputStream (in); 291 } else if("LZF".equals(compressionAlgorithm)) { 292 in = new LZFInputStream(in); 293 } else if(compressionAlgorithm != null) { 294 throw Message.getSQLException(Message.UNSUPPORTED_COMPRESSION_ALGORITHM_1, compressionAlgorithm); 295 } 296 return in; 297 } catch (IOException e) { 298 throw Message.convert(e); 299 } 300 } 301 302 } 303 304 | Popular Tags |