Spaces:
Sleeping
Sleeping
| """fontTools.misc.textTools.py -- miscellaneous routines.""" | |
| from __future__ import annotations | |
| import ast | |
| import string | |
| # alias kept for backward compatibility | |
| safeEval = ast.literal_eval | |
| class Tag(str): | |
| def transcode(blob): | |
| if isinstance(blob, bytes): | |
| blob = blob.decode("latin-1") | |
| return blob | |
| def __new__(self, content): | |
| return str.__new__(self, self.transcode(content)) | |
| def __ne__(self, other): | |
| return not self.__eq__(other) | |
| def __eq__(self, other): | |
| return str.__eq__(self, self.transcode(other)) | |
| def __hash__(self): | |
| return str.__hash__(self) | |
| def tobytes(self): | |
| return self.encode("latin-1") | |
| def readHex(content): | |
| """Convert a list of hex strings to binary data.""" | |
| return deHexStr(strjoin(chunk for chunk in content if isinstance(chunk, str))) | |
| def deHexStr(hexdata): | |
| """Convert a hex string to binary data.""" | |
| hexdata = strjoin(hexdata.split()) | |
| if len(hexdata) % 2: | |
| hexdata = hexdata + "0" | |
| data = [] | |
| for i in range(0, len(hexdata), 2): | |
| data.append(bytechr(int(hexdata[i : i + 2], 16))) | |
| return bytesjoin(data) | |
| def hexStr(data): | |
| """Convert binary data to a hex string.""" | |
| h = string.hexdigits | |
| r = "" | |
| for c in data: | |
| i = byteord(c) | |
| r = r + h[(i >> 4) & 0xF] + h[i & 0xF] | |
| return r | |
| def num2binary(l, bits=32): | |
| items = [] | |
| binary = "" | |
| for i in range(bits): | |
| if l & 0x1: | |
| binary = "1" + binary | |
| else: | |
| binary = "0" + binary | |
| l = l >> 1 | |
| if not ((i + 1) % 8): | |
| items.append(binary) | |
| binary = "" | |
| if binary: | |
| items.append(binary) | |
| items.reverse() | |
| assert l in (0, -1), "number doesn't fit in number of bits" | |
| return " ".join(items) | |
| def binary2num(bin): | |
| bin = strjoin(bin.split()) | |
| l = 0 | |
| for digit in bin: | |
| l = l << 1 | |
| if digit != "0": | |
| l = l | 0x1 | |
| return l | |
| def caselessSort(alist): | |
| """Return a sorted copy of a list. If there are only strings | |
| in the list, it will not consider case. | |
| """ | |
| try: | |
| return sorted(alist, key=lambda a: (a.lower(), a)) | |
| except TypeError: | |
| return sorted(alist) | |
| def pad(data, size): | |
| r"""Pad byte string 'data' with null bytes until its length is a | |
| multiple of 'size'. | |
| >>> len(pad(b'abcd', 4)) | |
| 4 | |
| >>> len(pad(b'abcde', 2)) | |
| 6 | |
| >>> len(pad(b'abcde', 4)) | |
| 8 | |
| >>> pad(b'abcdef', 4) == b'abcdef\x00\x00' | |
| True | |
| """ | |
| data = tobytes(data) | |
| if size > 1: | |
| remainder = len(data) % size | |
| if remainder: | |
| data += b"\0" * (size - remainder) | |
| return data | |
| def tostr(s: str | bytes, encoding: str = "ascii", errors: str = "strict") -> str: | |
| if not isinstance(s, str): | |
| return s.decode(encoding, errors) | |
| else: | |
| return s | |
| def tobytes(s: str | bytes, encoding: str = "ascii", errors: str = "strict") -> bytes: | |
| if isinstance(s, str): | |
| return s.encode(encoding, errors) | |
| else: | |
| return bytes(s) | |
| def bytechr(n): | |
| return bytes([n]) | |
| def byteord(c): | |
| return c if isinstance(c, int) else ord(c) | |
| def strjoin(iterable, joiner=""): | |
| return tostr(joiner).join(iterable) | |
| def bytesjoin(iterable, joiner=b""): | |
| return tobytes(joiner).join(tobytes(item) for item in iterable) | |
| if __name__ == "__main__": | |
| import doctest, sys | |
| sys.exit(doctest.testmod().failed) | |