Class SimplePatcher

java.lang.Object
one.pkg.tiny.utils.diff.SimplePatcher

@Experimental public class SimplePatcher extends Object
SimplePatcher is just an accidental byproduct, and I don't recommend anyone to use it.

Example:


 package one.tranic.goldpiglin.command;

 import one.tranic.goldpiglin.GoldPiglin;
 import one.tranic.goldpiglin.common.GoldPiglinLogger;
 import one.tranic.t.utils.SimplePatcher;
 import org.bukkit.command.Command;
 import org.bukkit.command.CommandSender;
 import org.bukkit.plugin.java.JavaPlugin;
 import org.jetbrains.annotations.NotNull;

 import java.io.ByteArrayOutputStream;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Stream;

 public class DiffCommand extends Command {
     private final static List<String> INTERNAL_ERROR = List.of("Internal error");
     private final static Path DIFF_DIR = GoldPiglin.getPlugin().getDataFolder().toPath().getParent().resolve("diff");
     private final static Path Plugin_DIR = GoldPiglin.getPlugin().getDataFolder().toPath().getParent();

     public DiffCommand(JavaPlugin plugin) {
         super("diff");
         this.setUsage("/diff <create> jar1 jar2 | /diff <merge> patch jar");

         if (!DIFF_DIR.toFile().exists()) {
             try {
                 Files.createDirectories(DIFF_DIR);
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }
     }

     private static List<String> getFiles(String prefix) {
         try (final Stream<Path> files = Files.list(Plugin_DIR)) {
             return files.filter(path ->
                             path.toString().endsWith("." + prefix) && path.toFile().isFile()
                     )
                     .map(Path::getFileName)
                     .map(Path::toString).toList();
         } catch (IOException e) {
             e.printStackTrace();
             return INTERNAL_ERROR;
         }
     }

     public static List<String> getJarFiles() {
         return getFiles("jar");
     }

     public static List<String> getDiffFiles() {
         return getFiles("diff");
     }

     @Override
     public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, String[] args) {
         if (args.length == 0) {
             return true;
         }
         if (args[0].equalsIgnoreCase("create")) {
             if (args.length < 3) {
                 sender.sendMessage("Usage: /diff create <jar1> <jar2>");
                 return true;
             }
             return runCreateDiff(sender, commandLabel, args);
         }
         if (args[0].equalsIgnoreCase("merge")) {
             if (args.length < 3) {
                 sender.sendMessage("Usage: /diff merge <patch> <jar>");
                 return true;
             }
             return runMergeDiff(sender, commandLabel, args);
         }
         return true;
     }

     private boolean runCreateDiff(@NotNull CommandSender sender, @NotNull String commandLabel, String[] args) {
         GoldPiglinLogger.logger.info("Args: {}", String.join(" ", args));
         var jar1 = args[1];
         var jar2 = args[2];

         var j1 = Plugin_DIR.resolve(jar1).toFile();
         var j2 = Plugin_DIR.resolve(jar2).toFile();

         if (!j1.exists() || !j2.exists()) {
             sender.sendMessage("One of the jars does not exist");
             return true;
         }

         try {
             var diff = DIFF_DIR.resolve(jar1 + "-" + jar2 + ".diff");
             var diffFile = diff.toFile();
             if (!diffFile.exists()) {
                 diffFile.createNewFile();
             } else {
                 diffFile.delete();
                 diffFile.createNewFile();
             }
             try (var fis1 = new FileInputStream(j1); var fis2 = new FileInputStream(j2)) {
                 try (ByteArrayOutputStream output = (ByteArrayOutputStream) SimplePatcher.createPatch(fis1, fis2); OutputStream fos = Files.newOutputStream(diff)) {
                     output.writeTo(fos);
                     fos.flush();
                 }
                 sender.sendMessage("Diff created at " + diff.toAbsolutePath());
             }

         } catch (IOException e) {
             sender.sendMessage("Error: " + e.getMessage());
             e.printStackTrace();
         }

         return true;
     }

     private boolean runMergeDiff(@NotNull CommandSender sender, @NotNull String commandLabel, String[] args) {
         GoldPiglinLogger.logger.info("Args: {}", String.join(" ", args));
         var patch = args[1];
         var jar = args[2];

         var p = DIFF_DIR.resolve(patch).toFile();
         var j = Plugin_DIR.resolve(jar).toFile();
         var j2 = Plugin_DIR.resolve(jar + ".new.jar");
         try {
             j2.toFile().createNewFile();
         } catch (IOException e) {
             e.printStackTrace();
             sender.sendMessage("Error: " + e.getMessage());
             return true;
         }

         try (var pS = new FileInputStream(p); var jS = new FileInputStream(j)) {
             try (ByteArrayOutputStream fps = (ByteArrayOutputStream) SimplePatcher.applyPatch(pS, jS); var fos = Files.newOutputStream(j2)) {
                 fps.writeTo(fos);
                 fos.flush();
             }
         } catch (Exception exception) {
             sender.sendMessage("Error: " + exception.getMessage());
             exception.printStackTrace();
             return true;
         }

         return false;
     }

     @Override
     public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) {
         List<String> list = new ArrayList<>();
         if (args.length == 1) {
             list.add("create");
             list.add("merge");
         }
         if (args.length == 2) {
             if (args[0].equalsIgnoreCase("create"))
                 list.addAll(getJarFiles());
             if (args[0].equalsIgnoreCase("merge"))
                 list.addAll(getDiffFiles());
         }
         if (args.length == 3 && (args[0].equalsIgnoreCase("merge") || args[0].equalsIgnoreCase("create"))) {
             list.addAll(getJarFiles());
         }
         return list;
     }
 }
 
  • Constructor Summary

    Constructors
    Constructor
    Description
     
  • Method Summary

    Modifier and Type
    Method
    Description
    static void
    applyPatch(File patch, File dst, File outputFile)
    Applies a binary patch to a target file and writes the patched content to an output file.
    static void
    applyPatch(File patchFile, File targetFile, File outputFile, @Nullable ICompress compression)
     
    Applies a patch to a target file and returns the resulting file as an output stream.
    static File
    applyPath(File patch, File dst)
    Applies a binary patch file to a specified destination file and generates a new file with the patched content.
    static File
    createPatch(File newFile, File oldFile)
    Creates a temporary binary patch file that represents the differences between the specified new file and old file.
    static void
    createPatch(File newFile, File oldFile, File patchFile)
    Creates a binary patch file that defines the changes required to transform the contents of the old file into the new file.
    static void
    createPatch(File newFile, File oldFile, File patchFile, @Nullable ICompress compression)
    Creates a binary patch file that describes the changes required to transform the contents of the old file into the new file.
    createPatch(InputStream newFile, InputStream oldFile)
    Creates a binary patch that transforms the contents of the source file into the destination file.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • SimplePatcher

      public SimplePatcher()
  • Method Details

    • createPatch

      public static OutputStream createPatch(InputStream newFile, InputStream oldFile) throws IOException
      Creates a binary patch that transforms the contents of the source file into the destination file.
      Parameters:
      newFile - the InputStream representing the source file's data
      oldFile - the InputStream representing the destination file's data
      Returns:
      an OutputStream containing the binary patch data
      Throws:
      IOException - if an I/O error occurs while reading from the input streams or writing to the patch
    • createPatch

      public static void createPatch(File newFile, File oldFile, File patchFile) throws IOException
      Creates a binary patch file that defines the changes required to transform the contents of the old file into the new file.

      The patch is stored in the specified patch file.

      Parameters:
      newFile - the file containing the target state after applying the patch
      oldFile - the file containing the original state before applying the patch
      patchFile - the file where the generated patch will be saved; must not yet exist
      Throws:
      IOException - if any of the input files do not exist, if the patch file already exists, or if an I/O error occurs while reading or writing
    • createPatch

      public static void createPatch(File newFile, File oldFile, File patchFile, @Nullable @Nullable ICompress compression) throws IOException
      Creates a binary patch file that describes the changes required to transform the contents of the old file into the new file.

      The patch is written to the specified patch file, with optional compression applied.

      Parameters:
      newFile - the file containing the target state after applying the patch
      oldFile - the file containing the original state before applying the patch
      patchFile - the file where the generated patch will be saved; must not yet exist
      compression - the compression method to be applied to the patch output; may be null if no compression is desired
      Throws:
      IOException - if any of the input files do not exist, if the patch file already exists, or if an I/O error occurs while reading or writing files
    • createPatch

      public static File createPatch(File newFile, File oldFile) throws IOException
      Creates a temporary binary patch file that represents the differences between the specified new file and old file.

      The temporary patch file is deleted if an exception occurs during its creation.

      Parameters:
      newFile - the file representing the new version of the content
      oldFile - the file representing the old version of the content
      Returns:
      a temporary file containing the binary patch data
      Throws:
      IOException - if an I/O error occurs, such as issues reading the input files, writing the patch file, or if any of the required files does not exist
    • applyPatch

      public static OutputStream applyPatch(InputStream patch, InputStream dst) throws IOException
      Applies a patch to a target file and returns the resulting file as an output stream.
      Parameters:
      patch - the input stream containing the patch data to be applied
      dst - the input stream of the target file that will be patched
      Returns:
      an output stream containing the patched file contents
      Throws:
      IOException - if an I/O error occurs while reading or writing streams
      IllegalStateException - if the patch does not match the target file, is corrupted, or contains invalid commands
    • applyPatch

      public static void applyPatch(File patch, File dst, File outputFile) throws IOException
      Applies a binary patch to a target file and writes the patched content to an output file.
      Parameters:
      patch - the patch file containing the binary data with instructions for applying the patch
      dst - the target file to which the patch will be applied
      outputFile - the file where the patched content will be written; must not yet exist
      Throws:
      IOException - if the patch file does not exist, the target file does not exist, the output file already exists, or if an I/O error occurs during the process
    • applyPatch

      public static void applyPatch(File patchFile, File targetFile, File outputFile, @Nullable @Nullable ICompress compression) throws IOException
      Throws:
      IOException
    • applyPath

      public static File applyPath(File patch, File dst) throws IOException
      Applies a binary patch file to a specified destination file and generates a new file with the patched content.
      Parameters:
      patch - the file containing the patch data to be applied
      dst - the file representing the target to which the patch will be applied
      Returns:
      a temporary file containing the patched content after applying the patch
      Throws:
      IOException - if an I/O error occurs during patch application, such as issues reading or writing files, if the patch or destination file does not exist, or if the generated output file cannot be created