1"""fontTools.misc.textTools.py -- miscellaneous routines."""
2
3
4from fontTools.misc.py23 import bytechr, byteord, bytesjoin, strjoin, tobytes
5import ast
6import string
7
8
9# alias kept for backward compatibility
10safeEval = ast.literal_eval
11
12
13def readHex(content):
14	"""Convert a list of hex strings to binary data."""
15	return deHexStr(strjoin(chunk for chunk in content if isinstance(chunk, str)))
16
17
18def deHexStr(hexdata):
19	"""Convert a hex string to binary data."""
20	hexdata = strjoin(hexdata.split())
21	if len(hexdata) % 2:
22		hexdata = hexdata + "0"
23	data = []
24	for i in range(0, len(hexdata), 2):
25		data.append(bytechr(int(hexdata[i:i+2], 16)))
26	return bytesjoin(data)
27
28
29def hexStr(data):
30	"""Convert binary data to a hex string."""
31	h = string.hexdigits
32	r = ''
33	for c in data:
34		i = byteord(c)
35		r = r + h[(i >> 4) & 0xF] + h[i & 0xF]
36	return r
37
38
39def num2binary(l, bits=32):
40	items = []
41	binary = ""
42	for i in range(bits):
43		if l & 0x1:
44			binary = "1" + binary
45		else:
46			binary = "0" + binary
47		l = l >> 1
48		if not ((i+1) % 8):
49			items.append(binary)
50			binary = ""
51	if binary:
52		items.append(binary)
53	items.reverse()
54	assert l in (0, -1), "number doesn't fit in number of bits"
55	return ' '.join(items)
56
57
58def binary2num(bin):
59	bin = strjoin(bin.split())
60	l = 0
61	for digit in bin:
62		l = l << 1
63		if digit != "0":
64			l = l | 0x1
65	return l
66
67
68def caselessSort(alist):
69	"""Return a sorted copy of a list. If there are only strings
70	in the list, it will not consider case.
71	"""
72
73	try:
74		return sorted(alist, key=lambda a: (a.lower(), a))
75	except TypeError:
76		return sorted(alist)
77
78
79def pad(data, size):
80	r""" Pad byte string 'data' with null bytes until its length is a
81	multiple of 'size'.
82
83	>>> len(pad(b'abcd', 4))
84	4
85	>>> len(pad(b'abcde', 2))
86	6
87	>>> len(pad(b'abcde', 4))
88	8
89	>>> pad(b'abcdef', 4) == b'abcdef\x00\x00'
90	True
91	"""
92	data = tobytes(data)
93	if size > 1:
94		remainder = len(data) % size
95		if remainder:
96			data += b"\0" * (size - remainder)
97	return data
98
99
100if __name__ == "__main__":
101	import doctest, sys
102	sys.exit(doctest.testmod().failed)
103