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 }