mirror of
https://github.com/packwiz/packwiz-installer.git
synced 2025-04-19 13:06:30 +02:00
Port hashing stuff to Kotlin
This commit is contained in:
parent
b45a2983e7
commit
ecaab219c2
@ -1,18 +0,0 @@
|
||||
package link.infra.packwiz.installer.metadata.hash;
|
||||
|
||||
import okio.ForwardingSource;
|
||||
import okio.Source;
|
||||
|
||||
public abstract class GeneralHashingSource extends ForwardingSource {
|
||||
|
||||
public GeneralHashingSource(Source delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
public abstract Hash getHash();
|
||||
|
||||
public boolean hashIsEqual(Object compareTo) {
|
||||
return compareTo.equals(getHash());
|
||||
}
|
||||
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
package link.infra.packwiz.installer.metadata.hash;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
|
||||
public abstract class Hash {
|
||||
protected abstract String getStringValue();
|
||||
|
||||
protected abstract String getType();
|
||||
|
||||
public static class TypeHandler implements JsonDeserializer<Hash>, JsonSerializer<Hash> {
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(Hash src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject out = new JsonObject();
|
||||
out.add("type", new JsonPrimitive(src.getType()));
|
||||
out.add("value", new JsonPrimitive(src.getStringValue()));
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hash deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
JsonObject obj = json.getAsJsonObject();
|
||||
String type, value;
|
||||
try {
|
||||
type = obj.get("type").getAsString();
|
||||
value = obj.get("value").getAsString();
|
||||
} catch (NullPointerException e) {
|
||||
throw new JsonParseException("Invalid hash JSON data");
|
||||
}
|
||||
try {
|
||||
return HashUtils.getHash(type, value);
|
||||
} catch (Exception e) {
|
||||
throw new JsonParseException("Failed to create hash object", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package link.infra.packwiz.installer.metadata.hash;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class HashUtils {
|
||||
private static final Map<String, IHasher> hashTypeConversion = new HashMap<String, IHasher>();
|
||||
static {
|
||||
hashTypeConversion.put("sha256", new HashingSourceHasher("sha256"));
|
||||
hashTypeConversion.put("murmur2", new Murmur2Hasher());
|
||||
}
|
||||
|
||||
public static IHasher getHasher(String type) throws Exception {
|
||||
IHasher hasher = hashTypeConversion.get(type);
|
||||
if (hasher == null) {
|
||||
throw new Exception("Hash type not supported: " + type);
|
||||
}
|
||||
return hasher;
|
||||
}
|
||||
|
||||
public static Hash getHash(String type, String value) throws Exception {
|
||||
if (hashTypeConversion.containsKey(type)) {
|
||||
return hashTypeConversion.get(type).getHash(value);
|
||||
}
|
||||
|
||||
throw new Exception("Hash type not supported: " + type);
|
||||
}
|
||||
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
package link.infra.packwiz.installer.metadata.hash;
|
||||
|
||||
import okio.HashingSource;
|
||||
import okio.Source;
|
||||
|
||||
public class HashingSourceHasher implements IHasher {
|
||||
private String type;
|
||||
|
||||
HashingSourceHasher(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
// i love naming things
|
||||
private class HashingSourceGeneralHashingSource extends GeneralHashingSource {
|
||||
HashingSource delegateHashing;
|
||||
HashingSourceHash value;
|
||||
|
||||
HashingSourceGeneralHashingSource(HashingSource delegate) {
|
||||
super(delegate);
|
||||
delegateHashing = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hash getHash() {
|
||||
if (value == null) {
|
||||
value = new HashingSourceHash(delegateHashing.hash().hex());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// this some funky inner class stuff
|
||||
// each of these classes is specific to the instance of the HasherHashingSource
|
||||
// therefore HashingSourceHashes from different parent instances will be not instanceof each other
|
||||
private class HashingSourceHash extends Hash {
|
||||
String value;
|
||||
private HashingSourceHash(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof HashingSourceHash)) {
|
||||
return false;
|
||||
}
|
||||
HashingSourceHash objHash = (HashingSourceHash) obj;
|
||||
if (value != null) {
|
||||
return value.equalsIgnoreCase(objHash.value);
|
||||
} else {
|
||||
return objHash.value == null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type + ": " + value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getStringValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeneralHashingSource getHashingSource(Source delegate) {
|
||||
switch (type) {
|
||||
case "md5":
|
||||
return new HashingSourceGeneralHashingSource(HashingSource.md5(delegate));
|
||||
case "sha256":
|
||||
return new HashingSourceGeneralHashingSource(HashingSource.sha256(delegate));
|
||||
case "sha512":
|
||||
return new HashingSourceGeneralHashingSource(HashingSource.sha512(delegate));
|
||||
}
|
||||
throw new RuntimeException("Invalid hash type provided");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hash getHash(String value) {
|
||||
return new HashingSourceHash(value);
|
||||
}
|
||||
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package link.infra.packwiz.installer.metadata.hash;
|
||||
|
||||
import okio.Source;
|
||||
|
||||
public interface IHasher {
|
||||
public GeneralHashingSource getHashingSource(Source delegate);
|
||||
public Hash getHash(String value);
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
package link.infra.packwiz.installer.metadata.hash;
|
||||
|
||||
import okio.Buffer;
|
||||
import okio.Source;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class Murmur2Hasher implements IHasher {
|
||||
private class Murmur2GeneralHashingSource extends GeneralHashingSource {
|
||||
Murmur2Hash value;
|
||||
Buffer internalBuffer = new Buffer();
|
||||
Buffer tempBuffer = new Buffer();
|
||||
Source delegate;
|
||||
|
||||
public Murmur2GeneralHashingSource(Source delegate) {
|
||||
super(delegate);
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long read(Buffer sink, long byteCount) throws IOException {
|
||||
long out = delegate.read(tempBuffer, byteCount);
|
||||
if (out > -1) {
|
||||
sink.write(tempBuffer.clone(), out);
|
||||
internalBuffer.write(tempBuffer, out);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hash getHash() {
|
||||
if (value == null) {
|
||||
byte[] data = computeNormalizedArray(internalBuffer.readByteArray());
|
||||
value = new Murmur2Hash(Murmur2Lib.hash32(data, data.length, 1));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// Credit to https://github.com/modmuss50/CAV2/blob/master/murmur.go
|
||||
private byte[] computeNormalizedArray(byte[] input) {
|
||||
byte[] output = new byte[input.length];
|
||||
int num = 0;
|
||||
for (byte b : input) {
|
||||
if (!(b == 9 || b == 10 || b == 13 || b == 32)) {
|
||||
output[num] = b;
|
||||
num++;
|
||||
}
|
||||
}
|
||||
byte[] outputTrimmed = new byte[num];
|
||||
System.arraycopy(output, 0, outputTrimmed, 0, num);
|
||||
return outputTrimmed;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class Murmur2Hash extends Hash {
|
||||
int value;
|
||||
private Murmur2Hash(String value) {
|
||||
// Parsing as long then casting to int converts values gt int max value but lt uint max value
|
||||
// into negatives. I presume this is how the murmur2 code handles this.
|
||||
this.value = (int)Long.parseLong(value);
|
||||
}
|
||||
|
||||
private Murmur2Hash(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Murmur2Hash)) {
|
||||
return false;
|
||||
}
|
||||
Murmur2Hash objHash = (Murmur2Hash) obj;
|
||||
return value == objHash.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "murmur2: " + value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getStringValue() {
|
||||
return Integer.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getType() {
|
||||
return "murmur2";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeneralHashingSource getHashingSource(Source delegate) {
|
||||
return new Murmur2GeneralHashingSource(delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hash getHash(String value) {
|
||||
return new Murmur2Hash(value);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package link.infra.packwiz.installer.metadata.hash
|
||||
|
||||
import okio.ForwardingSource
|
||||
import okio.Source
|
||||
|
||||
abstract class GeneralHashingSource(delegate: Source) : ForwardingSource(delegate) {
|
||||
abstract val hash: Hash
|
||||
|
||||
fun hashIsEqual(compareTo: Any) = compareTo == hash
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package link.infra.packwiz.installer.metadata.hash
|
||||
|
||||
import com.google.gson.*
|
||||
import java.lang.reflect.Type
|
||||
|
||||
abstract class Hash {
|
||||
protected abstract val stringValue: String
|
||||
protected abstract val type: String
|
||||
|
||||
class TypeHandler : JsonDeserializer<Hash>, JsonSerializer<Hash> {
|
||||
override fun serialize(src: Hash, typeOfSrc: Type, context: JsonSerializationContext): JsonElement = JsonObject().apply {
|
||||
add("type", JsonPrimitive(src.type))
|
||||
add("value", JsonPrimitive(src.stringValue))
|
||||
}
|
||||
|
||||
@Throws(JsonParseException::class)
|
||||
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Hash {
|
||||
val obj = json.asJsonObject
|
||||
val type: String
|
||||
val value: String
|
||||
try {
|
||||
type = obj["type"].asString
|
||||
value = obj["value"].asString
|
||||
} catch (e: NullPointerException) {
|
||||
throw JsonParseException("Invalid hash JSON data")
|
||||
}
|
||||
return try {
|
||||
HashUtils.getHash(type, value)
|
||||
} catch (e: Exception) {
|
||||
throw JsonParseException("Failed to create hash object", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package link.infra.packwiz.installer.metadata.hash
|
||||
|
||||
object HashUtils {
|
||||
private val hashTypeConversion: Map<String, IHasher> = mapOf(
|
||||
"sha256" to HashingSourceHasher("sha256"),
|
||||
"sha512" to HashingSourceHasher("sha512"),
|
||||
"murmur2" to Murmur2Hasher()
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Throws(Exception::class)
|
||||
fun getHasher(type: String): IHasher {
|
||||
return hashTypeConversion[type] ?: throw Exception("Hash type not supported: $type")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Throws(Exception::class)
|
||||
fun getHash(type: String, value: String): Hash {
|
||||
return hashTypeConversion[type]?.getHash(value) ?: throw Exception("Hash type not supported: $type")
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package link.infra.packwiz.installer.metadata.hash
|
||||
|
||||
import okio.HashingSource
|
||||
import okio.Source
|
||||
|
||||
class HashingSourceHasher internal constructor(private val type: String) : IHasher {
|
||||
// i love naming things
|
||||
private inner class HashingSourceGeneralHashingSource internal constructor(val delegateHashing: HashingSource) : GeneralHashingSource(delegateHashing) {
|
||||
override val hash: Hash by lazy(LazyThreadSafetyMode.NONE) {
|
||||
HashingSourceHash(delegateHashing.hash.hex())
|
||||
}
|
||||
}
|
||||
|
||||
// this some funky inner class stuff
|
||||
// each of these classes is specific to the instance of the HasherHashingSource
|
||||
// therefore HashingSourceHashes from different parent instances will be not instanceof each other
|
||||
private inner class HashingSourceHash(val value: String) : Hash() {
|
||||
override val stringValue get() = value
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is HashingSourceHash) {
|
||||
return false
|
||||
}
|
||||
return stringValue.equals(other.stringValue, ignoreCase = true)
|
||||
}
|
||||
|
||||
override fun toString(): String = "$type: $stringValue"
|
||||
override fun hashCode(): Int = value.hashCode()
|
||||
|
||||
override val type: String get() = this@HashingSourceHasher.type
|
||||
}
|
||||
|
||||
override fun getHashingSource(delegate: Source): GeneralHashingSource {
|
||||
when (type) {
|
||||
"md5" -> return HashingSourceGeneralHashingSource(HashingSource.md5(delegate))
|
||||
"sha256" -> return HashingSourceGeneralHashingSource(HashingSource.sha256(delegate))
|
||||
"sha512" -> return HashingSourceGeneralHashingSource(HashingSource.sha512(delegate))
|
||||
}
|
||||
throw RuntimeException("Invalid hash type provided")
|
||||
}
|
||||
|
||||
override fun getHash(value: String): Hash {
|
||||
return HashingSourceHash(value)
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package link.infra.packwiz.installer.metadata.hash
|
||||
|
||||
import okio.Source
|
||||
|
||||
interface IHasher {
|
||||
fun getHashingSource(delegate: Source): GeneralHashingSource
|
||||
fun getHash(value: String): Hash
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package link.infra.packwiz.installer.metadata.hash
|
||||
|
||||
import okio.Buffer
|
||||
import okio.Source
|
||||
import java.io.IOException
|
||||
|
||||
class Murmur2Hasher : IHasher {
|
||||
private inner class Murmur2GeneralHashingSource(delegate: Source) : GeneralHashingSource(delegate) {
|
||||
val internalBuffer = Buffer()
|
||||
val tempBuffer = Buffer()
|
||||
|
||||
override val hash: Hash by lazy(LazyThreadSafetyMode.NONE) {
|
||||
val data = computeNormalizedArray(internalBuffer.readByteArray())
|
||||
Murmur2Hash(Murmur2Lib.hash32(data, data.size, 1))
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun read(sink: Buffer, byteCount: Long): Long {
|
||||
val out = delegate.read(tempBuffer, byteCount)
|
||||
if (out > -1) {
|
||||
sink.write(tempBuffer.clone(), out)
|
||||
internalBuffer.write(tempBuffer, out)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Credit to https://github.com/modmuss50/CAV2/blob/master/murmur.go
|
||||
private fun computeNormalizedArray(input: ByteArray): ByteArray {
|
||||
val output = ByteArray(input.size)
|
||||
var index = 0
|
||||
for (b in input) {
|
||||
when (b.toInt()) {
|
||||
9, 10, 13, 32 -> {}
|
||||
else -> {
|
||||
output[index] = b
|
||||
index++
|
||||
}
|
||||
}
|
||||
}
|
||||
val outputTrimmed = ByteArray(index)
|
||||
System.arraycopy(output, 0, outputTrimmed, 0, index)
|
||||
return outputTrimmed
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class Murmur2Hash : Hash {
|
||||
val value: Int
|
||||
|
||||
constructor(value: String) {
|
||||
// Parsing as long then casting to int converts values gt int max value but lt uint max value
|
||||
// into negatives. I presume this is how the murmur2 code handles this.
|
||||
this.value = value.toLong().toInt()
|
||||
}
|
||||
|
||||
constructor(value: Int) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
override val stringValue get() = value.toString()
|
||||
override val type get() = "murmur2"
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is Murmur2Hash) {
|
||||
return false
|
||||
}
|
||||
return value == other.value
|
||||
}
|
||||
|
||||
override fun toString(): String = "murmur2: $value"
|
||||
override fun hashCode(): Int = value
|
||||
}
|
||||
|
||||
override fun getHashingSource(delegate: Source): GeneralHashingSource = Murmur2GeneralHashingSource(delegate)
|
||||
override fun getHash(value: String): Hash = Murmur2Hash(value)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user