content: package com.alipay.api.internal.util;
  
  import com.alipay.api.AlipayApiException;
  
  import java.io.*;
  import java.net.HttpURLConnection;
  import java.net.URL;
  import java.security.DigestInputStream;
  import java.security.MessageDigest;
  import java.util.ArrayList;
  import java.util.Enumeration;
  import java.util.List;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  import java.util.zip.GZIPInputStream;
  import java.util.zip.ZipEntry;
  import java.util.zip.ZipFile;
  
  /**
   * 异步API下载工具类。
   *
   * @author carver.gu
   * @since 1.0, Dec 1, 2010
   */
  public abstract class AtsUtils {
  
      private static final String  CTYPE_OCTET     = "application/octet-stream";
      private static final Pattern REGEX_FILE_NAME = Pattern.compile("attachment;filename=\"([\\w\\-]+)\"");
  
      private AtsUtils() {
      }
  
      /**
       * 解压gzip文件到指定的目录，目前只能解压gzip包里面只包含一个文件的压缩包。
       *
       * @param gzip  需要解压的gzip文件
       * @param toDir 需要解压到的目录
       * @return 解压后的文件
       * @throws IOException
       */
      public static File ungzip(File gzip, File toDir) throws IOException {
          toDir.mkdirs();
          File out = new File(toDir, gzip.getName());
          GZIPInputStream gin = null;
          FileOutputStream fout = null;
          try {
              FileInputStream fin = new FileInputStream(gzip);
              gin = new GZIPInputStream(fin);
              fout = new FileOutputStream(out);
              copy(gin, fout);
              gin.close();
              fout.close();
          } finally {
              closeQuietly(gin);
              closeQuietly(fout);
          }
          return out;
      }
  
      /**
       * 解压zip文件到指定的目录。
       *
       * @param zip   需要解压的zip文件
       * @param toDir 需要解压到的目录
       * @return 解压后的文件列表（不包含文件夹）
       */
      public static List<File> unzip(File zip, File toDir) throws IOException {
          ZipFile zf = null;
          List<File> files = null;
          try {
              zf = new ZipFile(zip);
              files = new ArrayList<File>();
              Enumeration<?> entries = zf.entries();
              while (entries.hasMoreElements()) {
                  ZipEntry entry = (ZipEntry) entries.nextElement();
                  if (!pathSecurityCheck(entry.getName())) {
                      continue;
                  }
                  if (entry.isDirectory()) {
                      new File(toDir, entry.getName()).mkdirs();
                      continue;
                  }
  
                  InputStream input = null;
                  OutputStream output = null;
                  try {
                      File f = new File(toDir, entry.getName());
                      input = zf.getInputStream(entry);
                      output = new FileOutputStream(f);
                      copy(input, output);
                      files.add(f);
                  } finally {
                      closeQuietly(output);
                      closeQuietly(input);
                  }
              }
          } finally {
              if (zf != null) {
                  zf.close();
              }
          }
          return files;
      }
  
      /**
       * 通过HTTP GET方式下载文件到指定的目录。
       *
       * @param url   需要下载的URL
       * @param toDir 需要下载到的目录
       * @return 下载后的文件
       */
      public static File download(String url, File toDir) throws AlipayApiException {
          toDir.mkdirs();
          HttpURLConnection conn = null;
          OutputStream output = null;
          File file = null;
          try {
              conn = getConnection(new URL(url));
              String ctype = conn.getContentType();
              if (CTYPE_OCTET.equals(ctype)) {
                  String fileName = getFileName(conn);
                  file = new File(toDir, fileName);
                  output = new FileOutputStream(file);
                  copy(conn.getInputStream(), output);
              } else {
                  String rsp = WebUtils.getResponseAsString(conn);
                  throw new AlipayApiException(rsp);
              }
          } catch (IOException e) {
              throw new AlipayApiException(e.getMessage());
          } finally {
              closeQuietly(output);
              if (conn != null) {
                  conn.disconnect();
              }
          }
          return file;
      }
  
      /**
       * 检查指定文件的md5sum和指定的检验码是否一致。
       *
       * @param file      需要检验的文件
       * @param checkCode 已知的md5sum检验码
       * @return true/false
       */
      public static boolean checkMd5sum(File file, String checkCode) throws IOException {
          DigestInputStream dInput = null;
          try {
              FileInputStream fInput = new FileInputStream(file);
              dInput = new DigestInputStream(fInput, getMd5Instance());
              byte[] buf = new byte[8192];
              while (dInput.read(buf) > 0) {
              }
              byte[] bytes = dInput.getMessageDigest().digest();
              return bytes2hex(bytes).equals(checkCode);
          } finally {
              closeQuietly(dInput);
          }
      }
  
      /**
       * 把字节数组转换成十六进制的字符串。
       */
      private static String bytes2hex(byte[] bytes) {
          StringBuilder sb = new StringBuilder();
          for (int i = 0; i < bytes.length; i++) {
              String hex = Integer.toHexString(bytes[i] & 0XFF);
              if (hex.length() == 1) {
                  sb.append("0").append(hex);
              } else {
                  sb.append(hex);
              }
          }
          return sb.toString();
      }
  
      private static MessageDigest getMd5Instance() {
          try {
              return MessageDigest.getInstance("md5");
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
      }
  
      private static String getFileName(HttpURLConnection conn) {
          String fileName = conn.getHeaderField("Content-Disposition");
          Matcher matcher = REGEX_FILE_NAME.matcher(fileName);
          if (matcher.find()) {
              return matcher.group(1);
          } else {
              return null;
          }
      }
  
      private static HttpURLConnection getConnection(URL url) throws IOException {
          HttpURLConnection conn = (HttpURLConnection) url.openConnection();
          conn.setRequestMethod("GET");
          conn.setDoInput(true);
          conn.setDoOutput(true);
          conn.setRequestProperty("Accept", "application/zip;text/html");
          return conn;
      }
  
      private static int copy(InputStream input, OutputStream output) throws IOException {
          long count = copyStream(input, output);
          if (count > Integer.MAX_VALUE) {
              return -1;
          }
          return (int) count;
      }
  
      private static long copyStream(InputStream input, OutputStream output) throws IOException {
          byte[] buffer = new byte[1024];
          long count = 0;
          int n = 0;
          while (-1 != (n = input.read(buffer))) {
              output.write(buffer, 0, n);
              count += n;
          }
          return count;
      }
  
      private static void closeQuietly(OutputStream output) {
          try {
              if (output != null) {
                  output.close();
              }
          } catch (IOException ioe) {
              // ignore
          }
      }
  
      private static void closeQuietly(InputStream input) {
          try {
              if (input != null) {
                  input.close();
              }
          } catch (IOException ioe) {
              // ignore
          }
      }
  
      public static boolean pathSecurityCheck(String path) {
          if (path == null) {
              return false;
          }
          if (path.contains("..") && (path.contains("/") || path.contains("\\"))) {
              return false;
          }
          return true;
      }
  
  }
  