mirror of
https://github.com/packwiz/packwiz-installer.git
synced 2025-04-19 21:16: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