#!/usr/bin/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 [-v] [-h]
#
# Sample usage:
# $ANDROID_BUILD_TOP/external/icu4c/stubdata$ ./icu_dat_generator.py --verbose
#
# Add new dat file:
# 1. Add icudtxxl-<datname>.txt to $ANDROID_BUILD_TOP/external/icu4c/stubdata.
# Check the example file under
# $ANDROID_BUILD_TOP/external/icu4c/stubdata/icudt48l-us.txt
# 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 glob
import os.path
import re
import shutil
import subprocess
import sys
def PrintHelpAndExit():
print "Usage:"
print " icu_dat_generator.py [-v|--verbose] [-h|--help]"
print "Example:"
print " $ANDROID_BUILD_TOP/external/icu4c/stubdata$ ./icu_dat_generator.py"
sys.exit(1)
def InvokeIcuTool(tool, working_dir, args):
command_list = [os.path.join(ICU_PREBUILT_DIR, 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 ExtractAllResourceToTempDir():
# copy icudtxxl-all.dat to icudtxxl.dat
src_dat = os.path.join(ICU4C_DIR, "stubdata", ICUDATA + "-all.dat")
dst_dat = os.path.join(ICU4C_DIR, "stubdata", ICUDATA + ".dat")
shutil.copyfile(src_dat, dst_dat)
InvokeIcuTool("icupkg", None, [dst_dat, "-x", "*", "-d", TMP_DAT_PATH])
def MakeDat(input_file, stubdata_dir):
print "------ Processing '%s'..." % (input_file)
if not os.path.isfile(input_file):
print "%s not a file!" % input_file
sys.exit(1)
GenResIndex(input_file)
CopyAndroidCnvFiles(stubdata_dir)
# Run "icupkg -tl -s icudt48l -a icudt48l-us.txt new icudt48l.dat".
args = ["-tl", "-s", TMP_DAT_PATH, "-a", input_file, "new", ICUDATA + ".dat"]
InvokeIcuTool("icupkg", TMP_DAT_PATH, args)
def WriteIndex(path, locales, cldr_version=None):
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 locale in locales:
f.write(locale + empty_value)
f.write(" }\n")
f.write("}\n")
f.close()
def AddResFile(collection, path):
# There are two consumers of the the input .txt file: this script and
# icupkg. We only care about .res files, but icupkg needs files they depend
# on too, so it's not an error to have to ignore non-.res files here.
end = path.find(".res")
if end > 0:
collection.add(path[path.find("/")+1:end])
return
# Open input file (such as icudt48l-us.txt).
# Go through the list and generate res_index.txt for locales, brkitr,
# coll, et cetera.
def GenResIndex(input_file):
res_index = "res_index.txt"
brkitrs = set()
colls = set()
currs = set()
langs = set()
locales = set()
regions = set()
zones = set()
for line in open(input_file, "r"):
if "root." in line or "res_index" in line or "_.res" in line:
continue
if "brkitr/" in line:
AddResFile(brkitrs, line)
elif "coll/" in line:
AddResFile(colls, line)
elif "curr/" in line:
AddResFile(currs, line)
elif "lang/" in line:
AddResFile(langs, line)
elif "region/" in line:
AddResFile(regions, line)
elif "zone/" in line:
AddResFile(zones, line)
elif ".res" in line:
# 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])
kind_to_locales = {
"brkitr": brkitrs,
"coll": colls,
"curr": currs,
"lang": langs,
"locales": locales,
"region": regions,
"zone": zones
}
# Find every locale we've mentioned, for whatever reason.
every_locale = set()
for locales in kind_to_locales.itervalues():
every_locale = every_locale.union(locales)
if VERBOSE:
for kind, locales in kind_to_locales.items():
print "%s=%s" % (kind, sorted(locales))
# Print a human-readable list of the languages supported.
every_language = set()
for locale in every_locale:
language = re.sub(r"(_.*)", "", locale)
if language != "pool" and language != "supplementalData":
every_language.add(language)
input_basename = os.path.basename(input_file)
print "%s includes %s." % (input_basename, ", ".join(sorted(every_language)))
# Find cases where we've included only part of a locale's data.
missing_files = []
for locale in every_locale:
for kind, locales in kind_to_locales.items():
p = os.path.join(ICU4C_DIR, "data", kind, locale + ".txt")
if not locale in locales and os.path.exists(p):
missing_files.append(p)
# Warn about the missing files.
for missing_file in sorted(missing_files):
relative_path = "/".join(missing_file.split("/")[-2:])
print "warning: missing data for supported locale: %s" % relative_path
# Write the genrb input files.
WriteIndex(os.path.join(TMP_DAT_PATH, res_index), locales, CLDR_VERSION)
for kind, locales in kind_to_locales.items():
if kind == "locales":
continue
WriteIndex(os.path.join(TMP_DAT_PATH, kind, res_index), locales)
# Call genrb to generate new res_index.res.
InvokeIcuTool("genrb", TMP_DAT_PATH, [res_index])
for kind, locales in kind_to_locales.items():
if kind == "locales":
continue
InvokeIcuTool("genrb", os.path.join(TMP_DAT_PATH, kind), [res_index])
def CopyAndroidCnvFiles(stubdata_dir):
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:
src_path = os.path.join(stubdata_dir, "cnv", cnv_file)
dst_path = os.path.join(TMP_DAT_PATH, cnv_file)
shutil.copyfile(src_path, dst_path)
if VERBOSE:
print "copy " + src_path + " " + dst_path
def main():
global ANDROID_BUILD_TOP # $ANDROID_BUILD_TOP
global ICU4C_DIR # $ANDROID_BUILD_TOP/external/icu4c
global ICU_PREBUILT_DIR # Directory containing pre-built ICU tools.
global ICUDATA # e.g. "icudt48l"
global CLDR_VERSION # CLDR version. The value varies between ICU releases.
global TMP_DAT_PATH # temp directory to store all resource files and
# intermediate dat files.
global VERBOSE
CLDR_VERSION = "2.0.1"
VERBOSE = False
show_help = False
try:
opts, args = getopt.getopt(sys.argv[1:], "hv", ["help", "verbose"])
except getopt.error:
PrintHelpAndExit()
for opt, _ in opts:
if opt in ("-h", "--help"):
show_help = True
elif opt in ("-v", "--verbose"):
VERBOSE = True
if args:
show_help = True
if show_help:
PrintHelpAndExit()
ANDROID_BUILD_TOP = os.environ.get("ANDROID_BUILD_TOP")
if not ANDROID_BUILD_TOP:
print "$ANDROID_BUILD_TOP not set! Run 'env_setup.sh'."
sys.exit(1)
ICU4C_DIR = os.path.join(ANDROID_BUILD_TOP, "external", "icu4c")
stubdata_dir = os.path.join(ICU4C_DIR, "stubdata")
# Find all the input files.
input_files = glob.glob(os.path.join(stubdata_dir, "icudt[0-9][0-9]l-*.txt"))
# Work out the ICU version from the input filenames, so we can find the
# appropriate pre-built ICU tools.
icu_version = re.sub(r"([^0-9])", "", os.path.basename(input_files[0]))
ICU_PREBUILT_DIR = os.path.join(os.environ.get("ANDROID_BUILD_TOP"),
"prebuilt", "linux-x86_64", "icu-%s.%s" % (icu_version[0], icu_version[1]))
if not os.path.exists(ICU_PREBUILT_DIR):
print "%s does not exist!" % ICU_PREBUILT_DIR
ICUDATA = "icudt" + icu_version + "l"
# Check that -all.dat exists (since we build the other .dat files from that).
full_data_filename = os.path.join(stubdata_dir, 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(ICU4C_DIR, "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()
# Process each input file in turn.
for input_file in sorted(input_files):
output_file = input_file[:-3] + "dat"
MakeDat(input_file, stubdata_dir)
shutil.copyfile(os.path.join(TMP_DAT_PATH, ICUDATA + ".dat"), output_file)
print "Generated ICU data: %s" % output_file
# Cleanup temporary working directory and icudtxxl.dat
shutil.rmtree(TMP_DAT_PATH)
os.remove(os.path.join(stubdata_dir, ICUDATA + ".dat"))
if __name__ == "__main__":
main()