├── .gitignore ├── README.md └── base91.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[co] 2 | 3 | # Packages 4 | *.egg 5 | *.egg-info 6 | dist 7 | build 8 | eggs 9 | parts 10 | bin 11 | var 12 | sdist 13 | develop-eggs 14 | .installed.cfg 15 | 16 | # Installer logs 17 | pip-log.txt 18 | 19 | # Unit test / coverage reports 20 | .coverage 21 | .tox 22 | 23 | #Translations 24 | *.mo 25 | 26 | #Mr Developer 27 | .mr.developer.cfg 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | base91-python 2 | ============= 3 | 4 | A python implementation of Base91 as described on http://base91.sourceforge.net/ , licenced under the New BSD License. 5 | 6 | Usage 7 | ----- 8 | 9 | import base91 10 | 11 | base91.encode('test') #result: 'fPNKd' 12 | base91.encode(b'\xfe\x03\x00W\xa9\xbc') #result: 'VLv(GdNE' 13 | 14 | base91.decode('8D9Kc)=/2$WzeFui#G9Km+<{VT2u9MZil}[A') # result: 'May a moody baby doom a yam?\n' 15 | 16 | -------------------------------------------------------------------------------- /base91.py: -------------------------------------------------------------------------------- 1 | # Base91 encode/decode for Python 2 and Python 3 2 | # 3 | # Copyright (c) 2012 Adrien Beraud 4 | # Copyright (c) 2015 Guillaume Jacquenot 5 | # All rights reserved. 6 | # 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions are met: 9 | # 10 | # * Redistributions of source code must retain the above copyright notice, 11 | # this list of conditions and the following disclaimer. 12 | # * Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # * Neither the name of Adrien Beraud, Wisdom Vibes Pte. Ltd., nor the names 16 | # of its contributors may be used to endorse or promote products derived 17 | # from this software without specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 23 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | # 30 | import struct 31 | 32 | base91_alphabet = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 33 | 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 34 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 35 | 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 36 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!', '#', '$', 37 | '%', '&', '(', ')', '*', '+', ',', '.', '/', ':', ';', '<', '=', 38 | '>', '?', '@', '[', ']', '^', '_', '`', '{', '|', '}', '~', '"'] 39 | 40 | decode_table = dict((v,k) for k,v in enumerate(base91_alphabet)) 41 | 42 | def decode(encoded_str): 43 | ''' Decode Base91 string to a bytearray ''' 44 | v = -1 45 | b = 0 46 | n = 0 47 | out = bytearray() 48 | for strletter in encoded_str: 49 | if not strletter in decode_table: 50 | continue 51 | c = decode_table[strletter] 52 | if(v < 0): 53 | v = c 54 | else: 55 | v += c*91 56 | b |= v << n 57 | n += 13 if (v & 8191)>88 else 14 58 | while True: 59 | out += struct.pack('B', b&255) 60 | b >>= 8 61 | n -= 8 62 | if not n>7: 63 | break 64 | v = -1 65 | if v+1: 66 | out += struct.pack('B', (b | v << n) & 255 ) 67 | return out 68 | 69 | def encode(bindata): 70 | ''' Encode a bytearray to a Base91 string ''' 71 | b = 0 72 | n = 0 73 | out = '' 74 | for count in range(len(bindata)): 75 | byte = bindata[count:count+1] 76 | b |= struct.unpack('B', byte)[0] << n 77 | n += 8 78 | if n>13: 79 | v = b & 8191 80 | if v > 88: 81 | b >>= 13 82 | n -= 13 83 | else: 84 | v = b & 16383 85 | b >>= 14 86 | n -= 14 87 | out += base91_alphabet[v % 91] + base91_alphabet[v // 91] 88 | if n: 89 | out += base91_alphabet[b % 91] 90 | if n>7 or b>90: 91 | out += base91_alphabet[b // 91] 92 | return out 93 | --------------------------------------------------------------------------------