# vim:fileencoding=utf-8 # License: BSD Copyright: 2016, Kovid Goyal def base64encode(bytes, altchars, pad_char): # Convert an array of bytes into a base-64 encoded string l = bytes.length remainder = l % 3 main_length = l - remainder encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' + (altchars or '+/') pad_char = '=' if pad_char is undefined else pad_char ans = v'[]' for v'var i = 0; i < main_length; i += 3': chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2] ans.push(encodings[(chunk & 16515072) >> 18], encodings[(chunk & 258048) >> 12], encodings[(chunk & 4032) >> 6], encodings[chunk & 63]) if remainder is 1: chunk = bytes[main_length] ans.push(encodings[(chunk & 252) >> 2], encodings[(chunk & 3) << 4], pad_char, pad_char) elif remainder is 2: chunk = (bytes[main_length] << 8) | bytes[main_length + 1] ans.push(encodings[(chunk & 64512) >> 10], encodings[(chunk & 1008) >> 4], encodings[(chunk & 15) << 2], pad_char) return ans.join('') def base64decode(string): # convert the output of base64encode back into an array of bytes # (Uint8Array) only works with the standard altchars and pad_char if jstype(window) is not 'undefined': chars = window.atob(string) else: chars = new Buffer(string, 'base64').toString('binary') # noqa: undef ans = Uint8Array(chars.length) for i in range(ans.length): ans[i] = chars.charCodeAt(i) return ans def urlsafe_b64encode(bytes, pad_char): return base64encode(bytes, '-_', pad_char) def urlsafe_b64decode(string): string = String.prototype.replace.call(string, /[_-]/g, def(m): return '+' if m is '-' else '/';) return base64decode(string) def hexlify(bytes): ans = v'[]' for v'var i = 0; i < bytes.length; i++': x = bytes[i].toString(16) if x.length is 1: x = '0' + x ans.push(x) return ans.join('') def unhexlify(string): num = string.length // 2 if num * 2 is not string.length: raise ValueError('string length is not a multiple of two') ans = Uint8Array(num) for v'var i = 0; i < num; i++': x = parseInt(string[i*2:i*2+2], 16) if isNaN(x): raise ValueError('string is not hex-encoded') ans[i] = x return ans utf8_decoder_table = v'''[ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8 ]''' def _from_code_point(x): if x <= 0xFFFF: return String.fromCharCode(x) x -= 0x10000 return String.fromCharCode((x >> 10) + 0xD800, (x % 0x400) + 0xDC00) def utf8_decode(bytes, errors, replacement): # Convert an array of UTF-8 encoded bytes into a string state = 0 ans = v'[]' for v'var i = 0, l = bytes.length; i < l; i++': # noqa byte = bytes[i] typ = utf8_decoder_table[byte] codep = (byte & 0x3f) | (codep << 6) if state is not 0 else (0xff >> typ) & (byte) state = utf8_decoder_table[256 + state*16 + typ] if state is 0: ans.push(_from_code_point(codep)) elif state is 1: if not errors or errors is 'strict': raise UnicodeDecodeError(str.format('The byte 0x{:02x} at position {} is not valid UTF-8', byte, i)) elif errors is 'replace': ans.push(replacement or '?') return ans.join('') def utf8_encode_js(string): # Encode a string as an array of UTF-8 bytes escstr = encodeURIComponent(string) ans = v'[]' for v'var i = 0; i < escstr.length; i++': ch = escstr[i] if ch is '%': ans.push(parseInt(escstr[i+1:i+3], 16)) i += 2 else: ans.push(ch.charCodeAt(0)) return Uint8Array(ans) if jstype(TextEncoder) is 'function': _u8enc = TextEncoder('utf-8') utf8_encode = _u8enc.encode.bind(_u8enc) _u8enc = undefined else: utf8_encode = utf8_encode_js def utf8_encode_native(string): return _u8enc.encode(string)