Base64: proper support for large Bytes, with subtle change of types (Bytes instead of String);
authorwenzelm
Sun, 16 Jun 2024 18:41:57 +0200
changeset 80393 6138c5b803be
parent 80392 c22a56495b4c
child 80394 348e10664e0f
Base64: proper support for large Bytes, with subtle change of types (Bytes instead of String);
src/Pure/Build/build_manager.scala
src/Pure/General/base64.scala
src/Pure/General/bytes.scala
--- a/src/Pure/Build/build_manager.scala	Sun Jun 16 18:18:55 2024 +0200
+++ b/src/Pure/Build/build_manager.scala	Sun Jun 16 18:41:57 2024 +0200
@@ -1174,7 +1174,7 @@
       val head =
         List(
           HTML.title("Isabelle Build Manager"),
-          Web_App.More_HTML.icon("data:image/x-icon;base64," + logo.encode_base64),
+          Web_App.More_HTML.icon("data:image/x-icon;base64," + logo.encode_base64.text),
           HTML.style_file("https://hawkz.github.io/gdcss/gd.css"),
           HTML.style("html { background-color: white; }"))
     }
--- a/src/Pure/General/base64.scala	Sun Jun 16 18:18:55 2024 +0200
+++ b/src/Pure/General/base64.scala	Sun Jun 16 18:41:57 2024 +0200
@@ -1,26 +1,34 @@
 /*  Title:      Pure/General/base64.scala
     Author:     Makarius
 
-Support for Base64 data encoding.
+Support for Base64 data representation.
 */
 
 package isabelle
 
 
+import java.io.{InputStream, OutputStream}
+
+
 object Base64 {
+  /* main operations */
+
   def encode(a: Array[Byte]): String = java.util.Base64.getEncoder.encodeToString(a)
   def decode(s: String): Array[Byte] = java.util.Base64.getDecoder.decode(s)
 
+  def encode_stream(s: OutputStream): OutputStream = java.util.Base64.getEncoder.wrap(s)
+  def decode_stream(s: InputStream): InputStream = java.util.Base64.getDecoder.wrap(s)
+
 
   /* Scala functions in ML */
 
   object Decode extends Scala.Fun_Bytes("Base64.decode") {
     val here = Scala_Project.here
-    def apply(arg: Bytes): Bytes = Bytes.decode_base64(arg.text)
+    def apply(bytes: Bytes): Bytes = bytes.decode_base64
   }
 
   object Encode extends Scala.Fun_Bytes("Base64.encode") {
     val here = Scala_Project.here
-    def apply(arg: Bytes): Bytes = Bytes(arg.encode_base64)
+    def apply(bytes: Bytes): Bytes = bytes.encode_base64
   }
 }
--- a/src/Pure/General/bytes.scala	Sun Jun 16 18:18:55 2024 +0200
+++ b/src/Pure/General/bytes.scala	Sun Jun 16 18:41:57 2024 +0200
@@ -55,8 +55,6 @@
 
   val newline: Bytes = apply("\n")
 
-  def decode_base64(s: String): Bytes = Bytes.reuse_array(Base64.decode(s))
-
 
   /* read */
 
@@ -441,12 +439,22 @@
     }
     catch { case ERROR(_) => None }
 
-  def encode_base64: String = Base64.encode(make_array)
+
+  /* Base64 data representation */
+
+  def encode_base64: Bytes = {
+    val out = new Bytes.Builder.Stream(hint = (size * 1.5).round)
+    using(Base64.encode_stream(out))(write_stream(_))
+    out.builder.done()
+  }
+
+  def decode_base64: Bytes =
+    using(Base64.decode_stream(stream()))(Bytes.read_stream(_, hint = (size / 1.2).round))
 
   def maybe_encode_base64: (Boolean, String) =
     wellformed_text match {
       case Some(s) => (false, s)
-      case None => (true, encode_base64)
+      case None => (true, encode_base64.text)
     }