xref: /aosp_15_r20/external/cronet/third_party/icu/scripts/icualign.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/python3
2*6777b538SAndroid Build Coastguard Worker
3*6777b538SAndroid Build Coastguard Worker# Copyright 2022 The Chromium Authors. All rights reserved.
4*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
5*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file.
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Workerimport itertools
8*6777b538SAndroid Build Coastguard Workerimport struct
9*6777b538SAndroid Build Coastguard Workerimport sys
10*6777b538SAndroid Build Coastguard Worker
11*6777b538SAndroid Build Coastguard WorkerPAGE_SIZE = 0x1000  # System page size.
12*6777b538SAndroid Build Coastguard WorkerTHRESHOLD = 0x2000  # Minimum size of the file to be aligned.
13*6777b538SAndroid Build Coastguard Worker
14*6777b538SAndroid Build Coastguard Worker
15*6777b538SAndroid Build Coastguard Worker# Read 2 bytes.
16*6777b538SAndroid Build Coastguard Workerdef read16(data, offset):
17*6777b538SAndroid Build Coastguard Worker    return struct.unpack_from("<H", data, offset)[0]
18*6777b538SAndroid Build Coastguard Worker
19*6777b538SAndroid Build Coastguard Worker
20*6777b538SAndroid Build Coastguard Worker# Read 4 bytes.
21*6777b538SAndroid Build Coastguard Workerdef read32(data, offset):
22*6777b538SAndroid Build Coastguard Worker    return struct.unpack_from("<I", data, offset)[0]
23*6777b538SAndroid Build Coastguard Worker
24*6777b538SAndroid Build Coastguard Worker
25*6777b538SAndroid Build Coastguard Worker# Write 4 bytes.
26*6777b538SAndroid Build Coastguard Workerdef write32(data, offset, value):
27*6777b538SAndroid Build Coastguard Worker    return struct.pack_into("<I", data, offset, value)
28*6777b538SAndroid Build Coastguard Worker
29*6777b538SAndroid Build Coastguard Worker
30*6777b538SAndroid Build Coastguard Worker################################################################################
31*6777b538SAndroid Build Coastguard Worker# (Adapted from `source/tools/toolutil/pkg_gencmn.cpp`)
32*6777b538SAndroid Build Coastguard Worker#
33*6777b538SAndroid Build Coastguard Worker# A .dat package file contains a simple Table of Contents of item names,
34*6777b538SAndroid Build Coastguard Worker# followed by the items themselves:
35*6777b538SAndroid Build Coastguard Worker#
36*6777b538SAndroid Build Coastguard Worker# 1. ToC table
37*6777b538SAndroid Build Coastguard Worker#
38*6777b538SAndroid Build Coastguard Worker# uint32_t count; - number of items
39*6777b538SAndroid Build Coastguard Worker# UDataOffsetTOCEntry entry[count]; - pair of uint32_t values per item:
40*6777b538SAndroid Build Coastguard Worker#     uint32_t nameOffset; - offset of the item name
41*6777b538SAndroid Build Coastguard Worker#     uint32_t dataOffset; - offset of the item data
42*6777b538SAndroid Build Coastguard Worker# both are byte offsets from the beginning of the data
43*6777b538SAndroid Build Coastguard Worker#
44*6777b538SAndroid Build Coastguard Worker# 2. item name strings
45*6777b538SAndroid Build Coastguard Worker#
46*6777b538SAndroid Build Coastguard Worker# All item names are stored as char * strings in one block between the ToC table
47*6777b538SAndroid Build Coastguard Worker# and the data items.
48*6777b538SAndroid Build Coastguard Worker#
49*6777b538SAndroid Build Coastguard Worker# 3. data items
50*6777b538SAndroid Build Coastguard Worker#
51*6777b538SAndroid Build Coastguard Worker# The data items are stored following the item names block.
52*6777b538SAndroid Build Coastguard Worker# The data items are stored in the sorted order of their names.
53*6777b538SAndroid Build Coastguard Worker################################################################################
54*6777b538SAndroid Build Coastguard Worker
55*6777b538SAndroid Build Coastguard Worker
56*6777b538SAndroid Build Coastguard Workerdef pad_data(data):
57*6777b538SAndroid Build Coastguard Worker    out = bytearray()
58*6777b538SAndroid Build Coastguard Worker
59*6777b538SAndroid Build Coastguard Worker    header_size = read16(data, 0)           # Size of the ICU header.
60*6777b538SAndroid Build Coastguard Worker    item_count = read32(data, header_size)  # Number of files inside icudtl.dat
61*6777b538SAndroid Build Coastguard Worker    toc_offset = header_size + 4            # Offset of the Table of Contents.
62*6777b538SAndroid Build Coastguard Worker
63*6777b538SAndroid Build Coastguard Worker    # Copy everything until the beginning of the data.
64*6777b538SAndroid Build Coastguard Worker    out_offset = read32(data, toc_offset + 4) + header_size
65*6777b538SAndroid Build Coastguard Worker    out += data[:out_offset]
66*6777b538SAndroid Build Coastguard Worker
67*6777b538SAndroid Build Coastguard Worker    # Iterate over the files.
68*6777b538SAndroid Build Coastguard Worker    for i in range(item_count):
69*6777b538SAndroid Build Coastguard Worker        # Offset inside the ToC for this file.
70*6777b538SAndroid Build Coastguard Worker        offset = toc_offset + (i * 8)
71*6777b538SAndroid Build Coastguard Worker
72*6777b538SAndroid Build Coastguard Worker        # Offset of the name and data, relative to the beginning of the data section.
73*6777b538SAndroid Build Coastguard Worker        name_offset = read32(data, offset)
74*6777b538SAndroid Build Coastguard Worker        data_offset = read32(data, offset + 4)
75*6777b538SAndroid Build Coastguard Worker
76*6777b538SAndroid Build Coastguard Worker        # Offset of the name and the data, relative to the beginning of the file.
77*6777b538SAndroid Build Coastguard Worker        name_file_offset = name_offset + header_size
78*6777b538SAndroid Build Coastguard Worker        data_file_offset = data_offset + header_size
79*6777b538SAndroid Build Coastguard Worker
80*6777b538SAndroid Build Coastguard Worker        # Calculate the size of this file.
81*6777b538SAndroid Build Coastguard Worker        if i + 1 < item_count:
82*6777b538SAndroid Build Coastguard Worker            next_offset = toc_offset + ((i + 1) * 8)
83*6777b538SAndroid Build Coastguard Worker            next_data_offset = read32(data, next_offset + 4)
84*6777b538SAndroid Build Coastguard Worker            size = next_data_offset - data_offset
85*6777b538SAndroid Build Coastguard Worker        else:
86*6777b538SAndroid Build Coastguard Worker            size = len(data) - (data_offset + header_size)
87*6777b538SAndroid Build Coastguard Worker
88*6777b538SAndroid Build Coastguard Worker        # Insert padding to align files bigger than the threshold.
89*6777b538SAndroid Build Coastguard Worker        page_offset = out_offset & (PAGE_SIZE - 1)
90*6777b538SAndroid Build Coastguard Worker        if size >= THRESHOLD and page_offset != 0:
91*6777b538SAndroid Build Coastguard Worker            padding = PAGE_SIZE - page_offset
92*6777b538SAndroid Build Coastguard Worker            out.extend(itertools.repeat(0x00, padding))
93*6777b538SAndroid Build Coastguard Worker            out_offset += padding
94*6777b538SAndroid Build Coastguard Worker
95*6777b538SAndroid Build Coastguard Worker        # Put the new offset into the Table of Contents.
96*6777b538SAndroid Build Coastguard Worker        write32(out, offset + 4, out_offset - header_size)
97*6777b538SAndroid Build Coastguard Worker
98*6777b538SAndroid Build Coastguard Worker        # Copy the content of the file.
99*6777b538SAndroid Build Coastguard Worker        out += data[data_file_offset : data_file_offset + size]
100*6777b538SAndroid Build Coastguard Worker        out_offset += size
101*6777b538SAndroid Build Coastguard Worker
102*6777b538SAndroid Build Coastguard Worker    return out
103*6777b538SAndroid Build Coastguard Worker
104*6777b538SAndroid Build Coastguard Worker
105*6777b538SAndroid Build Coastguard Workerif __name__ == "__main__":
106*6777b538SAndroid Build Coastguard Worker    # Check arguments.
107*6777b538SAndroid Build Coastguard Worker    if len(sys.argv) != 3:
108*6777b538SAndroid Build Coastguard Worker        error_str = "icualign: wrong number of arguments\n\n"
109*6777b538SAndroid Build Coastguard Worker        help_str = "usage: icualign <infilename> <outfilename>\n\n"
110*6777b538SAndroid Build Coastguard Worker        sys.exit(error_str + help_str)
111*6777b538SAndroid Build Coastguard Worker
112*6777b538SAndroid Build Coastguard Worker    # Extract arguments.
113*6777b538SAndroid Build Coastguard Worker    in_filename = sys.argv[1]
114*6777b538SAndroid Build Coastguard Worker    out_filename = sys.argv[2]
115*6777b538SAndroid Build Coastguard Worker
116*6777b538SAndroid Build Coastguard Worker    # Read the input file.
117*6777b538SAndroid Build Coastguard Worker    with open(in_filename, "rb") as in_file:
118*6777b538SAndroid Build Coastguard Worker        data = in_file.read()
119*6777b538SAndroid Build Coastguard Worker        # Apply padding to the file to achieve the desired alignment.
120*6777b538SAndroid Build Coastguard Worker        out_data = pad_data(data)
121*6777b538SAndroid Build Coastguard Worker        # Write the output file.
122*6777b538SAndroid Build Coastguard Worker        with open(out_filename, "wb") as out_file:
123*6777b538SAndroid Build Coastguard Worker            out_file.write(out_data)
124