z85.go 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // Package z85 implements ZeroMQ Base-85 encoding as specified by http://rfc.zeromq.org/spec:32/Z85
  2. package z85
  3. import (
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. )
  8. // ErrLength results from encoding or decoding wrongly aligned input data.
  9. var ErrLength = errors.New("z85: wrongly aligned input data")
  10. // InvalidByteError values describe errors resulting from an invalid byte in a z85 encoded data.
  11. type InvalidByteError byte
  12. func (e InvalidByteError) Error() string {
  13. return fmt.Sprintf("z85: invalid input byte: %#U", rune(e))
  14. }
  15. const (
  16. minDigit = '!'
  17. maxDigit = '}'
  18. )
  19. var (
  20. digits = []byte(
  21. "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#")
  22. decodeLookup = [maxDigit - minDigit + 1]byte{}
  23. )
  24. func init() {
  25. for i, d := range digits {
  26. decodeLookup[d-minDigit] = byte(i + 1) // +1 to use 0 as an invalid byte marker
  27. }
  28. }
  29. // Decode decodes z85 encoded src into DecodedLen(len(src)) bytes of dst, returning the
  30. // number of bytes written to dst, always DecodedLen(len(src)).
  31. // The len(src) must be divisible by 5, otherwise an ErrLength is returned.
  32. // If Decode encounters invalid input bytes, it returns an InvalidByteError.
  33. func Decode(dst, src []byte) (n int, err error) {
  34. if len(src)%5 != 0 {
  35. return 0, ErrLength
  36. }
  37. n = DecodedLen(len(src))
  38. for len(src) > 0 {
  39. var v uint32
  40. for i := 0; i < 5; i++ {
  41. digit := src[i]
  42. if digit < minDigit || digit > maxDigit {
  43. return 0, InvalidByteError(digit)
  44. }
  45. m := uint32(decodeLookup[digit-minDigit])
  46. if m == 0 {
  47. return 0, InvalidByteError(digit)
  48. }
  49. v = v*85 + (m - 1) // -1 readjust due to invalid byte marker
  50. }
  51. binary.BigEndian.PutUint32(dst, v)
  52. src = src[5:]
  53. dst = dst[4:]
  54. }
  55. return
  56. }
  57. // DecodedLen returns the length in bytes of the decoded data corresponding to n bytes of
  58. // z85-encoded data.
  59. func DecodedLen(n int) int {
  60. return n * 4 / 5
  61. }
  62. // Encode encodes src into EncodedLen(len(src)) bytes of dst using z85 encoding, returning the
  63. // number of bytes written to dst, always EncodedLen(len(src)).
  64. // The len(src) must be divisible by 4, otherwise an ErrLength is returned.
  65. func Encode(dst, src []byte) (n int, err error) {
  66. if len(src)%4 != 0 {
  67. return 0, ErrLength
  68. }
  69. n = EncodedLen(len(src))
  70. for len(src) > 0 {
  71. v := binary.BigEndian.Uint32(src)
  72. for i := 4; i >= 0; i-- {
  73. dst[i] = digits[v%85]
  74. v /= 85
  75. }
  76. src = src[4:]
  77. dst = dst[5:]
  78. }
  79. return
  80. }
  81. // EncodedLen returns the length in bytes of the z85 encoding of an input buffer of length n.
  82. func EncodedLen(n int) int {
  83. return n * 5 / 4
  84. }