src/Pure/PIDE/byte_message.scala
author wenzelm
Wed, 12 Dec 2018 12:31:05 +0100
changeset 69452 704915cf59fa
parent 69451 387894c2fb2c
child 69454 ef051edd4d10
permissions -rw-r--r--
more uniform multi-language operations; misc tuning and clarification;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     1
/*  Title:      Pure/General/byte_message.scala
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     2
    Author:     Makarius
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     3
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     4
Byte-oriented messages.
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     5
*/
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     6
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     7
package isabelle
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     8
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     9
import java.io.{ByteArrayOutputStream, OutputStream, InputStream, IOException}
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    10
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    11
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    12
object Byte_Message
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    13
{
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    14
  /* output operations */
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    15
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    16
  def write(stream: OutputStream, bytes: Bytes) { bytes.write_stream(stream) }
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    17
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    18
  def newline(stream: OutputStream) { stream.write(10) }
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    19
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    20
  def flush(stream: OutputStream): Unit =
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    21
    try { stream.flush() }
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    22
    catch { case _: IOException => }
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    23
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    24
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    25
  /* input operations */
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    26
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    27
  def read(stream: InputStream, n: Int): Bytes =
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    28
    Bytes.read_stream(stream, limit = n)
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    29
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    30
  def read_block(stream: InputStream, n: Int): (Option[Bytes], Int) =
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    31
  {
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    32
    val msg = read(stream, n)
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    33
    val len = msg.length
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    34
    (if (len == n) Some(msg) else None, len)
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    35
  }
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    36
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    37
  def read_line(stream: InputStream): Option[Bytes] =
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    38
  {
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    39
    val line = new ByteArrayOutputStream(100)
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    40
    var c = 0
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    41
    while ({ c = stream.read; c != -1 && c != 10 }) line.write(c)
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    42
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    43
    if (c == -1 && line.size == 0) None
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    44
    else {
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    45
      val a = line.toByteArray
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    46
      val n = a.length
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    47
      val len = if (n > 0 && a(n - 1) == 13) n - 1 else n
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    48
      Some(Bytes(a, 0, len))
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    49
    }
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    50
  }
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    51
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    52
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    53
  /* header with chunk lengths */
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    54
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    55
  def write_header(stream: OutputStream, ns: List[Int])
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    56
  {
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    57
    stream.write(UTF8.bytes(ns.mkString(",")))
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    58
    newline(stream)
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    59
  }
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    60
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    61
  private def err_header(line: String): Nothing =
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    62
    error("Malformed message header: " + quote(line))
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    63
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    64
  private def parse_header(line: String): List[Int] =
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    65
    try { space_explode(',', line).map(Value.Nat.parse) }
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    66
    catch { case ERROR(_) => err_header(line) }
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    67
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    68
  def read_header(stream: InputStream): Option[List[Int]] =
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    69
    read_line(stream).map(_.text).map(parse_header(_))
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    70
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    71
  def read_header1(stream: InputStream): Option[Int] =
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    72
    read_line(stream).map(_.text).map(line =>
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    73
      parse_header(line) match {
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    74
        case List(n) => n
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    75
        case _ => err_header(line)
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    76
      })
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    77
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    78
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    79
  /* messages with multiple chunks (arbitrary content) */
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    80
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    81
  def write_message(stream: OutputStream, chunks: List[Bytes])
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    82
  {
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    83
    write_header(stream, chunks.map(_.length))
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    84
    chunks.foreach(write(stream, _))
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    85
    flush(stream)
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    86
  }
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    87
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    88
  private def read_chunk(stream: InputStream, n: Int): Bytes =
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    89
    read_block(stream, n) match {
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    90
      case (Some(chunk), _) => chunk
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    91
      case (None, len) =>
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    92
        error("Malformed message chunk: unexpected EOF after " + len + " of " + n + " bytes")
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    93
    }
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    94
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    95
  def read_message(stream: InputStream): Option[List[Bytes]] =
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    96
    read_header(stream).map(ns => ns.map(n => read_chunk(stream, n)))
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    97
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    98
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    99
  /* hybrid messages: line or length+block (restricted content) */
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   100
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   101
  private def is_length(msg: Bytes): Boolean =
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   102
    !msg.is_empty && msg.iterator.forall(b => Symbol.is_ascii_digit(b.toChar))
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   103
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   104
  private def is_terminated(msg: Bytes): Boolean =
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   105
  {
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   106
    val len = msg.length
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   107
    len > 0 && Symbol.is_ascii_line_terminator(msg.charAt(len - 1))
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   108
  }
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   109
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   110
  def write_line_message(stream: OutputStream, msg: Bytes)
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   111
  {
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   112
    if (is_length(msg) || is_terminated(msg))
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   113
      error ("Bad content for line message:\n" ++ msg.text.take(100))
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   114
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   115
    val n = msg.length
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   116
    if (n > 100 || msg.iterator.contains(10)) write_header(stream, List(n + 1))
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   117
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   118
    write(stream, msg)
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   119
    newline(stream)
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   120
    flush(stream)
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   121
  }
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   122
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   123
  def read_line_message(stream: InputStream): Option[Bytes] =
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   124
    read_line(stream) match {
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   125
      case None => None
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   126
      case Some(line) =>
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   127
        Value.Nat.unapply(line.text) match {
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   128
          case None => Some(line)
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   129
          case Some(n) => read_block(stream, n)._1.map(_.trim_line)
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   130
        }
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   131
    }
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   132
}