"""Python implementation of Z85 85-bit encoding Z85 encoding is a plaintext encoding for a bytestring interpreted as 32bit integers. Since the chunks are 32bit, a bytestring must be a multiple of 4 bytes. See ZMQ RFC 32 for details. """ # Copyright (C) PyZMQ Developers # Distributed under the terms of the Modified BSD License. import sys import struct PY3 = sys.version_info[0] >= 3 # Z85CHARS is the base 85 symbol table Z85CHARS = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#" # Z85MAP maps integers in [0,84] to the appropriate character in Z85CHARS Z85MAP = dict([(c, idx) for idx, c in enumerate(Z85CHARS)]) _85s = [ 85**i for i in range(5) ][::-1] def encode(rawbytes): """encode raw bytes into Z85""" # Accepts only byte arrays bounded to 4 bytes if len(rawbytes) % 4: raise ValueError("length must be multiple of 4, not %i" % len(rawbytes)) nvalues = len(rawbytes) / 4 values = struct.unpack('>%dI' % nvalues, rawbytes) encoded = [] for v in values: for offset in _85s: encoded.append(Z85CHARS[(v // offset) % 85]) # In Python 3, encoded is a list of integers (obviously?!) if PY3: return bytes(encoded) else: return b''.join(encoded) def decode(z85bytes): """decode Z85 bytes to raw bytes""" if len(z85bytes) % 5: raise ValueError("Z85 length must be multiple of 5, not %i" % len(z85bytes)) nvalues = len(z85bytes) / 5 values = [] for i in range(0, len(z85bytes), 5): value = 0 for j, offset in enumerate(_85s): value += Z85MAP[z85bytes[i+j]] * offset values.append(value) return struct.pack('>%dI' % nvalues, *values)