55package net .minecraftforge .mcmaven .impl .repo .forge ;
66
77import java .io .File ;
8+ import java .io .FileInputStream ;
89import java .io .FileNotFoundException ;
910import java .io .FileOutputStream ;
1011import java .io .IOException ;
12+ import java .nio .charset .StandardCharsets ;
1113import java .util .ArrayList ;
1214import java .util .Collections ;
1315import java .util .HashMap ;
1921import java .util .function .Predicate ;
2022import java .util .function .Supplier ;
2123import java .util .stream .Collectors ;
24+ import java .util .zip .ZipEntry ;
2225import java .util .zip .ZipFile ;
26+ import java .util .zip .ZipInputStream ;
27+ import java .util .zip .ZipOutputStream ;
2328
2429import io .codechicken .diffpatch .cli .PatchOperation ;
2530import io .codechicken .diffpatch .util .LogLevel ;
@@ -70,6 +75,7 @@ public class Patcher implements Supplier<Task> {
7075 private final Task downloadSources ;
7176 private final Task predecomp ;
7277 private final Task last ;
78+ private final Task filterBinaryInjections ;
7379
7480 /**
7581 * Creates a new Patcher for the given Forge repo.
@@ -162,6 +168,15 @@ public class Patcher implements Supplier<Task> {
162168 }
163169
164170 this .last = last ;
171+
172+ var binaryInjections = new ArrayList <Patcher >();
173+ for (var p : this .getStack ()) {
174+ if (p .config .inject != null )
175+ binaryInjections .add (p );
176+ }
177+
178+ this .filterBinaryInjections = binaryInjections .isEmpty () ? null :
179+ Task .named ("filterBinaryInjections[" + this .name .getName () + ']' , this ::filterBinaryInjectionsImpl );
165180 }
166181
167182 private RuntimeException except (String message ) {
@@ -215,6 +230,14 @@ public MCPSide getMCPSide() {
215230 return this .mcpSide == null ? this .parent .getMCPSide () : this .mcpSide ;
216231 }
217232
233+ public String getName () {
234+ return this .name .getName ();
235+ }
236+
237+ public Artifact getArtifact () {
238+ return this .name ;
239+ }
240+
218241 public String getDataHash () {
219242 return this .dataHash ;
220243 }
@@ -675,4 +698,71 @@ private File injectSourcesImpl(Task inputTask, File output) {
675698 cache .save ();
676699 return output ;
677700 }
701+
702+ public @ Nullable Task filterBinaryInjections () {
703+ return this .filterBinaryInjections ;
704+ }
705+
706+ private File filterBinaryInjectionsImpl () {
707+ var output = new File (this .build , "binary-injections.jar" );
708+ var cache = Util .cache (output );
709+ cache .addKnown ("data" , this .getDataHash ());
710+ for (var p : getStack (false )) {
711+ if (p .config .inject != null )
712+ cache .addKnown ("parent-" + p .getName (), p .getDataHash ());
713+ }
714+
715+ if (Mavenizer .checkCache (output , cache ))
716+ return output ;
717+
718+ if (output .getParentFile () != null )
719+ output .getParentFile ().mkdirs ();
720+
721+ try (var zos = new ZipOutputStream (new FileOutputStream (output ))) {
722+ var servicesLists = new HashMap <String , List <String >>();
723+ var seen = new HashSet <String >();
724+ for (var patcher : this .getStack ()) {
725+ try (var zin = new ZipInputStream (new FileInputStream (this .data ))) {
726+ ZipEntry entry ;
727+ var prefix = config .inject ;
728+ while ((entry = zin .getNextEntry ()) != null ) {
729+ if (!entry .getName ().startsWith (prefix ) || entry .getName ().length () <= prefix .length ())
730+ continue ;
731+
732+ String name = entry .getName ().substring (prefix .length ());
733+
734+ if (name .startsWith ("META-INF/services/" ) && !entry .isDirectory ()) {
735+ var existing = servicesLists .computeIfAbsent (name , _ -> new ArrayList <>());
736+ if (existing .size () > 0 ) {
737+ existing .add ("" );
738+ existing .add ("# " + patcher .getArtifact ());
739+ }
740+ existing .add (new String (zin .readAllBytes (), StandardCharsets .UTF_8 ));
741+ } else if (seen .add (name )) {
742+ var _new = new ZipEntry (name );
743+ _new .setTime (0 );
744+ zos .putNextEntry (_new );
745+ zin .transferTo (zos );
746+ }
747+ }
748+ }
749+ }
750+
751+ for (var kv : servicesLists .entrySet ()) {
752+ String name = kv .getKey ();
753+ ZipEntry _new = new ZipEntry (name );
754+ _new .setTime (0 );
755+ zos .putNextEntry (_new );
756+ for (var line : kv .getValue ()) {
757+ zos .write (line .getBytes (StandardCharsets .UTF_8 ));
758+ zos .write ('\n' );
759+ }
760+ }
761+ } catch (IOException e ) {
762+ return Util .sneak (e );
763+ }
764+
765+ cache .save ();
766+ return output ;
767+ }
678768}
0 commit comments