// Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.
// Package ascii85 implements the ascii85 data encoding// as used in the btoa tool and Adobe's PostScript and PDF document formats.
package ascii85import ()/* * Encoder */// Encode encodes src into at most [MaxEncodedLen](len(src))// bytes of dst, returning the actual number of bytes written.//// The encoding handles 4-byte chunks, using a special encoding// for the last fragment, so Encode is not appropriate for use on// individual blocks of a large data stream. Use [NewEncoder] instead.//// Often, ascii85-encoded data is wrapped in <~ and ~> symbols.// Encode does not add these.func (, []byte) int {iflen() == 0 {return0 } := 0forlen() > 0 { [0] = 0 [1] = 0 [2] = 0 [3] = 0 [4] = 0// Unpack 4 bytes into uint32 to repack into base 85 5-byte.varuint32switchlen() {default: |= uint32([3])fallthroughcase3: |= uint32([2]) << 8fallthroughcase2: |= uint32([1]) << 16fallthroughcase1: |= uint32([0]) << 24 }// Special case: zero (!!!!!) shortens to z.if == 0 && len() >= 4 { [0] = 'z' = [1:] = [4:] ++continue }// Otherwise, 5 base 85 digits starting at !.for := 4; >= 0; -- { [] = '!' + byte(%85) /= 85 }// If src was short, discard the low destination bytes. := 5iflen() < 4 { -= 4 - len() = nil } else { = [4:] } = [:] += }return}// MaxEncodedLen returns the maximum length of an encoding of n source bytes.func ( int) int { return ( + 3) / 4 * 5 }// NewEncoder returns a new ascii85 stream encoder. Data written to// the returned writer will be encoded and then written to w.// Ascii85 encodings operate in 32-bit blocks; when finished// writing, the caller must Close the returned encoder to flush any// trailing partial block.func ( io.Writer) io.WriteCloser { return &encoder{w: } }type encoder struct { err error w io.Writer buf [4]byte// buffered data waiting to be encoded nbuf int// number of bytes in buf out [1024]byte// output buffer}func ( *encoder) ( []byte) ( int, error) {if .err != nil {return0, .err }// Leading fringe.if .nbuf > 0 {varintfor = 0; < len() && .nbuf < 4; ++ { .buf[.nbuf] = [] .nbuf++ } += = [:]if .nbuf < 4 {return } := Encode(.out[0:], .buf[0:])if _, .err = .w.Write(.out[0:]); .err != nil {return , .err } .nbuf = 0 }// Large interior chunks.forlen() >= 4 { := len(.out) / 5 * 4if > len() { = len() } -= % 4if > 0 { := Encode(.out[0:], [0:])if _, .err = .w.Write(.out[0:]); .err != nil {return , .err } } += = [:] }// Trailing fringe.copy(.buf[:], ) .nbuf = len() += len()return}// Close flushes any pending output from the encoder.// It is an error to call Write after calling Close.func ( *encoder) () error {// If there's anything left in the buffer, flush it outif .err == nil && .nbuf > 0 { := Encode(.out[0:], .buf[0:.nbuf]) .nbuf = 0 _, .err = .w.Write(.out[0:]) }return .err}/* * Decoder */typeCorruptInputErrorint64func ( CorruptInputError) () string {return"illegal ascii85 data at input byte " + strconv.FormatInt(int64(), 10)}// Decode decodes src into dst, returning both the number// of bytes written to dst and the number consumed from src.// If src contains invalid ascii85 data, Decode will return the// number of bytes successfully written and a [CorruptInputError].// Decode ignores space and control characters in src.// Often, ascii85-encoded data is wrapped in <~ and ~> symbols.// Decode expects these to have been stripped by the caller.//// If flush is true, Decode assumes that src represents the// end of the input stream and processes it completely rather// than wait for the completion of another 32-bit block.//// [NewDecoder] wraps an [io.Reader] interface around Decode.func (, []byte, bool) (, int, error) {varuint32varintfor , := range {iflen()- < 4 {return }switch {case <= ' ':continuecase == 'z' && == 0: = 5 = 0case'!' <= && <= 'u': = *85 + uint32(-'!') ++default:return0, 0, CorruptInputError() }if == 5 { = + 1 [] = byte( >> 24) [+1] = byte( >> 16) [+2] = byte( >> 8) [+3] = byte() += 4 = 0 = 0 } }if { = len()if > 0 {// The number of output bytes in the last fragment // is the number of leftover input bytes - 1: // the extra byte provides enough bits to cover // the inefficiency of the encoding for the block.if == 1 {return0, 0, CorruptInputError(len()) }for := ; < 5; ++ {// The short encoding truncated the output value. // We have to assume the worst case values (digit 84) // in order to ensure that the top bits are correct. = *85 + 84 }for := 0; < -1; ++ { [] = byte( >> 24) <<= 8 ++ } } }return}// NewDecoder constructs a new ascii85 stream decoder.func ( io.Reader) io.Reader { return &decoder{r: } }type decoder struct { err error readErr error r io.Reader buf [1024]byte// leftover input nbuf int out []byte// leftover decoded output outbuf [1024]byte}func ( *decoder) ( []byte) ( int, error) {iflen() == 0 {return0, nil }if .err != nil {return0, .err }for {// Copy leftover output from last decode.iflen(.out) > 0 { = copy(, .out) .out = .out[:]return }// Decode leftover input from last read.var , , intif .nbuf > 0 { , , .err = Decode(.outbuf[0:], .buf[0:.nbuf], .readErr != nil)if > 0 { .out = .outbuf[0:] .nbuf = copy(.buf[0:], .buf[:.nbuf])continue// copy out and return }if == 0 && .err == nil {// Special case: input buffer is mostly filled with non-data bytes. // Filter out such bytes to make room for more input. := 0for := 0; < .nbuf; ++ {if .buf[] > ' ' { .buf[] = .buf[] ++ } } .nbuf = } }// Out of input, out of decoded output. Check errors.if .err != nil {return0, .err }if .readErr != nil { .err = .readErrreturn0, .err }// Read more data. , .readErr = .r.Read(.buf[.nbuf:]) .nbuf += }}
The pages are generated with Goldsv0.7.0-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.