--- a/src/Pure/General/bytes.scala Sun Mar 26 12:53:53 2023 +0200
+++ b/src/Pure/General/bytes.scala Sun Mar 26 14:24:38 2023 +0200
@@ -9,6 +9,9 @@
import java.io.{ByteArrayInputStream, ByteArrayOutputStream, FileInputStream, FileOutputStream, InputStream, OutputStream, File as JFile}
import java.net.URL
+import java.nio.ByteBuffer
+import java.nio.channels.FileChannel
+import java.nio.file.StandardOpenOption
import org.tukaani.xz
import com.github.luben.zstd
@@ -75,6 +78,28 @@
def read(url: URL): Bytes = using(url.openStream)(read_stream(_))
+ def read_slice(path: Path, offset: Long = 0L, limit: Long = Long.MaxValue): Bytes = {
+ val start = offset.max(0L)
+ val len = (path.file.length - start).max(0L).min(limit)
+ if (len > Integer.MAX_VALUE) error("Cannot read large file slice: " + Space.bytes(len).print)
+ else if (len == 0L) empty
+ else {
+ using(FileChannel.open(path.java_path, StandardOpenOption.READ)) { file =>
+ file.position(start)
+ val n = len.toInt
+ val buf = ByteBuffer.allocate(n)
+ var i = 0
+ var m = 0
+ while ({
+ m = file.read(buf)
+ if (m != -1) i += m
+ m != -1 && n > i
+ }) ()
+ new Bytes(buf.array, 0, i)
+ }
+ }
+ }
+
/* write */
--- a/src/Pure/ML/ml_heap.scala Sun Mar 26 12:53:53 2023 +0200
+++ b/src/Pure/ML/ml_heap.scala Sun Mar 26 14:24:38 2023 +0200
@@ -19,30 +19,16 @@
def read_digest(heap: Path): Option[SHA1.Digest] = {
if (heap.is_file) {
- using(FileChannel.open(heap.java_path, StandardOpenOption.READ)) { file =>
- val len = file.size
- val n = sha1_prefix.length + SHA1.digest_length
- if (len >= n) {
- file.position(len - n)
-
- val buf = ByteBuffer.allocate(n)
- var i = 0
- var m = 0
- while ({
- m = file.read(buf)
- if (m != -1) i += m
- m != -1 && n > i
- }) ()
-
- if (i == n) {
- val prefix = new String(buf.array(), 0, sha1_prefix.length, UTF8.charset)
- val s = new String(buf.array(), sha1_prefix.length, SHA1.digest_length, UTF8.charset)
- if (prefix == sha1_prefix) Some(SHA1.fake_digest(s)) else None
- }
- else None
- }
+ val l = sha1_prefix.length
+ val m = l + SHA1.digest_length
+ val n = heap.file.length
+ val bs = Bytes.read_slice(heap, offset = n - m)
+ if (bs.length == m) {
+ val s = bs.text
+ if (s.startsWith(sha1_prefix)) Some(SHA1.fake_digest(s.substring(l)))
else None
}
+ else None
}
else None
}