package encodingx import ( "encoding/ascii85" "encoding/base64" "errors" "io" "os" ) var ( ErrLength = errors.New("base128: invalid length base128 string") ErrBit = errors.New("base128: high bit set in base128 string") ) var enctab = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,./:;<=>?@[]^_`{|}~'") var dectab = map[byte]byte{ 'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6, 'H': 7, 'I': 8, 'J': 9, 'K': 10, 'L': 11, 'M': 12, 'N': 13, 'O': 14, 'P': 15, 'Q': 16, 'R': 17, 'S': 18, 'T': 19, 'U': 20, 'V': 21, 'W': 22, 'X': 23, 'Y': 24, 'Z': 25, 'a': 26, 'b': 27, 'c': 28, 'd': 29, 'e': 30, 'f': 31, 'g': 32, 'h': 33, 'i': 34, 'j': 35, 'k': 36, 'l': 37, 'm': 38, 'n': 39, 'o': 40, 'p': 41, 'q': 42, 'r': 43, 's': 44, 't': 45, 'u': 46, 'v': 47, 'w': 48, 'x': 49, 'y': 50, 'z': 51, '0': 52, '1': 53, '2': 54, '3': 55, '4': 56, '5': 57, '6': 58, '7': 59, '8': 60, '9': 61, '!': 62, '#': 63, '$': 64, '%': 65, '&': 66, '(': 67, ')': 68, '*': 69, '+': 70, ',': 71, '.': 72, '/': 73, ':': 74, ';': 75, '<': 76, '=': 77, '>': 78, '?': 79, '@': 80, '[': 81, ']': 82, '^': 83, '_': 84, '`': 85, '{': 86, '|': 87, '}': 88, '~': 89, '\'': 90, } func Base91EncodeToString(d []byte) string { return string(Base91Encode(d)) } func Base91Encode(d []byte) []byte { var n, b uint var o []byte for i := 0; i < len(d); i++ { b |= uint(d[i]) << n n += 8 if n > 13 { v := b & 8191 if v > 88 { b >>= 13 n -= 13 } else { v = b & 16383 b >>= 14 n -= 14 } o = append(o, enctab[v%91], enctab[v/91]) } } if n > 0 { o = append(o, enctab[b%91]) if n > 7 || b > 90 { o = append(o, enctab[b/91]) } } return o } func Base91DecodeString(d string) []byte { return Base91Decode([]byte(d)) } func Base91Decode(d []byte) []byte { var b, n uint var o []byte v := -1 for i := 0; i < len(d); i++ { c, ok := dectab[d[i]] if !ok { continue } if v < 0 { v = int(c) } else { v += int(c) * 91 b |= uint(v) << n if v&8191 > 88 { n += 13 } else { n += 14 } o = append(o, byte(b&255)) b >>= 8 n -= 8 for n > 7 { o = append(o, byte(b&255)) b >>= 8 n -= 8 } v = -1 } } if v+1 > 0 { o = append(o, byte((b|uint(v)<>whichByte)) bufByte = (v & byte((1< 1 { buf = append(buf, bufByte|(v>>(8-whichByte))) } bufByte = v << whichByte if whichByte == 8 { whichByte = 0 } whichByte++ } return len(buf), nil } func Base128DecodeString(s string) ([]byte, error) { src := []byte(s) dst := make([]byte, Base128DecodedLen(len(src))) n, err := Base128Decode(dst, src) if err != nil { return nil, err } return dst[:n], nil } func Base128DecodedLen(encLen int) int { return encLen * 7 / 8 } func Base128EncodedLen(dataLen int) int { return ((dataLen * 8) + 6) / 7 } func Base128EncodeToString(src []byte) string { dst := make([]byte, Base128EncodedLen(len(src))) Base128Encode(dst, src) return string(dst) } func Base64Encode(bstr []byte) string { return base64.StdEncoding.EncodeToString(bstr) } func Base64Decode(str string) ([]byte, error) { return base64.StdEncoding.DecodeString(str) } func Base85Encode(bstr []byte) string { out := make([]byte, ascii85.MaxEncodedLen(len(bstr))) n := ascii85.Encode(out, bstr) return string(out[:n]) } func Base85Decode(str string) ([]byte, error) { out := make([]byte, len(str)) n, _, err := ascii85.Decode(out, []byte(str), true) if err != nil { return nil, err } return out[:n], nil } func Base85EncodeFile(src, dst string, progress func(float64)) error { fpsrc, err := os.Open(src) if err != nil { return err } defer fpsrc.Close() stat, err := fpsrc.Stat() if err != nil { return err } fpdst, err := os.Create(dst) if err != nil { return err } defer fpdst.Close() enc := ascii85.NewEncoder(fpdst) defer enc.Close() var sum int64 buf := make([]byte, 1000*1024) for { n, readErr := fpsrc.Read(buf) if n > 0 { sum += int64(n) if _, err := enc.Write(buf[:n]); err != nil { return err } reportProgress(progress, sum, stat.Size()) } if readErr != nil { if readErr == io.EOF { break } return readErr } } return nil } func Base85DecodeFile(src, dst string, progress func(float64)) error { fpsrc, err := os.Open(src) if err != nil { return err } defer fpsrc.Close() stat, err := fpsrc.Stat() if err != nil { return err } counter := &countingReader{r: fpsrc} dec := ascii85.NewDecoder(counter) fpdst, err := os.Create(dst) if err != nil { return err } defer fpdst.Close() buf := make([]byte, 1250*1024) for { n, readErr := dec.Read(buf) if n > 0 { if _, err := fpdst.Write(buf[:n]); err != nil { return err } reportProgress(progress, counter.n, stat.Size()) } if readErr != nil { if readErr == io.EOF { break } return readErr } } return nil } func Base64EncodeFile(src, dst string, progress func(float64)) error { fpsrc, err := os.Open(src) if err != nil { return err } defer fpsrc.Close() stat, err := fpsrc.Stat() if err != nil { return err } fpdst, err := os.Create(dst) if err != nil { return err } defer fpdst.Close() enc := base64.NewEncoder(base64.StdEncoding, fpdst) defer enc.Close() var sum int64 buf := make([]byte, 1024*1024) for { n, readErr := fpsrc.Read(buf) if n > 0 { sum += int64(n) if _, err := enc.Write(buf[:n]); err != nil { return err } reportProgress(progress, sum, stat.Size()) } if readErr != nil { if readErr == io.EOF { break } return readErr } } return nil } func Base64DecodeFile(src, dst string, progress func(float64)) error { fpsrc, err := os.Open(src) if err != nil { return err } defer fpsrc.Close() stat, err := fpsrc.Stat() if err != nil { return err } counter := &countingReader{r: fpsrc} dec := base64.NewDecoder(base64.StdEncoding, counter) fpdst, err := os.Create(dst) if err != nil { return err } defer fpdst.Close() buf := make([]byte, 1024*1024) for { n, readErr := dec.Read(buf) if n > 0 { if _, err := fpdst.Write(buf[:n]); err != nil { return err } reportProgress(progress, counter.n, stat.Size()) } if readErr != nil { if readErr == io.EOF { break } return readErr } } return nil } type countingReader struct { r io.Reader n int64 } func (c *countingReader) Read(p []byte) (int, error) { n, err := c.r.Read(p) c.n += int64(n) return n, err } func reportProgress(progress func(float64), current, total int64) { if progress == nil { return } if total <= 0 { progress(100) return } progress(float64(current) / float64(total) * 100) }