punycode.py (5626B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\stdlib\encodings\punycode.py 2 import codecs 3 4 def segregate(str): 5 base = [] 6 extended = {} 7 for c in str: 8 if ord(c) < 128: 9 base.append(c) 10 else: 11 extended[c] = 1 12 13 extended = extended.keys() 14 extended.sort() 15 return (''.join(base).encode('ascii'), extended) 16 17 18 def selective_len(str, max): 19 res = 0 20 for c in str: 21 if ord(c) < max: 22 res += 1 23 24 return res 25 26 27 def selective_find(str, char, index, pos): 28 l = len(str) 29 while 1: 30 pos += 1 31 if pos == l: 32 return (-1, -1) 33 c = str[pos] 34 if c == char: 35 return (index + 1, pos) 36 if c < char: 37 index += 1 38 39 40 def insertion_unsort(str, extended): 41 oldchar = 128 42 result = [] 43 oldindex = -1 44 for c in extended: 45 index = pos = -1 46 char = ord(c) 47 curlen = selective_len(str, char) 48 delta = (curlen + 1) * (char - oldchar) 49 while 1: 50 index, pos = selective_find(str, c, index, pos) 51 if index == -1: 52 break 53 delta += index - oldindex 54 result.append(delta - 1) 55 oldindex = index 56 delta = 0 57 58 oldchar = char 59 60 return result 61 62 63 def T(j, bias): 64 res = 36 * (j + 1) - bias 65 if res < 1: 66 return 1 67 if res > 26: 68 return 26 69 return res 70 71 72 digits = 'abcdefghijklmnopqrstuvwxyz0123456789' 73 74 def generate_generalized_integer(N, bias): 75 result = [] 76 j = 0 77 while 1: 78 t = T(j, bias) 79 if N < t: 80 result.append(digits[N]) 81 return result 82 result.append(digits[t + (N - t) % (36 - t)]) 83 N = (N - t) // (36 - t) 84 j += 1 85 86 87 def adapt(delta, first, numchars): 88 if first: 89 delta //= 700 90 else: 91 delta //= 2 92 delta += delta // numchars 93 divisions = 0 94 while delta > 455: 95 delta = delta // 35 96 divisions += 36 97 98 bias = divisions + 36 * delta // (delta + 38) 99 return bias 100 101 102 def generate_integers(baselen, deltas): 103 result = [] 104 bias = 72 105 for points, delta in enumerate(deltas): 106 s = generate_generalized_integer(delta, bias) 107 result.extend(s) 108 bias = adapt(delta, points == 0, baselen + points + 1) 109 110 return ''.join(result) 111 112 113 def punycode_encode(text): 114 base, extended = segregate(text) 115 base = base.encode('ascii') 116 deltas = insertion_unsort(text, extended) 117 extended = generate_integers(len(base), deltas) 118 if base: 119 return base + '-' + extended 120 return extended 121 122 123 def decode_generalized_number(extended, extpos, bias, errors): 124 result = 0 125 w = 1 126 j = 0 127 while 1: 128 try: 129 char = ord(extended[extpos]) 130 except IndexError: 131 if errors == 'strict': 132 raise UnicodeError, 'incomplete punicode string' 133 return (extpos + 1, None) 134 135 extpos += 1 136 if 65 <= char <= 90: 137 digit = char - 65 138 elif 48 <= char <= 57: 139 digit = char - 22 140 elif errors == 'strict': 141 raise UnicodeError("Invalid extended code point '%s'" % extended[extpos]) 142 else: 143 return (extpos, None) 144 t = T(j, bias) 145 result += digit * w 146 if digit < t: 147 return (extpos, result) 148 w = w * (36 - t) 149 j += 1 150 151 152 def insertion_sort(base, extended, errors): 153 char = 128 154 pos = -1 155 bias = 72 156 extpos = 0 157 while extpos < len(extended): 158 newpos, delta = decode_generalized_number(extended, extpos, bias, errors) 159 if delta is None: 160 return base 161 pos += delta + 1 162 char += pos // (len(base) + 1) 163 if char > 1114111: 164 if errors == 'strict': 165 raise UnicodeError, 'Invalid character U+%x' % char 166 char = ord('?') 167 pos = pos % (len(base) + 1) 168 base = base[:pos] + unichr(char) + base[pos:] 169 bias = adapt(delta, extpos == 0, len(base)) 170 extpos = newpos 171 172 return base 173 174 175 def punycode_decode(text, errors): 176 pos = text.rfind('-') 177 if pos == -1: 178 base = '' 179 extended = text 180 else: 181 base = text[:pos] 182 extended = text[pos + 1:] 183 base = unicode(base, 'ascii', errors) 184 extended = extended.upper() 185 return insertion_sort(base, extended, errors) 186 187 188 class Codec(codecs.Codec): 189 190 def encode(self, input, errors = 'strict'): 191 res = punycode_encode(input) 192 return (res, len(input)) 193 194 def decode(self, input, errors = 'strict'): 195 if errors not in ('strict', 'replace', 'ignore'): 196 raise UnicodeError, 'Unsupported error handling ' + errors 197 res = punycode_decode(input, errors) 198 return (res, len(input)) 199 200 201 class IncrementalEncoder(codecs.IncrementalEncoder): 202 203 def encode(self, input, final = False): 204 return punycode_encode(input) 205 206 207 class IncrementalDecoder(codecs.IncrementalDecoder): 208 209 def decode(self, input, final = False): 210 if self.errors not in ('strict', 'replace', 'ignore'): 211 raise UnicodeError, 'Unsupported error handling ' + self.errors 212 return punycode_decode(input, self.errors) 213 214 215 class StreamWriter(Codec, codecs.StreamWriter): 216 pass 217 218 219 class StreamReader(Codec, codecs.StreamReader): 220 pass 221 222 223 def getregentry(): 224 return codecs.CodecInfo(name='punycode', encode=Codec().encode, decode=Codec().decode, incrementalencoder=IncrementalEncoder, incrementaldecoder=IncrementalDecoder, streamwriter=StreamWriter, streamreader=StreamReader)