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