首页

分享apache的commons-compress的TarUtils压缩工具类对文件数据进行加解密、解析及格式化校验等操作

标签:commons-compress,apache,TarUtils,tar工具类     发布时间:2018-02-15   

一、前言

基于apachecommons-compress包中的org.apache.commons.compress.archivers.tar.TarUtils打包工具类对文件进行加解密、并对加密包文件解析解析parseOctal/parseBinaryLong/parseBinaryBigInteger/parseName、对文件包字节数据进行格式化formatNameBytes/formatUnsignedOctalString/formatLongBinary/formatBigIntegerBinary/formatCheckSumOctalBytes等操作。

二、源码说明

package org.apache.commons.compress.archivers.tar;@b@@b@import java.io.IOException;@b@import java.math.BigInteger;@b@import java.nio.ByteBuffer;@b@import org.apache.commons.compress.archivers.zip.ZipEncoding;@b@import org.apache.commons.compress.archivers.zip.ZipEncodingHelper;@b@@b@public class TarUtils@b@{@b@  private static final int BYTE_MASK = 255;@b@  static final ZipEncoding DEFAULT_ENCODING = ZipEncodingHelper.getZipEncoding(null);@b@  static final ZipEncoding FALLBACK_ENCODING = new ZipEncoding() {@b@    public boolean canEncode(String name) { return true; }@b@@b@    public ByteBuffer encode(String name) {@b@      int length = name.length();@b@      byte[] buf = new byte[length];@b@@b@      for (int i = 0; i < length; ++i)@b@        buf[i] = (byte)name.charAt(i);@b@@b@      return ByteBuffer.wrap(buf);@b@    }@b@@b@    public String decode(byte[] buffer) {@b@      int length = buffer.length;@b@      StringBuffer result = new StringBuffer(length);@b@@b@      for (int i = 0; i < length; ++i) {@b@        byte b = buffer[i];@b@        if (b == 0)@b@          break;@b@@b@        result.append((char)(b & 0xFF));@b@      }@b@@b@      return result.toString();@b@    }@b@  };@b@@b@  public static long parseOctal(byte[] buffer, int offset, int length)@b@  {@b@    long result = 0L;@b@    int end = offset + length;@b@    int start = offset;@b@@b@    if (length < 2) {@b@      throw new IllegalArgumentException("Length " + length + " must be at least 2");@b@    }@b@@b@    if (buffer[start] == 0) {@b@      return 0L;@b@    }@b@@b@    while ((start < end) && @b@      (buffer[start] == 32)) {@b@      ++start;@b@    }@b@@b@    byte trailer = buffer[(end - 1)];@b@    if ((trailer == 0) || (trailer == 32))@b@      --end;@b@    else {@b@      throw new IllegalArgumentException(exceptionMessage(buffer, offset, length, end - 1, trailer));@b@    }@b@@b@    trailer = buffer[(end - 1)];@b@    while ((start < end - 1) && (((trailer == 0) || (trailer == 32)))) {@b@      --end;@b@      trailer = buffer[(end - 1)];@b@    }@b@@b@    for (; start < end; ++start) {@b@      byte currentByte = buffer[start];@b@@b@      if ((currentByte < 48) || (currentByte > 55)) {@b@        throw new IllegalArgumentException(exceptionMessage(buffer, offset, length, start, currentByte));@b@      }@b@@b@      result = (result << 3) + currentByte - 48;@b@    }@b@@b@    return result;@b@  }@b@@b@  public static long parseOctalOrBinary(byte[] buffer, int offset, int length)@b@  {@b@    if ((buffer[offset] & 0x80) == 0)@b@      return parseOctal(buffer, offset, length);@b@@b@    boolean negative = buffer[offset] == -1;@b@    if (length < 9)@b@      return parseBinaryLong(buffer, offset, length, negative);@b@@b@    return parseBinaryBigInteger(buffer, offset, length, negative);@b@  }@b@@b@  private static long parseBinaryLong(byte[] buffer, int offset, int length, boolean negative)@b@  {@b@    if (length >= 9) {@b@      throw new IllegalArgumentException("At offset " + offset + ", " + length + " byte binary number" + " exceeds maximum signed long" + " value");@b@    }@b@@b@    long val = 0L;@b@    for (int i = 1; i < length; ++i)@b@      val = (val << 8) + (buffer[(offset + i)] & 0xFF);@b@@b@    if (negative)@b@    {@b@      val -= 1L;@b@      val ^= ()Math.pow(2.0D, (length - 1) * 8) - 1L;@b@    }@b@    return ((negative) ? -val : val);@b@  }@b@@b@  private static long parseBinaryBigInteger(byte[] buffer, int offset, int length, boolean negative)@b@  {@b@    byte[] remainder = new byte[length - 1];@b@    System.arraycopy(buffer, offset + 1, remainder, 0, length - 1);@b@    BigInteger val = new BigInteger(remainder);@b@    if (negative)@b@    {@b@      val = val.add(BigInteger.valueOf(-1L)).not();@b@    }@b@    if (val.bitLength() > 63) {@b@      throw new IllegalArgumentException("At offset " + offset + ", " + length + " byte binary number" + " exceeds maximum signed long" + " value");@b@    }@b@@b@    return ((negative) ? -val.longValue() : val.longValue());@b@  }@b@@b@  public static boolean parseBoolean(byte[] buffer, int offset)@b@  {@b@    return (buffer[offset] == 1);@b@  }@b@@b@  private static String exceptionMessage(byte[] buffer, int offset, int length, int current, byte currentByte)@b@  {@b@    String string = new String(buffer, offset, length);@b@    string = string.replaceAll("", "{NUL}");@b@    String s = "Invalid byte " + currentByte + " at offset " + (current - offset) + " in '" + string + "' len=" + length;@b@    return s;@b@  }@b@@b@  public static String parseName(byte[] buffer, int offset, int length)@b@  {@b@    try@b@    {@b@      return parseName(buffer, offset, length, DEFAULT_ENCODING);@b@    } catch (IOException ex) {@b@      try {@b@        return parseName(buffer, offset, length, FALLBACK_ENCODING);@b@      }@b@      catch (IOException ex2) {@b@        throw new RuntimeException(ex2);@b@      }@b@    }@b@  }@b@@b@  public static String parseName(byte[] buffer, int offset, int length, ZipEncoding encoding)@b@    throws IOException@b@  {@b@    int len = length;@b@    for (; len > 0; --len)@b@      if (buffer[(offset + len - 1)] != 0)@b@        break;@b@@b@@b@    if (len > 0) {@b@      byte[] b = new byte[len];@b@      System.arraycopy(buffer, offset, b, 0, len);@b@      return encoding.decode(b);@b@    }@b@    return "";@b@  }@b@@b@  public static int formatNameBytes(String name, byte[] buf, int offset, int length)@b@  {@b@    try@b@    {@b@      return formatNameBytes(name, buf, offset, length, DEFAULT_ENCODING);@b@    } catch (IOException ex) {@b@      try {@b@        return formatNameBytes(name, buf, offset, length, FALLBACK_ENCODING);@b@      }@b@      catch (IOException ex2)@b@      {@b@        throw new RuntimeException(ex2);@b@      }@b@    }@b@  }@b@@b@  public static int formatNameBytes(String name, byte[] buf, int offset, int length, ZipEncoding encoding)@b@    throws IOException@b@  {@b@    int len = name.length();@b@    ByteBuffer b = encoding.encode(name);@b@    while ((b.limit() > length) && (len > 0))@b@      b = encoding.encode(name.substring(0, --len));@b@@b@    int limit = b.limit() - b.position();@b@    System.arraycopy(b.array(), b.arrayOffset(), buf, offset, limit);@b@@b@    for (int i = limit; i < length; ++i) {@b@      buf[(offset + i)] = 0;@b@    }@b@@b@    return (offset + length);@b@  }@b@@b@  public static void formatUnsignedOctalString(long value, byte[] buffer, int offset, int length)@b@  {@b@    int remaining = length;@b@    --remaining;@b@    if (value == 0L) {@b@      buffer[(offset + remaining--)] = 48;@b@    } else {@b@      long val = value;@b@      for (; (remaining >= 0) && (val != 0L); --remaining)@b@      {@b@        buffer[(offset + remaining)] = (byte)(48 + (byte)(int)(val & 0x7));@b@        val >>>= 3;@b@      }@b@@b@      if (val != 0L) {@b@        throw new IllegalArgumentException(value + "=" + Long.toOctalString(value) + " will not fit in octal number buffer of length " + length);@b@      }@b@@b@    }@b@@b@    for (; remaining >= 0; --remaining)@b@      buffer[(offset + remaining)] = 48;@b@  }@b@@b@  public static int formatOctalBytes(long value, byte[] buf, int offset, int length)@b@  {@b@    int idx = length - 2;@b@    formatUnsignedOctalString(value, buf, offset, idx);@b@@b@    buf[(offset + idx++)] = 32;@b@    buf[(offset + idx)] = 0;@b@@b@    return (offset + length);@b@  }@b@@b@  public static int formatLongOctalBytes(long value, byte[] buf, int offset, int length)@b@  {@b@    int idx = length - 1;@b@@b@    formatUnsignedOctalString(value, buf, offset, idx);@b@    buf[(offset + idx)] = 32;@b@@b@    return (offset + length);@b@  }@b@@b@  public static int formatLongOctalOrBinaryBytes(long value, byte[] buf, int offset, int length)@b@  {@b@    long maxAsOctalChar = (length == 8) ? 2097151L : 8589934591L;@b@@b@    boolean negative = value < 0L;@b@    if ((!(negative)) && (value <= maxAsOctalChar)) {@b@      return formatLongOctalBytes(value, buf, offset, length);@b@    }@b@@b@    if (length < 9)@b@      formatLongBinary(value, buf, offset, length, negative);@b@@b@    formatBigIntegerBinary(value, buf, offset, length, negative);@b@@b@    buf[offset] = (byte)((negative) ? 255 : 128);@b@    return (offset + length);@b@  }@b@@b@  private static void formatLongBinary(long value, byte[] buf, int offset, int length, boolean negative)@b@  {@b@    int bits = (length - 1) * 8;@b@    long max = 1L << bits;@b@    long val = Math.abs(value);@b@    if (val >= max) {@b@      throw new IllegalArgumentException("Value " + value + " is too large for " + length + " byte field.");@b@    }@b@@b@    if (negative) {@b@      val ^= max - 1L;@b@      val |= 255 << bits;@b@      val += 1L;@b@    }@b@    for (int i = offset + length - 1; i >= offset; --i) {@b@      buf[i] = (byte)(int)val;@b@      val >>= 8;@b@    }@b@  }@b@@b@  private static void formatBigIntegerBinary(long value, byte[] buf, int offset, int length, boolean negative)@b@  {@b@    BigInteger val = BigInteger.valueOf(value);@b@    byte[] b = val.toByteArray();@b@    int len = b.length;@b@    int off = offset + length - len;@b@    System.arraycopy(b, 0, buf, off, len);@b@    byte fill = (byte)((negative) ? 255 : 0);@b@    for (int i = offset + 1; i < off; ++i)@b@      buf[i] = fill;@b@  }@b@@b@  public static int formatCheckSumOctalBytes(long value, byte[] buf, int offset, int length)@b@  {@b@    int idx = length - 2;@b@    formatUnsignedOctalString(value, buf, offset, idx);@b@@b@    buf[(offset + idx++)] = 0;@b@    buf[(offset + idx)] = 32;@b@@b@    return (offset + length);@b@  }@b@@b@  public static long computeCheckSum(byte[] buf)@b@  {@b@    long sum = 0L;@b@@b@    for (int i = 0; i < buf.length; ++i) {@b@      sum += (0xFF & buf[i]);@b@    }@b@@b@    return sum;@b@  }@b@@b@  public static boolean verifyCheckSum(byte[] header)@b@  {@b@    long storedSum = 0L;@b@    long unsignedSum = 0L;@b@    long signedSum = 0L;@b@@b@    int digits = 0;@b@    for (int i = 0; i < header.length; ++i) {@b@      byte b = header[i];@b@      if ((148 <= i) && (i < 156)) {@b@        if ((48 <= b) && (b <= 55) && (digits++ < 6))@b@          storedSum = storedSum * 8L + b - 48L;@b@        else if (digits > 0)@b@          digits = 6;@b@@b@        b = 32;@b@      }@b@      unsignedSum += (0xFF & b);@b@      signedSum += b;@b@    }@b@@b@    return ((storedSum == unsignedSum) || (storedSum == signedSum) || (storedSum > unsignedSum));@b@  }@b@}

ZipEncoding接口

package org.apache.commons.compress.archivers.zip;@b@@b@import java.io.IOException;@b@import java.nio.ByteBuffer;@b@@b@public abstract interface ZipEncoding@b@{@b@  public abstract boolean canEncode(String paramString);@b@@b@  public abstract ByteBuffer encode(String paramString)@b@    throws IOException;@b@@b@  public abstract String decode(byte[] paramArrayOfByte)@b@    throws IOException;@b@}

ZipEncodingHelper类

package org.apache.commons.compress.archivers.zip;@b@@b@import java.nio.ByteBuffer;@b@import java.nio.charset.Charset;@b@import java.nio.charset.UnsupportedCharsetException;@b@import java.util.Collections;@b@import java.util.HashMap;@b@import java.util.Map;@b@@b@public abstract class ZipEncodingHelper@b@{@b@  private static final Map<String, SimpleEncodingHolder> simpleEncodings;@b@  private static final byte[] HEX_DIGITS;@b@  static final String UTF8 = "UTF8";@b@  private static final String UTF_DASH_8 = "UTF-8";@b@  static final ZipEncoding UTF8_ZIP_ENCODING;@b@@b@  static ByteBuffer growBuffer(ByteBuffer b, int newCapacity)@b@  {@b@    b.limit(b.position());@b@    b.rewind();@b@@b@    int c2 = b.capacity() * 2;@b@    ByteBuffer on = ByteBuffer.allocate((c2 < newCapacity) ? newCapacity : c2);@b@@b@    on.put(b);@b@    return on;@b@  }@b@@b@  static void appendSurrogate(ByteBuffer bb, char c)@b@  {@b@    bb.put(37);@b@    bb.put(85);@b@@b@    bb.put(HEX_DIGITS[(c >> '\f' & 0xF)]);@b@    bb.put(HEX_DIGITS[(c >> '\b' & 0xF)]);@b@    bb.put(HEX_DIGITS[(c >> '\4' & 0xF)]);@b@    bb.put(HEX_DIGITS[(c & 0xF)]);@b@  }@b@@b@  public static ZipEncoding getZipEncoding(String name)@b@  {@b@    if (isUTF8(name)) {@b@      return UTF8_ZIP_ENCODING;@b@    }@b@@b@    if (name == null) {@b@      return new FallbackZipEncoding();@b@    }@b@@b@    SimpleEncodingHolder h = (SimpleEncodingHolder)simpleEncodings.get(name);@b@@b@    if (h != null) {@b@      return h.getEncoding();@b@    }@b@@b@    try@b@    {@b@      Charset cs = Charset.forName(name);@b@      return new NioZipEncoding(cs);@b@    } catch (UnsupportedCharsetException e) {@b@    }@b@    return new FallbackZipEncoding(name);@b@  }@b@@b@  static boolean isUTF8(String encoding)@b@  {@b@    if (encoding == null)@b@    {@b@      encoding = System.getProperty("file.encoding");@b@    }@b@    return (("UTF8".equalsIgnoreCase(encoding)) || ("UTF-8".equalsIgnoreCase(encoding)));@b@  }@b@@b@  static@b@  {@b@    Map se = new HashMap();@b@@b@    char[] cp437_high_chars = { 199, 252, 233, 226, 228, 224, 229, 231, 234, 235, 232, 239, 238, 236, 196, 197, 201, 230, 198, 244, 246, 242, 251, 249, 255, 214, 220, 162, 163, 165, 8359, 402, 225, 237, 243, 250, 241, 209, 170, 186, 191, 8976, 172, 189, 188, 161, 171, 187, 9617, 9618, 9619, 9474, 9508, 9569, 9570, 9558, 9557, 9571, 9553, 9559, 9565, 9564, 9563, 9488, 9492, 9524, 9516, 9500, 9472, 9532, 9566, 9567, 9562, 9556, 9577, 9574, 9568, 9552, 9580, 9575, 9576, 9572, 9573, 9561, 9560, 9554, 9555, 9579, 9578, 9496, 9484, 9608, 9604, 9612, 9616, 9600, 945, 223, 915, 960, 931, 963, 181, 964, 934, 920, 937, 948, 8734, 966, 949, 8745, 8801, 177, 8805, 8804, 8992, 8993, 247, 8776, 176, 8729, 183, 8730, 8319, 178, 9632, 160 };@b@@b@    SimpleEncodingHolder cp437 = new SimpleEncodingHolder(cp437_high_chars);@b@@b@    se.put("CP437", cp437);@b@    se.put("Cp437", cp437);@b@    se.put("cp437", cp437);@b@    se.put("IBM437", cp437);@b@    se.put("ibm437", cp437);@b@@b@    char[] cp850_high_chars = { 199, 252, 233, 226, 228, 224, 229, 231, 234, 235, 232, 239, 238, 236, 196, 197, 201, 230, 198, 244, 246, 242, 251, 249, 255, 214, 220, 248, 163, 216, 215, 402, 225, 237, 243, 250, 241, 209, 170, 186, 191, 174, 172, 189, 188, 161, 171, 187, 9617, 9618, 9619, 9474, 9508, 193, 194, 192, 169, 9571, 9553, 9559, 9565, 162, 165, 9488, 9492, 9524, 9516, 9500, 9472, 9532, 227, 195, 9562, 9556, 9577, 9574, 9568, 9552, 9580, 164, 240, 208, 202, 203, 200, 305, 205, 206, 207, 9496, 9484, 9608, 9604, 166, 204, 9600, 211, 223, 212, 210, 245, 213, 181, 254, 222, 218, 219, 217, 253, 221, 175, 180, 173, 177, 8215, 190, 182, 167, 247, 184, 176, 168, 183, 185, 179, 178, 9632, 160 };@b@@b@    SimpleEncodingHolder cp850 = new SimpleEncodingHolder(cp850_high_chars);@b@@b@    se.put("CP850", cp850);@b@    se.put("Cp850", cp850);@b@    se.put("cp850", cp850);@b@    se.put("IBM850", cp850);@b@    se.put("ibm850", cp850);@b@    simpleEncodings = Collections.unmodifiableMap(se);@b@@b@    HEX_DIGITS = new byte[] { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70 };@b@@b@    UTF8_ZIP_ENCODING = new FallbackZipEncoding("UTF8");@b@  }@b@@b@  private static class SimpleEncodingHolder@b@  {@b@    private final char[] highChars;@b@    private Simple8BitZipEncoding encoding;@b@@b@    SimpleEncodingHolder(char[] highChars)@b@    {@b@      this.highChars = highChars;@b@    }@b@@b@    public synchronized Simple8BitZipEncoding getEncoding()@b@    {@b@      if (this.encoding == null)@b@        this.encoding = new Simple8BitZipEncoding(this.highChars);@b@@b@      return this.encoding;@b@    }@b@  }@b@}