diff options
Diffstat (limited to 'src/plugins/cerence/unpack.py')
-rw-r--r-- | src/plugins/cerence/unpack.py | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/src/plugins/cerence/unpack.py b/src/plugins/cerence/unpack.py new file mode 100644 index 00000000..825d333e --- /dev/null +++ b/src/plugins/cerence/unpack.py @@ -0,0 +1,386 @@ +#!/usr/bin/env python +# Copyright (C) 2021 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import zipfile +import tempfile +import shutil +import fnmatch + +# +# This utility script unpacks the Cerence SDK to appropriate directory +# structure for Qt Virtual Keyboard. +# +# Usage: unpack.py <filename.zip> [<target dir>] +# +# - <filename.zip> The Cerence SDK zip. +# - <target dir> Target directory to unpack files to. The +# directory can be located out of tree. +# The default directory is src/plugins/cerence/sdk. +# +# The script will overwrite existing files, so be careful. +# + +# +# Unpack rule list +# +# Each list entry is a dictionary consisting of target directory as +# key and matching pattern as value. The dictionary can be defined in +# the following ways: +# +# Note: The rules within the dictionary are executed in arbitrary order. +# Add a new list entry if the order is significant. +# +# Format: +# 1. { 'target dir 1': [ 'pattern1', 'pattern2', ... ], 'target dir 2': ... } +# - Each pattern is matched against the zip file contents. The file is +# copied to target dir if the pattern matches. Each pattern is handled +# independent of each other. +# +# 2. { 'target dir 1': [ [ 'file group pattern', 'sub pattern1', ... ] ], 'target dir 2': ... } +# - First the file group pattern is matched against the zip file contents. +# Then all the sub patterns are matched in the sub directory specified by +# the first match. If all the sub patterns match, then first match from +# file group pattern and all the matching files from sub pattterns are copied. +# The purpose of this option is to copy coupled files, e.g. DLL and LIB +# files found in the same directory. +# + +T9WRITE_DIR = 't9write/' +T9WRITE_DATA_DIR = 't9write/data/' +XT9_DIR = 'xt9/' +XT9_DATA_DIR = 'xt9/data/' + +UNPACK_RULES = [ + +############################################################################## +# +# T9 Write +# +############################################################################## + +{ # Header files +T9WRITE_DIR + 'api': [ + '*/decuma_hwr.h', + '*/decuma_hwr_cjk.h', + '*/decuma_hwr_types.h', + '*/decuma_point.h', + '*/decumaBasicTypes.h', + '*/decumaBasicTypesMinMax.h', + '*/decumaCharacterSetType.h', + '*/decumaCurve.h', + '*/decumaFunctionalSupport.h', + '*/decumaFunctionalSupportCheck.h', + '*/decumaLanguages.h', + '*/decumaLiteFunctionalSupport.h', + '*/decumaPlusFunctionalSupport.h', + '*/decumaRuntimeMallocData.h', + '*/decumaStatus.h', + '*/decumaStorageSpecifiers.h', + '*/decumaSymbolCategories.h', + '*/decumaUnicodeTypes.h', + '*/cerence_handwriting_alpha_version.h', + '*/cerence_handwriting_api_version.h', + '*/cerence_handwriting_cjk_version.h', + '*/xxchApiOem.h', + '*/xxchOem.h', +], +}, { # Data +T9WRITE_DATA_DIR + 'arabic': [ + '*/Arabic/*_le.bin', +], +T9WRITE_DATA_DIR + 'hebrew': [ + '*/Hebrew/*_le.bin', +], +T9WRITE_DATA_DIR + 'thai': [ + '*/*Thai*/*_le.bin', +], +T9WRITE_DATA_DIR + '': [ + '*/*_le.bin', + '*/*.hdb', + '*/*.phd', +], +}, { # Libraries +# T9 Write ARM Linux 32-bit +T9WRITE_DIR + 'lib/linux/arm/static/alphabetic': [ + '*T9Write_Alphabetic*/arm_linux*_32bit/*.a', + '*T9Write_Alphabetic*/arm_linux*_32bit/*.o', +], +T9WRITE_DIR + 'lib/linux/arm/shared/alphabetic': [ + '*T9Write_Alphabetic*/arm_linux*_32bit/*.so', +], +T9WRITE_DIR + 'lib/linux/arm/static/cjk': [ + '*T9Write_CJK*/arm_linux*_32bit/*.a', + '*T9Write_CJK*/arm_linux*_32bit/*.o', +], +T9WRITE_DIR + 'lib/linux/arm/shared/cjk': [ + '*T9Write_CJK*/arm_linux*_32bit/*.so', +], +# T9 Write ARM Linux 64-bit +T9WRITE_DIR + 'lib/linux/arm64/static/alphabetic': [ + '*T9Write_Alphabetic*/arm_linux*_64bit/*.a', + '*T9Write_Alphabetic*/arm_linux*_64bit/*.o', +], +T9WRITE_DIR + 'lib/linux/arm64/shared/alphabetic': [ + '*T9Write_Alphabetic*/arm_linux*_64bit/*.so', +], +T9WRITE_DIR + 'lib/linux/arm64/static/cjk': [ + '*T9Write_CJK*/arm_linux*_64bit/*.a', + '*T9Write_CJK*/arm_linux*_64bit/*.o', +], +T9WRITE_DIR + 'lib/linux/arm64/shared/cjk': [ + '*T9Write_CJK*/arm_linux*_64bit/*.so', +], +# T9 Write x86 Linux 32-bit +T9WRITE_DIR + 'lib/linux/x86/static/alphabetic': [ + '*T9Write_Alphabetic*/i86_linux*_32bit/*.a', + '*T9Write_Alphabetic*/i86_linux*_32bit/*.o', +], +T9WRITE_DIR + 'lib/linux/x86/shared/alphabetic': [ + '*T9Write_Alphabetic*/i86_linux*_32bit/*.so', +], +T9WRITE_DIR + 'lib/linux/x86/static/cjk': [ + '*T9Write_CJK*/i86_linux*_32bit/*.a', + '*T9Write_CJK*/i86_linux*_32bit/*.o', +], +T9WRITE_DIR + 'lib/linux/x86/shared/cjk': [ + '*T9Write_CJK*/i86_linux*_32bit/*.so', +], +# T9 Write x86 Linux 64-bit +T9WRITE_DIR + 'lib/linux/x86_64/static/alphabetic': [ + '*T9Write_Alphabetic*/i86_linux*_64bit/*.a', + '*T9Write_Alphabetic*/i86_linux*_64bit/*.o', +], +T9WRITE_DIR + 'lib/linux/x86_64/shared/alphabetic': [ + '*T9Write_Alphabetic*/i86_linux*_64bit/*.so', +], +T9WRITE_DIR + 'lib/linux/x86_64/static/cjk': [ + '*T9Write_CJK*/i86_linux*_64bit/*.a', + '*T9Write_CJK*/i86_linux*_64bit/*.o', +], +T9WRITE_DIR + 'lib/linux/x86_64/shared/cjk': [ + '*T9Write_CJK*/i86_linux*_64bit/*.so', +], +# T9 Write x86 Win32 32-bit +T9WRITE_DIR + 'lib/win32/x86/static/alphabetic': [ + '*T9Write_Alphabetic*/i86_win32_32bit/libt9write*.lib', +], +T9WRITE_DIR + 'lib/win32/x86/shared/alphabetic': [ + [ '*T9Write_Alphabetic*/i86_win32_32bit/t9write*.dll', 't9write*.lib' ], +], +T9WRITE_DIR + 'lib/win32/x86/static/cjk': [ + '*T9Write_CJK*/i86_win32_32bit/libt9write*.lib', +], +T9WRITE_DIR + 'lib/win32/x86/shared/cjk': [ + [ '*T9Write_CJK*/i86_win32_32bit/t9write*.dll', 't9write*.lib' ], +], +# T9 Write x86 Win32 64-bit +T9WRITE_DIR + 'lib/win32/amd64/static/alphabetic': [ + '*T9Write_Alphabetic*/i86_win32_64bit/libt9write*.lib', +], +T9WRITE_DIR + 'lib/win32/amd64/shared/alphabetic': [ + [ '*T9Write_Alphabetic*/i86_win32_64bit/t9write*.dll', 't9write*.lib' ], +], +T9WRITE_DIR + 'lib/win32/amd64/static/cjk': [ + '*T9Write_CJK*/i86_win32_64bit/libt9write*.lib', +], +T9WRITE_DIR + 'lib/win32/amd64/shared/cjk': [ + [ '*T9Write_CJK*/i86_win32_64bit/t9write*.dll', 't9write*.lib' ], +], +}, + +############################################################################## +# +# XT9 +# +############################################################################## + +{ # Header files +XT9_DIR + 'api': [ + '*/et9api.h', + '*/et9awapi.h', + '*/et9cpapi.h', + '*/et9kapi.h', + '*/et9kbdef.h', + '*/et9navapi.h', + '*/xxet9oem.h', +], +}, { # Libraries +# XT9 ARM Linux 32-bit +XT9_DIR + 'lib/linux/arm/static': [ + '*/Xt9/*/arm_linux*_32bit/*.a', + '*/Xt9/*/arm_linux*_32bit/*.o', +], +XT9_DIR + 'lib/linux/arm/shared': [ + '*/Xt9/*/arm_linux*_32bit/*.so', +], +# XT9 ARM Linux 64-bit +XT9_DIR + 'lib/linux/arm64/static': [ + '*/Xt9/*/arm_linux*_64bit/*.a', + '*/Xt9/*/arm_linux*_64bit/*.o', +], +XT9_DIR + 'lib/linux/arm64/shared': [ + '*/Xt9/*/arm_linux*_64bit/*.so', +], +# XT9 x86 Linux 32-bit +XT9_DIR + 'lib/linux/x86/static': [ + '*/Xt9/*/i86_linux*_32bit/*.a', + '*/Xt9/*/i86_linux*_32bit/*.o', +], +XT9_DIR + 'lib/linux/x86/shared': [ + '*/Xt9/*/i86_linux*_32bit/*.so', +], +# XT9 x86 Linux 64-bit +XT9_DIR + 'lib/linux/x86_64/static': [ + '*/Xt9/*/i86_linux*_64bit/*.a', + '*/Xt9/*/i86_linux*_64bit/*.o', +], +XT9_DIR + 'lib/linux/x86_64/shared': [ + '*/Xt9/*/i86_linux*_64bit/*.so', +], +# XT9 x86 Win32 32-bit +XT9_DIR + 'lib/win32/x86/static': [ + '*/Xt9/*/i86_win32_32bit/libxt9*.lib', +], +XT9_DIR + 'lib/win32/x86/shared': [ + [ '*/Xt9/*/i86_win32_32bit/xt9*.dll', 'xt9*.lib' ], +], +# XT9 x86 Win32 64-bit +XT9_DIR + 'lib/win32/amd64/static': [ + '*/Xt9/*/i86_win32_64bit/libxt9*.lib', +], +XT9_DIR + 'lib/win32/amd64/shared': [ + [ '*/Xt9/*/i86_win32_64bit/xt9*.dll', 'xt9*.lib' ], +], +}, + +############################################################################## +# +# XT9 Data +# +############################################################################## + +{ +XT9_DATA_DIR: [ + '*/*.ldb', +], +}, + +] + +# +# Blacklist +# +# File matching rules for blacklisted items. Matched before UNPACK_RULES. +# + +BLACKLIST_RULES = [ +'*__MACOSX*', +'*/.DS_Store', +] + +def blacklist(file_list): + result = [] + for file_name in file_list: + match = False + for blacklist_rule in BLACKLIST_RULES: + match = fnmatch.fnmatch(file_name, blacklist_rule) + if match: + break + if not match: + result.append(file_name) + return result + +def unzip(zip_file, target_dir): + zip_list = [] + if os.path.isdir(zip_file): + base_dir, sdk_dir = os.path.split(zip_file.replace('\\', '/').rstrip('/')) + base_dir_length = len(base_dir) + 1 if base_dir else 0 + if not 'T9Write' in sdk_dir: + print("Error: The input directory name '" + sdk_dir + "' does not contain 'T9Write'.") + print("Please unzip the file to a directory named after the zip file and try again.") + return zip_list + for root, dirs, files in os.walk(zip_file): + for file_name in files: + sub_dir = root[base_dir_length:] + dst_dir = os.path.join(target_dir, sub_dir) + if not os.path.exists(dst_dir): + os.makedirs(dst_dir) + shutil.copy2(os.path.join(root, file_name), dst_dir) + os.chmod(os.path.join(dst_dir, file_name), 0o644) + zip_list.append(os.path.join(sub_dir, file_name).replace('\\', '/')) + return zip_list + with zipfile.ZipFile(zip_file, 'r') as z: + zip_list = sorted(blacklist(z.namelist())) + zip_basename = os.path.splitext(os.path.basename(zip_file))[0] + if zip_list and zip_basename in zip_list[0]: + zip_basename = '' + zip_list = [os.path.join(zip_basename, zip_name).replace('\\', '/') for zip_name in zip_list] + z.extractall(os.path.join(target_dir, zip_basename)) + return zip_list + +def match_file_list(file_list, base_dir, fnpattern): + result_list = [file_name for file_name in file_list \ + if fnmatch.fnmatch(file_name, fnpattern) and \ + os.path.isfile(os.path.join(base_dir, file_name))] + for file_name in result_list: + file_list.remove(file_name) + return result_list + +def unpack(zip_list, zip_dir, out_dir): + if not zip_list: + return + for unpack_rules in UNPACK_RULES: + process_unpack_rules(zip_list, zip_dir, out_dir, unpack_rules) + +def process_unpack_rules(zip_list, zip_dir, out_dir, unpack_rules): + for (target_dir, match_rules) in unpack_rules.items(): + for match_rule in match_rules: + # Match + match_rule_group = match_rule if isinstance(match_rule, list) else [match_rule] + match_group_candidates = [match_file_list(zip_list, zip_dir, match_rule_group[0])] + if len(match_rule_group) > 1: + while len(match_group_candidates[0]) > 0: + match_group0_candidate = match_group_candidates[0][0] + all_sub_groups_match = True + for sub_group_rule in match_rule_group[1:]: + fnpattern = os.path.join(os.path.dirname(match_group0_candidate), sub_group_rule).replace('\\', '/') + sub_group_candidates = match_file_list(zip_list, zip_dir, fnpattern) + if not sub_group_candidates: + all_sub_groups_match = False + break + match_group_candidates.append(sub_group_candidates) + if all_sub_groups_match: + match_group_candidates[0] = [match_group0_candidate] + break + else: + match_group_candidates = [match_group_candidates[0][1:]] + + # Copy + if match_group_candidates: + for match_group_candidate in match_group_candidates: + for zip_name in match_group_candidate: + dst_dir = os.path.join(out_dir, target_dir) + if not os.path.exists(dst_dir): + os.makedirs(dst_dir) + src = os.path.join(zip_dir, zip_name).replace('\\', '/') + dst = os.path.join(dst_dir, os.path.basename(zip_name)).replace('\\', '/') + print(zip_name + ' -> ' + dst) + shutil.copy2(src, dst) + +if __name__ == '__main__': + if len(sys.argv) < 2: + print("Usage: %s <filename.zip> [<target dir>]" % os.path.basename(__file__)) + exit() + + out_dir = os.path.join(sys.path[0], 'sdk') if len(sys.argv) == 2 else sys.argv[2] + zip_dir = tempfile.mkdtemp() + + try: + unpack(unzip(sys.argv[1], zip_dir), zip_dir, out_dir) + except Exception as e: + print(e) + finally: + shutil.rmtree(zip_dir) |