xref: /aosp_15_r20/external/fonttools/Lib/fontTools/ttLib/tables/grUtils.py (revision e1fe3e4ad2793916b15cccdc4a7da52a7e1dd0e9)
1import struct, warnings
2
3try:
4    import lz4
5except ImportError:
6    lz4 = None
7else:
8    import lz4.block
9
10# old scheme for VERSION < 0.9 otherwise use lz4.block
11
12
13def decompress(data):
14    (compression,) = struct.unpack(">L", data[4:8])
15    scheme = compression >> 27
16    size = compression & 0x07FFFFFF
17    if scheme == 0:
18        pass
19    elif scheme == 1 and lz4:
20        res = lz4.block.decompress(struct.pack("<L", size) + data[8:])
21        if len(res) != size:
22            warnings.warn("Table decompression failed.")
23        else:
24            data = res
25    else:
26        warnings.warn("Table is compressed with an unsupported compression scheme")
27    return (data, scheme)
28
29
30def compress(scheme, data):
31    hdr = data[:4] + struct.pack(">L", (scheme << 27) + (len(data) & 0x07FFFFFF))
32    if scheme == 0:
33        return data
34    elif scheme == 1 and lz4:
35        res = lz4.block.compress(
36            data, mode="high_compression", compression=16, store_size=False
37        )
38        return hdr + res
39    else:
40        warnings.warn("Table failed to compress by unsupported compression scheme")
41    return data
42
43
44def _entries(attrs, sameval):
45    ak = 0
46    vals = []
47    lastv = 0
48    for k, v in attrs:
49        if len(vals) and (k != ak + 1 or (sameval and v != lastv)):
50            yield (ak - len(vals) + 1, len(vals), vals)
51            vals = []
52        ak = k
53        vals.append(v)
54        lastv = v
55    yield (ak - len(vals) + 1, len(vals), vals)
56
57
58def entries(attributes, sameval=False):
59    g = _entries(sorted(attributes.items(), key=lambda x: int(x[0])), sameval)
60    return g
61
62
63def bininfo(num, size=1):
64    if num == 0:
65        return struct.pack(">4H", 0, 0, 0, 0)
66    srange = 1
67    select = 0
68    while srange <= num:
69        srange *= 2
70        select += 1
71    select -= 1
72    srange //= 2
73    srange *= size
74    shift = num * size - srange
75    return struct.pack(">4H", num, srange, select, shift)
76
77
78def num2tag(n):
79    if n < 0x200000:
80        return str(n)
81    else:
82        return (
83            struct.unpack("4s", struct.pack(">L", n))[0].replace(b"\000", b"").decode()
84        )
85
86
87def tag2num(n):
88    try:
89        return int(n)
90    except ValueError:
91        n = (n + "    ")[:4]
92        return struct.unpack(">L", n.encode("ascii"))[0]
93