def rledecode_hqx(space, hexbin): "Decode hexbin RLE-coded string." # that's a guesstimation of the resulting length res = StringBuilder(len(hexbin)) end = len(hexbin) i = 0 lastpushed = -1 while i < end: c = hexbin[i] i += 1 if c != '\x90': res.append(c) lastpushed = ord(c) else: if i == end: raise_Incomplete(space, 'String ends with the RLE code \x90') count = ord(hexbin[i]) - 1 i += 1 if count < 0: res.append('\x90') lastpushed = 0x90 else: if lastpushed < 0: raise_Error(space, 'String starts with the RLE code \x90') res.append_multiple_char(chr(lastpushed), count) return space.wrap(res.build())
def a2b_hqx(space, ascii): """Decode .hqx coding. Returns (bin, done).""" # overestimate the resulting length res = StringBuilder(len(ascii)) done = 0 pending_value = 0 pending_bits = 0 for c in ascii: n = ord(table_a2b_hqx[ord(c)]) if n <= 0x3F: pending_value = (pending_value << 6) | n pending_bits += 6 if pending_bits == 24: # flush res.append(chr(pending_value >> 16)) res.append(chr((pending_value >> 8) & 0xff)) res.append(chr(pending_value & 0xff)) pending_value = 0 pending_bits = 0 elif n == FAIL: raise_Error(space, 'Illegal character') elif n == DONE: if pending_bits >= 8: res.append(chr(pending_value >> (pending_bits - 8))) if pending_bits >= 16: res.append(chr((pending_value >> (pending_bits - 16)) & 0xff)) done = 1 break #elif n == SKIP: pass else: if pending_bits > 0: raise_Incomplete(space, 'String has incomplete number of bytes') return space.newtuple([space.wrap(res.build()), space.wrap(done)])
def _a2b_write(space, res, length, char): if res.getlength() < length: # common case: we have enough room. res.append(chr(char)) else: # overflows. Only accept zeros from now on. if char != 0: raise_Error(space, "Trailing garbage")
def _char2value(space, c): if c <= '9': if c >= '0': return ord(c) - ord('0') elif c <= 'F': if c >= 'A': return ord(c) - (ord('A') - 10) elif c <= 'f': if c >= 'a': return ord(c) - (ord('a') - 10) raise_Error(space, 'Non-hexadecimal digit found')
def unhexlify(space, hexstr): '''Binary data of hexadecimal representation. hexstr must contain an even number of hex digits (upper or lower case). This function is also available as "unhexlify()".''' if len(hexstr) & 1: raise_Error(space, 'Odd-length string') res = StringBuilder(len(hexstr) >> 1) for i in range(0, len(hexstr), 2): a = _char2value(space, hexstr[i]) b = _char2value(space, hexstr[i + 1]) res.append(chr((a << 4) | b)) return space.newbytes(res.build())
def _a2b_read(space, s, index): try: c = s[index] except IndexError: return 0 # Check the character for legality. The 64 instead of the expected 63 # is because there are a few uuencodes out there that use '`' as zero # instead of space. if c < " " or c > chr(32 + 64): if c == "\n" or c == "\r": return 0 raise_Error(space, "Illegal char") return (ord(c) - 0x20) & 0x3F
def _a2b_read(space, s, index): try: c = s[index] except IndexError: return 0 # Check the character for legality. The 64 instead of the expected 63 # is because there are a few uuencodes out there that use '`' as zero # instead of space. if c < ' ' or c > chr(32 + 64): if c == '\n' or c == '\r': return 0 raise_Error(space, "Illegal char") return (ord(c) - 0x20) & 0x3f
def a2b_base64(space, ascii): "Decode a line of base64 data." res = StringBuilder((len(ascii) // 4) * 3) # maximum estimate quad_pos = 0 leftchar = 0 leftbits = 0 last_char_was_a_pad = False bin_used = 0 for c in ascii: if c == PAD: if quad_pos > 2 or (quad_pos == 2 and last_char_was_a_pad): break # stop on 'xxx=' or on 'xx==' last_char_was_a_pad = True else: n = ord(table_a2b_base64[ord(c)]) if n == 0xff: continue # ignore strange characters # # Shift it in on the low end, and see if there's # a byte ready for output. quad_pos = (quad_pos + 1) & 3 leftchar = (leftchar << 6) | n leftbits += 6 # if leftbits >= 8: leftbits -= 8 res.append(chr(leftchar >> leftbits)) leftchar &= ((1 << leftbits) - 1) bin_used += 1 # last_char_was_a_pad = False else: if leftbits != 0: if leftbits == 6: # There is exactly one extra valid, non-padding, base64 character. # This is an invalid length, as there is no possible input that # could encoded into such a base64 string. msg = ( "Invalid base64-encoded string: number of data " "characters (%d) cannot be 1 more than a multiple of 4" % ((bin_used // 3) * 4 + 1)) raise_Error(space, msg) raise_Error(space, "Incorrect padding") return space.newbytes(res.build())
def b2a_uu(space, bin): "Uuencode a line of data." length = len(bin) if length > 45: raise_Error(space, "At most 45 bytes at once") res = StringBuilder(2 + ((length + 2) // 3) * 4) res.append(chr(0x20 + length)) for i in range(0, length, 3): A = _b2a_read(bin, i) B = _b2a_read(bin, i + 1) C = _b2a_read(bin, i + 2) # res.append(chr(0x20 + (A >> 2))) res.append(chr(0x20 + ((A & 0x3) << 4 | B >> 4))) res.append(chr(0x20 + ((B & 0xF) << 2 | C >> 6))) res.append(chr(0x20 + (C & 0x3F))) res.append("\n") return space.wrap(res.build())
def b2a_uu(space, bin): "Uuencode a line of data." length = len(bin) if length > 45: raise_Error(space, 'At most 45 bytes at once') res = StringBuilder(2 + ((length + 2) // 3) * 4) res.append(chr(0x20 + length)) for i in range(0, length, 3): A = _b2a_read(bin, i) B = _b2a_read(bin, i + 1) C = _b2a_read(bin, i + 2) # res.append(chr(0x20 + (A >> 2))) res.append(chr(0x20 + ((A & 0x3) << 4 | B >> 4))) res.append(chr(0x20 + ((B & 0xF) << 2 | C >> 6))) res.append(chr(0x20 + (C & 0x3F))) res.append('\n') return space.wrap(res.build())
def b2a_uu(space, bin, __kwonly__, backtick=False): "Uuencode a line of data." length = len(bin) if length > 45: raise_Error(space, 'At most 45 bytes at once') res = StringBuilder(2 + ((length + 2) // 3) * 4) _b2a_write(res, length, backtick) for i in range(0, length, 3): A = _b2a_read(bin, i) B = _b2a_read(bin, i + 1) C = _b2a_read(bin, i + 2) # _b2a_write(res, A >> 2, backtick) _b2a_write(res, (A & 0x3) << 4 | B >> 4, backtick) _b2a_write(res, (B & 0xF) << 2 | C >> 6, backtick) _b2a_write(res, C & 0x3F, backtick) res.append('\n') return space.newbytes(res.build())
def a2b_uu(space, ascii): "Decode a line of uuencoded data." if len(ascii) == 0: # obscure case, for compability with CPython length = (-0x20) & 0x3F else: length = (ord(ascii[0]) - 0x20) & 0x3F res = StringBuilder(length) for i in range(1, len(ascii), 4): A = _a2b_read(space, ascii, i) B = _a2b_read(space, ascii, i + 1) C = _a2b_read(space, ascii, i + 2) D = _a2b_read(space, ascii, i + 3) # if res.getlength() < length: res.append(chr(A << 2 | B >> 4)) elif A != 0 or B != 0: raise_Error(space, "Trailing garbage") # if res.getlength() < length: res.append(chr((B & 0xF) << 4 | C >> 2)) elif C != 0: raise_Error(space, "Trailing garbage") # if res.getlength() < length: res.append(chr((C & 0x3) << 6 | D)) elif D != 0: raise_Error(space, "Trailing garbage") remaining = length - res.getlength() if remaining > 0: res.append_multiple_char("\x00", remaining) return space.wrap(res.build())
def a2b_uu(space, ascii): "Decode a line of uuencoded data." if len(ascii) == 0: # obscure case, for compability with CPython length = (-0x20) & 0x3f else: length = (ord(ascii[0]) - 0x20) & 0x3f res = StringBuilder(length) for i in range(1, len(ascii), 4): A = _a2b_read(space, ascii, i) B = _a2b_read(space, ascii, i + 1) C = _a2b_read(space, ascii, i + 2) D = _a2b_read(space, ascii, i + 3) # if res.getlength() < length: res.append(chr(A << 2 | B >> 4)) elif A != 0 or B != 0: raise_Error(space, "Trailing garbage") # if res.getlength() < length: res.append(chr((B & 0xf) << 4 | C >> 2)) elif C != 0: raise_Error(space, "Trailing garbage") # if res.getlength() < length: res.append(chr((C & 0x3) << 6 | D)) elif D != 0: raise_Error(space, "Trailing garbage") remaining = length - res.getlength() if remaining > 0: res.append_multiple_char('\x00', remaining) return space.wrap(res.build())
def a2b_base64(space, ascii): "Decode a line of base64 data." res = StringBuilder((len(ascii) // 4) * 3) # maximum estimate quad_pos = 0 leftchar = 0 leftbits = 0 last_char_was_a_pad = False for c in ascii: if c == PAD: if quad_pos > 2 or (quad_pos == 2 and last_char_was_a_pad): break # stop on 'xxx=' or on 'xx==' last_char_was_a_pad = True else: n = ord(table_a2b_base64[ord(c)]) if n == 0xff: continue # ignore strange characters # # Shift it in on the low end, and see if there's # a byte ready for output. quad_pos = (quad_pos + 1) & 3 leftchar = (leftchar << 6) | n leftbits += 6 # if leftbits >= 8: leftbits -= 8 res.append(chr(leftchar >> leftbits)) leftchar &= ((1 << leftbits) - 1) # last_char_was_a_pad = False else: if leftbits != 0: raise_Error(space, "Incorrect padding") return space.wrapbytes(res.build())
def a2b_base64(space, ascii): "Decode a line of base64 data." res = StringBuilder((len(ascii) // 4) * 3) # maximum estimate quad_pos = 0 leftchar = 0 leftbits = 0 last_char_was_a_pad = False for c in ascii: if c == PAD: if quad_pos > 2 or (quad_pos == 2 and last_char_was_a_pad): break # stop on 'xxx=' or on 'xx==' last_char_was_a_pad = True else: n = ord(table_a2b_base64[ord(c)]) if n == 0xff: continue # ignore strange characters # # Shift it in on the low end, and see if there's # a byte ready for output. quad_pos = (quad_pos + 1) & 3 leftchar = (leftchar << 6) | n leftbits += 6 # if leftbits >= 8: leftbits -= 8 res.append(chr(leftchar >> leftbits)) leftchar &= ((1 << leftbits) - 1) # last_char_was_a_pad = False else: if leftbits != 0: raise_Error(space, "Incorrect padding") return space.wrap(res.build())