/** * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.util; import it.unimi.dsi.fastutil.bytes.ByteArrayList; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.Enumeration; import java.util.zip.DataFormatException; import java.util.zip.Deflater; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; import java.util.zip.Inflater; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.opengamma.OpenGammaRuntimeException; /** * Utility methods to assist with ZIP files. * <p> * This is a thread-safe static utility class. */ public final class ZipUtils { /** Logger. */ private static final Logger s_logger = LoggerFactory.getLogger(ZipUtils.class); /** * Restricted constructor */ private ZipUtils() { } //------------------------------------------------------------------------- /** * Unzips a ZIP archive. * * @param archive the archive file, not null * @param outputDir the output directory, not null */ public static void unzipArchive(final File archive, final File outputDir) { ArgumentChecker.notNull(archive, "archive"); ArgumentChecker.notNull(outputDir, "outputDir"); s_logger.debug("Unzipping file:{} to {}", archive, outputDir); try { FileUtils.forceMkdir(outputDir); unzipArchive(new ZipFile(archive), outputDir); } catch (Exception ex) { throw new OpenGammaRuntimeException("Error while extracting file: " + archive + " to: " + outputDir, ex); } } //------------------------------------------------------------------------- /** * Unzips a ZIP archive. * * @param zipFile the archive file, not null * @param outputDir the output directory, not null */ public static void unzipArchive(final ZipFile zipFile, final File outputDir) { ArgumentChecker.notNull(zipFile, "zipFile"); ArgumentChecker.notNull(outputDir, "outputDir"); try { Enumeration<? extends ZipEntry> entries = zipFile.entries(); while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); if (entry.isDirectory()) { FileUtils.forceMkdir(new File(outputDir, entry.getName())); continue; } File entryDestination = new File(outputDir, entry.getName()); entryDestination.getParentFile().mkdirs(); InputStream in = zipFile.getInputStream(entry); OutputStream out = new FileOutputStream(entryDestination); IOUtils.copy(in, out); IOUtils.closeQuietly(in); IOUtils.closeQuietly(out); } zipFile.close(); } catch (IOException ex) { throw new OpenGammaRuntimeException("Error while extracting file: " + zipFile.getName() + " to: " + outputDir, ex); } } //------------------------------------------------------------------------- /** * GZIP compress a {@code String}. * <p> * This only produces GZIP format. * * @param input the string to compress, not null * @return the compressed bytes, not null */ public static byte[] zipString(final String input) { return zipString(input, false); } /** * GZIP compress a {@code String}. * <p> * If optimizing then the compressor checks if UTF-8 is shorter and just uses that. * * @param input the string to compress, not null * @param optimize true to optimize length by not compressing if shorter * @return the compressed bytes, not null */ public static byte[] zipString(final String input, boolean optimize) { ArgumentChecker.notNull(input, "input"); byte[] bytes = input.getBytes(StandardCharsets.UTF_8); if (optimize && input.length() < 20) { return bytes; } ByteArrayOutputStream baos = new ByteArrayOutputStream(input.length()); try (GZIPOutputStream out = new GZIPOutputStream(baos)) { out.write(bytes); } catch (IOException ex) { throw new OpenGammaRuntimeException(ex.getMessage(), ex); } byte[] result = baos.toByteArray(); if (optimize && result.length > bytes.length) { return bytes; } return result; } /** * GZIP uncompress to a {@code String}. * <p> * This expects the magic '1F 9D' prefix for GZIP. * If it does not find it then uncompressed UTF-8 is assumed. * * @param input the bytes to compress, not null * @return the compressed string, not null */ public static String unzipString(final byte[] input) { ArgumentChecker.notNull(input, "input"); if (input.length < 2 || input[0] != 31 || input[1] != -117) { // GZIP (1F 9D) return new String(input, StandardCharsets.UTF_8); } try (ByteArrayInputStream bais = new ByteArrayInputStream(input)) { try (GZIPInputStream in = new GZIPInputStream(bais)) { byte[] bytes = IOUtils.toByteArray(in); return new String(bytes, StandardCharsets.UTF_8); } } catch (IOException ex) { throw new OpenGammaRuntimeException(ex.getMessage(), ex); } } //------------------------------------------------------------------------- /** * ZLIB compress a {@code String}. * <p> * This only produces ZLIB format using {@code Deflater}. * * @param input the string to compress, not null * @return the compressed bytes, not null */ public static byte[] deflateString(final String input) { ArgumentChecker.notNull(input, "input"); byte[] bytes = input.getBytes(StandardCharsets.UTF_8); Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION); deflater.setInput(bytes); ByteArrayList collector = new ByteArrayList(bytes.length + 32); byte[] buf = new byte[1024]; deflater.finish(); while (deflater.finished() == false) { int size = deflater.deflate(buf); collector.addElements(collector.size(), buf, 0, size); } deflater.end(); return collector.toByteArray(); } /** * ZLIB uncompress to a {@code String}. * <p> * This only handles ZLIB format using {@code Inflater}. * * @param input the bytes to compress, not null * @return the compressed string, not null */ public static String inflateString(final byte[] input) { ArgumentChecker.notNull(input, "input"); try { Inflater inflater = new Inflater(); inflater.setInput(input); ByteArrayList collector = new ByteArrayList(input.length * 4); byte[] buf = new byte[1024]; while (inflater.finished() == false) { int size = inflater.inflate(buf); collector.addElements(collector.size(), buf, 0, size); } inflater.end(); byte[] bytes = collector.toByteArray(); return new String(bytes, StandardCharsets.UTF_8); } catch (DataFormatException ex) { throw new OpenGammaRuntimeException(ex.getMessage(), ex); } } }