src/Pure/PIDE/byte_message.scala
author wenzelm
Thu, 13 Dec 2018 21:36:09 +0100
changeset 69467 e8893c893241
parent 69454 ef051edd4d10
child 73340 0ffcad1f6130
permissions -rw-r--r--
tuned signature;
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
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    16
  def write(stream: OutputStream, bytes: List[Bytes]): Unit =
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    17
    bytes.foreach(_.write_stream(stream))
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    18
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    19
  def flush(stream: OutputStream): Unit =
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    20
    try { stream.flush() }
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    21
    catch { case _: IOException => }
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    22
69467
e8893c893241 tuned signature;
wenzelm
parents: 69454
diff changeset
    23
  def write_line(stream: OutputStream, bytes: Bytes): Unit =
e8893c893241 tuned signature;
wenzelm
parents: 69454
diff changeset
    24
  {
e8893c893241 tuned signature;
wenzelm
parents: 69454
diff changeset
    25
    write(stream, List(bytes, Bytes.newline))
e8893c893241 tuned signature;
wenzelm
parents: 69454
diff changeset
    26
    flush(stream)
e8893c893241 tuned signature;
wenzelm
parents: 69454
diff changeset
    27
  }
e8893c893241 tuned signature;
wenzelm
parents: 69454
diff changeset
    28
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    29
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    30
  /* input operations */
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    31
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    32
  def read(stream: InputStream, n: Int): Bytes =
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    33
    Bytes.read_stream(stream, limit = n)
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    34
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    35
  def read_block(stream: InputStream, n: Int): (Option[Bytes], Int) =
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    36
  {
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    37
    val msg = read(stream, n)
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    38
    val len = msg.length
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    39
    (if (len == n) Some(msg) else None, len)
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    40
  }
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    41
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    42
  def read_line(stream: InputStream): Option[Bytes] =
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    43
  {
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    44
    val line = new ByteArrayOutputStream(100)
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    45
    var c = 0
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    46
    while ({ c = stream.read; c != -1 && c != 10 }) line.write(c)
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    47
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    48
    if (c == -1 && line.size == 0) None
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    49
    else {
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    50
      val a = line.toByteArray
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    51
      val n = a.length
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    52
      val len = if (n > 0 && a(n - 1) == 13) n - 1 else n
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    53
      Some(Bytes(a, 0, len))
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    54
    }
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    55
  }
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    56
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    57
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    58
  /* messages with multiple chunks (arbitrary content) */
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    59
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    60
  private def make_header(ns: List[Int]): List[Bytes] =
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    61
    List(Bytes(ns.mkString(",")), Bytes.newline)
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    62
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    63
  def write_message(stream: OutputStream, chunks: List[Bytes])
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    64
  {
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    65
    write(stream, make_header(chunks.map(_.length)) ::: chunks)
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    66
    flush(stream)
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    67
  }
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    68
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    69
  private def parse_header(line: String): List[Int] =
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    70
    try { space_explode(',', line).map(Value.Nat.parse) }
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    71
    catch { case ERROR(_) => error("Malformed message header: " + quote(line)) }
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    72
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    73
  private def read_chunk(stream: InputStream, n: Int): Bytes =
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    74
    read_block(stream, n) match {
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    75
      case (Some(chunk), _) => chunk
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    76
      case (None, len) =>
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    77
        error("Malformed message chunk: unexpected EOF after " + len + " of " + n + " bytes")
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    78
    }
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    79
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    80
  def read_message(stream: InputStream): Option[List[Bytes]] =
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    81
    read_line(stream).map(line => parse_header(line.text).map(read_chunk(stream, _)))
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    82
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    83
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    84
  /* hybrid messages: line or length+block (restricted content) */
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    85
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    86
  private def is_length(msg: Bytes): Boolean =
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    87
    !msg.is_empty && msg.iterator.forall(b => Symbol.is_ascii_digit(b.toChar))
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    88
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    89
  private def is_terminated(msg: Bytes): Boolean =
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    90
  {
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    91
    val len = msg.length
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    92
    len > 0 && Symbol.is_ascii_line_terminator(msg.charAt(len - 1))
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    93
  }
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    94
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    95
  def write_line_message(stream: OutputStream, msg: Bytes)
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    96
  {
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    97
    if (is_length(msg) || is_terminated(msg))
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    98
      error ("Bad content for line message:\n" ++ msg.text.take(100))
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    99
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   100
    val n = msg.length
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
   101
    write(stream,
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
   102
      (if (n > 100 || msg.iterator.contains(10)) make_header(List(n + 1)) else Nil) :::
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
   103
        List(msg, Bytes.newline))
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   104
    flush(stream)
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   105
  }
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   106
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   107
  def read_line_message(stream: InputStream): Option[Bytes] =
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   108
    read_line(stream) match {
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   109
      case None => None
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   110
      case Some(line) =>
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   111
        Value.Nat.unapply(line.text) match {
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   112
          case None => Some(line)
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   113
          case Some(n) => read_block(stream, n)._1.map(_.trim_line)
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   114
        }
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   115
    }
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   116
}