-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feat[mc_downloader]: native library downloading and extraction
Currently implemented only for JNA
- Loading branch information
Showing
5 changed files
with
181 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
119 changes: 119 additions & 0 deletions
119
app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/NativesExtractor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
package net.kdt.pojavlaunch.tasks; | ||
|
||
import net.kdt.pojavlaunch.Architecture; | ||
import net.kdt.pojavlaunch.Tools; | ||
import net.kdt.pojavlaunch.utils.FileUtils; | ||
|
||
import java.io.File; | ||
import java.io.FileInputStream; | ||
import java.io.FilterInputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.util.ArrayList; | ||
import java.util.zip.CRC32; | ||
import java.util.zip.ZipEntry; | ||
import java.util.zip.ZipInputStream; | ||
|
||
public class NativesExtractor { | ||
private static final ArrayList<String> LIBRARY_BLACKLIST = createLibraryBlacklist(); | ||
private final File mDestinationDir; | ||
private final String mLibraryLocation; | ||
|
||
public NativesExtractor(File mDestinationDir) { | ||
this.mDestinationDir = mDestinationDir; | ||
this.mLibraryLocation = "jni/"+getAarArchitectureName()+"/"; | ||
} | ||
|
||
/** | ||
* Create a library blacklist so that downloaded natives are not able to | ||
* override built-in libraries. | ||
* @return the resulting blacklist of library file names | ||
*/ | ||
private static ArrayList<String> createLibraryBlacklist() { | ||
String[] includedLibraryNames = new File(Tools.NATIVE_LIB_DIR).list(); | ||
ArrayList<String> blacklist = new ArrayList<>(includedLibraryNames.length); | ||
for(String libraryName : includedLibraryNames) { | ||
// allow overriding jnidispatch (as the integrated version may be too old) | ||
if(libraryName.equals("libjnidispatch.so")) continue; | ||
blacklist.add(libraryName); | ||
} | ||
blacklist.trimToSize(); | ||
return blacklist; | ||
} | ||
|
||
private static String getAarArchitectureName() { | ||
switch (Architecture.getDeviceArchitecture()) { | ||
case Architecture.ARCH_ARM: | ||
return "armeabi-v7a"; | ||
case Architecture.ARCH_ARM64: | ||
return "arm64-v8a"; | ||
case Architecture.ARCH_X86: | ||
return "x86"; | ||
case Architecture.ARCH_X86_64: | ||
return "x86_64"; | ||
} | ||
throw new RuntimeException("Unknown CPU architecture!"); | ||
} | ||
|
||
public void extractFromAar(File source) throws IOException { | ||
try (FileInputStream fileInputStream = new FileInputStream(source)) { | ||
try(ZipInputStream zipInputStream = new ZipInputStream(fileInputStream)) { | ||
// Wrap the ZIP input stream into a non-closeable stream to | ||
// avoid it being closed by processEntry() | ||
NonCloseableInputStream entryCopyStream = new NonCloseableInputStream(zipInputStream); | ||
|
||
while(true) { | ||
ZipEntry entry = zipInputStream.getNextEntry(); | ||
if(entry == null) break; | ||
|
||
String entryName = entry.getName(); | ||
if(!entryName.startsWith(mLibraryLocation) || entry.isDirectory()) continue; | ||
// Entry name is actually the full path, so we need to strip the path before extraction | ||
entryName = FileUtils.getFileName(entryName); | ||
// getFileName may make the file name null, avoid that case. | ||
if(entryName == null || LIBRARY_BLACKLIST.contains(entryName)) continue; | ||
|
||
processEntry(entryCopyStream, entry, new File(mDestinationDir, entryName)); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private static long fileCrc32(File target) throws IOException { | ||
try(FileInputStream fileInputStream = new FileInputStream(target)) { | ||
CRC32 crc32 = new CRC32(); | ||
byte[] buffer = new byte[1024]; | ||
int len; | ||
while((len = fileInputStream.read(buffer)) != -1) { | ||
crc32.update(buffer, 0, len); | ||
} | ||
return crc32.getValue(); | ||
} | ||
} | ||
|
||
private void processEntry(InputStream sourceStream, ZipEntry zipEntry, File entryDestination) throws IOException { | ||
if(entryDestination.exists()) { | ||
long expectedSize = zipEntry.getSize(); | ||
long expectedCrc32 = zipEntry.getCrc(); | ||
long realSize = entryDestination.length(); | ||
long realCrc32 = fileCrc32(entryDestination); | ||
// File in archive is the same as the local one, don't extract | ||
if(realSize == expectedSize && realCrc32 == expectedCrc32) return; | ||
} | ||
// copyInputStreamToFile copies the stream to a file and then closes it. | ||
org.apache.commons.io.FileUtils.copyInputStreamToFile(sourceStream, entryDestination); | ||
} | ||
|
||
|
||
private static class NonCloseableInputStream extends FilterInputStream { | ||
|
||
protected NonCloseableInputStream(InputStream in) { | ||
super(in); | ||
} | ||
|
||
@Override | ||
public void close() { | ||
// Do nothing (the point of this class) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters