src/Pure/General/bytes.scala
changeset 76358 cff0828c374f
parent 76353 3698d0f3da18
child 76361 3b9f36ef7365
equal deleted inserted replaced
76357:49463aef2ead 76358:cff0828c374f
   190   def write_stream(stream: OutputStream): Unit = stream.write(bytes, offset, length)
   190   def write_stream(stream: OutputStream): Unit = stream.write(bytes, offset, length)
   191 
   191 
   192 
   192 
   193   /* XZ / Zstd data compression */
   193   /* XZ / Zstd data compression */
   194 
   194 
   195   private def detect_xz: Boolean =
   195   def detect_xz: Boolean =
   196     length >= 6 &&
   196     length >= 6 &&
   197       bytes(offset)     == 0xFD.toByte &&
   197       bytes(offset)     == 0xFD.toByte &&
   198       bytes(offset + 1) == 0x37.toByte &&
   198       bytes(offset + 1) == 0x37.toByte &&
   199       bytes(offset + 2) == 0x7A.toByte &&
   199       bytes(offset + 2) == 0x7A.toByte &&
   200       bytes(offset + 3) == 0x58.toByte &&
   200       bytes(offset + 3) == 0x58.toByte &&
   201       bytes(offset + 4) == 0x5A.toByte &&
   201       bytes(offset + 4) == 0x5A.toByte &&
   202       bytes(offset + 5) == 0x00.toByte
   202       bytes(offset + 5) == 0x00.toByte
   203 
   203 
   204   private def detect_zstd: Boolean =
   204   def detect_zstd: Boolean =
   205     length >= 4 &&
   205     length >= 4 &&
   206       bytes(offset)     == 0x28.toByte &&
   206       bytes(offset)     == 0x28.toByte &&
   207       bytes(offset + 1) == 0xB5.toByte &&
   207       bytes(offset + 1) == 0xB5.toByte &&
   208       bytes(offset + 2) == 0x2F.toByte &&
   208       bytes(offset + 2) == 0x2F.toByte &&
   209       bytes(offset + 3) == 0xFD.toByte
   209       bytes(offset + 3) == 0xFD.toByte
   210 
   210 
   211   private def detect_error(name: String = ""): Nothing =
   211   def uncompress_xz(cache: Compress.Cache = Compress.Cache.none): Bytes =
   212     error("Cannot detect compression scheme" + (if (name.isEmpty) "" else " " + name))
   212     using(new xz.XZInputStream(stream(), cache.for_xz))(Bytes.read_stream(_, hint = length))
       
   213 
       
   214   def uncompress_zstd(cache: Compress.Cache = Compress.Cache.none): Bytes = {
       
   215     Zstd.init()
       
   216     val n = zstd.Zstd.decompressedSize(bytes, offset, length)
       
   217     if (n > 0 && n < Integer.MAX_VALUE) {
       
   218       Bytes(zstd.Zstd.decompress(array, n.toInt))
       
   219     }
       
   220     else {
       
   221       using(new zstd.ZstdInputStream(stream(), cache.for_zstd))(Bytes.read_stream(_, hint = length))
       
   222     }
       
   223   }
   213 
   224 
   214   def uncompress(cache: Compress.Cache = Compress.Cache.none): Bytes =
   225   def uncompress(cache: Compress.Cache = Compress.Cache.none): Bytes =
   215     using(
   226     if (detect_xz) uncompress_xz(cache = cache)
   216       if (detect_xz) new xz.XZInputStream(stream(), cache.for_xz)
   227     else if (detect_zstd) uncompress_zstd(cache = cache)
   217       else if (detect_zstd) {
   228     else error("Cannot detect compression scheme")
   218         Zstd.init()
       
   219         new zstd.ZstdInputStream(stream(), cache.for_zstd)
       
   220       }
       
   221       else detect_error()
       
   222     )(Bytes.read_stream(_, hint = length))
       
   223 
       
   224   def uncompress_xz(cache: Compress.Cache = Compress.Cache.none): Bytes =
       
   225     if (detect_xz) uncompress(cache = cache) else detect_error("XZ")
       
   226 
       
   227   def uncompress_zstd(cache: Compress.Cache = Compress.Cache.none): Bytes =
       
   228     if (detect_zstd) uncompress(cache = cache) else detect_error("Zstd")
       
   229 
   229 
   230   def compress(
   230   def compress(
   231     options: Compress.Options = Compress.Options(),
   231     options: Compress.Options = Compress.Options(),
   232     cache: Compress.Cache = Compress.Cache.none
   232     cache: Compress.Cache = Compress.Cache.none
   233   ): Bytes = {
   233   ): Bytes = {
   234     val result = new ByteArrayOutputStream(length)
   234     options match {
   235     using(
   235       case options_xz: Compress.Options_XZ =>
   236       options match {
   236         val result = new ByteArrayOutputStream(length)
   237         case options_xz: Compress.Options_XZ =>
   237         using(new xz.XZOutputStream(result, options_xz.make, cache.for_xz))(write_stream)
   238           new xz.XZOutputStream(result, options_xz.make, cache.for_xz)
   238         new Bytes(result.toByteArray, 0, result.size)
   239         case options_zstd: Compress.Options_Zstd =>
   239       case options_zstd: Compress.Options_Zstd =>
   240           Zstd.init()
   240         Zstd.init()
   241           new zstd.ZstdOutputStream(result, cache.for_zstd, options_zstd.level)
   241         Bytes(zstd.Zstd.compress(array, options_zstd.level))
   242       })(write_stream)
   242     }
   243     new Bytes(result.toByteArray, 0, result.size)
       
   244   }
   243   }
   245 
   244 
   246   def maybe_compress(
   245   def maybe_compress(
   247     options: Compress.Options = Compress.Options(),
   246     options: Compress.Options = Compress.Options(),
   248     cache: Compress.Cache = Compress.Cache.none
   247     cache: Compress.Cache = Compress.Cache.none