Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove empty dirs #54

Merged
merged 4 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions core/src/main/scala/com/eed3si9n/jarjarabrams/Zip.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.eed3si9n.jarjarabrams

import com.eed3si9n.jarjar.util.{ DuplicateJarEntryException, EntryStruct }
import java.nio.file.{ Files, NoSuchFileException, Path, StandardCopyOption }
import com.eed3si9n.jarjar.util.{ DuplicateJarEntryException, EntryStruct, IoUtil }
import java.nio.file.{ Files, NoSuchFileException, Path }
import java.nio.file.attribute.FileTime
import java.io.{ ByteArrayOutputStream, FileNotFoundException, InputStream, OutputStream }
import java.security.MessageDigest
Expand Down Expand Up @@ -83,7 +83,7 @@ object Zip {
}
}
}
Files.move(tempJar, outputJar, StandardCopyOption.REPLACE_EXISTING)
IoUtil.copyZipWithoutEmptyDirectories(tempJar.toFile, outputJar.toFile)
resetModifiedTime(outputJar)
outputJar
}
Expand Down
4 changes: 2 additions & 2 deletions core/src/test/scala/testpkg/ShaderTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ object ShaderTest extends BasicTestSuite {
Paths.get(byteBuddyJar),
resetTimestamp = false,
expectedClass = expectedByteBuddyClass,
expectedSha = "673a5b1d7282ec68def6d6e6845c29d96142e4e3b39796484e122cd92f65edee"
expectedSha = "42454701a0b53a13af17d015c1785ef5ea342d8c324315ed17d80831cba98be3"
)
}

Expand All @@ -24,7 +24,7 @@ object ShaderTest extends BasicTestSuite {
Paths.get(byteBuddyJar),
resetTimestamp = true,
expectedClass = expectedByteBuddyClass,
expectedSha = "33ceee11fb2b5e4d46ebe552025bc17bc4d9391974c55e07d63f9e85d2ec381a"
expectedSha = "0db0b1300533c06a934dca1e7016f6dc2d432c66f1927102d6f6b49086dcfddb"
)
}

Expand Down
94 changes: 31 additions & 63 deletions jarjar/src/main/java/com/eed3si9n/jarjar/util/IoUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@
package com.eed3si9n.jarjar.util;

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
Expand Down Expand Up @@ -53,82 +50,53 @@ public static void copy(File from, File to, byte[] buf) throws IOException {
}

/**
* Create a copy of an zip file without its empty directories.
* Create a copy of a zip file, removing all empty directories.
* @param inputFile
* @param outputFile
* @throws IOException
*/
public static void copyZipWithoutEmptyDirectories(final File inputFile, final File outputFile) throws IOException
{
public static void copyZipWithoutEmptyDirectories(File inputFile, File outputFile) throws IOException {
final byte[] buf = new byte[0x2000];
ZipFile inputZip = new ZipFile(inputFile);
ZipOutputStream outputStream = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(outputFile)));

final ZipFile inputZip = new ZipFile(inputFile);
BufferedOutputStream buffered = new BufferedOutputStream(new FileOutputStream(outputFile));

final ZipOutputStream outputStream = new ZipOutputStream(buffered);
try
{
// read a the entries of the input zip file and sort them
final Enumeration<? extends ZipEntry> e = inputZip.entries();
final ArrayList<ZipEntry> sortedList = new ArrayList<ZipEntry>();
while (e.hasMoreElements()) {
final ZipEntry entry = e.nextElement();
sortedList.add(entry);
}

Collections.sort(sortedList, new Comparator<ZipEntry>()
{
public int compare(ZipEntry o1, ZipEntry o2)
{
return o1.getName().compareTo(o2.getName());
}
});

// treat them again and write them in output, wenn they not are empty directories
for (int i = sortedList.size()-1; i>=0; i--)
{
final ZipEntry inputEntry = sortedList.get(i);
final String name = inputEntry.getName();
final boolean isEmptyDirectory;
if (inputEntry.isDirectory())
{
if (i == sortedList.size()-1)
{
// no item afterwards; it was an empty directory
isEmptyDirectory = true;
}
else
{
final String nextName = sortedList.get(i+1).getName();
isEmptyDirectory = !nextName.startsWith(name);
}
}
else
{
isEmptyDirectory = false;
// First pass: create a set of directories to retain
Set<String> dirsToRetain = new HashSet<>();
Enumeration<? extends ZipEntry> entries = inputZip.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if (!entry.isDirectory()) {
String name = entry.getName();
int index = name.lastIndexOf('/');
while (index > 0) {
name = name.substring(0, index);
dirsToRetain.add(name + "/");
index = name.lastIndexOf('/');
}
}
}


// write the entry
if (isEmptyDirectory)
{
sortedList.remove(inputEntry);
}
else
{
final ZipEntry outputEntry = new ZipEntry(inputEntry);
outputStream.putNextEntry(outputEntry);
// Second pass: copy entries, excluding directories not in the set
entries = inputZip.entries();
while (entries.hasMoreElements()) {
ZipEntry inputEntry = entries.nextElement();
if (!inputEntry.isDirectory() || dirsToRetain.contains(inputEntry.getName())) {
ZipEntry outputEntry = new ZipEntry(inputEntry);
outputEntry.setCompressedSize(-1);
outputStream.putNextEntry(outputEntry);
if (!inputEntry.isDirectory()) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
final InputStream is = inputZip.getInputStream(inputEntry);
IoUtil.pipe(is, baos, buf);
is.close();
outputStream.write(baos.toByteArray());
}
outputStream.closeEntry();
}
} finally {
outputStream.close();
}

outputStream.close();
inputZip.close();
}

}
68 changes: 68 additions & 0 deletions jarjar/src/test/java/com/eed3si9n/jarjar/util/IOUtilTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.eed3si9n.jarjar.util;

import org.junit.Assert;
import org.junit.Test;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

public class IOUtilTest {
@Test
public void testCopyZipWithoutEmptyDirectories() throws IOException {
// create a temporary directory tree with a few empty files and empty directories
Path tree = Files.createTempDirectory("tree");
Path zips = Files.createTempDirectory("zips");

// Create a zip with some empty directories
Path a = Files.createDirectory(Paths.get(tree.toString(), "a"));
Files.createFile(Paths.get(a.toString(), "a.txt"));
Files.createDirectory(Paths.get(tree.toString(), "b"));
Path c = Files.createDirectory(Paths.get(tree.toString(), "c"));
Files.createDirectory(Paths.get(c.toString(), "d"));
File inputZipFile = Paths.get(zips.toString(), "input.zip").toFile();
zipDirectory(tree, inputZipFile);

File outputZipFile = Paths.get(zips.toString(), "output.zip").toFile();
IoUtil.copyZipWithoutEmptyDirectories(inputZipFile, outputZipFile);
try (ZipFile outputZip = new ZipFile(outputZipFile)) {
Assert.assertNotNull(outputZip.getEntry("a/a.txt"));
Assert.assertNotNull(outputZip.getEntry("a/"));
Assert.assertNull(outputZip.getEntry("b/"));
Assert.assertNull(outputZip.getEntry("c/"));
Assert.assertNull(outputZip.getEntry("c/d/"));
}
}

private static void zipDirectory(Path sourceDir, File zipFile) throws IOException {
try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFile));
Stream<Path> paths = Files.walk(sourceDir)
) {
paths.forEach(path -> {
String name = sourceDir.relativize(path).toString();
if (Files.isDirectory(path)) {
name = name + "/";
}
ZipEntry zipEntry = new ZipEntry(name);
try {
zipOutputStream.putNextEntry(zipEntry);
if (!Files.isDirectory(path)) {
Files.copy(path, zipOutputStream);
}
zipOutputStream.closeEntry();
} catch (IOException e) {
throw new RuntimeIOException(e);
}
});
}
}


}
Loading