summaryrefslogtreecommitdiffstats
path: root/src/console/zmq/utils/z85.py
diff options
context:
space:
mode:
authorDan Klein <danklei@cisco.com>2015-08-24 09:28:43 +0300
committerDan Klein <danklei@cisco.com>2015-08-24 09:28:43 +0300
commit20eb7d362f9bce1951bd61ad3f78cf8f4267d1d5 (patch)
treeb2c3fe1c721d5f6898b4bb8e81f7c68502e313e9 /src/console/zmq/utils/z85.py
parent49f6b00b58c3ec734218fcd69259771a42c157bd (diff)
parent651a7d779551e193bd9dbadbe8b2a02bdab231b4 (diff)
Merge branch 'master' into dan_stateless
Diffstat (limited to 'src/console/zmq/utils/z85.py')
-rwxr-xr-xsrc/console/zmq/utils/z85.py56
1 files changed, 56 insertions, 0 deletions
diff --git a/src/console/zmq/utils/z85.py b/src/console/zmq/utils/z85.py
new file mode 100755
index 00000000..1bb1784e
--- /dev/null
+++ b/src/console/zmq/utils/z85.py
@@ -0,0 +1,56 @@
+"""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)