Add streaming hash utility function to quartz multiplatform, follow the existing pool/worker design

Change hashing in ImageDownloader.kt to use streaming
This commit is contained in:
davotoula
2025-10-25 23:22:31 +02:00
parent e1c54f52e3
commit 93994564f6
6 changed files with 217 additions and 32 deletions
@@ -20,6 +20,22 @@
*/
package com.vitorpamplona.quartz.utils.sha256
import java.io.InputStream
val pool = Sha256Pool(5) // max parallel operations
actual fun sha256(data: ByteArray) = pool.hash(data)
/**
* Calculate SHA256 hash by streaming the input in chunks.
* This avoids loading the entire input into memory at once.
* Useful for hashing large files without running out of memory.
*
* @param inputStream The input stream to hash
* @param bufferSize Size of chunks to read (default 8KB)
* @return SHA256 hash bytes
*/
fun sha256Stream(
inputStream: InputStream,
bufferSize: Int = 8192,
) = pool.hashStream(inputStream, bufferSize)
@@ -20,6 +20,7 @@
*/
package com.vitorpamplona.quartz.utils.sha256
import java.io.InputStream
import java.security.MessageDigest
class Sha256Hasher {
@@ -30,4 +31,26 @@ class Sha256Hasher {
fun digest(byteArray: ByteArray) = digest.digest(byteArray)
fun reset() = digest.reset()
/**
* Calculate SHA256 hash by streaming the input in chunks.
* This avoids loading the entire input into memory at once.
*
* @param inputStream The input stream to hash
* @param bufferSize Size of chunks to read (default 8KB)
* @return SHA256 hash bytes
*/
fun hashStream(
inputStream: InputStream,
bufferSize: Int = 8192,
): ByteArray {
val buffer = ByteArray(bufferSize)
var bytesRead: Int
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
digest.update(buffer, 0, bytesRead)
}
return digest.digest().also { digest.reset() }
}
}
@@ -21,6 +21,7 @@
package com.vitorpamplona.quartz.utils.sha256
import com.vitorpamplona.quartz.utils.Log
import java.io.InputStream
import java.util.concurrent.ArrayBlockingQueue
class Sha256Pool(
@@ -54,4 +55,24 @@ class Sha256Pool(
release(hasher)
}
}
/**
* Calculate SHA256 hash by streaming the input in chunks.
* This avoids loading the entire input into memory at once.
*
* @param inputStream The input stream to hash
* @param bufferSize Size of chunks to read (default 8KB)
* @return SHA256 hash bytes
*/
fun hashStream(
inputStream: InputStream,
bufferSize: Int = 8192,
): ByteArray {
val hasher = acquire()
try {
return hasher.hashStream(inputStream, bufferSize)
} finally {
release(hasher)
}
}
}