Harry Terkelsen | 1fa4e39 | 2022-02-23 15:03:09 -0800 | [diff] [blame^] | 1 | #!/usr/bin/env python |
| 2 | |
| 3 | # Copyright 2022 Google LLC. |
| 4 | # Use of this source code is governed by a BSD-style license that can be |
| 5 | # found in the LICENSE file. |
| 6 | |
| 7 | ''' |
| 8 | Generate a source file containing the given binary data. |
| 9 | |
| 10 | Output type is C++. |
| 11 | |
| 12 | This is required for a WASM build because the Emscripten toolchain cannot |
| 13 | load data files using file I/O, nor can it consume assembly files. |
| 14 | |
| 15 | This is in use by the Flutter web engine and Skia CanvasKit. See |
| 16 | [this](https://github.com/google/skia/blob/main/modules/canvaskit/README.md) |
| 17 | for an example of a build using this. |
| 18 | ''' |
| 19 | |
| 20 | from __future__ import print_function |
| 21 | |
| 22 | import os |
| 23 | import struct |
| 24 | import sys |
| 25 | import mmap |
| 26 | |
| 27 | def get_version_number(path): |
| 28 | input_data = open(path, 'rb').read() |
| 29 | n = input_data.find(b'icudt') |
| 30 | if n == -1: |
| 31 | exit("Cannot find a version number in %s." % path) |
| 32 | |
| 33 | return input_data[n + 5:n + 7].decode("ascii") |
| 34 | |
| 35 | def iterate_as_uint32(path): |
| 36 | with open(path, 'rb') as f: |
| 37 | s = struct.Struct('@I') |
| 38 | assert s.size == 4 |
| 39 | mm = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) |
| 40 | assert (len(mm) % s.size) == 0 |
| 41 | for offset in range(0, len(mm), s.size): |
| 42 | yield s.unpack_from(mm, offset)[0] |
| 43 | mm.close() |
| 44 | |
| 45 | |
| 46 | def convert(fmt, src_path, dst_path): |
| 47 | header, line_begin, line_end, footer = fmt |
| 48 | assert os.path.exists(src_path) |
| 49 | version_number = get_version_number(src_path) |
| 50 | name = 'icudt%s_dat' % version_number |
| 51 | src = iterate_as_uint32(src_path) |
| 52 | with open(dst_path, 'w') as o: |
| 53 | o.write(header.format(name)) |
| 54 | while True: |
| 55 | line = ','.join('%d' % v for _, v in zip(range(8), src)) |
| 56 | if not line: |
| 57 | break |
| 58 | o.write('%s%s%s\n' % (line_begin, line, line_end)) |
| 59 | o.write(footer.format(name)) |
| 60 | |
| 61 | |
| 62 | cpp = ('#include <cstdint>\nextern "C" uint32_t {0}[] __attribute__((aligned(16))) = {{\n', |
| 63 | '', ',', '}};\n') |
| 64 | |
| 65 | if __name__ == '__main__': |
| 66 | convert(cpp, sys.argv[1], sys.argv[2]) |