add missing import

This commit is contained in:
Tungstend 2022-10-19 23:41:14 +08:00
parent bc2e74fea9
commit 92b1df630e
43 changed files with 400 additions and 71 deletions

View File

@ -30,6 +30,8 @@ dependencies {
implementation 'org.nanohttpd:nanohttpd:2.3.1'
implementation 'com.github.steveice10:opennbt:1.4'
implementation 'org.apache.commons:commons-lang3:3.12.0'
implementation 'org.apache.commons:commons-compress:1.21'
implementation 'com.moandjiezana.toml:toml4j:0.7.2'
implementation 'org.jenkins-ci:constant-pool-scanner:1.2'
implementation 'com.google.code.gson:gson:2.9.0'
implementation 'androidx.appcompat:appcompat:1.5.1'

View File

@ -25,6 +25,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
import java.util.stream.Collectors;
// Todo : fix
public class DefaultCacheRepository extends CacheRepository {
private Path librariesDir;
private Path indexFile;

View File

@ -15,7 +15,6 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
// Todo : fix
public final class LibraryAnalyzer implements Iterable<LibraryAnalyzer.LibraryMark> {
private Version version;
private final Map<String, Pair<Library, String>> libraries;
@ -25,16 +24,16 @@ public final class LibraryAnalyzer implements Iterable<LibraryAnalyzer.LibraryMa
this.libraries = libraries;
}
public String getVersion(LibraryType type) {
public Optional<String> getVersion(LibraryType type) {
return getVersion(type.getPatchId());
}
public String getVersion(String type) {
return Objects.requireNonNull(libraries.get(type)).getValue();
public Optional<String> getVersion(String type) {
return Optional.ofNullable(libraries.get(type)).map(Pair::getValue);
}
public Library getLibrary(LibraryType type) {
return Objects.requireNonNull(libraries.get(type.getPatchId())).getKey();
public Optional<Library> getLibrary(LibraryType type) {
return Optional.ofNullable(libraries.get(type.getPatchId())).map(Pair::getKey);
}
@NotNull
@ -65,36 +64,19 @@ public final class LibraryAnalyzer implements Iterable<LibraryAnalyzer.LibraryMa
}
public boolean hasModLoader() {
for (String s : libraries.keySet()) {
if (Objects.requireNonNull(LibraryType.fromPatchId(s)).isModLoader()) {
return true;
}
}
return false;
return libraries.keySet().stream().map(LibraryType::fromPatchId)
.filter(Objects::nonNull)
.anyMatch(LibraryType::isModLoader);
}
public boolean hasModLauncher() {
final String modLauncher = "cpw.mods.modlauncher.Launcher";
boolean has = false;
for (Version patch : version.getPatches()) {
if (version.getMainClass().equals(modLauncher)) {
has = true;
break;
}
}
return modLauncher.equals(version.getMainClass()) || has;
return modLauncher.equals(version.getMainClass()) || version.getPatches().stream().anyMatch(patch -> modLauncher.equals(patch.getMainClass()));
}
public boolean hasBootstrapLauncher() {
final String bootstrapLauncher = "cpw.mods.bootstraplauncher.BootstrapLauncher";
boolean has = false;
for (Version patch : version.getPatches()) {
if (version.getMainClass().equals(bootstrapLauncher)) {
has = true;
break;
}
}
return bootstrapLauncher.equals(version.getMainClass()) || has;
return bootstrapLauncher.equals(version.getMainClass()) || version.getPatches().stream().anyMatch(patch -> bootstrapLauncher.equals(patch.getMainClass()));
}
private Version removingMatchedLibrary(Version version, String libraryId) {
@ -119,12 +101,11 @@ public final class LibraryAnalyzer implements Iterable<LibraryAnalyzer.LibraryMa
*/
public LibraryAnalyzer removeLibrary(String libraryId) {
if (!has(libraryId)) return this;
List<Version> newPatches = new ArrayList<>();
for (Version p : version.getPatches()) {
removingMatchedLibrary(p, libraryId);
newPatches.add(p);
}
version = removingMatchedLibrary(version, libraryId).setPatches(newPatches);
version = removingMatchedLibrary(version, libraryId)
.setPatches(version.getPatches().stream()
.filter(patch -> !libraryId.equals(patch.getId()))
.map(patch -> removingMatchedLibrary(patch, libraryId))
.collect(Collectors.toList()));
return this;
}

View File

@ -14,6 +14,7 @@ import com.tungsten.fclcore.game.StringArgument;
import com.tungsten.fclcore.game.Version;
import com.tungsten.fclcore.game.VersionLibraryBuilder;
import com.tungsten.fclcore.task.Task;
import com.tungsten.fclcore.util.Logging;
import com.tungsten.fclcore.util.SimpleMultimap;
import com.tungsten.fclcore.util.StringUtils;
import com.tungsten.fclcore.util.gson.JsonUtils;
@ -152,11 +153,11 @@ public class MaintainTask extends Task<Version> {
builder.addJvmArgument("-Dhmcl.transformer.candidates=${library_directory}/" + library.getPath());
if (!libraryExisting) builder.addLibrary(hmclTransformerDiscoveryService);
Path libraryPath = repository.getLibraryFile(version, hmclTransformerDiscoveryService).toPath();
try (InputStream input = MaintainTask.class.getResourceAsStream("/assets/game/HMCLTransformerDiscoveryService-1.0.jar")) {
try (InputStream input = MaintainTask.class.getResourceAsStream("/assets/game/FCLTransformerDiscoveryService-1.0.jar")) {
Files.createDirectories(libraryPath.getParent());
Files.copy(input, libraryPath, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
Logging.LOG.log(Level.WARNING, "Unable to unpack HMCLTransformerDiscoveryService", e);
Logging.LOG.log(Level.WARNING, "Unable to unpack FCLTransformerDiscoveryService", e);
}
});
}

View File

@ -1,5 +1,7 @@
package com.tungsten.fclcore.download.fabric;
import static com.tungsten.fclcore.util.Lang.wrap;
import com.tungsten.fclcore.download.DownloadProvider;
import com.tungsten.fclcore.download.VersionList;
import com.tungsten.fclcore.mod.RemoteMod;

View File

@ -1,5 +1,7 @@
package com.tungsten.fclcore.download.fabric;
import static com.tungsten.fclcore.util.Lang.wrap;
import com.google.gson.reflect.TypeToken;
import com.tungsten.fclcore.download.DownloadProvider;
import com.tungsten.fclcore.download.VersionList;

View File

@ -1,5 +1,7 @@
package com.tungsten.fclcore.download.forge;
import static com.tungsten.fclcore.util.Lang.mapOf;
import static com.tungsten.fclcore.util.Lang.wrap;
import static com.tungsten.fclcore.util.Logging.LOG;
import static com.tungsten.fclcore.util.Pair.pair;
@ -169,7 +171,6 @@ public final class ForgeBMCLVersionList extends VersionList<ForgeRemoteVersion>
throw new JsonParseException("ForgeVersion mcversion cannot be null");
}
@Immutable
public static final class File {
private final String format;
private final String category;

View File

@ -25,6 +25,7 @@ import java.util.Collections;
import java.util.Map;
import java.util.Optional;
// Todo : fix
public final class ForgeInstallTask extends Task<Version> {
private final DefaultDependencyManager dependencyManager;

View File

@ -151,7 +151,6 @@ public class ForgeNewInstallProfile implements Validation {
* {MINECRAFT_JAR}: path of the Minecraft jar.
* {SIDE}: values other than "client" will be ignored.
* @return arguments to pass to the processor jar.
* @see ForgeNewInstallTask#parseLiteral(String, Map, ExceptionalFunction)
*/
public List<String> getArgs() {
return args == null ? Collections.emptyList() : args;
@ -163,7 +162,6 @@ public class ForgeNewInstallProfile implements Validation {
* Keys can be in one of [artifact] or {entry}. Should be file path.
* Values can be in one of {entry} or 'literal'. Should be SHA-1 checksum.
* @return files output from this processor.
* @see ForgeNewInstallTask#parseLiteral(String, Map, ExceptionalFunction)
*/
public Map<String, String> getOutputs() {
return outputs == null ? Collections.emptyMap() : outputs;

View File

@ -42,6 +42,7 @@ import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.zip.ZipException;
// Todo : fix
public class ForgeNewInstallTask extends Task<Version> {
private class ProcessorTask extends Task<Void> {

View File

@ -1,5 +1,7 @@
package com.tungsten.fclcore.download.game;
import static com.tungsten.fclcore.util.Logging.LOG;
import com.google.gson.JsonParseException;
import com.tungsten.fclcore.download.AbstractDependencyManager;
import com.tungsten.fclcore.game.AssetIndex;

View File

@ -1,35 +1,18 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.tungsten.fclcore.download.game;
import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.game.DefaultGameRepository;
import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import static com.tungsten.fclcore.download.LibraryAnalyzer.LibraryType.MINECRAFT;
import com.tungsten.fclcore.download.DefaultDependencyManager;
import com.tungsten.fclcore.game.DefaultGameRepository;
import com.tungsten.fclcore.game.Version;
import com.tungsten.fclcore.task.Task;
import com.tungsten.fclcore.util.gson.JsonUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.MINECRAFT;
public class GameInstallTask extends Task<Version> {
private final DefaultGameRepository gameRepository;

View File

@ -18,6 +18,7 @@ import java.util.List;
/**
* Remove class digital verification file in game jar
*/
// Todo : fix
public final class GameVerificationFixTask extends Task<Void> {
private final DefaultDependencyManager dependencyManager;
private final String gameVersion;

View File

@ -27,6 +27,7 @@ import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.logging.Level;
// Todo : fix
public class LibraryDownloadTask extends Task<Void> {
private FileDownloadTask task;
protected final File jar;

View File

@ -35,6 +35,7 @@ import java.util.*;
/**
* <b>Note</b>: OptiFine should be installed in the end.
*/
// Todo : fix
public final class OptiFineInstallTask extends Task<Version> {
private final DefaultGameRepository gameRepository;

View File

@ -1,5 +1,7 @@
package com.tungsten.fclcore.download.quilt;
import static com.tungsten.fclcore.util.Lang.wrap;
import com.tungsten.fclcore.download.DownloadProvider;
import com.tungsten.fclcore.download.VersionList;
import com.tungsten.fclcore.mod.RemoteMod;

View File

@ -1,5 +1,7 @@
package com.tungsten.fclcore.download.quilt;
import static com.tungsten.fclcore.util.Lang.wrap;
import com.google.gson.reflect.TypeToken;
import com.tungsten.fclcore.download.DownloadProvider;
import com.tungsten.fclcore.download.VersionList;

View File

@ -10,6 +10,7 @@ import java.nio.file.*;
import java.util.*;
import java.util.logging.Level;
// Todo : fix
public class Datapack {
private boolean isMultiple;
private final Path path;

View File

@ -15,6 +15,7 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
// Todo : fix
public final class FabricModMetadata {
private final String id;
private final String name;

View File

@ -1,6 +1,9 @@
package com.tungsten.fclcore.mod;
import static com.tungsten.fclcore.util.Logging.LOG;
import com.google.gson.JsonParseException;
import com.moandjiezana.toml.Toml;
import com.tungsten.fclcore.util.io.FileUtils;
import java.io.IOException;
@ -13,6 +16,7 @@ import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.logging.Level;
// Todo : fix
public final class ForgeNewModMetadata {
private final String modLoader;

View File

@ -13,6 +13,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
// Todo : fix
public final class ForgeOldModMetadata {
@SerializedName("modid")

View File

@ -9,6 +9,7 @@ import java.util.*;
import java.util.logging.Level;
import java.util.stream.Collectors;
// Todo : fix
public final class LocalModFile implements Comparable<LocalModFile> {
private Path file;

View File

@ -16,6 +16,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
// Todo : fix
public final class MinecraftInstanceTask<T> extends Task<ModpackConfiguration<T>> {
private final File zipFile;

View File

@ -12,6 +12,7 @@ import java.util.HashMap;
import java.util.Objects;
import java.util.TreeSet;
// Todo : fix
public final class ModManager {
private final GameRepository repository;
private final String id;

View File

@ -13,6 +13,7 @@ import java.nio.file.Files;
import java.util.*;
import java.util.function.Predicate;
// Todo : fix
public class ModpackInstallTask<T> extends Task<Void> {
private final File modpackFile;

View File

@ -5,6 +5,8 @@ import com.tungsten.fclcore.download.DefaultDependencyManager;
import com.tungsten.fclcore.game.LaunchOptions;
import com.tungsten.fclcore.task.Task;
import org.apache.commons.compress.archivers.zip.ZipFile;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;

View File

@ -16,6 +16,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
// Todo : fix
public class PackMcMeta implements Validation {
@SerializedName("pack")

View File

@ -26,8 +26,6 @@ import java.util.stream.Collectors;
/**
* Complete the CurseForge version.
*
* @author huangyuhui
*/
public final class CurseCompletionTask extends Task<Void> {

View File

@ -7,7 +7,9 @@ import com.google.gson.reflect.TypeToken;
import com.tungsten.fclcore.mod.LocalModFile;
import com.tungsten.fclcore.mod.RemoteMod;
import com.tungsten.fclcore.mod.RemoteModRepository;
import com.tungsten.fclcore.util.MurmurHash2;
import com.tungsten.fclcore.util.io.HttpRequest;
import com.tungsten.fclcore.util.io.JarUtils;
import org.jetbrains.annotations.Nullable;

View File

@ -45,7 +45,6 @@ public final class CurseInstallTask extends Task<Void> {
* @param zipFile the CurseForge modpack file.
* @param manifest The manifest content of given CurseForge modpack.
* @param name the new version name
* @see CurseManifest#readCurseForgeModpackManifest
*/
public CurseInstallTask(DefaultDependencyManager dependencyManager, File zipFile, Modpack modpack, CurseManifest manifest, String name) {
this.dependencyManager = dependencyManager;

View File

@ -6,15 +6,19 @@ import com.tungsten.fclcore.mod.MismatchedModpackTypeException;
import com.tungsten.fclcore.mod.Modpack;
import com.tungsten.fclcore.mod.ModpackProvider;
import com.tungsten.fclcore.mod.ModpackUpdateTask;
import com.tungsten.fclcore.task.Task;
import com.tungsten.fclcore.util.gson.JsonUtils;
import com.tungsten.fclcore.util.io.IOUtils;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.zip.ZipFile;
// Todo : fix
public final class CurseModpackProvider implements ModpackProvider {
public static final CurseModpackProvider INSTANCE = new CurseModpackProvider();

View File

@ -2,6 +2,8 @@ package com.tungsten.fclcore.mod.mcbbs;
import static com.tungsten.fclcore.util.DigestUtils.digest;
import static com.tungsten.fclcore.util.Hex.encodeHex;
import static com.tungsten.fclcore.util.Lang.wrap;
import static com.tungsten.fclcore.util.Lang.wrapConsumer;
import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;

View File

@ -28,6 +28,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
// Todo : fix
public class McbbsModpackExportTask extends Task<Void> {
private final DefaultGameRepository repository;
private final String version;

View File

@ -13,11 +13,13 @@ import com.tungsten.fclcore.task.Task;
import com.tungsten.fclcore.util.gson.JsonUtils;
import com.tungsten.fclcore.util.io.IOUtils;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.zip.ZipFile;
public final class McbbsModpackProvider implements ModpackProvider {
public static final McbbsModpackProvider INSTANCE = new McbbsModpackProvider();

View File

@ -9,11 +9,14 @@ import com.tungsten.fclcore.mod.ModpackUpdateTask;
import com.tungsten.fclcore.task.Task;
import com.tungsten.fclcore.util.gson.JsonUtils;
import org.apache.commons.compress.archivers.zip.ZipFile;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Path;
// Todo : fix
public final class ModrinthModpackProvider implements ModpackProvider {
public static final ModrinthModpackProvider INSTANCE = new ModrinthModpackProvider();

View File

@ -4,6 +4,9 @@ import com.google.gson.annotations.SerializedName;
import com.tungsten.fclcore.util.gson.JsonUtils;
import com.tungsten.fclcore.util.io.IOUtils;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import java.io.IOException;
import java.util.List;

View File

@ -21,6 +21,7 @@ import java.util.List;
/**
* Export the game to a mod pack file.
*/
// Todo : fix
public class MultiMCModpackExportTask extends Task<Void> {
private final DefaultGameRepository repository;
private final String versionId;

View File

@ -4,6 +4,7 @@ import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import com.tungsten.fclcore.download.DefaultDependencyManager;
import com.tungsten.fclcore.download.GameBuilder;
import com.tungsten.fclcore.game.Arguments;
import com.tungsten.fclcore.game.DefaultGameRepository;
import com.tungsten.fclcore.game.Version;
import com.tungsten.fclcore.mod.MinecraftInstanceTask;
@ -25,6 +26,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Optional;
// Todo : fix
public final class MultiMCModpackInstallTask extends Task<Void> {
private final File zipFile;

View File

@ -8,6 +8,9 @@ import com.tungsten.fclcore.mod.ModpackUpdateTask;
import com.tungsten.fclcore.task.Task;
import com.tungsten.fclcore.util.io.FileUtils;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

View File

@ -9,6 +9,8 @@ import com.tungsten.fclcore.mod.ModpackUpdateTask;
import com.tungsten.fclcore.task.Task;
import com.tungsten.fclcore.util.gson.JsonUtils;
import org.apache.commons.compress.archivers.zip.ZipFile;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;

View File

@ -24,6 +24,7 @@ import com.tungsten.fclcore.util.io.FileUtils;
/**
* A task that can download a file online.
*/
// Todo : fix
public class FileDownloadTask extends FetchTask<Void> {
public static class IntegrityCheck {

View File

@ -965,7 +965,7 @@ public abstract class Task<T> {
}
private static String getCaller() {
return ReflectionHelper.getCaller(packageName -> !"org.jackhuang.hmcl.task".equals(packageName)).toString();
return ReflectionHelper.getCaller(packageName -> !"com.tungsten.fclcore.task".equals(packageName)).toString();
}
private static final class SimpleTask<T> extends Task<T> {
@ -1002,8 +1002,6 @@ public abstract class Task<T> {
/**
* A task that combines two tasks and make sure [pred] runs before succ.
*
* @author huangyuhui
*/
private final class UniCompose<U> extends Task<U> {

View File

@ -0,0 +1,312 @@
package com.tungsten.fclcore.util;
import java.nio.charset.StandardCharsets;
/**
* Implementation of the MurmurHash2 32-bit and 64-bit hash functions.
*
* <p>MurmurHash is a non-cryptographic hash function suitable for general
* hash-based lookup. The name comes from two basic operations, multiply (MU)
* and rotate (R), used in its inner loop. Unlike cryptographic hash functions,
* it is not specifically designed to be difficult to reverse by an adversary,
* making it unsuitable for cryptographic purposes.</p>
*
* <p>This contains a Java port of the 32-bit hash function {@code MurmurHash2}
* and the 64-bit hash function {@code MurmurHash64A} from Austin Applyby's
* original {@code c++} code in SMHasher.</p>
*
* <p>This is a re-implementation of the original C code plus some additional
* features.</p>
*
* <p>This is public domain code with no copyrights. From home page of
* <a href="https://github.com/aappleby/smhasher">SMHasher</a>:</p>
*
* <blockquote>
* "All MurmurHash versions are public domain software, and the author
* disclaims all copyright to their code."
* </blockquote>
*
* @see <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>
* @see <a href="https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp">
* Original MurmurHash2 c++ code</a>
* @since 1.13
*/
public final class MurmurHash2 {
// Constants for 32-bit variant
private static final int M32 = 0x5bd1e995;
private static final int R32 = 24;
// Constants for 64-bit variant
private static final long M64 = 0xc6a4a7935bd1e995L;
private static final int R64 = 47;
/**
* No instance methods.
*/
private MurmurHash2() {
}
/**
* Generates a 32-bit hash from byte array with the given length and seed.
*
* @param data The input byte array
* @param length The length of the array
* @param seed The initial seed value
* @return The 32-bit hash
*/
public static int hash32(final byte[] data, final int length, final int seed) {
// Initialize the hash to a random value
int h = seed ^ length;
// Mix 4 bytes at a time into the hash
final int nblocks = length >> 2;
// body
for (int i = 0; i < nblocks; i++) {
final int index = (i << 2);
int k = getLittleEndianInt(data, index);
k *= M32;
k ^= k >>> R32;
k *= M32;
h *= M32;
h ^= k;
}
// Handle the last few bytes of the input array
final int index = (nblocks << 2);
switch (length - index) {
case 3:
h ^= (data[index + 2] & 0xff) << 16;
// fallthrough
case 2:
h ^= (data[index + 1] & 0xff) << 8;
// fallthrough
case 1:
h ^= (data[index] & 0xff);
h *= M32;
}
// Do a few final mixes of the hash to ensure the last few
// bytes are well-incorporated.
h ^= h >>> 13;
h *= M32;
h ^= h >>> 15;
return h;
}
/**
* Generates a 32-bit hash from byte array with the given length and a default seed value.
* This is a helper method that will produce the same result as:
*
* <pre>
* int seed = 0x9747b28c;
* int hash = MurmurHash2.hash32(data, length, seed);
* </pre>
*
* @param data The input byte array
* @param length The length of the array
* @return The 32-bit hash
* @see #hash32(byte[], int, int)
*/
public static int hash32(final byte[] data, final int length) {
return hash32(data, length, 0x9747b28c);
}
/**
* Generates a 32-bit hash from a string with a default seed.
* <p>
* Before 1.14 the string was converted using default encoding.
* Since 1.14 the string is converted to bytes using UTF-8 encoding.
* </p>
* This is a helper method that will produce the same result as:
*
* <pre>
* int seed = 0x9747b28c;
* byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
* int hash = MurmurHash2.hash32(bytes, bytes.length, seed);
* </pre>
*
* @param text The input string
* @return The 32-bit hash
* @see #hash32(byte[], int, int)
*/
public static int hash32(final String text) {
final byte[] bytes = text.getBytes(StandardCharsets.UTF_8);
return hash32(bytes, bytes.length);
}
/**
* Generates a 32-bit hash from a substring with a default seed value.
* The string is converted to bytes using the default encoding.
* This is a helper method that will produce the same result as:
*
* <pre>
* int seed = 0x9747b28c;
* byte[] bytes = text.substring(from, from + length).getBytes(StandardCharsets.UTF_8);
* int hash = MurmurHash2.hash32(bytes, bytes.length, seed);
* </pre>
*
* @param text The input string
* @param from The starting index
* @param length The length of the substring
* @return The 32-bit hash
* @see #hash32(byte[], int, int)
*/
public static int hash32(final String text, final int from, final int length) {
return hash32(text.substring(from, from + length));
}
/**
* Generates a 64-bit hash from byte array of the given length and seed.
*
* @param data The input byte array
* @param length The length of the array
* @param seed The initial seed value
* @return The 64-bit hash of the given array
*/
public static long hash64(final byte[] data, final int length, final int seed) {
long h = (seed & 0xffffffffL) ^ (length * M64);
final int nblocks = length >> 3;
// body
for (int i = 0; i < nblocks; i++) {
final int index = (i << 3);
long k = getLittleEndianLong(data, index);
k *= M64;
k ^= k >>> R64;
k *= M64;
h ^= k;
h *= M64;
}
final int index = (nblocks << 3);
switch (length - index) {
case 7:
h ^= ((long) data[index + 6] & 0xff) << 48;
// fallthrough
case 6:
h ^= ((long) data[index + 5] & 0xff) << 40;
// fallthrough
case 5:
h ^= ((long) data[index + 4] & 0xff) << 32;
// fallthrough
case 4:
h ^= ((long) data[index + 3] & 0xff) << 24;
// fallthrough
case 3:
h ^= ((long) data[index + 2] & 0xff) << 16;
// fallthrough
case 2:
h ^= ((long) data[index + 1] & 0xff) << 8;
// fallthrough
case 1:
h ^= ((long) data[index] & 0xff);
h *= M64;
}
h ^= h >>> R64;
h *= M64;
h ^= h >>> R64;
return h;
}
/**
* Generates a 64-bit hash from byte array with given length and a default seed value.
* This is a helper method that will produce the same result as:
*
* <pre>
* int seed = 0xe17a1465;
* int hash = MurmurHash2.hash64(data, length, seed);
* </pre>
*
* @param data The input byte array
* @param length The length of the array
* @return The 64-bit hash
* @see #hash64(byte[], int, int)
*/
public static long hash64(final byte[] data, final int length) {
return hash64(data, length, 0xe17a1465);
}
/**
* Generates a 64-bit hash from a string with a default seed.
* <p>
* Before 1.14 the string was converted using default encoding.
* Since 1.14 the string is converted to bytes using UTF-8 encoding.
* </p>
* This is a helper method that will produce the same result as:
*
* <pre>
* int seed = 0xe17a1465;
* byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
* int hash = MurmurHash2.hash64(bytes, bytes.length, seed);
* </pre>
*
* @param text The input string
* @return The 64-bit hash
* @see #hash64(byte[], int, int)
*/
public static long hash64(final String text) {
final byte[] bytes = text.getBytes(StandardCharsets.UTF_8);
return hash64(bytes, bytes.length);
}
/**
* Generates a 64-bit hash from a substring with a default seed value.
* The string is converted to bytes using the default encoding.
* This is a helper method that will produce the same result as:
*
* <pre>
* int seed = 0xe17a1465;
* byte[] bytes = text.substring(from, from + length).getBytes(StandardCharsets.UTF_8);
* int hash = MurmurHash2.hash64(bytes, bytes.length, seed);
* </pre>
*
* @param text The The input string
* @param from The starting index
* @param length The length of the substring
* @return The 64-bit hash
* @see #hash64(byte[], int, int)
*/
public static long hash64(final String text, final int from, final int length) {
return hash64(text.substring(from, from + length));
}
/**
* Gets the little-endian int from 4 bytes starting at the specified index.
*
* @param data The data
* @param index The index
* @return The little-endian int
*/
private static int getLittleEndianInt(final byte[] data, final int index) {
return ((data[index] & 0xff)) |
((data[index + 1] & 0xff) << 8) |
((data[index + 2] & 0xff) << 16) |
((data[index + 3] & 0xff) << 24);
}
/**
* Gets the little-endian long from 8 bytes starting at the specified index.
*
* @param data The data
* @param index The index
* @return The little-endian long
*/
private static long getLittleEndianLong(final byte[] data, final int index) {
return (((long) data[index] & 0xff)) |
(((long) data[index + 1] & 0xff) << 8) |
(((long) data[index + 2] & 0xff) << 16) |
(((long) data[index + 3] & 0xff) << 24) |
(((long) data[index + 4] & 0xff) << 32) |
(((long) data[index + 5] & 0xff) << 40) |
(((long) data[index + 6] & 0xff) << 48) |
(((long) data[index + 7] & 0xff) << 56);
}
}