logo

class

sys::Buf

sys::Obj
  sys::Buf
   1  //
   2  // Copyright (c) 2006, Brian Frank and Andy Frank
   3  // Licensed under the Academic Free License version 3.0
   4  //
   5  // History:
   6  //   16 Mar 06  Brian Frank  Creation
   7  //
   8  
   9  **
  10  ** Buf is used to model a buffer of bytes with random access.  Buf is
  11  ** typically backed by a block of memory.  Buf provides an `InStream`
  12  ** and `OutStream` to read and write into the buffer using a configurable
  13  ** position accessed via `Buf.pos` and `Buf.seek`.
  14  **
  15  ** When using an InStream, bytes are read starting at pos where pos
  16  ** is advanced after each read.  The end of stream is reached when pos
  17  ** reaches size.  When using the OutStream, bytes are written starting at pos
  18  ** with pos advanced after each write.  If pos is less then size then
  19  ** the existing bytes are rewritten and size is not advanced, otherwise
  20  ** the buffer is automatically grown and size is advanced as bytes are
  21  ** appended.  It is common to write bytes into the buffer using the
  22  ** OutStream, then call `Buf.flip` to prepare the buffer to be used for reading.
  23  **
  24  class Buf
  25  {
  26  
  27  //////////////////////////////////////////////////////////////////////////
  28  // Constructors
  29  //////////////////////////////////////////////////////////////////////////
  30  
  31    **
  32    ** Make a byte buffer with the initial given capacity.
  33    **
  34    new make(Int capacity := 1024)
  35  
  36  //////////////////////////////////////////////////////////////////////////
  37  // Identity
  38  //////////////////////////////////////////////////////////////////////////
  39  
  40    **
  41    ** Two Bufs are equal if they have string of bytes.
  42    **
  43    override Bool equals(Obj that)
  44  
  45    **
  46    ** Return hash code based on string of bytes.
  47    **
  48    override Int hash()
  49  
  50    **
  51    ** Return hex string of bytes.
  52    **
  53    override Str toStr()
  54  
  55  //////////////////////////////////////////////////////////////////////////
  56  // Access
  57  //////////////////////////////////////////////////////////////////////////
  58  
  59    **
  60    ** Return if size() == 0.
  61    **
  62    Bool empty()
  63  
  64    **
  65    ** Return the total number of bytes in the buffer.  If the size is
  66    ** set greater than capacity then the buffer's capacity is automatically
  67    ** grown, otherwise capacity remains the same.  Setting size does not
  68    ** actually change any bytes in the buffer.
  69    **
  70    virtual Int size
  71  
  72    **
  73    ** The number of bytes this buffer can hold without allocating more
  74    ** memory.  Capacity is always greater or equal to size.  If adding a
  75    ** large number of bytes, it may be more efficient to manually set
  76    ** capacity.  See the trim() method to automatically set capacity to
  77    ** size.  Throw ArgErr if attempting to set capacity less than size.
  78    **
  79    virtual Int capacity
  80  
  81    **
  82    ** Return the current position for the next read or write.  The
  83    ** position is always between 0 and size().  If pos is less then
  84    ** size then future writes will rewrite the existing bytes without
  85    ** growing size.
  86    **
  87    virtual Int pos()
  88  
  89    **
  90    ** Return the remaining number of bytes to read: size-pos.
  91    **
  92    virtual Int remaining()
  93  
  94    **
  95    ** Return if more bytes are available to read: remaining() > 0.
  96    **
  97    virtual Bool more()
  98  
  99    **
 100    ** Set the current position to the specified byte offset.  A
 101    ** negative index may be used to access from the end of the buffer.
 102    ** For example seek(-1) is translated into seek(size-1).
 103    ** Return this.
 104    **
 105    virtual Buf seek(Int pos)
 106  
 107    **
 108    ** Flip a buffer from write-mode to read-mode.  This method sets
 109    ** total size to current position, and position to 0.  Return this.
 110    **
 111    virtual Buf flip()
 112  
 113    **
 114    ** Get the byte at the specified absolute index.  A negative index
 115    ** may be used to access from the end of the buffer.  For example
 116    ** get(-1)  is translated into get(size()-1).  This method accesses
 117    ** the buffer absolutely independent of current position.  The get
 118    ** method is accessed via the [] shortcut operator.  Throw IndexErr
 119    ** if index out of range.
 120    **
 121    virtual Int get(Int index)
 122  
 123    **
 124    ** Return a new buffer containing the bytes in the specified absolute
 125    ** range.  Negative indexes may be used to access from the end of
 126    ** the buf.  This method accesses the buffer absolutely independent
 127    ** of current position.  This method is accessed via the [] operator.
 128    ** Throw IndexErr if range illegal.
 129    **
 130    ** Examples:
 131    **   buf := Buf.make
 132    **   buf.write(0xaa).write(0xbb).write(0xcc).write(0xdd)
 133    **   buf[0..2]   -> 0x[aabbcc]
 134    **   buf[3..3]   -> 0x[dd]
 135    **   buf[-2..-1] -> 0x[ccdd]
 136    **   buf[0...2]  -> 0x[aabb]
 137    **   buf[1..-2]  -> 0x[bbcc]
 138    **
 139    virtual Buf slice(Range range)
 140  
 141  //////////////////////////////////////////////////////////////////////////
 142  // Modification
 143  //////////////////////////////////////////////////////////////////////////
 144  
 145    **
 146    ** Set is used to overwrite the byte at the specified the index.  A
 147    ** negative index may be used to access an index from the end of the
 148    ** buffer.  The set method is accessed via the []= shortcut operator.
 149    ** Return this.  Throw IndexErr if index is out of range.
 150    **
 151    virtual Buf set(Int index, Int byte)
 152  
 153    **
 154    ** Read the buffer for a fresh read by reseting the buffer's pos
 155    ** and size to zero.  The buffer's capacity remains the same.
 156    **
 157    Buf clear()
 158  
 159    **
 160    ** Trim the capacity such that the underlying storage is optimized
 161    ** for the current size.  Return this.
 162    **
 163    Buf trim()
 164  
 165    **
 166    ** Character set for both the OutStream and InStream.
 167    **
 168    Charset charset
 169  
 170  //////////////////////////////////////////////////////////////////////////
 171  // OutStream
 172  //////////////////////////////////////////////////////////////////////////
 173  
 174    **
 175    ** Get the OutStream which writes to this buffer.
 176    ** This method always returns the same instance.
 177    **
 178    OutStream out()
 179  
 180    **
 181    ** Convenience for [out.write]`OutStream.write`
 182    ** Return this.
 183    **
 184    Buf write(Int byte)
 185  
 186    **
 187    ** Convenience for [out.writeBuf]`OutStream.writeBuf`
 188    ** Return this.
 189    **
 190    Buf writeBuf(Buf buf, Int n := buf.remaining)
 191  
 192    **
 193    ** Convenience for [out.writeI2]`OutStream.writeI2`
 194    ** Return this.
 195    **
 196    Buf writeI2(Int n)
 197  
 198    **
 199    ** Convenience for [out.writeI4]`OutStream.writeI4`
 200    ** Return this.
 201    **
 202    Buf writeI4(Int n)
 203  
 204    **
 205    ** Convenience for [out.writeI8]`OutStream.writeI8`
 206    ** Return this.
 207    **
 208    Buf writeI8(Int n)
 209  
 210    **
 211    ** Convenience for [out.writeF4]`OutStream.writeF4`
 212    ** Return this.
 213    **
 214    Buf writeF4(Float r)
 215  
 216    **
 217    ** Convenience for [out.writeF8]`OutStream.writeF8`
 218    ** Return this.
 219    **
 220    Buf writeF8(Float r)
 221  
 222    **
 223    ** Convenience for [out.writeBool]`OutStream.writeBool`
 224    ** Return this.
 225    **
 226    Buf writeBool(Bool b)
 227  
 228    **
 229    ** Convenience for [out.writeUtf]`OutStream.writeUtf`
 230    ** Return this.
 231    **
 232    Buf writeUtf(Str s)
 233  
 234    **
 235    ** Convenience for [out.writeChar]`OutStream.writeChar`
 236    ** Return this.
 237    **
 238    Buf writeChar(Int char)
 239  
 240    **
 241    ** Convenience for [out.writeChars]`OutStream.writeChars`
 242    ** Return this.
 243    **
 244    Buf writeChars(Str str, Int off := 0, Int len := str.size-off)
 245  
 246    **
 247    ** Convenience for [out.print]`OutStream.print`
 248    ** Return this.
 249    **
 250    Buf print(Obj s)
 251  
 252    **
 253    ** Convenience for [out.printLine]`OutStream.printLine`
 254    ** Return this.
 255    **
 256    Buf printLine(Obj obj := "")
 257  
 258    **
 259    ** Convenience for [out.writeObj]`OutStream.writeObj`
 260    ** Return this.
 261    **
 262    Buf writeObj(Obj obj, Str:Obj options := null)
 263  
 264  //////////////////////////////////////////////////////////////////////////
 265  // InStream
 266  //////////////////////////////////////////////////////////////////////////
 267  
 268    **
 269    ** Get the InStream which reads from this buffer.
 270    ** This method always returns the same instance.
 271    **
 272    InStream in()
 273  
 274    **
 275    ** Convenience for [in.read]`InStream.read`
 276    **
 277    Int read()
 278  
 279    **
 280    ** Convenience for [in.readBuf]`InStream.readBuf`
 281    **
 282    Int readBuf(Buf buf, Int n)
 283  
 284    **
 285    ** Convenience for [in.unread]`InStream.unread`
 286    ** Return this.
 287    **
 288    Buf unread(Int b)
 289  
 290    **
 291    ** Convenience for [in.readAllBuf]`InStream.readAllBuf`
 292    **
 293    Buf readAllBuf()
 294  
 295    **
 296    ** Convenience for [in.readBufFully]`InStream.readBufFully`
 297    **
 298    Buf readBufFully(Buf buf, Int n)
 299  
 300    **
 301    ** Convenience for [in.peek]`InStream.peek`
 302    **
 303    Int peek()
 304  
 305    **
 306    ** Convenience for [in.readU1]`InStream.readU1`
 307    **
 308    Int readU1()
 309  
 310    **
 311    ** Convenience for [in.readS1]`InStream.readS1`
 312    **
 313    Int readS1()
 314  
 315    **
 316    ** Convenience for [in.readU2]`InStream.readU2`
 317    **
 318    Int readU2()
 319  
 320    **
 321    ** Convenience for [in.readS2]`InStream.readS2`
 322    **
 323    Int readS2()
 324  
 325    **
 326    ** Convenience for [in.readU4]`InStream.readU4`
 327    **
 328    Int readU4()
 329  
 330    **
 331    ** Convenience for [in.readS4]`InStream.readS4`
 332    **
 333    Int readS4()
 334  
 335    **
 336    ** Convenience for [in.readS8]`InStream.readS8`
 337    **
 338    Int readS8()
 339  
 340    **
 341    ** Convenience for [in.readF4]`InStream.readF4`
 342    **
 343    Float readF4()
 344  
 345    **
 346    ** Convenience for [in.readF8]`InStream.readF8`
 347    **
 348    Float readF8()
 349  
 350    **
 351    ** Convenience for [in.readBool]`InStream.readBool`
 352    **
 353    Bool readBool()
 354  
 355    **
 356    ** Convenience for [in.readUtf]`InStream.readUtf`
 357    **
 358    Str readUtf()
 359  
 360    **
 361    ** Convenience for [in.readChar]`InStream.readChar`
 362    **
 363    Int readChar()
 364  
 365    **
 366    ** Convenience for [in.unreadChar]`InStream.unreadChar`
 367    ** Return this.
 368    **
 369    Buf unreadChar(Int b)
 370  
 371    **
 372    ** Convenience for [in.peekChar]`InStream.peekChar`
 373    **
 374    Int peekChar()
 375  
 376    **
 377    ** Convenience for [in.readLine]`InStream.readLine`
 378    **
 379    Str readLine(Int max := 4096)
 380  
 381    **
 382    ** Convenience for [in.readStrToken]`InStream.readStrToken`
 383    **
 384    Str readStrToken(Int max := 4096, |Int ch->Bool| c := null)
 385  
 386    **
 387    ** Convenience for [in.readAllLines]`InStream.readAllLines`
 388    **
 389    Str[] readAllLines()
 390  
 391    **
 392    ** Convenience for [in.eachLine]`InStream.eachLine`
 393    **
 394    Void eachLine(|Str line| f)
 395  
 396    **
 397    ** Convenience for [in.readAllStr]`InStream.readAllStr`
 398    **
 399    Str readAllStr(Bool normalizeNewlines := true)
 400  
 401    **
 402    ** Convenience for [in.readObj]`InStream.readObj`
 403    **
 404    Obj readObj()
 405  
 406  //////////////////////////////////////////////////////////////////////////
 407  // Conversions
 408  //////////////////////////////////////////////////////////////////////////
 409  
 410    **
 411    ** Encode the buffer contents from 0 to size into a
 412    ** hexadecimal string.
 413    **
 414    ** Example:
 415    **   Buf.make.print("\r\n").toHex   -> "0d0a"
 416    **   Buf.fromHex("0d0a").readAllStr -> "\r\n"
 417    **
 418    Str toHex()
 419  
 420    **
 421    ** Decode the specified hexadecimal string into its binary
 422    ** contents.  Any characters which are not included in the
 423    ** set "0-9, a-f, A-F" are ignored as long as they appear
 424    ** between bytes (hi and lo nibbles must be contiguous).
 425    **
 426    ** Example:
 427    **   Buf.make.print("\r\n").toHex   -> "0d0a"
 428    **   Buf.fromHex("0d0a").readAllStr -> "\r\n"
 429    **
 430    static Buf fromHex(Str s)
 431  
 432    **
 433    ** Encode the buffer contents from 0 to size to a Base64
 434    ** string as defined by MIME RFC 2045.  No line breaks are
 435    ** added.
 436    **
 437    ** Example:
 438    **   Buf.make.print("Fan").toBase64  -> "RmFu"
 439    **   Buf.fromBase64("RmFu").readAllStr -> "Fan"
 440    **
 441    Str toBase64()
 442  
 443    **
 444    ** Decode the specified Base64 string into its binary contents
 445    ** as defined by MIME RFC 2045.  Any characters which are not
 446    ** included in the Base64 character set are safely ignored.
 447    **
 448    ** Example:
 449    **   Buf.make.print("Fan").toBase64  -> "RmFu"
 450    **   Buf.fromBase64("RmFu").readAllStr -> "Fan"
 451    **
 452    static Buf fromBase64(Str s)
 453  
 454    **
 455    ** Apply the specified message digest algorthm to this buffer's
 456    ** contents from 0 to size and return the resulting hash.  Digests
 457    ** are secure one-way hash functions which input an arbitrary sized
 458    ** buffer and return a fixed sized buffer.  Common algorithms include:
 459    ** "MD5", "SHA-1", and "SHA-256"; the full list supported is platform
 460    ** dependent.  On the Java VM, the algorithm maps to those avaialble
 461    ** via the 'java.security.MessageDigest' API.  Throw ArgErr if the
 462    ** algorithm is not available.
 463    **
 464    ** Example:
 465    **   Buf.make.print("password").print("salt").toDigest("MD5").toHex
 466    **    ->  "b305cadbb3bce54f3aa59c64fec00dea"
 467    **
 468    Buf toDigest(Str algorithm)
 469  
 470  }