1"""fontTools.misc.textTools.py -- miscellaneous routines.""" 2 3import ast 4import string 5 6 7# alias kept for backward compatibility 8safeEval = ast.literal_eval 9 10 11class Tag(str): 12 @staticmethod 13 def transcode(blob): 14 if isinstance(blob, bytes): 15 blob = blob.decode("latin-1") 16 return blob 17 18 def __new__(self, content): 19 return str.__new__(self, self.transcode(content)) 20 21 def __ne__(self, other): 22 return not self.__eq__(other) 23 24 def __eq__(self, other): 25 return str.__eq__(self, self.transcode(other)) 26 27 def __hash__(self): 28 return str.__hash__(self) 29 30 def tobytes(self): 31 return self.encode("latin-1") 32 33 34def readHex(content): 35 """Convert a list of hex strings to binary data.""" 36 return deHexStr(strjoin(chunk for chunk in content if isinstance(chunk, str))) 37 38 39def deHexStr(hexdata): 40 """Convert a hex string to binary data.""" 41 hexdata = strjoin(hexdata.split()) 42 if len(hexdata) % 2: 43 hexdata = hexdata + "0" 44 data = [] 45 for i in range(0, len(hexdata), 2): 46 data.append(bytechr(int(hexdata[i : i + 2], 16))) 47 return bytesjoin(data) 48 49 50def hexStr(data): 51 """Convert binary data to a hex string.""" 52 h = string.hexdigits 53 r = "" 54 for c in data: 55 i = byteord(c) 56 r = r + h[(i >> 4) & 0xF] + h[i & 0xF] 57 return r 58 59 60def num2binary(l, bits=32): 61 items = [] 62 binary = "" 63 for i in range(bits): 64 if l & 0x1: 65 binary = "1" + binary 66 else: 67 binary = "0" + binary 68 l = l >> 1 69 if not ((i + 1) % 8): 70 items.append(binary) 71 binary = "" 72 if binary: 73 items.append(binary) 74 items.reverse() 75 assert l in (0, -1), "number doesn't fit in number of bits" 76 return " ".join(items) 77 78 79def binary2num(bin): 80 bin = strjoin(bin.split()) 81 l = 0 82 for digit in bin: 83 l = l << 1 84 if digit != "0": 85 l = l | 0x1 86 return l 87 88 89def caselessSort(alist): 90 """Return a sorted copy of a list. If there are only strings 91 in the list, it will not consider case. 92 """ 93 94 try: 95 return sorted(alist, key=lambda a: (a.lower(), a)) 96 except TypeError: 97 return sorted(alist) 98 99 100def pad(data, size): 101 r"""Pad byte string 'data' with null bytes until its length is a 102 multiple of 'size'. 103 104 >>> len(pad(b'abcd', 4)) 105 4 106 >>> len(pad(b'abcde', 2)) 107 6 108 >>> len(pad(b'abcde', 4)) 109 8 110 >>> pad(b'abcdef', 4) == b'abcdef\x00\x00' 111 True 112 """ 113 data = tobytes(data) 114 if size > 1: 115 remainder = len(data) % size 116 if remainder: 117 data += b"\0" * (size - remainder) 118 return data 119 120 121def tostr(s, encoding="ascii", errors="strict"): 122 if not isinstance(s, str): 123 return s.decode(encoding, errors) 124 else: 125 return s 126 127 128def tobytes(s, encoding="ascii", errors="strict"): 129 if isinstance(s, str): 130 return s.encode(encoding, errors) 131 else: 132 return bytes(s) 133 134 135def bytechr(n): 136 return bytes([n]) 137 138 139def byteord(c): 140 return c if isinstance(c, int) else ord(c) 141 142 143def strjoin(iterable, joiner=""): 144 return tostr(joiner).join(iterable) 145 146 147def bytesjoin(iterable, joiner=b""): 148 return tobytes(joiner).join(tobytes(item) for item in iterable) 149 150 151if __name__ == "__main__": 152 import doctest, sys 153 154 sys.exit(doctest.testmod().failed) 155