|
1 | 1 | # The MIT License (MIT)
|
2 | 2 | #
|
3 |
| -# Copyright (c) 2019 Brent Rubell for Adafruit Industries. |
| 3 | +# Copyright (c) 2014 Paul Sokolovsky |
| 4 | +# Modified by Brent Rubell for Adafruit Industries, 2019 |
4 | 5 | #
|
5 | 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 | 7 | # of this software and associated documentation files (the "Software"), to deal
|
|
26 | 27 | Helpers for conversions between binary and ASCII
|
27 | 28 |
|
28 | 29 |
|
29 |
| -* Author(s): Brent Rubell |
| 30 | +* Author(s): Paul Sokolovsky, Brent Rubell |
30 | 31 |
|
31 | 32 | Implementation Notes
|
32 | 33 | --------------------
|
33 | 34 |
|
34 | 35 | **Hardware:**
|
35 | 36 |
|
36 |
| -.. todo:: Add links to any specific hardware product page(s), or category page(s). Use unordered list & hyperlink rST |
37 |
| - inline format: "* `Link Text <url>`_" |
38 |
| -
|
39 | 37 | **Software and Dependencies:**
|
40 | 38 |
|
41 | 39 | * Adafruit CircuitPython firmware for the supported boards:
|
42 | 40 | https://github.com/adafruit/circuitpython/releases
|
43 | 41 |
|
44 |
| -.. todo:: Uncomment or remove the Bus Device and/or the Register library dependencies based on the library's use of either. |
45 |
| -
|
46 |
| -# * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice |
47 |
| -# * Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register |
48 | 42 | """
|
49 |
| - |
50 |
| -# imports |
| 43 | +try: |
| 44 | + from binascii import hexlify, unhexlify |
| 45 | +except ImportError: |
| 46 | + pass |
51 | 47 |
|
52 | 48 | __version__ = "0.0.0-auto.0"
|
53 | 49 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_binascii.git"
|
| 50 | + |
| 51 | +# pylint: disable=bad-whitespace |
| 52 | +TABLE_A2B_B64 = [ |
| 53 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 54 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 55 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, |
| 56 | + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, |
| 57 | + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
| 58 | + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,-1, -1, -1, -1, -1, |
| 59 | + -1, 26, 27, 28, 29, 30,31, 32, 33, 34, 35, 36, 37, 38, 39, 40, |
| 60 | + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,-1, -1, -1, -1, -1, |
| 61 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 62 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 63 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 64 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 65 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 66 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 67 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 68 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 69 | +] |
| 70 | + |
| 71 | + |
| 72 | +if not "unhexlify" in globals(): |
| 73 | + # pylint: disable=function-redefined |
| 74 | + def unhexlify(hexstr): |
| 75 | + """Return the binary data represented by hexstr. |
| 76 | + :param str hexstr: Hexadecimal string. |
| 77 | + """ |
| 78 | + if len(hexstr) % 2 != 0: |
| 79 | + raise ValueError("Odd-length string") |
| 80 | + |
| 81 | + return bytes([int(hexstr[i : i + 2], 16) for i in range(0, len(hexstr), 2)]) |
| 82 | + |
| 83 | + |
| 84 | +if not "hexlify" in globals(): |
| 85 | + # pylint: disable=function-redefined |
| 86 | + def hexlify(data): |
| 87 | + """Return the hexadecimal representation of the |
| 88 | + binary data. Every byte of data is converted into |
| 89 | + the corresponding 2-digit hex representation. |
| 90 | + The returned bytes object is therefore twice |
| 91 | + as long as the length of data. |
| 92 | +
|
| 93 | + :param bytes data: Binary data, as bytes. |
| 94 | + """ |
| 95 | + if not data: |
| 96 | + raise TypeError("Data provided is zero-length") |
| 97 | + data = "".join("%02x" % i for i in data) |
| 98 | + return data.encode() |
| 99 | + |
| 100 | +B2A_HEX = hexlify |
| 101 | +A2B_HEX = unhexlify |
| 102 | + |
| 103 | +def _transform(n): |
| 104 | + if n == -1: |
| 105 | + return '\xff' |
| 106 | + return chr(n) |
| 107 | +TABLE_A2B_B64 = ''.join(map(_transform, TABLE_A2B_B64)) |
| 108 | +assert len(TABLE_A2B_B64) == 256 |
| 109 | + |
| 110 | +def a2b_base64(b64_data): |
| 111 | + "Decode a line of base64 data." |
| 112 | + res = [] |
| 113 | + quad_pos = 0 |
| 114 | + leftchar = 0 |
| 115 | + leftbits = 0 |
| 116 | + last_char_was_a_pad = False |
| 117 | + |
| 118 | + for char in b64_data: |
| 119 | + char = chr(char) |
| 120 | + if char == "=": |
| 121 | + if quad_pos > 2 or (quad_pos == 2 and last_char_was_a_pad): |
| 122 | + break # stop on 'xxx=' or on 'xx==' |
| 123 | + last_char_was_a_pad = True |
| 124 | + else: |
| 125 | + n = ord(TABLE_A2B_B64[ord(char)]) |
| 126 | + if n == 0xff: |
| 127 | + continue # ignore strange characters |
| 128 | + # |
| 129 | + # Shift it in on the low end, and see if there's |
| 130 | + # a byte ready for output. |
| 131 | + quad_pos = (quad_pos + 1) & 3 |
| 132 | + leftchar = (leftchar << 6) | n |
| 133 | + leftbits += 6 |
| 134 | + # |
| 135 | + if leftbits >= 8: |
| 136 | + leftbits -= 8 |
| 137 | + res.append((leftchar >> leftbits).to_bytes(1, 'big')) |
| 138 | + leftchar &= ((1 << leftbits) - 1) |
| 139 | + # |
| 140 | + last_char_was_a_pad = False |
| 141 | + else: |
| 142 | + if leftbits != 0: |
| 143 | + raise Exception("Incorrect padding") |
| 144 | + |
| 145 | + return b''.join(res) |
| 146 | + |
| 147 | +# ____________________________________________________________ |
| 148 | + |
| 149 | +TABLE_B2A_B64 = ( |
| 150 | + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") |
| 151 | + |
| 152 | +def b2a_base64(bin_data): |
| 153 | + "Base64-code line of data." |
| 154 | + |
| 155 | + newlength = (len(bin_data) + 2) // 3 |
| 156 | + newlength = newlength * 4 + 1 |
| 157 | + res = [] |
| 158 | + |
| 159 | + leftchar = 0 |
| 160 | + leftbits = 0 |
| 161 | + for char in bin_data: |
| 162 | + # Shift into our buffer, and output any 6bits ready |
| 163 | + leftchar = (leftchar << 8) | char |
| 164 | + leftbits += 8 |
| 165 | + res.append(TABLE_B2A_B64[(leftchar >> (leftbits-6)) & 0x3f]) |
| 166 | + leftbits -= 6 |
| 167 | + if leftbits >= 6: |
| 168 | + res.append(TABLE_B2A_B64[(leftchar >> (leftbits-6)) & 0x3f]) |
| 169 | + leftbits -= 6 |
| 170 | + # |
| 171 | + if leftbits == 2: |
| 172 | + res.append(TABLE_B2A_B64[(leftchar & 3) << 4]) |
| 173 | + res.append("=") |
| 174 | + res.append("=") |
| 175 | + elif leftbits == 4: |
| 176 | + res.append(TABLE_B2A_B64[(leftchar & 0xf) << 2]) |
| 177 | + res.append("=") |
| 178 | + res.append('\n') |
| 179 | + return ''.join(res).encode('ascii') |
0 commit comments