// Path: common/src/main/java/eu/mikroskeem/shuriken/common/streams/ByteArrays.java
// public class ByteArrays {
//     /**
//      * Convert an {@link InputStream} to byte array
//      *
//      * @param inputStream Source {@link InputStream}
//      * @return byte array or null, if reading failed
//      */
//     @Nullable
//     @Contract("null -> fail; !null -> !null")
//     public static byte[] fromInputStream(InputStream inputStream) {
//         notNull(inputStream, "Input stream must not be null!");
//         ByteArrayOutputStream output = new ByteArrayOutputStream();
//         try {
//             byte[] buffer = new byte[1024];
//             int length;
//             while ((length =inputStream.read(buffer)) != -1)
//                 output.write(buffer, 0, length);
//             return output.toByteArray();
//         } catch (IOException e){
//             SneakyThrow.throwException(e);
//             return null;
//         } finally {
//             try {
//                 inputStream.close();
//                 output.close();
//             }
//             catch (IOException ignored){}
//         }
//     }
// }
// 
// Path: instrumentation/src/main/java/eu/mikroskeem/shuriken/instrumentation/ClassTools.java
// @NotNull
// public static String getClassResourcePath(@NotNull String className) {
//     return className.replace('.', '/').concat(".class");
// }


import eu.mikroskeem.shuriken.common.streams.ByteArrays;
import org.jetbrains.annotations.NotNull;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Path;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import static eu.mikroskeem.shuriken.instrumentation.ClassTools.getClassResourcePath;
        this.mainClassName = getClassResourcePath(mainClassName);

        // This is done in JarOutputStream constructor as well
        ByteArrayOutputStream manifest; man.write(manifest = new ByteArrayOutputStream());
        addEntry(JarFile.MANIFEST_NAME, manifest.toByteArray());
    }

    /**
     * Adds new entry into jar
     *
     * @param entryPath Entry path
     * @param data Entry data
     */
    public void addEntry(@NotNull String entryPath, @NotNull byte[] data) throws IOException {
        putNextEntry(new JarEntry(entryPath));
        write(data);
        closeEntry();
    }

    /**
     * Adds class to jar
     *
     * @param clazz Target {@link Class}
     */
    public void addClassToJar(@NotNull Class<?> clazz) throws IOException {
        String clz = getClassResourcePath(clazz);
        InputStream classStream;
        if((classStream = clazz.getClassLoader().getResourceAsStream(clz)) == null) {
            throw new IOException("Could not open resource: " + clz);
        }
// Path: common/src/main/java/eu/mikroskeem/shuriken/common/streams/ByteArrays.java
// public class ByteArrays {
//     /**
//      * Convert an {@link InputStream} to byte array
//      *
//      * @param inputStream Source {@link InputStream}
//      * @return byte array or null, if reading failed
//      */
//     @Nullable
//     @Contract("null -> fail; !null -> !null")
//     public static byte[] fromInputStream(InputStream inputStream) {
//         notNull(inputStream, "Input stream must not be null!");
//         ByteArrayOutputStream output = new ByteArrayOutputStream();
//         try {
//             byte[] buffer = new byte[1024];
//             int length;
//             while ((length =inputStream.read(buffer)) != -1)
//                 output.write(buffer, 0, length);
//             return output.toByteArray();
//         } catch (IOException e){
//             SneakyThrow.throwException(e);
//             return null;
//         } finally {
//             try {
//                 inputStream.close();
//                 output.close();
//             }
//             catch (IOException ignored){}
//         }
//     }
// }
// 
// Path: instrumentation/src/main/java/eu/mikroskeem/shuriken/instrumentation/ClassTools.java
// @NotNull
// public static String getClassResourcePath(@NotNull String className) {
//     return className.replace('.', '/').concat(".class");
// }


// Path: instrumentation/src/main/java/eu/mikroskeem/shuriken/instrumentation/runtime/AgentJarOutputStream.java
import eu.mikroskeem.shuriken.common.streams.ByteArrays;
import org.jetbrains.annotations.NotNull;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Path;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import static eu.mikroskeem.shuriken.instrumentation.ClassTools.getClassResourcePath;

        this.mainClassName = getClassResourcePath(mainClassName);

        // This is done in JarOutputStream constructor as well
        ByteArrayOutputStream manifest; man.write(manifest = new ByteArrayOutputStream());
        addEntry(JarFile.MANIFEST_NAME, manifest.toByteArray());
    }

    /**
     * Adds new entry into jar
     *
     * @param entryPath Entry path
     * @param data Entry data
     */
    public void addEntry(@NotNull String entryPath, @NotNull byte[] data) throws IOException {
        putNextEntry(new JarEntry(entryPath));
        write(data);
        closeEntry();
    }

    /**
     * Adds class to jar
     *
     * @param clazz Target {@link Class}
     */
    public void addClassToJar(@NotNull Class<?> clazz) throws IOException {
        String clz = getClassResourcePath(clazz);
        InputStream classStream;
        if((classStream = clazz.getClassLoader().getResourceAsStream(clz)) == null) {
            throw new IOException("Could not open resource: " + clz);
        }
        addEntry(clz, ByteArrays.fromInputStream(classStream));