Remove split_abi and dependent compornents
split_abi and dependent compornents have been introduced in order to split fat .apk (including multiple .so files) into seperate ones, including preinstall .apk which has no .so file.
However;
- Because of migration from ndk-build to raw toolchain, fat .apk is no more built.
- Becaise of update of staging repository's infrastructure,
now preinstall .apk can include .so file inside.
Therefore there is no usecase where spli_abi is used.
This is just a clean-up of unused files. Hence no behavior change is intended.
BUG=none
TEST=compile
git-svn-id: https://mozc.googlecode.com/svn/trunk@418 a6090854-d499-a067-5803-1114d4e51264
diff --git a/src/android/split_abi.py b/src/android/split_abi.py
deleted file mode 100644
index d646056..0000000
--- a/src/android/split_abi.py
+++ /dev/null
@@ -1,294 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright 2010-2014, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Splits the specified apk file into each ABIs.
-
-"Fat APK" contains multipul shared objects in order to run on all the ABIs.
-But this means such APK is larger than "Thin" APK.
-This script creates Thin APKs from Fat APK.
-
-Version code format:
- 00000BBBBB:
- B: Build number
-
- or
-
- 0005BBBBBA
- A: ABI (0: Fat, 5: x86, 4: armeabi-v7a, 3: armeabi, 1:mips)
- B: Build number
-
-Note:
-- This process must be done before signing.
-- Prefix 5 is introduced because of historical reason.
- Previously Build Number (B) is placed after ABI (A) but
- it's found that swpping the order is reasonable.
- Previously version code for x86 is always greater than that for armeabi.
- Therefore version-check rule like "Version code of update must be greater
- than that of previous" cannot be introduced.
-"""
-
-
-__author__ = "matsuzakit"
-
-import cStringIO
-import logging
-import optparse
-import os
-import re
-import shutil
-import tempfile
-import zipfile
-
-from build_tools import android_binary_xml
-
-
-_UNSIGNED_APK_SUFFIX = '-unsigned.apk'
-
-
-class Error(Exception):
- """Base exception class."""
-
-
-class UnexpectedFormatError(Error):
- pass
-
-
-class IllegalArgumentError(Error):
- pass
-
-
-def ParseArgs():
- parser = optparse.OptionParser()
- parser.add_option('--dir', dest='bin_dir',
- help='Binary directory. Files of which name ends with '
- '"-unsigned.apk" are processed.')
- options = parser.parse_args()[0]
- if not options.bin_dir:
- raise IllegalArgumentError('--dir is mandatory')
- return options
-
-
-# TODO(matsuzakit): Make zip relating logics independent
-# from file-based operations.
-# Currently they are file-based for reuseabilty.
-# But file-based design is not good from the view points of
-# performance and testability
-def DeleteEntriesFromZip(zip_path, delete_file_names):
- """Deletes entries from zip file.
-
- Args:
- zip_path: Path to zip file.
- delete_file_names: File names in archive to be deleted.
- """
- logging.info('Deleting %s from %s', delete_file_names, zip_path)
- tmp_file = cStringIO.StringIO()
- in_zip_file = zipfile.ZipFile(zip_path)
- try:
- out_zip_file = zipfile.ZipFile(tmp_file, 'w')
- try:
- for zipinfo in in_zip_file.infolist():
- if zipinfo.filename not in delete_file_names:
- # Reusing zipinfo as 1st argument is mandatory
- # because compression_type must be kept.
- out_zip_file.writestr(zipinfo,
- in_zip_file.read(zipinfo.filename))
- finally:
- out_zip_file.close()
- finally:
- in_zip_file.close()
- with open(zip_path, 'w') as out_file:
- out_file.write(tmp_file.getvalue())
-
-
-def ReplaceFilesInZip(zip_path, base_directory, file_names,
- compress_type=zipfile.ZIP_DEFLATED):
- """Replaces files in zip file with given file_names.
-
- If no corresponding entries in zip file, simply appended.
-
- Args:
- zip_path: Path to zip file.
- base_directory: Base direcotry of file_names.
- file_names: File names to be appended.
- compress_type: zipfile.ZIP_DEFLATED or zipfile.ZIP_STORED.
- """
- DeleteEntriesFromZip(zip_path, file_names)
- logging.info('Appending %s to %s', file_names, zip_path)
- zip_file = zipfile.ZipFile(zip_path, 'a')
- try:
- for file_name in file_names:
- zip_file.write(os.path.join(base_directory, file_name),
- file_name, compress_type)
- finally:
- zip_file.close()
-
-
-def UnzipFiles(zip_path, file_names, out_dir):
- """Extracts files from zip file.
-
- Args:
- zip_path: Path to zip file.
- file_names: File names to be extracted.
- out_dir: Destination directory.
- Returns:
- Paths of extracted files.
- """
- logging.info('Extracting %s from %s', file_names, zip_path)
- result = []
- zip_file = zipfile.ZipFile(zip_path)
- try:
- for zip_info in zip_file.infolist():
- if zip_info.filename in file_names:
- out_path = os.path.join(out_dir, zip_info.filename)
- if not os.path.isdir(os.path.dirname(out_path)):
- os.makedirs(os.path.dirname(out_path))
- with open(out_path, 'w') as out_file:
- out_file.write(zip_file.read(zip_info.filename))
- result.append(out_path)
- finally:
- zip_file.close()
- return result
-
-
-def GetVersionCode(base_version_code, abi):
- """Gets version code based on base version code and abi."""
- # armeabi-v7a's version code must be greater than armeabi's.
- # By this v7a's apk is prioritized on the Play.
- # Without this all the ARM devices download armeabi version
- # because armeabi can be run on all of them (including v7a).
- if abi == 'x86':
- abi_code = 5
- elif abi == 'armeabi-v7a':
- abi_code = 4
- elif abi == 'armeabi':
- abi_code = 3
- elif abi == 'mips':
- abi_code = 1
- else:
- raise IllegalArgumentError('Unexpected ABI; %s' % abi)
- if base_version_code >= 10000:
- raise IllegalArgumentError('Version code is greater than 10000. '
- 'It is time to revisit version code scheme.')
- return int('5%05d%d' % (base_version_code, abi_code))
-
-
-def ModifyAndroidManifestFile(apk_path, abi):
- """Modifies given apk file to make it thin apk.
-
- After the execution of this method,
- unneeded .so files (evaluated by given abi name)
- are removed and AndroidManifest.xml file's
- version code is modified.
-
- Args:
- apk_path: the path to the apk file to be modified.
- abi: the ABI name.
- Raises:
- UnexpectedFormatError: manifest element must be only one.
- """
- logging.info('Modifing %s to ABI %s', apk_path, abi)
- temp_dir_in = tempfile.mkdtemp()
- temp_dir_out = tempfile.mkdtemp()
- original_file_paths = UnzipFiles(apk_path,
- 'AndroidManifest.xml', temp_dir_in)
- if len(original_file_paths) != 1:
- raise UnexpectedFormatError(
- 'AndroidManifest.xml file is expected to be only one.')
- original_file_path = original_file_paths[0]
- document = android_binary_xml.AndroidBinaryXml(original_file_path)
- manifest_elements = document.FindElements(None, 'manifest')
- if len(manifest_elements) != 1:
- raise UnexpectedFormatError('manifest element is expected to be only one.')
- manifest_element = manifest_elements[0]
- version_code_attribute = manifest_element.GetAttribute(
- 'http://schemas.android.com/apk/res/android', 'versionCode')
- base_version_code = version_code_attribute.GetIntValue()
- logging.info('new ver code %s', GetVersionCode(base_version_code, abi))
- version_code_attribute.SetIntValue(GetVersionCode(base_version_code, abi))
- document.Write(os.path.join(temp_dir_out, 'AndroidManifest.xml'))
- ReplaceFilesInZip(apk_path, temp_dir_out, ['AndroidManifest.xml'])
-
-
-def GetUnneededFiles(abi_to_files, abi):
- unneeded_files = []
- for entry_abi, entry_files in abi_to_files.iteritems():
- if entry_abi != abi:
- unneeded_files.extend(entry_files)
- logging.info('Unneeded files are %s', unneeded_files)
- return unneeded_files
-
-
-def CreateCopyFile(original_file, abi_name):
- # Original : Mozc-unsigned.apk
- # Copy : Mozc-x86-unsigned.apk
- copied_file = ''.join(
- [original_file[:original_file.find(_UNSIGNED_APK_SUFFIX)],
- '-', abi_name, _UNSIGNED_APK_SUFFIX])
- logging.info('Copying from %s to %s', original_file, copied_file)
- shutil.copyfile(original_file, copied_file)
- return copied_file
-
-
-def CreateAbiToFileMapping(file_name):
- zip_file = zipfile.ZipFile(file_name)
- try:
- abi_to_files = {}
- for zip_info in zip_file.infolist():
- m = re.match(r'lib/(.+?)/.*', zip_info.filename)
- if m:
- files = abi_to_files.setdefault(m.group(1), [])
- files.append(zip_info.filename)
- logging.info('ABIs are: %s', abi_to_files.keys())
- finally:
- zip_file.close()
- return abi_to_files
-
-
-def main():
- # Enable logging.info.
- logging.getLogger().setLevel(logging.INFO)
- options = ParseArgs()
-
- for apk_file in [os.path.join(options.bin_dir, f)
- for f in os.listdir(options.bin_dir)
- if f.endswith(_UNSIGNED_APK_SUFFIX)]:
- logging.info('Processing %s', apk_file)
- abi_to_files = CreateAbiToFileMapping(apk_file)
-
- for abi in abi_to_files:
- logging.info('Processing ABI: %s', abi)
- copied_file = CreateCopyFile(apk_file, abi)
- unneeded_files = GetUnneededFiles(abi_to_files, abi)
- DeleteEntriesFromZip(copied_file, unneeded_files)
- ModifyAndroidManifestFile(copied_file, abi)
-
-
-if __name__ == '__main__':
- main()
diff --git a/src/android/src/com/google/android/inputmethod/japanese/MozcUtil.java b/src/android/src/com/google/android/inputmethod/japanese/MozcUtil.java
index 1f5475a..ff2a54d 100644
--- a/src/android/src/com/google/android/inputmethod/japanese/MozcUtil.java
+++ b/src/android/src/com/google/android/inputmethod/japanese/MozcUtil.java
@@ -303,7 +303,7 @@
*
* ABI independent version code is equivalent to "Build number" of Mozc project.
*
- * <p>Must be consistent with split_abi.py
+ * <p>Must be consistent with mozc_version.py
*/
public static int getAbiIndependentVersionCode(Context context) {
// Version code format:
diff --git a/src/build_tools/android_binary_xml.py b/src/build_tools/android_binary_xml.py
deleted file mode 100644
index c97387f..0000000
--- a/src/build_tools/android_binary_xml.py
+++ /dev/null
@@ -1,523 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright 2010-2014, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Splits the specified apk file into each ABIs.
-
-"Fat APK" contains multipul shared objects in order to run on all the ABIs.
-But this means such APK is larger than "Thin" APK.
-This script creates Thin APKs from Fat APK.
-
-Note:
-The format of Android Binary XML is not documented.
-This script is based on below source code.
-${ANDROID_SOURCE_TREE}/frameworks/base/include/utils/ResourceTypes.h
-All the digits are in little endian.
-
-Android Binary XML consists of file headr and chunks.
-File header block consists of following 8 bytes.
-0x00: Magic number in int32 (0x00080003)
-0x04: File size
-
-Chunks follow the header.
-- String chunk
-- Resource ID chunk
-- Start Namespace chunk
-- End Namespace chunk
-- Start Element chunk
-- End Element chunk
-
-A chunk starts with following 8 bytes.
-0x00: Magic number in int32.
-0x04: Size of this block in int32.
-
-Next chunk is located at (the head of a chunk + (value of 0x04)).
-
--- String chunk
-0x00: Magic number in int32 (0x001C0001)
-0x04: Size of this block in int32
-0x08: Number of the entries in the string table in int32
-0x0C: Number of style in int32 (unused). Expected to be 0.
-0x10: Flags in int32 (unused)
-0x14: String data offset in int32 (unused)
-0x18: Style data offset in int32 (unused). Expected to be 0.
-0x1C: Offset table of the string table, consists of int16.
- The size of this block is (value of 0x08 * 2).
-0x1C + (value of 0x08 * 2): Strings (repeated).
- Each strings start with size value (int16)
- and the body (UTF-16LE).
-
--- Resource ID chunk
-0x00: Magic number in int32 (0x00080180)
-0x04: Size of this block in int32
-(Omit the descirption of the content. We simply ignore them)
-
--- Namespace chunk
-0x00: Magic number in int32 (0x00100100)
-0x04: Size of this block in int32
-(Omit the descirption of the content. We simply ignore them)
-
--- Element chunk
-0x00: Start-element header in int32 (0x00100102)
-0x04: Size of this block in int32
-0x08: Line number (unused)
-0x1C: XML Comment or 0xFFFFFFFF if none.
-0x10: Namespace name index.
- Reference to string table in int32, or 0xFFFFFFFF for default NS.
-0x14: Element name index. Reference to string table in int32.
-0x18: Attribute start offset from 0x10 in uint16. Always 0x14.
-0x1A: Attribute size in uint16. Always 0x14.
-0x1C: Attribute count in uint16
-0x1E: Index of 'id' attribute in uint16
-0x20: Index of 'class' attribute in uint16
-0x22: Index of 'style' attribute in uint16
-0x24: Attributes.
-
-Each Attribute (=5*4bytes) consists of
-0x00: Namespace name.
- Reference to string table in int32, or 0xFFFFFFFF for default NS.
-0x04: Attribute name. Reference to string table in int32.
-0x08: Attribute value.
-0x0C: Value type. This script handles only int constant, 0x10000008.
-0x10: Value
-"""
-
-__author__ = "matsuzakit"
-
-import logging
-import struct
-
-
-# Magic numbers
-START_FILE_TAG = 0x00080003
-
-CHUNK_TAG_STRING = 0x001C0001
-CHUNK_TAG_RESOURCE_ID = 0x00080180
-CHUNK_TAG_START_NAMESPACE = 0x00100100
-CHUNK_TAG_END_NAMESPACE = 0x00100101
-CHUNK_TAG_START_ELEMENT = 0x00100102
-CHUNK_TAG_END_ELEMENT = 0x00100103
-
-ATTRIBUTE_START_OFFSET = 0x14
-ATTRIBUTE_STRUCT_SIZE = 0x14
-
-# Struct formats
-FILE_HEADER_FORMAT = '<II'
-CHUNK_HEADER_FORMAT = '<II'
-STRING_CHUNK_CONTENT_FORMAT = '<IIIIIII'
-STRING_ENTRY_SIZE_FORMAT = '<H'
-START_ELEMENT_FORMAT = '<IIIIIIHHHHHH'
-END_ELEMENT_FORMAT = '<IIIIII'
-ATTRIBUTE_FORMAT = '<IIIII'
-
-DEFAULT_NS_INDEX = 0xFFFFFFFF
-
-
-class Error(Exception):
- """Base exception class for this module."""
- pass
-
-
-class UnexpectedFormatException(Error):
- """If the XML file's format does not meet our expectation."""
- pass
-
-
-class IllegalArgumentException(Error):
- """If passed argument is illegal."""
- pass
-
-
-def _Unpack(content, offset, format_string):
- """Unpack the content at the offset.
-
- Args:
- content: String to be unpacked.
- offset: Offset from the beginning of the content.
- format_string: Format string of struct module.
- Returns:
- See struct.unpack.
- """
- size = struct.calcsize(format_string)
- result = struct.unpack(format_string, content[offset : offset + size])
- return result
-
-
-def _Pack(content, offset, format_string, values):
- """Pack values to the content at the offset.
-
- Args:
- content: String to be packed.
- offset: Offset from the beginning of the file.
- format_string: Format string of struct module.
- values: Values to struct.pack.
- Returns:
- Updated content.
- """
- size = struct.calcsize(format_string)
- return ''.join([content[:offset],
- struct.pack(format_string, *values),
- content[offset + size:]])
-
-
-class Serializable(object):
- """Serializable object."""
-
- def __init__(self, content):
- self._content = content
-
- def Serialize(self, output_stream):
- """Serializes the content (self._content)."""
- output_stream.write(self._content)
-
-
-class Chunk(Serializable):
- """Generic chunk."""
-
- def __init__(self, content):
- Serializable.__init__(self, content)
-
- def SetStringChunk(self, string_chunk):
- """Sets string chunk.
-
- On initialization phase string chunk might not be available
- so after parsing invoke this to set it.
-
- Args:
- string_chunk: StringChunk to be set.
- """
- self._string_chunk = string_chunk
-
-
-class StringChunk(Chunk):
- """String chunk.
-
- Only one String chunks should be in the file.
-
- Attributes:
- string_entries: List of string entries.
- Other chunks would access the entries via the list's index.
- """
-
- def __init__(self, content):
- Chunk.__init__(self, content)
- logging.debug('-- String chunk')
-
- (chunk_tag,
- _, # chunk_size
- string_entry_size,
- style_size,
- _, # flag
- _, # string_data_offset
- style_data_offset) = _Unpack(content, 0, STRING_CHUNK_CONTENT_FORMAT)
- if chunk_tag != CHUNK_TAG_STRING:
- raise UnexpectedFormatException('CHUNK_TAG_STRING is not found')
-
- logging.debug('String entry size: %d', string_entry_size)
- if style_size != 0 or style_data_offset != 0:
- raise UnexpectedFormatException(
- 'Unexpected style data is found.')
-
- # Parse string offset table block.
- string_offset_format = '<%s' % ('I' * string_entry_size)
- string_offset_table = _Unpack(content,
- struct.calcsize(STRING_CHUNK_CONTENT_FORMAT),
- string_offset_format)
-
- # Parse string table block.
- string_entries_offset = (struct.calcsize(STRING_CHUNK_CONTENT_FORMAT)
- + struct.calcsize(string_offset_format))
- self.string_entries = []
- for i in xrange(0, string_entry_size):
- entry_start_offset = string_offset_table[i] + string_entries_offset
- # The size of the string, in character length of UTF-16.
- entry_size = _Unpack(content, entry_start_offset,
- STRING_ENTRY_SIZE_FORMAT)[0]
- string_body_offset = (entry_start_offset
- + struct.calcsize(STRING_ENTRY_SIZE_FORMAT))
- # Each UTF-16 character consumes 2 bytes.
- entry_in_utf16 = content[string_body_offset :
- string_body_offset + entry_size * 2]
- entry = unicode(entry_in_utf16, 'utf-16le').encode('utf-8')
- logging.debug('String entry #%d (0x%X): %s', i, entry_start_offset, entry)
- self.string_entries.append(entry)
-
- def GetIndexByString(self, string):
- return self.string_entries.index(string)
-
-
-class Attribute(Serializable):
- """Attribute in StartElementChunk.
-
- Attributes:
- namespace_name_index: Index in String Chunk of namespace name.
- attribute_name_index: Index in String Chunk of attribute name.
- """
-
- def __init__(self, content):
- Serializable.__init__(self, content)
- (self.namespace_name_index,
- self.attribute_name_index,
- _,
- _, # value_type
- _) = _Unpack(content, 0, ATTRIBUTE_FORMAT)
- logging.debug('attr %s:%s',
- self.namespace_name_index, self.attribute_name_index)
-
- def GetIntValue(self):
- """Gets the value as integer.
-
- The value might be updated by SetIntValue so direct access to the value
- is not expected.
- Returns:
- Integer value of the attribute.
- """
- value = _Unpack(self._content, 0, ATTRIBUTE_FORMAT)[4]
- return value
-
- def SetIntValue(self, value):
- """Sets the value as integer. This updates the result of serialize."""
- values = _Unpack(self._content, 0, ATTRIBUTE_FORMAT)
- new_values = list(values)
- new_values[4] = value
- self._content = _Pack(self._content, 0, ATTRIBUTE_FORMAT, new_values)
-
-
-class StartElementChunk(Chunk):
- """Start element chunk.
-
- This chunk contains all the informations about an element.
- Attributes:
- namespace_name_index: Index in String Chunk of namespace name.
- element_name_index: Index in String Chunk of element name.
- """
-
- def __init__(self, content):
- Chunk.__init__(self, content[:struct.calcsize(START_ELEMENT_FORMAT)])
- logging.debug('-- Start Element chunk')
- (chunk_tag,
- _, # chunk_size
- _, # line_number
- _, # comment_index
- self.namespace_name_index,
- self.element_name_index,
- attribute_start,
- attribute_struct_size,
- attribute_size,
- _,
- _,
- _) = _Unpack(content, 0, START_ELEMENT_FORMAT)
- if chunk_tag != CHUNK_TAG_START_ELEMENT:
- raise UnexpectedFormatException('CHUNK_TAG_START_ELEMENT is not found')
- logging.debug('<%d:%d>',
- self.namespace_name_index, self.element_name_index)
- if attribute_start != ATTRIBUTE_START_OFFSET:
- raise UnexpectedFormatException(
- 'attribute_start must be %d but met %d.'
- % (ATTRIBUTE_START_OFFSET, attribute_start))
- if attribute_struct_size != ATTRIBUTE_STRUCT_SIZE:
- raise UnexpectedFormatException(
- 'attribute_struct_size must be %d but met %d.'
- % (ATTRIBUTE_STRUCT_SIZE, attribute_start))
-
- self._attributes = []
- for i in xrange(0, attribute_size):
- offset = struct.calcsize(START_ELEMENT_FORMAT) + i * ATTRIBUTE_STRUCT_SIZE
- self._attributes.append(
- Attribute(content[offset : offset + ATTRIBUTE_STRUCT_SIZE]))
-
- def GetAttribute(self, namespace_name, attribute_name):
- """Gets an attribute if exists.
-
- Args:
- namespace_name: Namespace name or None for default NS.
- attribute_name: Attribute name.
- Returns:
- An attribute or None if not exists.
- Raises:
- IllegalArgumentException: Given attribute_name is not in string chunk.
- """
- if namespace_name:
- namespace_index = self._string_chunk.GetIndexByString(namespace_name)
- else:
- namespace_index = DEFAULT_NS_INDEX
- attribute_index = self._string_chunk.GetIndexByString(attribute_name)
- if attribute_index is None:
- raise IllegalArgumentException('Attribute %s is not found',
- attribute_name)
- for attribute in self._attributes:
- if (attribute.namespace_name_index == namespace_index and
- attribute.attribute_name_index == attribute_index):
- return attribute
- return None
-
- def Serialize(self, output_stream):
- super(StartElementChunk, self).Serialize(output_stream)
- for attr in self._attributes:
- attr.Serialize(output_stream)
-
-
-class EndElementChunk(Chunk):
- def __init__(self, content):
- Chunk.__init__(self, content)
- logging.debug('-- End Element chunk')
- (chunk_tag,
- _, # chunk_size
- _, # line_number
- _,
- namespace_name_index,
- element_name_index) = _Unpack(content, 0, END_ELEMENT_FORMAT)
- if chunk_tag != CHUNK_TAG_END_ELEMENT:
- raise UnexpectedFormatException('CHUNK_TAG_END_ELEMENT is not found')
- logging.debug('</%d:%d>',
- namespace_name_index, element_name_index)
-
-
-class ResourceIdChunk(Chunk):
- def __init__(self, content):
- Chunk.__init__(self, content)
- logging.debug('-- Resource ID chunk')
- (chunk_tag, _) = _Unpack(content, 0, CHUNK_HEADER_FORMAT)
- if chunk_tag != CHUNK_TAG_RESOURCE_ID:
- raise UnexpectedFormatException('CHUNK_TAG_RESOURCE_ID is not found')
-
-
-class StartNamespaceChunk(Chunk):
- def __init__(self, content):
- Chunk.__init__(self, content)
- logging.debug('-- Start Namespace chunk')
- (chunk_tag, _) = _Unpack(content, 0, CHUNK_HEADER_FORMAT)
- if chunk_tag != CHUNK_TAG_START_NAMESPACE:
- raise UnexpectedFormatException('CHUNK_TAG_START_NAMESPACE is not found')
-
-
-class EndNamespaceChunk(Chunk):
- def __init__(self, content):
- Chunk.__init__(self, content)
- logging.debug('-- End Namespace chunk')
- (chunk_tag, _) = _Unpack(content, 0, CHUNK_HEADER_FORMAT)
- if chunk_tag != CHUNK_TAG_END_NAMESPACE:
- raise UnexpectedFormatException('CHUNK_TAG_END_NAMESPACE is not found')
-
-
-TAG_TO_CHUNK = {
- CHUNK_TAG_STRING: StringChunk,
- CHUNK_TAG_RESOURCE_ID: ResourceIdChunk,
- CHUNK_TAG_START_NAMESPACE: StartNamespaceChunk,
- CHUNK_TAG_END_NAMESPACE: EndNamespaceChunk,
- CHUNK_TAG_START_ELEMENT: StartElementChunk,
- CHUNK_TAG_END_ELEMENT: EndElementChunk,
-}
-
-
-class AndroidBinaryXml(object):
- """Compiled XML file."""
-
- def __init__(self, xml_path):
- """Initialize an object.
-
- Args:
- xml_path: A path to an Android Binary XML file.
- Raises:
- UnexpectedFormatException:
- If the file format doesn't meet this script's expectation.
- """
- with open(xml_path) as xml_file:
- self._content = xml_file.read()
- logging.info('Read from %s', xml_path)
- self._chunks = self._GetChunks()
-
- # Inject string chunk.
- string_chunk = self._GetStringChunk()
- for chunk in self._chunks:
- chunk.SetStringChunk(string_chunk)
-
- def _GetChunks(self):
- (file_tag, file_size) = _Unpack(self._content, 0, FILE_HEADER_FORMAT)
- if file_tag != START_FILE_TAG:
- raise UnexpectedFormatException('START_FILE_TAG is not found.')
- if file_size != len(self._content):
- raise UnexpectedFormatException('File size is incorrect.')
- offset = struct.calcsize(FILE_HEADER_FORMAT)
- chunks = []
- while len(self._content) > offset:
- chunk_tag, chunk_size = _Unpack(self._content, offset,
- CHUNK_HEADER_FORMAT)
- partial_content = self._content[offset : offset + chunk_size]
- chunk_type = TAG_TO_CHUNK.get(chunk_tag)
- if chunk_type is None:
- raise UnexpectedFormatException('Unexpected tag 0x%X at 0x%X'
- % (chunk_tag, offset))
- chunks.append(chunk_type(partial_content))
- offset += chunk_size
- return chunks
-
- def _GetStringChunk(self):
- string_chunks = [c for c in self._chunks if isinstance(c, StringChunk)]
- if len(string_chunks) != 1:
- raise UnexpectedFormatException(
- 'Found %d string chunks but only one is expected.')
- return string_chunks[0]
-
- def FindElements(self, namespace_name, element_name):
- """Finds elements which match given namespace_name and element_name.
-
- Args:
- namespace_name: Namespace name or None for default NS.
- element_name: Element name.
- Returns:
- Element list.
- Raises:
- IllegalArgumentException: If passed argument is illegal.
- """
- string_chunk = self._GetStringChunk()
- if namespace_name:
- namespace_index = string_chunk.GetIndexByString(namespace_name)
- else:
- namespace_index = DEFAULT_NS_INDEX
- if element_name is None:
- raise IllegalArgumentException('Element name is mandatory.')
- element_index = string_chunk.GetIndexByString(element_name)
- if element_index is None:
- raise IllegalArgumentException('Element %s is not found.', element_name)
- return [chunk for chunk in self._chunks
- if isinstance(chunk, StartElementChunk)
- and chunk.namespace_name_index == namespace_index
- and chunk.element_name_index == element_index]
-
- def Write(self, out_path):
- with open(out_path, 'w') as output_stream:
- output_stream.write(
- self._content[0 : struct.calcsize(FILE_HEADER_FORMAT)])
- for chunk in self._chunks:
- chunk.Serialize(output_stream)
-
-
-if __name__ == '__main__':
- logging.info('This script is intended to be imported from other script.')
diff --git a/src/mozc_version_template.txt b/src/mozc_version_template.txt
index b2ca90c..9bccf66 100644
--- a/src/mozc_version_template.txt
+++ b/src/mozc_version_template.txt
@@ -1,6 +1,6 @@
MAJOR=2
MINOR=16
-BUILD=1958
+BUILD=1959
REVISION=102
# NACL_DICTIONARY_VERSION is the target version of the system dictionary to be
# downloaded by NaCl Mozc.