| """Base64 encoder/decoder utility for Starlark |
| |
| Handles string only and not binary data |
| |
| Implementation based on https://gist.github.com/trondhumbor/ce57c0c2816bb45a8fbb but adapted to use |
| the subset of python available in Starlark. |
| """ |
| |
| load(":strings.bzl", "chr", "ord") |
| |
| def decode(data): |
| """Decode a Base64 encoded string. |
| |
| See https://en.wikipedia.org/wiki/Base64. |
| |
| Args: |
| data: base64 encoded string |
| |
| Returns: |
| A string containing the decoded data |
| """ |
| padding = data.count("=") |
| data = data.replace("=", "A") |
| |
| binstring = "" |
| for i in range(len(data)): |
| index = BASE64_CHARS.find(data[i]) |
| if index == -1: |
| fail("expected a base64 encoded string") |
| binstring += _int_to_binary(index, 6) |
| |
| eight_chunks = _chunk(binstring, 8) |
| |
| outstring = "" |
| for chunk in eight_chunks: |
| outstring += chr(int(chunk, 2)) |
| |
| return outstring if padding == 0 else outstring[:-padding] |
| |
| def encode(data): |
| """Base64 encode a string. |
| |
| See https://en.wikipedia.org/wiki/Base64. |
| |
| Args: |
| data: string to encode |
| |
| Returns: |
| The base64 encoded string |
| """ |
| padding = 0 |
| if len(data) % 3 != 0: |
| padding = (len(data) + 3 - len(data) % 3) - len(data) |
| data += "\0" * padding |
| |
| three_chunks = _chunk(data, 3) |
| |
| binstring = "" |
| for chunk in three_chunks: |
| for i in range(len(chunk)): |
| binstring += _int_to_binary(ord(chunk[i])) |
| |
| six_chunks = _chunk(binstring, 6) |
| |
| outstring = "" |
| for element in six_chunks: |
| outstring += BASE64_CHARS[int(element, 2)] |
| |
| return outstring if padding == 0 else outstring[:-padding] + "=" * padding |
| |
| def _chunk(data, length): |
| return [data[i:i + length] for i in range(0, len(data), length)] |
| |
| BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" |
| |
| # Starlark support octal values that we can leverage for this conversion. |
| # Generated by lib/private/string.py utility script. |
| INT_TO_BINARY = [ |
| "00000000", |
| "00000001", |
| "00000010", |
| "00000011", |
| "00000100", |
| "00000101", |
| "00000110", |
| "00000111", |
| "00001000", |
| "00001001", |
| "00001010", |
| "00001011", |
| "00001100", |
| "00001101", |
| "00001110", |
| "00001111", |
| "00010000", |
| "00010001", |
| "00010010", |
| "00010011", |
| "00010100", |
| "00010101", |
| "00010110", |
| "00010111", |
| "00011000", |
| "00011001", |
| "00011010", |
| "00011011", |
| "00011100", |
| "00011101", |
| "00011110", |
| "00011111", |
| "00100000", |
| "00100001", |
| "00100010", |
| "00100011", |
| "00100100", |
| "00100101", |
| "00100110", |
| "00100111", |
| "00101000", |
| "00101001", |
| "00101010", |
| "00101011", |
| "00101100", |
| "00101101", |
| "00101110", |
| "00101111", |
| "00110000", |
| "00110001", |
| "00110010", |
| "00110011", |
| "00110100", |
| "00110101", |
| "00110110", |
| "00110111", |
| "00111000", |
| "00111001", |
| "00111010", |
| "00111011", |
| "00111100", |
| "00111101", |
| "00111110", |
| "00111111", |
| "01000000", |
| "01000001", |
| "01000010", |
| "01000011", |
| "01000100", |
| "01000101", |
| "01000110", |
| "01000111", |
| "01001000", |
| "01001001", |
| "01001010", |
| "01001011", |
| "01001100", |
| "01001101", |
| "01001110", |
| "01001111", |
| "01010000", |
| "01010001", |
| "01010010", |
| "01010011", |
| "01010100", |
| "01010101", |
| "01010110", |
| "01010111", |
| "01011000", |
| "01011001", |
| "01011010", |
| "01011011", |
| "01011100", |
| "01011101", |
| "01011110", |
| "01011111", |
| "01100000", |
| "01100001", |
| "01100010", |
| "01100011", |
| "01100100", |
| "01100101", |
| "01100110", |
| "01100111", |
| "01101000", |
| "01101001", |
| "01101010", |
| "01101011", |
| "01101100", |
| "01101101", |
| "01101110", |
| "01101111", |
| "01110000", |
| "01110001", |
| "01110010", |
| "01110011", |
| "01110100", |
| "01110101", |
| "01110110", |
| "01110111", |
| "01111000", |
| "01111001", |
| "01111010", |
| "01111011", |
| "01111100", |
| "01111101", |
| "01111110", |
| "01111111", |
| "10000000", |
| "10000001", |
| "10000010", |
| "10000011", |
| "10000100", |
| "10000101", |
| "10000110", |
| "10000111", |
| "10001000", |
| "10001001", |
| "10001010", |
| "10001011", |
| "10001100", |
| "10001101", |
| "10001110", |
| "10001111", |
| "10010000", |
| "10010001", |
| "10010010", |
| "10010011", |
| "10010100", |
| "10010101", |
| "10010110", |
| "10010111", |
| "10011000", |
| "10011001", |
| "10011010", |
| "10011011", |
| "10011100", |
| "10011101", |
| "10011110", |
| "10011111", |
| "10100000", |
| "10100001", |
| "10100010", |
| "10100011", |
| "10100100", |
| "10100101", |
| "10100110", |
| "10100111", |
| "10101000", |
| "10101001", |
| "10101010", |
| "10101011", |
| "10101100", |
| "10101101", |
| "10101110", |
| "10101111", |
| "10110000", |
| "10110001", |
| "10110010", |
| "10110011", |
| "10110100", |
| "10110101", |
| "10110110", |
| "10110111", |
| "10111000", |
| "10111001", |
| "10111010", |
| "10111011", |
| "10111100", |
| "10111101", |
| "10111110", |
| "10111111", |
| "11000000", |
| "11000001", |
| "11000010", |
| "11000011", |
| "11000100", |
| "11000101", |
| "11000110", |
| "11000111", |
| "11001000", |
| "11001001", |
| "11001010", |
| "11001011", |
| "11001100", |
| "11001101", |
| "11001110", |
| "11001111", |
| "11010000", |
| "11010001", |
| "11010010", |
| "11010011", |
| "11010100", |
| "11010101", |
| "11010110", |
| "11010111", |
| "11011000", |
| "11011001", |
| "11011010", |
| "11011011", |
| "11011100", |
| "11011101", |
| "11011110", |
| "11011111", |
| "11100000", |
| "11100001", |
| "11100010", |
| "11100011", |
| "11100100", |
| "11100101", |
| "11100110", |
| "11100111", |
| "11101000", |
| "11101001", |
| "11101010", |
| "11101011", |
| "11101100", |
| "11101101", |
| "11101110", |
| "11101111", |
| "11110000", |
| "11110001", |
| "11110010", |
| "11110011", |
| "11110100", |
| "11110101", |
| "11110110", |
| "11110111", |
| "11111000", |
| "11111001", |
| "11111010", |
| "11111011", |
| "11111100", |
| "11111101", |
| "11111110", |
| "11111111", |
| ] |
| |
| def _int_to_binary(i, digits = 8): |
| if i < 0 or i > 255: |
| fail("expected a int between 0 and 255 (inclusive)") |
| if digits < 1 or digits > 8: |
| fail("expected digits to be between 1 and 8 (inclusive)") |
| return INT_TO_BINARY[i][8 - digits:] |