1 #!/usr/bin/env python 2 # 3 # Copyright (C) 2010 The Android Open Source Project 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 # 17 # Generate ICU dat files for locale relevant resources. 18 # 19 # Usage: 20 # icu_dat_generator.py icu-version [-v] [-h] 21 # 22 # Sample usage: 23 # $ANDROID_BUILD_TOP/external/icu4c/stubdata$ ./icu_dat_generator.py 4.4 --verbose 24 # 25 # Add new dat file: 26 # 1. Add icudtxxl-<datname>.txt to $ANDROID_BUILD_TOP/external/icu4c/stubdata. 27 # Check the exemplar file under 28 # $ANDROID_BUILD_TOP/external/icu4c/stubdata/icudt42l-us.dat. 29 # 2. Add an entry to main() --> datlist[] 30 # 3. Run this script to generate dat files. 31 # 32 # For ICU upgrade 33 # We cannot get CLDR version from dat file unless calling ICU function. 34 # If there is a CLDR version change, please modify "global CLDR_VERSION". 35 36 import getopt 37 import os.path 38 import shutil 39 import subprocess 40 import sys 41 42 # Return 0 if the version_string contains non-digit characters. 43 def GetIcuVersion(version_string): 44 list = version_string.split(".") 45 version = "" 46 for number in list: 47 if (number.isdigit()): 48 version += number 49 else: 50 return -1 51 return version 52 53 54 def PrintHelp(): 55 print "Usage:" 56 print "icu_dat_generator.py icu-version [-v|--verbose] [-h|--help]" 57 print "Example:" 58 print "$ANDROID_BUILD_TOP/external/icu4c/stubdata$ ./icu_dat_generator.py 4.4" 59 60 61 def InvokeIcuTool(tool, working_dir, args): 62 command_list = [os.path.join(GetIcuPrebuiltDir(), tool)] 63 command_list.extend(args) 64 65 if VERBOSE: 66 command = "[%s] %s" % (working_dir, " ".join(command_list)) 67 print command 68 69 ret = subprocess.call(command_list, cwd = working_dir) 70 if ret != 0: 71 sys.exit(command_list[0:]) 72 73 74 def GetIcuPrebuiltDir(): 75 return os.path.join(os.environ.get("ANDROID_EABI_TOOLCHAIN"), "..", "..", 76 "..", "icu-" + ICU_VERSION) 77 78 79 def ExtractAllResourceToTempDir(): 80 # copy icudtxxl-all.dat to icudtxxl.dat 81 source_dat = os.path.join(ANDROID_ROOT, "external", "icu4c", "stubdata", 82 ICUDATA + "-all.dat") 83 dest_dat = os.path.join(ANDROID_ROOT, "external", "icu4c", "stubdata", 84 ICUDATA_DAT) 85 shutil.copyfile(source_dat, dest_dat) 86 InvokeIcuTool("icupkg", None, [dest_dat, "-x", "*", "-d", TMP_DAT_PATH]) 87 88 89 def MakeDat(icu_dat_path, dat_name): 90 # Get the resource list. e.g. icudt42l-us.txt, icudt42l-default.txt. 91 dat_list_file_path = os.path.join(icu_dat_path, ICUDATA + "-" + dat_name + 92 ".txt") 93 if not os.path.isfile(dat_list_file_path): 94 print "%s not present for resource list." % dat_list_file_path 95 return 96 GenResIndex(dat_list_file_path) 97 CopyAndroidCnvFiles(icu_dat_path) 98 os.chdir(TMP_DAT_PATH) 99 # Run command such as "icupkg -tl -s icudt42l -a icudt42l-us.txt 100 # new icudt42l.dat" 101 InvokeIcuTool("icupkg", None, ["-tl", "-s", TMP_DAT_PATH, "-a", dat_list_file_path, "new", 102 ICUDATA_DAT]) 103 104 105 def WriteIndex(path, list, cldr_version = None): 106 res_index = "res_index.txt" 107 empty_value = " {\"\"}\n" # key-value pair for all locale entries 108 109 f = open(path, "w") 110 f.write("res_index:table(nofallback) {\n") 111 if cldr_version: 112 f.write(" CLDRVersion { %s }\n" % cldr_version) 113 f.write(" InstalledLocales {\n") 114 for item in list: 115 f.write(item + empty_value) 116 117 f.write(" }\n") 118 f.write("}\n") 119 f.close() 120 121 122 def ShowMissing(whats, locales, data_dir_name, dat_file): 123 if not len(whats): 124 return 125 dat_file = os.path.basename(dat_file) 126 for missing in locales.difference(whats): 127 p = os.path.join(ANDROID_ROOT, "external", "icu4c", "data", data_dir_name, 128 missing + ".txt") 129 if os.path.exists(p): 130 print "warning: %s exists but isn't included in %s" % (p, dat_file) 131 132 133 # Open dat file such as icudt42l-us.txt. 134 # Go through the list and generate res_index.txt for locales, brkitr, 135 # coll and rbnf. 136 def GenResIndex(dat_list_file_path): 137 res_index = "res_index.txt" 138 139 locales = set() 140 brkitrs = set() 141 colls = set() 142 currs = set() 143 langs = set() 144 regions = set() 145 zones = set() 146 rbnfs = set() 147 148 for line in open(dat_list_file_path, "r"): 149 if line.find("root.") >= 0: 150 continue 151 if line.find("res_index") >= 0: 152 continue 153 if line.find("_.res") >= 0: 154 continue; 155 if line.find("brkitr/") >= 0: 156 end = line.find(".res") 157 if end > 0: 158 brkitrs.add(line[line.find("/")+1:end]) 159 elif line.find("coll/") >= 0: 160 end = line.find(".res") 161 if end > 0: 162 colls.add(line[line.find("/")+1:end]) 163 elif line.find("curr/") >= 0: 164 end = line.find(".res") 165 if end > 0: 166 currs.add(line[line.find("/")+1:end]) 167 elif line.find("lang/") >= 0: 168 end = line.find(".res") 169 if end > 0: 170 langs.add(line[line.find("/")+1:end]) 171 elif line.find("region/") >= 0: 172 end = line.find(".res") 173 if end > 0: 174 regions.add(line[line.find("/")+1:end]) 175 elif line.find("zone/") >= 0: 176 end = line.find(".res") 177 if end > 0: 178 zones.add(line[line.find("/")+1:end]) 179 elif line.find("rbnf/") >= 0: 180 end = line.find(".res") 181 if end > 0: 182 rbnfs.add(line[line.find("/")+1:end]) 183 elif line.find(".res") >= 0: 184 # We need to determine the resource is locale resource or misc resource. 185 # To determine the locale resource, we assume max script length is 3. 186 end = line.find(".res") 187 if end <= 3 or (line.find("_") <= 3 and line.find("_") > 0): 188 locales.add(line[:end]) 189 190 ShowMissing(brkitrs, locales, "brkitr", dat_list_file_path) 191 ShowMissing(colls, locales, "coll", dat_list_file_path) 192 ShowMissing(currs, locales, "curr", dat_list_file_path) 193 ShowMissing(langs, locales, "lang", dat_list_file_path) 194 ShowMissing(regions, locales, "region", dat_list_file_path) 195 ShowMissing(zones, locales, "zone", dat_list_file_path) 196 ShowMissing(rbnfs, locales, "rbnf", dat_list_file_path) 197 198 WriteIndex(os.path.join(TMP_DAT_PATH, res_index), locales, CLDR_VERSION) 199 WriteIndex(os.path.join(TMP_DAT_PATH, "brkitr", res_index), brkitrs) 200 WriteIndex(os.path.join(TMP_DAT_PATH, "coll", res_index), colls) 201 WriteIndex(os.path.join(TMP_DAT_PATH, "curr", res_index), currs) 202 WriteIndex(os.path.join(TMP_DAT_PATH, "lang", res_index), langs) 203 WriteIndex(os.path.join(TMP_DAT_PATH, "region", res_index), regions) 204 WriteIndex(os.path.join(TMP_DAT_PATH, "zone", res_index), zones) 205 WriteIndex(os.path.join(TMP_DAT_PATH, "rbnf", res_index), rbnfs) 206 207 # Call genrb to generate new res_index.res. 208 InvokeIcuTool("genrb", TMP_DAT_PATH, [res_index]) 209 InvokeIcuTool("genrb", os.path.join(TMP_DAT_PATH, "brkitr"), [res_index]) 210 InvokeIcuTool("genrb", os.path.join(TMP_DAT_PATH, "coll"), [res_index]) 211 InvokeIcuTool("genrb", os.path.join(TMP_DAT_PATH, "curr"), [res_index]) 212 InvokeIcuTool("genrb", os.path.join(TMP_DAT_PATH, "lang"), [res_index]) 213 InvokeIcuTool("genrb", os.path.join(TMP_DAT_PATH, "region"), [res_index]) 214 InvokeIcuTool("genrb", os.path.join(TMP_DAT_PATH, "zone"), [res_index]) 215 if len(rbnfs): 216 InvokeIcuTool("genrb", os.path.join(TMP_DAT_PATH, "rbnf"), [res_index]) 217 218 219 def CopyAndroidCnvFiles(icu_dat_path): 220 android_specific_cnv = ["gsm-03.38-2000.cnv", 221 "iso-8859_16-2001.cnv", 222 "docomo-shift_jis-2007.cnv", 223 "kddi-jisx-208-2007.cnv", 224 "kddi-shift_jis-2007.cnv", 225 "softbank-jisx-208-2007.cnv", 226 "softbank-shift_jis-2007.cnv"] 227 for cnv_file in android_specific_cnv: 228 source_path = os.path.join(icu_dat_path, "cnv", cnv_file) 229 dest_path = os.path.join(TMP_DAT_PATH, cnv_file) 230 shutil.copyfile(source_path, dest_path) 231 if VERBOSE: 232 print "copy " + source_path + " " + dest_path 233 234 235 def main(): 236 global ANDROID_ROOT # Android project home directory 237 global ICU_VERSION # ICU version number 238 global ICUDATA # e.g. "icudt42l" 239 global ICUDATA_DAT # e.g. "icudt42l.dat" 240 global CLDR_VERSION # CLDR version. The value can be vary upon ICU release. 241 global TMP_DAT_PATH # temp directory to store all resource files and 242 # intermediate dat files. 243 global HELP 244 global VERBOSE 245 246 argc = len(sys.argv) 247 if argc < 2: 248 print "You must provide icu version number." 249 print "Example: ./icu_dat_generator.py 4.4" 250 sys.exit(1) 251 ICU_VERSION = sys.argv[1] 252 version = GetIcuVersion(ICU_VERSION) 253 if (version == -1): 254 print sys.argv[1] + " is not a valid icu version number!" 255 sys.exit(1) 256 ICUDATA = "icudt" + version + "l" 257 CLDR_VERSION = "1.8" 258 ANDROID_ROOT = os.environ.get("ANDROID_BUILD_TOP") 259 if not ANDROID_ROOT: 260 print "$ANDROID_BUILD_TOP not set! Run 'env_setup.sh'." 261 sys.exit(1) 262 ICUDATA_DAT = ICUDATA + ".dat" 263 HELP = False 264 VERBOSE = False 265 266 try: 267 opts, args = getopt.getopt(sys.argv[2:], 'hv', ['help', 'verbose']) 268 except getopt.error: 269 print "Invalid option" 270 PrintHelp() 271 sys.exit(1) 272 for opt, arg in opts: 273 if opt in ('-h', '--help'): 274 PrintHelp() 275 sys.exit(1) 276 elif opt in ('-v', '--verbose'): 277 VERBOSE = True 278 279 280 # Check for requiered source files. 281 icu_dat_path = os.path.join(ANDROID_ROOT, "external", "icu4c", "stubdata") 282 full_data_filename = os.path.join(icu_dat_path, ICUDATA + "-all.dat") 283 if not os.path.isfile(full_data_filename): 284 print "%s not present." % full_data_filename 285 sys.exit(1) 286 287 # Create a temporary working directory. 288 TMP_DAT_PATH = os.path.join(ANDROID_ROOT, "external", "icu4c", "tmp") 289 if os.path.exists(TMP_DAT_PATH): 290 shutil.rmtree(TMP_DAT_PATH) 291 os.mkdir(TMP_DAT_PATH) 292 293 # Extract resource files from icudtxxl-all.dat to TMP_DAT_PATH. 294 ExtractAllResourceToTempDir() 295 296 datlist = ["us", "us-euro", "default", "us-japan", "zh", "medium", "large"] 297 for dat_subtag in datlist: 298 MakeDat(icu_dat_path, dat_subtag) 299 # Copy icudtxxl.dat to stubdata directory with corresponding subtag. 300 shutil.copyfile(os.path.join(TMP_DAT_PATH, ICUDATA_DAT), 301 os.path.join(icu_dat_path, ICUDATA + "-" + dat_subtag + ".dat")) 302 print "Generate ICU data:" + os.path.join(icu_dat_path, ICUDATA + "-" + dat_subtag + ".dat") 303 304 # Cleanup temporary working directory and icudtxxl.dat 305 shutil.rmtree(TMP_DAT_PATH) 306 os.remove(os.path.join(icu_dat_path, ICUDATA_DAT)) 307 308 if __name__ == "__main__": 309 main() 310