Buckets:
| #! /usr/bin/env python3 | |
| """Conversions to/from quoted-printable transport encoding as per RFC 1521.""" | |
| # (Dec 1991 version). | |
| __all__ = ["encode", "decode", "encodestring", "decodestring"] | |
| ESCAPE = b'=' | |
| MAXLINESIZE = 76 | |
| HEX = b'0123456789ABCDEF' | |
| EMPTYSTRING = b'' | |
| try: | |
| from binascii import a2b_qp, b2a_qp | |
| except ImportError: | |
| a2b_qp = None | |
| b2a_qp = None | |
| def needsquoting(c, quotetabs, header): | |
| """Decide whether a particular byte ordinal needs to be quoted. | |
| The 'quotetabs' flag indicates whether embedded tabs and spaces should be | |
| quoted. Note that line-ending tabs and spaces are always encoded, as per | |
| RFC 1521. | |
| """ | |
| assert isinstance(c, bytes) | |
| if c in b' \t': | |
| return quotetabs | |
| # if header, we have to escape _ because _ is used to escape space | |
| if c == b'_': | |
| return header | |
| return c == ESCAPE or not (b' ' <= c <= b'~') | |
| def quote(c): | |
| """Quote a single character.""" | |
| assert isinstance(c, bytes) and len(c)==1 | |
| c = ord(c) | |
| return ESCAPE + bytes((HEX[c//16], HEX[c%16])) | |
| def encode(input, output, quotetabs, header=False): | |
| """Read 'input', apply quoted-printable encoding, and write to 'output'. | |
| 'input' and 'output' are binary file objects. The 'quotetabs' flag | |
| indicates whether embedded tabs and spaces should be quoted. Note that | |
| line-ending tabs and spaces are always encoded, as per RFC 1521. | |
| The 'header' flag indicates whether we are encoding spaces as _ as per RFC | |
| 1522.""" | |
| if b2a_qp is not None: | |
| data = input.read() | |
| odata = b2a_qp(data, quotetabs=quotetabs, header=header) | |
| output.write(odata) | |
| return | |
| def write(s, output=output, lineEnd=b'\n'): | |
| # RFC 1521 requires that the line ending in a space or tab must have | |
| # that trailing character encoded. | |
| if s and s[-1:] in b' \t': | |
| output.write(s[:-1] + quote(s[-1:]) + lineEnd) | |
| elif s == b'.': | |
| output.write(quote(s) + lineEnd) | |
| else: | |
| output.write(s + lineEnd) | |
| prevline = None | |
| while 1: | |
| line = input.readline() | |
| if not line: | |
| break | |
| outline = [] | |
| # Strip off any readline induced trailing newline | |
| stripped = b'' | |
| if line[-1:] == b'\n': | |
| line = line[:-1] | |
| stripped = b'\n' | |
| # Calculate the un-length-limited encoded line | |
| for c in line: | |
| c = bytes((c,)) | |
| if needsquoting(c, quotetabs, header): | |
| c = quote(c) | |
| if header and c == b' ': | |
| outline.append(b'_') | |
| else: | |
| outline.append(c) | |
| # First, write out the previous line | |
| if prevline is not None: | |
| write(prevline) | |
| # Now see if we need any soft line breaks because of RFC-imposed | |
| # length limitations. Then do the thisline->prevline dance. | |
| thisline = EMPTYSTRING.join(outline) | |
| while len(thisline) > MAXLINESIZE: | |
| # Don't forget to include the soft line break `=' sign in the | |
| # length calculation! | |
| write(thisline[:MAXLINESIZE-1], lineEnd=b'=\n') | |
| thisline = thisline[MAXLINESIZE-1:] | |
| # Write out the current line | |
| prevline = thisline | |
| # Write out the last line, without a trailing newline | |
| if prevline is not None: | |
| write(prevline, lineEnd=stripped) | |
| def encodestring(s, quotetabs=False, header=False): | |
| if b2a_qp is not None: | |
| return b2a_qp(s, quotetabs=quotetabs, header=header) | |
| from io import BytesIO | |
| infp = BytesIO(s) | |
| outfp = BytesIO() | |
| encode(infp, outfp, quotetabs, header) | |
| return outfp.getvalue() | |
| def decode(input, output, header=False): | |
| """Read 'input', apply quoted-printable decoding, and write to 'output'. | |
| 'input' and 'output' are binary file objects. | |
| If 'header' is true, decode underscore as space (per RFC 1522).""" | |
| if a2b_qp is not None: | |
| data = input.read() | |
| odata = a2b_qp(data, header=header) | |
| output.write(odata) | |
| return | |
| new = b'' | |
| while 1: | |
| line = input.readline() | |
| if not line: break | |
| i, n = 0, len(line) | |
| if n > 0 and line[n-1:n] == b'\n': | |
| partial = 0; n = n-1 | |
| # Strip trailing whitespace | |
| while n > 0 and line[n-1:n] in b" \t\r": | |
| n = n-1 | |
| else: | |
| partial = 1 | |
| while i < n: | |
| c = line[i:i+1] | |
| if c == b'_' and header: | |
| new = new + b' '; i = i+1 | |
| elif c != ESCAPE: | |
| new = new + c; i = i+1 | |
| elif i+1 == n and not partial: | |
| partial = 1; break | |
| elif i+1 < n and line[i+1:i+2] == ESCAPE: | |
| new = new + ESCAPE; i = i+2 | |
| elif i+2 < n and ishex(line[i+1:i+2]) and ishex(line[i+2:i+3]): | |
| new = new + bytes((unhex(line[i+1:i+3]),)); i = i+3 | |
| else: # Bad escape sequence -- leave it in | |
| new = new + c; i = i+1 | |
| if not partial: | |
| output.write(new + b'\n') | |
| new = b'' | |
| if new: | |
| output.write(new) | |
| def decodestring(s, header=False): | |
| if a2b_qp is not None: | |
| return a2b_qp(s, header=header) | |
| from io import BytesIO | |
| infp = BytesIO(s) | |
| outfp = BytesIO() | |
| decode(infp, outfp, header=header) | |
| return outfp.getvalue() | |
| # Other helper functions | |
| def ishex(c): | |
| """Return true if the byte ordinal 'c' is a hexadecimal digit in ASCII.""" | |
| assert isinstance(c, bytes) | |
| return b'0' <= c <= b'9' or b'a' <= c <= b'f' or b'A' <= c <= b'F' | |
| def unhex(s): | |
| """Get the integer value of a hexadecimal number.""" | |
| bits = 0 | |
| for c in s: | |
| c = bytes((c,)) | |
| if b'0' <= c <= b'9': | |
| i = ord('0') | |
| elif b'a' <= c <= b'f': | |
| i = ord('a')-10 | |
| elif b'A' <= c <= b'F': | |
| i = ord(b'A')-10 | |
| else: | |
| assert False, "non-hex digit "+repr(c) | |
| bits = bits*16 + (ord(c) - i) | |
| return bits | |
| def main(): | |
| import sys | |
| import getopt | |
| try: | |
| opts, args = getopt.getopt(sys.argv[1:], 'td') | |
| except getopt.error as msg: | |
| sys.stdout = sys.stderr | |
| print(msg) | |
| print("usage: quopri [-t | -d] [file] ...") | |
| print("-t: quote tabs") | |
| print("-d: decode; default encode") | |
| sys.exit(2) | |
| deco = False | |
| tabs = False | |
| for o, a in opts: | |
| if o == '-t': tabs = True | |
| if o == '-d': deco = True | |
| if tabs and deco: | |
| sys.stdout = sys.stderr | |
| print("-t and -d are mutually exclusive") | |
| sys.exit(2) | |
| if not args: args = ['-'] | |
| sts = 0 | |
| for file in args: | |
| if file == '-': | |
| fp = sys.stdin.buffer | |
| else: | |
| try: | |
| fp = open(file, "rb") | |
| except OSError as msg: | |
| sys.stderr.write("%s: can't open (%s)\n" % (file, msg)) | |
| sts = 1 | |
| continue | |
| try: | |
| if deco: | |
| decode(fp, sys.stdout.buffer) | |
| else: | |
| encode(fp, sys.stdout.buffer, tabs) | |
| finally: | |
| if file != '-': | |
| fp.close() | |
| if sts: | |
| sys.exit(sts) | |
| if __name__ == '__main__': | |
| main() | |
Xet Storage Details
- Size:
- 7.27 kB
- Xet hash:
- cfe60ebbf8e0b155310e5fff51a9c8d76c6496a1ce002e846cd2484ae9f39208
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.