Kind Pure package
Name v0
Namespace nt / cford32
Exported functions n/a — not supported for pure packages by the node (vm/qfuncs)
Module gno.land/p/nt/cford32/v0
gno 0.9 ⧉
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]. not supported for pure packages by the node (vm/qfuncs)
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
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/nt/seqid/v0].
51 //
52 // [specified by Douglas Crockford]: https://www.crockford.com/base32.html
53 package cford32
54
55 import (
56 "io"
57 "strconv"
58 )
59
60 const (
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.
89 type CorruptInputError int64
90
91 func (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.
105 func 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
176 const mask = 31
177
178 // PutUint64 returns a cford32-encoded byte slice.
179 func 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].
201 func 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
225 func 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.
231 func 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
261 func DecodedLen(n int ) int {
262 return n/ 8 * 5 + n% 8 * 5 / 8
263 }
264
265 func 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.
273 func 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
331 func 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.
390 func 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.
399 func 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
406 func 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.
417 func 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.
424 func EncodeToStringLower(src [] byte ) string {
425 buf := make([] byte , EncodedLen(len(src)))
426 EncodeLower(buf, src)
427 return string (buf)
428 }
429
430 func 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
482 type 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
491 func NewEncoder(w io.Writer) io.WriteCloser {
492 return &encoder{w: w, enc: Encode}
493 }
494
495 func NewEncoderLower(w io.Writer) io.WriteCloser {
496 return &encoder{w: w, enc: EncodeLower}
497 }
498
499 func (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.
547 func (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.
563 func 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.
572 func 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.
582 func 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.
591 func 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
603 type 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.
613 func NewDecoder(r io.Reader) io.Reader {
614 return &decoder{r: &newlineFilteringReader{r}}
615 }
616
617 func 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
626 func (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
688 type newlineFilteringReader struct {
689 wrapped io.Reader
690 }
691
692 func (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 }
705