From 1b62972f0639f9568bad2b0299c65c12c0b87724 Mon Sep 17 00:00:00 2001 From: huangyuhui Date: Fri, 20 Jul 2018 11:44:50 +0800 Subject: [PATCH] Fix 1.13 version parsing --- .../org/jackhuang/hmcl/game/GameVersion.java | 123 ++++++------------ build.gradle | 9 +- 2 files changed, 48 insertions(+), 84 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameVersion.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameVersion.java index 6cd25ec40..ca605951a 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameVersion.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameVersion.java @@ -20,112 +20,75 @@ package org.jackhuang.hmcl.game; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipFile; import org.jackhuang.hmcl.util.IOUtils; +import org.jenkinsci.constant_pool_scanner.ConstantPool; +import org.jenkinsci.constant_pool_scanner.ConstantPoolScanner; +import org.jenkinsci.constant_pool_scanner.ConstantType; +import org.jenkinsci.constant_pool_scanner.StringConstant; import java.io.File; import java.io.IOException; +import java.util.List; import java.util.Optional; - -import static java.nio.charset.StandardCharsets.US_ASCII; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; /** * @author huangyuhui */ public final class GameVersion { - private static int lessThan32(byte[] b, int x) { - for (; x < b.length; x++) - if (b[x] < 32) - return x; - return -1; + private static Optional getVersionOfClassMinecraft(ZipFile file, ZipArchiveEntry entry) throws IOException { + ConstantPool pool = ConstantPoolScanner.parse(file.getInputStream(entry), ConstantType.STRING); + + return StreamSupport.stream(pool.list(StringConstant.class).spliterator(), false) + .map(StringConstant::get) + .filter(s -> s.startsWith("Minecraft Minecraft ")) + .map(s -> s.substring("Minecraft Minecraft ".length())) + .findFirst(); } - public static int matchArray(byte[] a, byte[] b) { - for (int i = 0; i < a.length - b.length; i++) { - int j = 1; - for (int k = 0; k < b.length; k++) { - if (b[k] == a[(i + k)]) - continue; - j = 0; + private static Optional getVersionFromClassMinecraftServer(ZipFile file, ZipArchiveEntry entry) throws IOException { + ConstantPool pool = ConstantPoolScanner.parse(file.getInputStream(entry), ConstantType.STRING); + + List list = StreamSupport.stream(pool.list(StringConstant.class).spliterator(), false) + .map(StringConstant::get) + .collect(Collectors.toList()); + + int idx = -1; + + for (int i = 0; i < list.size(); ++i) + if (list.get(i).startsWith("Can't keep up!")) { + idx = i; break; } - if (j != 0) - return i; - } - return -1; - } - private static Optional getVersionOfOldMinecraft(ZipFile file, ZipArchiveEntry entry) throws IOException { - byte[] tmp = IOUtils.readFullyAsByteArray(file.getInputStream(entry)); + for (int i = idx - 1; i >= 0; --i) + if (list.get(i).matches(".*[0-9].*")) + return Optional.of(list.get(i)); - byte[] bytes = "Minecraft Minecraft ".getBytes(US_ASCII); - int j = matchArray(tmp, bytes); - if (j < 0) - return Optional.empty(); - int i = j + bytes.length; - - if ((j = lessThan32(tmp, i)) < 0) - return Optional.empty(); - - return Optional.of(new String(tmp, i, j - i, US_ASCII)); - } - - private static Optional getVersionOfNewMinecraft(ZipFile file, ZipArchiveEntry entry) throws IOException { - byte[] tmp = IOUtils.readFullyAsByteArray(file.getInputStream(entry)); - - byte[] str = "-server.txt".getBytes(US_ASCII); - int j = matchArray(tmp, str); - if (j < 0) return Optional.empty(); - int i = j + str.length; - i += 11; - j = lessThan32(tmp, i); - if (j < 0) return Optional.empty(); - String result = new String(tmp, i, j - i, US_ASCII); - - char ch = result.charAt(0); - // 1.8.1+ - if (ch < '0' || ch > '9') { - str = "Can't keep up! Did the system time change, or is the server overloaded?".getBytes(US_ASCII); - j = matchArray(tmp, str); - if (j < 0) return Optional.empty(); - i = -1; - while (j > 0) { - if (tmp[j] >= 48 && tmp[j] <= 57) { - i = j; - break; - } - j--; - } - if (i == -1) return Optional.empty(); - int k = i; - if (tmp[i + 1] >= (int) 'a' && tmp[i + 1] <= (int) 'z') - i++; - while (tmp[k] >= 48 && tmp[k] <= 57 || tmp[k] == (int) '-' || tmp[k] == (int) '.' || tmp[k] >= 97 && tmp[k] <= (int) 'z') - k--; - k++; - return Optional.of(new String(tmp, k, i - k + 1, US_ASCII)); - } - return Optional.of(result); + return Optional.empty(); } public static Optional minecraftVersion(File file) { if (file == null || !file.exists() || !file.isFile() || !file.canRead()) return Optional.empty(); - ZipFile f = null; + ZipFile gameJar = null; try { - f = new ZipFile(file); - ZipArchiveEntry minecraft = f - .getEntry("net/minecraft/client/Minecraft.class"); - if (minecraft != null) - return getVersionOfOldMinecraft(f, minecraft); - ZipArchiveEntry main = f.getEntry("net/minecraft/client/main/Main.class"); - ZipArchiveEntry minecraftServer = f.getEntry("net/minecraft/server/MinecraftServer.class"); - if ((main != null) && (minecraftServer != null)) - return getVersionOfNewMinecraft(f, minecraftServer); + gameJar = new ZipFile(file); + ZipArchiveEntry minecraft = gameJar.getEntry("net/minecraft/client/Minecraft.class"); + if (minecraft != null) { + Optional result = getVersionOfClassMinecraft(gameJar, minecraft); + if (result.isPresent()) + return result; + } + ZipArchiveEntry minecraftServer = gameJar.getEntry("net/minecraft/server/MinecraftServer.class"); + if (minecraftServer != null) + return getVersionFromClassMinecraftServer(gameJar, minecraftServer); return Optional.empty(); } catch (IOException e) { return Optional.empty(); } finally { - IOUtils.closeQuietly(f); + IOUtils.closeQuietly(gameJar); } } } diff --git a/build.gradle b/build.gradle index ad33237f0..8a8ac1fc2 100644 --- a/build.gradle +++ b/build.gradle @@ -38,10 +38,11 @@ allprojects { sourceCompatibility = 1.8 dependencies { - compile "com.google.code.gson:gson:2.8.2" - compile "org.apache.commons:commons-compress:1.15" - compile "org.tukaani:xz:1.2" - compile "org.hildan.fxgson:fx-gson:3.1.0" + compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5' + compile group: 'org.apache.commons', name: 'commons-compress', version: '1.17' + compile group: 'org.tukaani', name: 'xz', version: '1.8' + compile group: 'org.hildan.fxgson', name: 'fx-gson', version: '3.1.0' + compile group: 'org.jenkins-ci', name: 'constant-pool-scanner', version: '1.2' testCompile group: 'junit', name: 'junit', version: '4.12' }