2424package com .fox2code .foxloader .patching .game ;
2525
2626import com .fox2code .foxloader .patching .TransformerUtils ;
27+ import com .fox2code .foxloader .utils .io .IOUtils ;
2728import org .objectweb .asm .ClassReader ;
2829import org .objectweb .asm .ClassWriter ;
2930import org .objectweb .asm .tree .ClassNode ;
3334import java .util .*;
3435import java .util .function .Function ;
3536import java .util .zip .ZipEntry ;
37+ import java .util .zip .ZipFile ;
3638import java .util .zip .ZipInputStream ;
3739import java .util .zip .ZipOutputStream ;
3840
@@ -115,7 +117,7 @@ public static void patchSlimJarDev(File slimJar, File patchedJar) throws IOExcep
115117 }
116118 boolean failedRename = false ;
117119 try {
118- patchSlimJarImpl (slimJar , patchedJar , true );
120+ patchSlimJarImpl (slimJar , null , patchedJar , true );
119121 } finally {
120122 if (!patchedJar .renameTo (patchedJar )) {
121123 failedRename = true ;
@@ -127,10 +129,20 @@ public static void patchSlimJarDev(File slimJar, File patchedJar) throws IOExcep
127129 }
128130
129131 public static void patchSlimJar (File slimJar , File patchedJar ) throws IOException {
130- patchSlimJarImpl (slimJar , patchedJar , false );
132+ patchSlimJarImpl (slimJar , null , patchedJar , false );
131133 }
132134
133- private static void patchSlimJarImpl (File slimJar , File patchedJar , boolean check ) throws IOException {
135+ public static void patchSlimJarWithCoreMods (File slimJar , List <File > coreMods , File patchedJar ) throws IOException {
136+ if (coreMods == null || coreMods .isEmpty ()) {
137+ patchSlimJar (slimJar , patchedJar );
138+ return ;
139+ }
140+ try (JarSourceSet jarSourceSet = new JarSourceSet (coreMods )) {
141+ patchSlimJarImpl (slimJar , jarSourceSet , patchedJar , false );
142+ }
143+ }
144+
145+ private static void patchSlimJarImpl (File slimJar ,JarSourceSet jarSourceSet , File patchedJar , boolean check ) throws IOException {
134146 HashSet <String > classesToPatch = new HashSet <>(gameClassPatches .keySet ());
135147 try (ZipInputStream zipInputStream = new ZipInputStream (Files .newInputStream (slimJar .toPath ()));
136148 ZipOutputStream zipOutputStream = new ZipOutputStream (Files .newOutputStream (patchedJar .toPath ()))) {
@@ -139,27 +151,18 @@ private static void patchSlimJarImpl(File slimJar, File patchedJar, boolean chec
139151 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream (131072 );
140152 while ((zipEntry = zipInputStream .getNextEntry ()) != null ) {
141153 String path = zipEntry .getName ();
142- if (path .endsWith (".class" )) {
143- byteArrayOutputStream .reset ();
144- copy (zipInputStream , byteArrayOutputStream );
145- ClassReader classReader = new ClassReader (byteArrayOutputStream .toByteArray ());
146- ClassNode classNode = new ClassNode ();
147- classReader .accept (classNode , ClassReader .SKIP_FRAMES );
148- classesToPatch .remove (classNode .name );
149- classNode = patchClassNode (classNode );
150- if (classNode != null ) {
151- zipOutputStream .putNextEntry (new ZipEntry (zipEntry .getName ()));
152- ClassWriter classWriter = new ClassWriter (ClassWriter .COMPUTE_MAXS );
153- classNode .accept (classWriter );
154- byte [] compiled = classWriter .toByteArray ();
155- zipOutputStream .write (compiled );
156- zipOutputStream .closeEntry ();
157- if (check ) TransformerUtils .checkBytecodeValidity (compiled );
158- }
159- } else {
160- zipOutputStream .putNextEntry (new ZipEntry (zipEntry .getName ()));
161- copy (zipInputStream , zipOutputStream );
162- zipOutputStream .closeEntry ();
154+ InputStream jarSourceInputStream = jarSourceSet != null ?
155+ jarSourceSet .getInputStreamParsed (path ) : null ;
156+ patchAndInsert (byteArrayOutputStream , classesToPatch , zipOutputStream ,
157+ jarSourceInputStream == null ? zipInputStream : jarSourceInputStream ,
158+ path , check , jarSourceInputStream != null );
159+ }
160+ if (jarSourceSet != null ) {
161+ while ((zipEntry = jarSourceSet .nextExtraZipEntry ()) != null ) {
162+ String path = zipEntry .getName ();
163+ InputStream inputStream = jarSourceSet .getInputStreamOfCurrentEntry ();
164+ patchAndInsert (byteArrayOutputStream , classesToPatch , zipOutputStream ,
165+ inputStream , path , check , true );
163166 }
164167 }
165168 zipOutputStream .finish ();
@@ -169,13 +172,104 @@ private static void patchSlimJarImpl(File slimJar, File patchedJar, boolean chec
169172 }
170173 }
171174
172- // Utils port for game patches
173- static void copy (InputStream inputStream , OutputStream outputStream ) throws IOException {
174- byte [] byteChunk = new byte [4096 ];
175- int n ;
175+ private static void patchAndInsert (
176+ ByteArrayOutputStream byteArrayOutputStream , HashSet <String > classesToPatch ,
177+ ZipOutputStream zipOutputStream , InputStream inputStream ,
178+ String path , boolean check , boolean closeInput ) throws IOException {
179+ if (path .endsWith (".class" )) {
180+ byteArrayOutputStream .reset ();
181+ IOUtils .copy (inputStream , byteArrayOutputStream );
182+ if (closeInput ) {
183+ inputStream .close ();
184+ }
185+ ClassReader classReader = new ClassReader (byteArrayOutputStream .toByteArray ());
186+ ClassNode classNode = new ClassNode ();
187+ classReader .accept (classNode , ClassReader .SKIP_FRAMES );
188+ classesToPatch .remove (classNode .name );
189+ classNode = patchClassNode (classNode );
190+ if (classNode != null ) {
191+ zipOutputStream .putNextEntry (new ZipEntry (path ));
192+ ClassWriter classWriter = new ClassWriter (ClassWriter .COMPUTE_MAXS );
193+ classNode .accept (classWriter );
194+ byte [] compiled = classWriter .toByteArray ();
195+ zipOutputStream .write (compiled );
196+ zipOutputStream .closeEntry ();
197+ if (check ) TransformerUtils .checkBytecodeValidity (compiled );
198+ }
199+ } else {
200+ zipOutputStream .putNextEntry (new ZipEntry (path ));
201+ IOUtils .copy (inputStream , zipOutputStream );
202+ if (closeInput ) {
203+ inputStream .close ();
204+ }
205+ zipOutputStream .closeEntry ();
206+ }
207+ }
208+
209+ private static final class JarSourceSet implements Closeable {
210+ private final List <ZipFile > zipFiles ;
211+ private final HashSet <String > parsedFiles ;
212+ private final Iterator <ZipFile > zipFileIterator ;
213+ private ZipFile currentZipFile ;
214+ private Enumeration <? extends ZipEntry > zipEntryEnumeration ;
215+ private ZipEntry currentZipEntry ;
176216
177- while ((n = inputStream .read (byteChunk )) > 0 ) {
178- outputStream .write (byteChunk , 0 , n );
217+ private JarSourceSet (List <File > files ) throws IOException {
218+ this .zipFiles = new ArrayList <>();
219+ try {
220+ for (File file : files ) {
221+ this .zipFiles .add (new ZipFile (file ));
222+ }
223+ } catch (IOException ioe ) {
224+ try {
225+ this .close ();
226+ } catch (IOException ignored ) {}
227+ throw ioe ;
228+ }
229+ this .parsedFiles = new HashSet <>();
230+ this .zipFileIterator = this .zipFiles .iterator ();
231+ }
232+
233+ public InputStream getInputStreamParsed (String path ) throws IOException {
234+ this .parsedFiles .add (path );
235+ for (ZipFile zipFile : this .zipFiles ) {
236+ ZipEntry zipEntry = zipFile .getEntry (path );
237+ if (zipEntry != null ) {
238+ return zipFile .getInputStream (zipEntry );
239+ }
240+ }
241+ return null ;
242+ }
243+
244+ public ZipEntry nextExtraZipEntry () {
245+ while (true ) {
246+ while (this .zipEntryEnumeration == null ||
247+ !this .zipEntryEnumeration .hasMoreElements ()) {
248+ if (!this .zipFileIterator .hasNext ()) {
249+ return null ;
250+ }
251+ this .currentZipFile = this .zipFileIterator .next ();
252+ this .zipEntryEnumeration = this .currentZipFile .entries ();
253+ }
254+ while (this .zipEntryEnumeration .hasMoreElements ()) {
255+ ZipEntry zipEntry = this .zipEntryEnumeration .nextElement ();
256+ if (this .parsedFiles .add (zipEntry .getName ())) {
257+ return this .currentZipEntry = zipEntry ;
258+ }
259+ }
260+ }
261+ }
262+
263+ public InputStream getInputStreamOfCurrentEntry () throws IOException {
264+ return this .currentZipFile .getInputStream (this .currentZipEntry );
265+ }
266+
267+ @ Override
268+ public void close () throws IOException {
269+ for (ZipFile zipFile : this .zipFiles ) {
270+ zipFile .close ();
271+ }
272+ this .zipFiles .clear ();
179273 }
180274 }
181275}
0 commit comments