package me.coley.recaf.workspace;

import me.coley.recaf.util.IOUtil;

import java.io.*;
import java.nio.file.Path;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

/**
 * Importable jar resource.
 *
 * @author Matt
 */
public class JarResource extends ArchiveResource {
	/**
	 * Constructs a jar resource.
	 *
	 * @param path
	 * 		Path reference to a jar file.
	 *
	 * @throws IOException
	 * 		When the path does not exist.
	 */
	public JarResource(Path path) throws IOException {
		super(ResourceKind.JAR, path);
	}

	@Override
	protected Map<String, byte[]> loadClasses() throws IOException {
		// iterate jar entries
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		byte[] buffer = new byte[8192];
		EntryLoader loader = getEntryLoader();

		try {
			ZipInputStream zis = new ZipInputStream(new FileInputStream(getPath().toFile()));
			ZipEntry entry;

			while ((entry = zis.getNextEntry()) != null) {
				// verify entries are classes and valid files
				// - skip intentional garbage / zip file abnormalities
				if (shouldSkip(entry.getName()))
					continue;
				if (!loader.isValidClassEntry(entry))
					continue;

				out.reset();
				byte[] in = IOUtil.toByteArray(zis, out, buffer);

				// There is no possible way a "class" under 30 bytes is valid
				if (in.length < 30)
					continue;

				loader.onClass(entry.getName(), in);
			}
		} catch (ZipException e) {
			if (e.getMessage().contains("invalid entry CRC")) {
				// "ZipFile"/"JarFile" reads the entire ZIP file structure before letting us do any entry parsing.
				// This may not always be ideal, but this way has one major bonus. It totally ignores CRC validity.
				// It also ignores a few other zip entry values.
				// Since somebody can intentionally write bogus data there to crash "ZipInputStream" this way works.
				ZipFile zf = new ZipFile(getPath().toString());
				Enumeration<? extends ZipEntry> entries = zf.entries();
				while (entries.hasMoreElements()) {
					ZipEntry entry = entries.nextElement();

					if (shouldSkip(entry.getName()))
						continue;
					if (!loader.isValidClassEntry(entry))
						continue;

					InputStream zis = zf.getInputStream(entry);
					byte[] in = IOUtil.toByteArray(zis);
					loader.onClass(entry.getName(), in);
				}
			}
		}
		loader.finishClasses();
		return loader.getClasses();
	}

	@Override
	protected Map<String, byte[]> loadFiles() throws IOException {
		// iterate jar entries
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		byte[] buffer = new byte[8192];
		EntryLoader loader = getEntryLoader();
		try (ZipFile zipFile = new ZipFile(getPath().toFile())) {
			Enumeration<? extends ZipEntry> entries = zipFile.entries();
			while(entries.hasMoreElements()) {
				// verify entries are not classes and are valid files
				// - skip intentional garbage / zip file abnormalities
				ZipEntry entry = entries.nextElement();
				if (shouldSkip(entry.getName()))
					continue;
				if(loader.isValidClassEntry(entry))
					continue;
				if(!loader.isValidFileEntry(entry))
					continue;
				out.reset();
				InputStream stream = zipFile.getInputStream(entry);
				byte[] in = IOUtil.toByteArray(stream, out, buffer);
				loader.onFile(entry.getName(), in);
			}
		}
		loader.finishFiles();
		return loader.getFiles();
	}
}

@@ -1915,16 +1915,21 @@
 ks.%0A%09%09%09%09
+try (
 ZipFile 
@@ -1966,18 +1966,21 @@
 tring())
-;%0A
+) %7B%0A%09
 %09%09%09%09Enum
@@ -2035,16 +2035,17 @@
 ();%0A%09%09%09%09
+%09
 while (e
@@ -2068,24 +2068,25 @@
 ements()) %7B%0A
+%09
 %09%09%09%09%09ZipEntr
@@ -2115,24 +2115,25 @@
 Element();%0A%0A
+%09
 %09%09%09%09%09if (sho
@@ -2156,32 +2156,33 @@
 tName()))%0A%09%09%09%09%09%09
+%09
 continue;%0A%09%09%09%09%09i
@@ -2171,24 +2171,25 @@
 %09%09continue;%0A
+%09
 %09%09%09%09%09if (!lo
@@ -2221,24 +2221,25 @@
 try))%0A%09%09%09%09%09%09
+%09
 continue;%0A%0A%09
@@ -2233,24 +2233,25 @@
 %09continue;%0A%0A
+%09
 %09%09%09%09%09InputSt
@@ -2288,24 +2288,25 @@
 ntry);%0A%09%09%09%09%09
+%09
 byte%5B%5D in = 
@@ -2331,24 +2331,25 @@
 (zis);%0A%09%09%09%09%09
+%09
 loader.onCla
@@ -2373,16 +2373,23 @@
 ), in);%0A
+%09%09%09%09%09%7D%0A
 %09%09%09%09%7D%0A%09%09

Fix file handle leak from 3x zip file logic backport