charset.py (6277B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\stdlib\email\charset.py 2 __all__ = ['Charset', 3 'add_alias', 4 'add_charset', 5 'add_codec'] 6 import codecs 7 import email.base64mime 8 import email.quoprimime 9 from email import errors 10 from email.encoders import encode_7or8bit 11 QP = 1 12 BASE64 = 2 13 SHORTEST = 3 14 MISC_LEN = 7 15 DEFAULT_CHARSET = 'us-ascii' 16 CHARSETS = {'iso-8859-1': (QP, QP, None), 17 'iso-8859-2': (QP, QP, None), 18 'iso-8859-3': (QP, QP, None), 19 'iso-8859-4': (QP, QP, None), 20 'iso-8859-9': (QP, QP, None), 21 'iso-8859-10': (QP, QP, None), 22 'iso-8859-13': (QP, QP, None), 23 'iso-8859-14': (QP, QP, None), 24 'iso-8859-15': (QP, QP, None), 25 'iso-8859-16': (QP, QP, None), 26 'windows-1252': (QP, QP, None), 27 'viscii': (QP, QP, None), 28 'us-ascii': (None, None, None), 29 'big5': (BASE64, BASE64, None), 30 'gb2312': (BASE64, BASE64, None), 31 'euc-jp': (BASE64, None, 'iso-2022-jp'), 32 'shift_jis': (BASE64, None, 'iso-2022-jp'), 33 'iso-2022-jp': (BASE64, None, None), 34 'koi8-r': (BASE64, BASE64, None), 35 'utf-8': (SHORTEST, BASE64, 'utf-8'), 36 '8bit': (None, BASE64, 'utf-8')} 37 ALIASES = {'latin_1': 'iso-8859-1', 38 'latin-1': 'iso-8859-1', 39 'latin_2': 'iso-8859-2', 40 'latin-2': 'iso-8859-2', 41 'latin_3': 'iso-8859-3', 42 'latin-3': 'iso-8859-3', 43 'latin_4': 'iso-8859-4', 44 'latin-4': 'iso-8859-4', 45 'latin_5': 'iso-8859-9', 46 'latin-5': 'iso-8859-9', 47 'latin_6': 'iso-8859-10', 48 'latin-6': 'iso-8859-10', 49 'latin_7': 'iso-8859-13', 50 'latin-7': 'iso-8859-13', 51 'latin_8': 'iso-8859-14', 52 'latin-8': 'iso-8859-14', 53 'latin_9': 'iso-8859-15', 54 'latin-9': 'iso-8859-15', 55 'latin_10': 'iso-8859-16', 56 'latin-10': 'iso-8859-16', 57 'cp949': 'ks_c_5601-1987', 58 'euc_jp': 'euc-jp', 59 'euc_kr': 'euc-kr', 60 'ascii': 'us-ascii'} 61 CODEC_MAP = {'gb2312': 'eucgb2312_cn', 62 'big5': 'big5_tw', 63 'us-ascii': None} 64 65 def add_charset(charset, header_enc = None, body_enc = None, output_charset = None): 66 if body_enc == SHORTEST: 67 raise ValueError('SHORTEST not allowed for body_enc') 68 CHARSETS[charset] = (header_enc, body_enc, output_charset) 69 70 71 def add_alias(alias, canonical): 72 ALIASES[alias] = canonical 73 74 75 def add_codec(charset, codecname): 76 CODEC_MAP[charset] = codecname 77 78 79 class Charset: 80 81 def __init__(self, input_charset = DEFAULT_CHARSET): 82 try: 83 if isinstance(input_charset, unicode): 84 input_charset.encode('ascii') 85 else: 86 input_charset = unicode(input_charset, 'ascii') 87 except UnicodeError: 88 raise errors.CharsetError(input_charset) 89 90 input_charset = input_charset.lower() 91 if not (input_charset in ALIASES or input_charset in CHARSETS): 92 try: 93 input_charset = codecs.lookup(input_charset).name 94 except LookupError: 95 pass 96 97 self.input_charset = ALIASES.get(input_charset, input_charset) 98 henc, benc, conv = CHARSETS.get(self.input_charset, (SHORTEST, BASE64, None)) 99 if not conv: 100 conv = self.input_charset 101 self.header_encoding = henc 102 self.body_encoding = benc 103 self.output_charset = ALIASES.get(conv, conv) 104 self.input_codec = CODEC_MAP.get(self.input_charset, self.input_charset) 105 self.output_codec = CODEC_MAP.get(self.output_charset, self.output_charset) 106 107 def __str__(self): 108 return self.input_charset.lower() 109 110 __repr__ = __str__ 111 112 def __eq__(self, other): 113 return str(self) == str(other).lower() 114 115 def __ne__(self, other): 116 return not self.__eq__(other) 117 118 def get_body_encoding(self): 119 if self.body_encoding == QP: 120 return 'quoted-printable' 121 elif self.body_encoding == BASE64: 122 return 'base64' 123 else: 124 return encode_7or8bit 125 126 def convert(self, s): 127 if self.input_codec != self.output_codec: 128 return unicode(s, self.input_codec).encode(self.output_codec) 129 else: 130 return s 131 132 def to_splittable(self, s): 133 if isinstance(s, unicode) or self.input_codec is None: 134 return s 135 try: 136 return unicode(s, self.input_codec, 'replace') 137 except LookupError: 138 return s 139 140 def from_splittable(self, ustr, to_output = True): 141 if to_output: 142 codec = self.output_codec 143 else: 144 codec = self.input_codec 145 if not isinstance(ustr, unicode) or codec is None: 146 return ustr 147 try: 148 return ustr.encode(codec, 'replace') 149 except LookupError: 150 return ustr 151 152 def get_output_charset(self): 153 return self.output_charset or self.input_charset 154 155 def encoded_header_len(self, s): 156 cset = self.get_output_charset() 157 if self.header_encoding == BASE64: 158 return email.base64mime.base64_len(s) + len(cset) + MISC_LEN 159 elif self.header_encoding == QP: 160 return email.quoprimime.header_quopri_len(s) + len(cset) + MISC_LEN 161 elif self.header_encoding == SHORTEST: 162 lenb64 = email.base64mime.base64_len(s) 163 lenqp = email.quoprimime.header_quopri_len(s) 164 return min(lenb64, lenqp) + len(cset) + MISC_LEN 165 else: 166 return len(s) 167 168 def header_encode(self, s, convert = False): 169 cset = self.get_output_charset() 170 if convert: 171 s = self.convert(s) 172 if self.header_encoding == BASE64: 173 return email.base64mime.header_encode(s, cset) 174 if self.header_encoding == QP: 175 return email.quoprimime.header_encode(s, cset, maxlinelen=None) 176 if self.header_encoding == SHORTEST: 177 lenb64 = email.base64mime.base64_len(s) 178 lenqp = email.quoprimime.header_quopri_len(s) 179 if lenb64 < lenqp: 180 return email.base64mime.header_encode(s, cset) 181 else: 182 return email.quoprimime.header_encode(s, cset, maxlinelen=None) 183 else: 184 return s 185 186 def body_encode(self, s, convert = True): 187 if convert: 188 s = self.convert(s) 189 if self.body_encoding is BASE64: 190 return email.base64mime.body_encode(s) 191 elif self.body_encoding is QP: 192 return email.quoprimime.body_encode(s) 193 else: 194 return s