#!/usr/bin/env python
#
# Copyright (C) 2010 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Generate ICU dat files for locale relevant resources.
#
# Usage:
# icu_dat_generator.py icu-version [-v] [-h]
#
# Sample usage:
# $ANDROID_BUILD_TOP/external/icu4c/stubdata$ ./icu_dat_generator.py 4.4 --verbose
#
# Add new dat file:
# 1. Add icudtxxl-<datname>.txt to $ANDROID_BUILD_TOP/external/icu4c/stubdata.
# Check the exemplar file under
# $ANDROID_BUILD_TOP/external/icu4c/stubdata/icudt42l-us.dat.
# 2. Add an entry to main() --> datlist[]
# 3. Run this script to generate dat files.
#
# For ICU upgrade
# We cannot get CLDR version from dat file unless calling ICU function.
# If there is a CLDR version change, please modify "global CLDR_VERSION".
import getopt
import os.path
import shutil
import subprocess
import sys
# Return 0 if the version_string contains non-digit characters.
def GetIcuVersion(version_string):
list = version_string.split(".")
version = ""
for number in list:
if (number.isdigit()):
version += number
else:
return -1
return version
def PrintHelp():
print "Usage:"
print "icu_dat_generator.py icu-version [-v|--verbose] [-h|--help]"
print "Example:"
print "$ANDROID_BUILD_TOP/external/icu4c/stubdata$ ./icu_dat_generator.py 4.4"
def InvokeIcuTool(tool, working_dir, args):
command_list = [os.path.join(GetIcuPrebuiltDir(), tool)]
command_list.extend(args)
if VERBOSE:
command = "[%s] %s" % (working_dir, " ".join(command_list))
print command
ret = subprocess.call(command_list, cwd = working_dir)
if ret != 0:
sys.exit(command_list[0:])
def GetIcuPrebuiltDir():
return os.path.join(os.environ.get("ANDROID_EABI_TOOLCHAIN"), "..", "..",
"..", "icu-" + ICU_VERSION)
def ExtractAllResourceToTempDir():
# copy icudtxxl-all.dat to icudtxxl.dat
source_dat = os.path.join(ANDROID_ROOT, "external", "icu4c", "stubdata",
ICUDATA + "-all.dat")
dest_dat = os.path.join(ANDROID_ROOT, "external", "icu4c", "stubdata",
ICUDATA_DAT)
shutil.copyfile(source_dat, dest_dat)
InvokeIcuTool("icupkg", None, [dest_dat, "-x", "*", "-d", TMP_DAT_PATH])
def MakeDat(icu_dat_path, dat_name):
# Get the resource list. e.g. icudt42l-us.txt, icudt42l-default.txt.
dat_list_file_path = os.path.join(icu_dat_path, ICUDATA + "-" + dat_name +
".txt")
if not os.path.isfile(dat_list_file_path):
print "%s not present for resource list." % dat_list_file_path
return
GenResIndex(dat_list_file_path)
CopyAndroidCnvFiles(icu_dat_path)
os.chdir(TMP_DAT_PATH)
# Run command such as "icupkg -tl -s icudt42l -a icudt42l-us.txt
# new icudt42l.dat"
InvokeIcuTool("icupkg", None, ["-tl", "-s", TMP_DAT_PATH, "-a", dat_list_file_path, "new",
ICUDATA_DAT])
def WriteIndex(path, list, cldr_version = None):
res_index = "res_index.txt"
empty_value = " {\"\"}\n" # key-value pair for all locale entries
f = open(path, "w")
f.write("res_index:table(nofallback) {\n")
if cldr_version:
f.write(" CLDRVersion { %s }\n" % cldr_version)
f.write(" InstalledLocales {\n")
for item in list:
f.write(item + empty_value)
f.write(" }\n")
f.write("}\n")
f.close()
def ShowMissing(whats, locales, data_dir_name, dat_file):
if not len(whats):
return
dat_file = os.path.basename(dat_file)
for missing in locales.difference(whats):
p = os.path.join(ANDROID_ROOT, "external", "icu4c", "data", data_dir_name,
missing + ".txt")
if os.path.exists(p):
print "warning: %s exists but isn't included in %s" % (p, dat_file)
# Open dat file such as icudt42l-us.txt.
# Go through the list and generate res_index.txt for locales, brkitr,
# coll and rbnf.
def GenResIndex(dat_list_file_path):
res_index = "res_index.txt"
locales = set()
brkitrs = set()
colls = set()
currs = set()
langs = set()
regions = set()
zones = set()
rbnfs = set()
for line in open(dat_list_file_path, "r"):
if line.find("root.") >= 0:
continue
if line.find("res_index") >= 0:
continue
if line.find("_.res") >= 0:
continue;
if line.find("brkitr/") >= 0:
end = line.find(".res")
if end > 0:
brkitrs.add(line[line.find("/")+1:end])
elif line.find("coll/") >= 0:
end = line.find(".res")
if end > 0:
colls.add(line[line.find("/")+1:end])
elif line.find("curr/") >= 0:
end = line.find(".res")
if end > 0:
currs.add(line[line.find("/")+1:end])
elif line.find("lang/") >= 0:
end = line.find(".res")
if end > 0:
langs.add(line[line.find("/")+1:end])
elif line.find("region/") >= 0:
end = line.find(".res")
if end > 0:
regions.add(line[line.find("/")+1:end])
elif line.find("zone/") >= 0:
end = line.find(".res")
if end > 0:
zones.add(line[line.find("/")+1:end])
elif line.find("rbnf/") >= 0:
end = line.find(".res")
if end > 0:
rbnfs.add(line[line.find("/")+1:end])
elif line.find(".res") >= 0:
# We need to determine the resource is locale resource or misc resource.
# To determine the locale resource, we assume max script length is 3.
end = line.find(".res")
if end <= 3 or (line.find("_") <= 3 and line.find("_") > 0):
locales.add(line[:end])
ShowMissing(brkitrs, locales, "brkitr", dat_list_file_path)
ShowMissing(colls, locales, "coll", dat_list_file_path)
ShowMissing(currs, locales, "curr", dat_list_file_path)
ShowMissing(langs, locales, "lang", dat_list_file_path)
ShowMissing(regions, locales, "region", dat_list_file_path)
ShowMissing(zones, locales, "zone", dat_list_file_path)
ShowMissing(rbnfs, locales, "rbnf", dat_list_file_path)
WriteIndex(os.path.join(TMP_DAT_PATH, res_index), locales, CLDR_VERSION)
WriteIndex(os.path.join(TMP_DAT_PATH, "brkitr", res_index), brkitrs)
WriteIndex(os.path.join(TMP_DAT_PATH, "coll", res_index), colls)
WriteIndex(os.path.join(TMP_DAT_PATH, "curr", res_index), currs)
WriteIndex(os.path.join(TMP_DAT_PATH, "lang", res_index), langs)
WriteIndex(os.path.join(TMP_DAT_PATH, "region", res_index), regions)
WriteIndex(os.path.join(TMP_DAT_PATH, "zone", res_index), zones)
WriteIndex(os.path.join(TMP_DAT_PATH, "rbnf", res_index), rbnfs)
# Call genrb to generate new res_index.res.
InvokeIcuTool("genrb", TMP_DAT_PATH, [res_index])
InvokeIcuTool("genrb", os.path.join(TMP_DAT_PATH, "brkitr"), [res_index])
InvokeIcuTool("genrb", os.path.join(TMP_DAT_PATH, "coll"), [res_index])
InvokeIcuTool("genrb", os.path.join(TMP_DAT_PATH, "curr"), [res_index])
InvokeIcuTool("genrb", os.path.join(TMP_DAT_PATH, "lang"), [res_index])
InvokeIcuTool("genrb", os.path.join(TMP_DAT_PATH, "region"), [res_index])
InvokeIcuTool("genrb", os.path.join(TMP_DAT_PATH, "zone"), [res_index])
if len(rbnfs):
InvokeIcuTool("genrb", os.path.join(TMP_DAT_PATH, "rbnf"), [res_index])
def CopyAndroidCnvFiles(icu_dat_path):
android_specific_cnv = ["gsm-03.38-2000.cnv",
"iso-8859_16-2001.cnv",
"docomo-shift_jis-2007.cnv",
"kddi-jisx-208-2007.cnv",
"kddi-shift_jis-2007.cnv",
"softbank-jisx-208-2007.cnv",
"softbank-shift_jis-2007.cnv"]
for cnv_file in android_specific_cnv:
source_path = os.path.join(icu_dat_path, "cnv", cnv_file)
dest_path = os.path.join(TMP_DAT_PATH, cnv_file)
shutil.copyfile(source_path, dest_path)
if VERBOSE:
print "copy " + source_path + " " + dest_path
def main():
global ANDROID_ROOT # Android project home directory
global ICU_VERSION # ICU version number
global ICUDATA # e.g. "icudt42l"
global ICUDATA_DAT # e.g. "icudt42l.dat"
global CLDR_VERSION # CLDR version. The value can be vary upon ICU release.
global TMP_DAT_PATH # temp directory to store all resource files and
# intermediate dat files.
global HELP
global VERBOSE
argc = len(sys.argv)
if argc < 2:
print "You must provide icu version number."
print "Example: ./icu_dat_generator.py 4.4"
sys.exit(1)
ICU_VERSION = sys.argv[1]
version = GetIcuVersion(ICU_VERSION)
if (version == -1):
print sys.argv[1] + " is not a valid icu version number!"
sys.exit(1)
ICUDATA = "icudt" + version + "l"
CLDR_VERSION = "1.8"
ANDROID_ROOT = os.environ.get("ANDROID_BUILD_TOP")
if not ANDROID_ROOT:
print "$ANDROID_BUILD_TOP not set! Run 'env_setup.sh'."
sys.exit(1)
ICUDATA_DAT = ICUDATA + ".dat"
HELP = False
VERBOSE = False
try:
opts, args = getopt.getopt(sys.argv[2:], 'hv', ['help', 'verbose'])
except getopt.error:
print "Invalid option"
PrintHelp()
sys.exit(1)
for opt, arg in opts:
if opt in ('-h', '--help'):
PrintHelp()
sys.exit(1)
elif opt in ('-v', '--verbose'):
VERBOSE = True
# Check for requiered source files.
icu_dat_path = os.path.join(ANDROID_ROOT, "external", "icu4c", "stubdata")
full_data_filename = os.path.join(icu_dat_path, ICUDATA + "-all.dat")
if not os.path.isfile(full_data_filename):
print "%s not present." % full_data_filename
sys.exit(1)
# Create a temporary working directory.
TMP_DAT_PATH = os.path.join(ANDROID_ROOT, "external", "icu4c", "tmp")
if os.path.exists(TMP_DAT_PATH):
shutil.rmtree(TMP_DAT_PATH)
os.mkdir(TMP_DAT_PATH)
# Extract resource files from icudtxxl-all.dat to TMP_DAT_PATH.
ExtractAllResourceToTempDir()
datlist = ["us", "us-euro", "default", "us-japan", "zh", "medium", "large"]
for dat_subtag in datlist:
MakeDat(icu_dat_path, dat_subtag)
# Copy icudtxxl.dat to stubdata directory with corresponding subtag.
shutil.copyfile(os.path.join(TMP_DAT_PATH, ICUDATA_DAT),
os.path.join(icu_dat_path, ICUDATA + "-" + dat_subtag + ".dat"))
print "Generate ICU data:" + os.path.join(icu_dat_path, ICUDATA + "-" + dat_subtag + ".dat")
# Cleanup temporary working directory and icudtxxl.dat
shutil.rmtree(TMP_DAT_PATH)
os.remove(os.path.join(icu_dat_path, ICUDATA_DAT))
if __name__ == "__main__":
main()