cford32.gno
18.84 Kb ยท 704 lines
1// Modified from the Go Source code for encoding/base32.
2// Copyright 2009 The Go Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file.
5
6// Package cford32 implements a base32-like encoding/decoding package, with the
7// encoding scheme [specified by Douglas Crockford].
8//
9// From the website, the requirements of said encoding scheme are to:
10//
11// - Be human readable and machine readable.
12// - Be compact. Humans have difficulty in manipulating long strings of arbitrary symbols.
13// - Be error resistant. Entering the symbols must not require keyboarding gymnastics.
14// - Be pronounceable. Humans should be able to accurately transmit the symbols to other humans using a telephone.
15//
16// This is slightly different from a simple difference in encoding table from
17// the Go's stdlib `encoding/base32`, as when decoding the characters i I l L are
18// parsed as 1, and o O is parsed as 0.
19//
20// This package additionally provides ways to encode uint64's efficiently,
21// as well as efficient encoding to a lowercase variation of the encoding.
22// The encodings never use paddings.
23//
24// # Uint64 Encoding
25//
26// Aside from lower/uppercase encoding, there is a compact encoding, allowing
27// to encode all values in [0,2^34), and the full encoding, allowing all
28// values in [0,2^64). The compact encoding uses 7 characters, and the full
29// encoding uses 13 characters. Both are parsed unambiguously by the Uint64
30// decoder.
31//
32// The compact encodings have the first character between ['0','f'], while the
33// full encoding's first character ranges between ['g','z']. Practically, in
34// your usage of the package, you should consider which one to use and stick
35// with it, while considering that the compact encoding, once it reaches 2^34,
36// automatically switches to the full encoding. The properties of the generated
37// strings are still maintained: for instance, any two encoded uint64s x,y
38// consistently generated with the compact encoding, if the numeric value is
39// x < y, will also be x < y in lexical ordering. However, values [0,2^34) have a
40// "double encoding", which if mixed together lose the lexical ordering property.
41//
42// The Uint64 encoding is most useful for generating string versions of Uint64
43// IDs. Practically, it allows you to retain sleek and compact IDs for your
44// application for the first 2^34 (>17 billion) entities, while seamlessly
45// rolling over to the full encoding should you exceed that. You are encouraged
46// to use it unless you have a requirement or preferences for IDs consistently
47// being always the same size.
48//
49// To use the cford32 encoding for IDs, you may want to consider using package
50// [gno.land/p/demo/seqid].
51//
52// [specified by Douglas Crockford]: https://www.crockford.com/base32.html
53package cford32
54
55import (
56 "io"
57 "strconv"
58)
59
60const (
61 encTable = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
62 encTableLower = "0123456789abcdefghjkmnpqrstvwxyz"
63
64 // each line is 16 bytes
65 decTable = "" +
66 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + // 00-0f
67 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + // 10-1f
68 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + // 20-2f
69 "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\xff\xff\xff\xff\xff\xff" + // 30-3f
70 "\xff\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x01\x12\x13\x01\x14\x15\x00" + // 40-4f
71 "\x16\x17\x18\x19\x1a\xff\x1b\x1c\x1d\x1e\x1f\xff\xff\xff\xff\xff" + // 50-5f
72 "\xff\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x01\x12\x13\x01\x14\x15\x00" + // 60-6f
73 "\x16\x17\x18\x19\x1a\xff\x1b\x1c\x1d\x1e\x1f\xff\xff\xff\xff\xff" + // 70-7f
74 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + // 80-ff (not ASCII)
75 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
76 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
77 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
78 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
79 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
80 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
81 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
82)
83
84// CorruptInputError is returned by parsing functions when an invalid character
85// in the input is found. The integer value represents the byte index where
86// the error occurred.
87//
88// This is typically because the given character does not exist in the encoding.
89type CorruptInputError int64
90
91func (e CorruptInputError) Error() string {
92 return "illegal cford32 data at input byte " + strconv.FormatInt(int64(e), 10)
93}
94
95// Uint64 parses a cford32-encoded byte slice into a uint64.
96//
97// - The parser requires all provided character to be valid cford32 characters.
98// - The parser disregards case.
99// - If the first character is '0' <= c <= 'f', then the passed value is assumed
100// encoded in the compact encoding, and must be 7 characters long.
101// - If the first character is 'g' <= c <= 'z', then the passed value is
102// assumed encoded in the full encoding, and must be 13 characters long.
103//
104// If any of these requirements fail, a CorruptInputError will be returned.
105func Uint64(b []byte) (uint64, error) {
106 if len(b) == 0 {
107 return 0, CorruptInputError(0)
108 }
109 b0 := decTable[b[0]]
110 switch {
111 default:
112 return 0, CorruptInputError(0)
113 case len(b) == 7 && b0 < 16:
114 decVals := [7]byte{
115 decTable[b[0]],
116 decTable[b[1]],
117 decTable[b[2]],
118 decTable[b[3]],
119 decTable[b[4]],
120 decTable[b[5]],
121 decTable[b[6]],
122 }
123 for idx, v := range decVals {
124 if v >= 32 {
125 return 0, CorruptInputError(idx)
126 }
127 }
128
129 return 0 +
130 uint64(decVals[0])<<30 |
131 uint64(decVals[1])<<25 |
132 uint64(decVals[2])<<20 |
133 uint64(decVals[3])<<15 |
134 uint64(decVals[4])<<10 |
135 uint64(decVals[5])<<5 |
136 uint64(decVals[6]), nil
137 case len(b) == 13 && b0 >= 16 && b0 < 32:
138 decVals := [13]byte{
139 decTable[b[0]] & 0x0F, // disregard high bit
140 decTable[b[1]],
141 decTable[b[2]],
142 decTable[b[3]],
143 decTable[b[4]],
144 decTable[b[5]],
145 decTable[b[6]],
146 decTable[b[7]],
147 decTable[b[8]],
148 decTable[b[9]],
149 decTable[b[10]],
150 decTable[b[11]],
151 decTable[b[12]],
152 }
153 for idx, v := range decVals {
154 if v >= 32 {
155 return 0, CorruptInputError(idx)
156 }
157 }
158
159 return 0 +
160 uint64(decVals[0])<<60 |
161 uint64(decVals[1])<<55 |
162 uint64(decVals[2])<<50 |
163 uint64(decVals[3])<<45 |
164 uint64(decVals[4])<<40 |
165 uint64(decVals[5])<<35 |
166 uint64(decVals[6])<<30 |
167 uint64(decVals[7])<<25 |
168 uint64(decVals[8])<<20 |
169 uint64(decVals[9])<<15 |
170 uint64(decVals[10])<<10 |
171 uint64(decVals[11])<<5 |
172 uint64(decVals[12]), nil
173 }
174}
175
176const mask = 31
177
178// PutUint64 returns a cford32-encoded byte slice.
179func PutUint64(id uint64) [13]byte {
180 return [13]byte{
181 encTable[id>>60&mask|0x10], // specify full encoding
182 encTable[id>>55&mask],
183 encTable[id>>50&mask],
184 encTable[id>>45&mask],
185 encTable[id>>40&mask],
186 encTable[id>>35&mask],
187 encTable[id>>30&mask],
188 encTable[id>>25&mask],
189 encTable[id>>20&mask],
190 encTable[id>>15&mask],
191 encTable[id>>10&mask],
192 encTable[id>>5&mask],
193 encTable[id&mask],
194 }
195}
196
197// PutUint64Lower returns a cford32-encoded byte array, swapping uppercase
198// letters with lowercase.
199//
200// For more information on how the value is encoded, see [Uint64].
201func PutUint64Lower(id uint64) [13]byte {
202 return [13]byte{
203 encTableLower[id>>60&mask|0x10],
204 encTableLower[id>>55&mask],
205 encTableLower[id>>50&mask],
206 encTableLower[id>>45&mask],
207 encTableLower[id>>40&mask],
208 encTableLower[id>>35&mask],
209 encTableLower[id>>30&mask],
210 encTableLower[id>>25&mask],
211 encTableLower[id>>20&mask],
212 encTableLower[id>>15&mask],
213 encTableLower[id>>10&mask],
214 encTableLower[id>>5&mask],
215 encTableLower[id&mask],
216 }
217}
218
219// PutCompact returns a cford32-encoded byte slice, using the compact
220// representation of cford32 described in the package documentation where
221// possible (all values of id < 1<<34). The lowercase encoding is used.
222//
223// The resulting byte slice will be 7 bytes long for all compact values,
224// and 13 bytes long for
225func PutCompact(id uint64) []byte {
226 return AppendCompact(id, nil)
227}
228
229// AppendCompact works like [PutCompact] but appends to the given byte slice
230// instead of allocating one anew.
231func AppendCompact(id uint64, b []byte) []byte {
232 const maxCompact = 1 << 34
233 if id < maxCompact {
234 return append(b,
235 encTableLower[id>>30&mask],
236 encTableLower[id>>25&mask],
237 encTableLower[id>>20&mask],
238 encTableLower[id>>15&mask],
239 encTableLower[id>>10&mask],
240 encTableLower[id>>5&mask],
241 encTableLower[id&mask],
242 )
243 }
244 return append(b,
245 encTableLower[id>>60&mask|0x10],
246 encTableLower[id>>55&mask],
247 encTableLower[id>>50&mask],
248 encTableLower[id>>45&mask],
249 encTableLower[id>>40&mask],
250 encTableLower[id>>35&mask],
251 encTableLower[id>>30&mask],
252 encTableLower[id>>25&mask],
253 encTableLower[id>>20&mask],
254 encTableLower[id>>15&mask],
255 encTableLower[id>>10&mask],
256 encTableLower[id>>5&mask],
257 encTableLower[id&mask],
258 )
259}
260
261func DecodedLen(n int) int {
262 return n/8*5 + n%8*5/8
263}
264
265func EncodedLen(n int) int {
266 return n/5*8 + (n%5*8+4)/5
267}
268
269// Encode encodes src using the encoding enc,
270// writing [EncodedLen](len(src)) bytes to dst.
271//
272// The encoding does not contain any padding, unlike Go's base32.
273func Encode(dst, src []byte) {
274 // Copied from encoding/base32/base32.go (go1.22)
275 if len(src) == 0 {
276 return
277 }
278
279 di, si := 0, 0
280 n := (len(src) / 5) * 5
281 for si < n {
282 // Combining two 32 bit loads allows the same code to be used
283 // for 32 and 64 bit platforms.
284 hi := uint32(src[si+0])<<24 | uint32(src[si+1])<<16 | uint32(src[si+2])<<8 | uint32(src[si+3])
285 lo := hi<<8 | uint32(src[si+4])
286
287 dst[di+0] = encTable[(hi>>27)&0x1F]
288 dst[di+1] = encTable[(hi>>22)&0x1F]
289 dst[di+2] = encTable[(hi>>17)&0x1F]
290 dst[di+3] = encTable[(hi>>12)&0x1F]
291 dst[di+4] = encTable[(hi>>7)&0x1F]
292 dst[di+5] = encTable[(hi>>2)&0x1F]
293 dst[di+6] = encTable[(lo>>5)&0x1F]
294 dst[di+7] = encTable[(lo)&0x1F]
295
296 si += 5
297 di += 8
298 }
299
300 // Add the remaining small block
301 remain := len(src) - si
302 if remain == 0 {
303 return
304 }
305
306 // Encode the remaining bytes in reverse order.
307 val := uint32(0)
308 switch remain {
309 case 4:
310 val |= uint32(src[si+3])
311 dst[di+6] = encTable[val<<3&0x1F]
312 dst[di+5] = encTable[val>>2&0x1F]
313 fallthrough
314 case 3:
315 val |= uint32(src[si+2]) << 8
316 dst[di+4] = encTable[val>>7&0x1F]
317 fallthrough
318 case 2:
319 val |= uint32(src[si+1]) << 16
320 dst[di+3] = encTable[val>>12&0x1F]
321 dst[di+2] = encTable[val>>17&0x1F]
322 fallthrough
323 case 1:
324 val |= uint32(src[si+0]) << 24
325 dst[di+1] = encTable[val>>22&0x1F]
326 dst[di+0] = encTable[val>>27&0x1F]
327 }
328}
329
330// EncodeLower is like [Encode], but uses the lowercase
331func EncodeLower(dst, src []byte) {
332 // Copied from encoding/base32/base32.go (go1.22)
333 if len(src) == 0 {
334 return
335 }
336
337 di, si := 0, 0
338 n := (len(src) / 5) * 5
339 for si < n {
340 // Combining two 32 bit loads allows the same code to be used
341 // for 32 and 64 bit platforms.
342 hi := uint32(src[si+0])<<24 | uint32(src[si+1])<<16 | uint32(src[si+2])<<8 | uint32(src[si+3])
343 lo := hi<<8 | uint32(src[si+4])
344
345 dst[di+0] = encTableLower[(hi>>27)&0x1F]
346 dst[di+1] = encTableLower[(hi>>22)&0x1F]
347 dst[di+2] = encTableLower[(hi>>17)&0x1F]
348 dst[di+3] = encTableLower[(hi>>12)&0x1F]
349 dst[di+4] = encTableLower[(hi>>7)&0x1F]
350 dst[di+5] = encTableLower[(hi>>2)&0x1F]
351 dst[di+6] = encTableLower[(lo>>5)&0x1F]
352 dst[di+7] = encTableLower[(lo)&0x1F]
353
354 si += 5
355 di += 8
356 }
357
358 // Add the remaining small block
359 remain := len(src) - si
360 if remain == 0 {
361 return
362 }
363
364 // Encode the remaining bytes in reverse order.
365 val := uint32(0)
366 switch remain {
367 case 4:
368 val |= uint32(src[si+3])
369 dst[di+6] = encTableLower[val<<3&0x1F]
370 dst[di+5] = encTableLower[val>>2&0x1F]
371 fallthrough
372 case 3:
373 val |= uint32(src[si+2]) << 8
374 dst[di+4] = encTableLower[val>>7&0x1F]
375 fallthrough
376 case 2:
377 val |= uint32(src[si+1]) << 16
378 dst[di+3] = encTableLower[val>>12&0x1F]
379 dst[di+2] = encTableLower[val>>17&0x1F]
380 fallthrough
381 case 1:
382 val |= uint32(src[si+0]) << 24
383 dst[di+1] = encTableLower[val>>22&0x1F]
384 dst[di+0] = encTableLower[val>>27&0x1F]
385 }
386}
387
388// AppendEncode appends the cford32 encoded src to dst
389// and returns the extended buffer.
390func AppendEncode(dst, src []byte) []byte {
391 n := EncodedLen(len(src))
392 dst = grow(dst, n)
393 Encode(dst[len(dst):][:n], src)
394 return dst[:len(dst)+n]
395}
396
397// AppendEncodeLower appends the lowercase cford32 encoded src to dst
398// and returns the extended buffer.
399func AppendEncodeLower(dst, src []byte) []byte {
400 n := EncodedLen(len(src))
401 dst = grow(dst, n)
402 EncodeLower(dst[len(dst):][:n], src)
403 return dst[:len(dst)+n]
404}
405
406func grow(s []byte, n int) []byte {
407 // slices.Grow
408 if n -= cap(s) - len(s); n > 0 {
409 news := make([]byte, cap(s)+n)
410 copy(news[:cap(s)], s[:cap(s)])
411 return news[:len(s)]
412 }
413 return s
414}
415
416// EncodeToString returns the cford32 encoding of src.
417func EncodeToString(src []byte) string {
418 buf := make([]byte, EncodedLen(len(src)))
419 Encode(buf, src)
420 return string(buf)
421}
422
423// EncodeToStringLower returns the cford32 lowercase encoding of src.
424func EncodeToStringLower(src []byte) string {
425 buf := make([]byte, EncodedLen(len(src)))
426 EncodeLower(buf, src)
427 return string(buf)
428}
429
430func decode(dst, src []byte) (n int, err error) {
431 dsti := 0
432 olen := len(src)
433
434 for len(src) > 0 {
435 // Decode quantum using the base32 alphabet
436 var dbuf [8]byte
437 dlen := 8
438
439 for j := 0; j < 8; {
440 if len(src) == 0 {
441 // We have reached the end and are not expecting any padding
442 dlen = j
443 break
444 }
445 in := src[0]
446 src = src[1:]
447 dbuf[j] = decTable[in]
448 if dbuf[j] == 0xFF {
449 return n, CorruptInputError(olen - len(src) - 1)
450 }
451 j++
452 }
453
454 // Pack 8x 5-bit source blocks into 5 byte destination
455 // quantum
456 switch dlen {
457 case 8:
458 dst[dsti+4] = dbuf[6]<<5 | dbuf[7]
459 n++
460 fallthrough
461 case 7:
462 dst[dsti+3] = dbuf[4]<<7 | dbuf[5]<<2 | dbuf[6]>>3
463 n++
464 fallthrough
465 case 5:
466 dst[dsti+2] = dbuf[3]<<4 | dbuf[4]>>1
467 n++
468 fallthrough
469 case 4:
470 dst[dsti+1] = dbuf[1]<<6 | dbuf[2]<<1 | dbuf[3]>>4
471 n++
472 fallthrough
473 case 2:
474 dst[dsti+0] = dbuf[0]<<3 | dbuf[1]>>2
475 n++
476 }
477 dsti += 5
478 }
479 return n, nil
480}
481
482type encoder struct {
483 err error
484 w io.Writer
485 enc func(dst, src []byte)
486 buf [5]byte // buffered data waiting to be encoded
487 nbuf int // number of bytes in buf
488 out [1024]byte // output buffer
489}
490
491func NewEncoder(w io.Writer) io.WriteCloser {
492 return &encoder{w: w, enc: Encode}
493}
494
495func NewEncoderLower(w io.Writer) io.WriteCloser {
496 return &encoder{w: w, enc: EncodeLower}
497}
498
499func (e *encoder) Write(p []byte) (n int, err error) {
500 if e.err != nil {
501 return 0, e.err
502 }
503
504 // Leading fringe.
505 if e.nbuf > 0 {
506 var i int
507 for i = 0; i < len(p) && e.nbuf < 5; i++ {
508 e.buf[e.nbuf] = p[i]
509 e.nbuf++
510 }
511 n += i
512 p = p[i:]
513 if e.nbuf < 5 {
514 return
515 }
516 e.enc(e.out[0:], e.buf[0:])
517 if _, e.err = e.w.Write(e.out[0:8]); e.err != nil {
518 return n, e.err
519 }
520 e.nbuf = 0
521 }
522
523 // Large interior chunks.
524 for len(p) >= 5 {
525 nn := len(e.out) / 8 * 5
526 if nn > len(p) {
527 nn = len(p)
528 nn -= nn % 5
529 }
530 e.enc(e.out[0:], p[0:nn])
531 if _, e.err = e.w.Write(e.out[0 : nn/5*8]); e.err != nil {
532 return n, e.err
533 }
534 n += nn
535 p = p[nn:]
536 }
537
538 // Trailing fringe.
539 copy(e.buf[:], p)
540 e.nbuf = len(p)
541 n += len(p)
542 return
543}
544
545// Close flushes any pending output from the encoder.
546// It is an error to call Write after calling Close.
547func (e *encoder) Close() error {
548 // If there's anything left in the buffer, flush it out
549 if e.err == nil && e.nbuf > 0 {
550 e.enc(e.out[0:], e.buf[0:e.nbuf])
551 encodedLen := EncodedLen(e.nbuf)
552 e.nbuf = 0
553 _, e.err = e.w.Write(e.out[0:encodedLen])
554 }
555 return e.err
556}
557
558// Decode decodes src using cford32. It writes at most
559// [DecodedLen](len(src)) bytes to dst and returns the number of bytes
560// written. If src contains invalid cford32 data, it will return the
561// number of bytes successfully written and [CorruptInputError].
562// Newline characters (\r and \n) are ignored.
563func Decode(dst, src []byte) (n int, err error) {
564 buf := make([]byte, len(src))
565 l := stripNewlines(buf, src)
566 return decode(dst, buf[:l])
567}
568
569// AppendDecode appends the cford32 decoded src to dst
570// and returns the extended buffer.
571// If the input is malformed, it returns the partially decoded src and an error.
572func AppendDecode(dst, src []byte) ([]byte, error) {
573 n := DecodedLen(len(src))
574
575 dst = grow(dst, n)
576 dstsl := dst[len(dst) : len(dst)+n]
577 n, err := Decode(dstsl, src)
578 return dst[:len(dst)+n], err
579}
580
581// DecodeString returns the bytes represented by the cford32 string s.
582func DecodeString(s string) ([]byte, error) {
583 buf := []byte(s)
584 l := stripNewlines(buf, buf)
585 n, err := decode(buf, buf[:l])
586 return buf[:n], err
587}
588
589// stripNewlines removes newline characters and returns the number
590// of non-newline characters copied to dst.
591func stripNewlines(dst, src []byte) int {
592 offset := 0
593 for _, b := range src {
594 if b == '\r' || b == '\n' {
595 continue
596 }
597 dst[offset] = b
598 offset++
599 }
600 return offset
601}
602
603type decoder struct {
604 err error
605 r io.Reader
606 buf [1024]byte // leftover input
607 nbuf int
608 out []byte // leftover decoded output
609 outbuf [1024 / 8 * 5]byte
610}
611
612// NewDecoder constructs a new base32 stream decoder.
613func NewDecoder(r io.Reader) io.Reader {
614 return &decoder{r: &newlineFilteringReader{r}}
615}
616
617func readEncodedData(r io.Reader, buf []byte) (n int, err error) {
618 for n < 1 && err == nil {
619 var nn int
620 nn, err = r.Read(buf[n:])
621 n += nn
622 }
623 return
624}
625
626func (d *decoder) Read(p []byte) (n int, err error) {
627 // Use leftover decoded output from last read.
628 if len(d.out) > 0 {
629 n = copy(p, d.out)
630 d.out = d.out[n:]
631 if len(d.out) == 0 {
632 return n, d.err
633 }
634 return n, nil
635 }
636
637 if d.err != nil {
638 return 0, d.err
639 }
640
641 // Read nn bytes from input, bounded [8,len(d.buf)]
642 nn := (len(p)/5 + 1) * 8
643 if nn > len(d.buf) {
644 nn = len(d.buf)
645 }
646
647 nn, d.err = readEncodedData(d.r, d.buf[d.nbuf:nn])
648 d.nbuf += nn
649 if d.nbuf < 1 {
650 return 0, d.err
651 }
652
653 // Decode chunk into p, or d.out and then p if p is too small.
654 nr := d.nbuf
655 if d.err != io.EOF && nr%8 != 0 {
656 nr -= nr % 8
657 }
658 nw := DecodedLen(d.nbuf)
659
660 if nw > len(p) {
661 nw, err = decode(d.outbuf[0:], d.buf[0:nr])
662 d.out = d.outbuf[0:nw]
663 n = copy(p, d.out)
664 d.out = d.out[n:]
665 } else {
666 n, err = decode(p, d.buf[0:nr])
667 }
668 d.nbuf -= nr
669 for i := 0; i < d.nbuf; i++ {
670 d.buf[i] = d.buf[i+nr]
671 }
672
673 if err != nil && (d.err == nil || d.err == io.EOF) {
674 d.err = err
675 }
676
677 if len(d.out) > 0 {
678 // We cannot return all the decoded bytes to the caller in this
679 // invocation of Read, so we return a nil error to ensure that Read
680 // will be called again. The error stored in d.err, if any, will be
681 // returned with the last set of decoded bytes.
682 return n, nil
683 }
684
685 return n, d.err
686}
687
688type newlineFilteringReader struct {
689 wrapped io.Reader
690}
691
692func (r *newlineFilteringReader) Read(p []byte) (int, error) {
693 n, err := r.wrapped.Read(p)
694 for n > 0 {
695 s := p[0:n]
696 offset := stripNewlines(s, s)
697 if err != nil || offset > 0 {
698 return offset, err
699 }
700 // Previous buffer entirely whitespace, read again
701 n, err = r.wrapped.Read(p)
702 }
703 return n, err
704}