transcend-io / conflux

Zip/unzip files of any size in the browser using streams.
MIT License
93 stars 14 forks source link

zip stream created by conflux cannot be parsed by Java (java.util.zip) #98

Open fuweichin opened 2 years ago

fuweichin commented 2 years ago

I need to upload a directory (of files) to server, so I

Then I did an integration test, and I got a problem:

But for STORE zip file created by 7Zip, its stream can be successfully parsed by Java (java.util.zip)

fuweichin commented 2 years ago

By the way, I created a java unit test to reproduce the error, see code below. conflux.zip standands for a zip file created with conflux 7zip.zip standands for a zip file created with 7Zip using STORE method

ZipTest.java

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.attribute.BasicFileAttributeView;
import java.util.ArrayList;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.junit.Test;

public class ZipTest {
  @Test
  public void unpackZip() {
    //XXX conflux.zip 7zip.zip
    File inputFile=new File(System.getProperty("user.home"), "Downloads"+File.separator+"conflux.zip");
    File outputDir=new File(inputFile.getPath().replaceFirst("\\.zip$", ""));
    try(FileInputStream input=new FileInputStream(inputFile)){
      ZipTest.unpack(input, outputDir);
    }catch(IOException e){
      e.printStackTrace();
    }
  }
  public static void unpack(InputStream input, File outputDir) throws IOException {
    boolean setFileTimes=true;
    boolean doNameCheck=false;
    outputDir.mkdirs();
    ArrayList<File> dirs=new ArrayList<File>();
    ArrayList<ZipEntry> entries=new ArrayList<ZipEntry>();
    byte[] buffer=new byte[8192];
    try(ZipInputStream zipInput=new ZipInputStream(input);){
      for(ZipEntry entry=zipInput.getNextEntry(); entry!=null; entry=zipInput.getNextEntry()){
        System.out.println(entry.getName()); //XXX
        if(doNameCheck){
          // TODO checkEntryPath(entry.getName());
        }
        File file=new File(outputDir, entry.getName()).getCanonicalFile();
        if(entry.isDirectory()){
          if(!file.exists() && !file.mkdir()){
            throw new IOException("Failed to mkdir "+entry.getName());
          }
          if(setFileTimes){
            // Note: directory's file time should be set later, from inner to outer
            dirs.add(file);
            entries.add(entry);
          }
        }else{
          File parentFile=file.getParentFile();
          // TODO ensureParentDirectories(parentFile);
          try(FileOutputStream output=new FileOutputStream(file)){
            int len;
            while ((len = zipInput.read(buffer)) > 0) {
              output.write(buffer, 0, len);
            }
          }
          if(setFileTimes){
            Files.getFileAttributeView(file.toPath(), BasicFileAttributeView.class)
                .setTimes(entry.getLastModifiedTime(), entry.getLastAccessTime(), entry.getCreationTime());
          }
        }
      }
      zipInput.closeEntry();
      if(setFileTimes){
        for(int i=dirs.size()-1; i>=0; i--){
          File dir=dirs.get(i);
          ZipEntry entry=entries.get(i);
          Files.getFileAttributeView(dir.toPath(), BasicFileAttributeView.class)
              .setTimes(entry.getLastModifiedTime(), entry.getLastAccessTime(), entry.getCreationTime());
        }
      }
    }
  }
}