diff --git a/doc/Architecture.md b/doc/Architecture.md index 578fb790..aede6c63 100644 --- a/doc/Architecture.md +++ b/doc/Architecture.md @@ -1,5 +1,4 @@ #### directory structure -`src/ARSCLib/` - Java .arsc library used to parse binary xml resources in apks `doc/` - documentation `src/api-impl/` - Java code implementing the android APIs `src/api-impl-jni/` - C code implementing things which it doesn't make sense to do in Java (ideally this would be most things) @@ -36,9 +35,7 @@ against) 2. GtkApplication glue parses the cmdline and calls `static void open(GtkApplication *app, GFile** files, gint nfiles, const gchar* hint, struct jni_callback_data *d)` 3. `static void open(GtkApplication *app, GFile** files, gint nfiles, const gchar* hint, struct jni_callback_data *d)`: 1. constructs the classpath from the following: - - the path to api-impl.jar (contains the following, renamed to classes{2}.dex so that art loads them) - - `hax_arsc_parser.dex` is dalvik bytecode implementing .arsc parsing duties (to be replaced by C code eventually) - - `hax.dex` contains all the implementations of android framework functions + - the path to api-impl.jar (contains all the implementations of android framework functions) - the path to the app's apk (passed to us on cmdline), making the bytecode within (and resources.arsc, which is currently the only other file read straight from the apk) available in classpath - the path to a microG apk, needed for apps with a dependency on GSF; this is specified after the app's apk so that the the app's apk is the first zip file in the classpath (needed for getting the right resources.arsc, TODO: ask for the classloader which loaded the activity that was specified on the cmdline) 2. contructs other options (mainly library path) for and launches the dalvik virtual machine diff --git a/meson.build b/meson.build index b6ec2682..d88d0b5c 100644 --- a/meson.build +++ b/meson.build @@ -157,21 +157,16 @@ executable('android-translation-layer', [ ], install_rpath: get_option('prefix') / get_option('libdir') / 'art:' + get_option('prefix') / get_option('libdir') / 'java/dex/android_translation_layer/natives') -# hax_arsc_lib.dex (named as classes2.dex so it works inside a jar) -subdir('src/ARSCLib') -hax_arsc_lib_dex = custom_target('hax_arsc_lib.dex', build_by_default: true, input: [hax_arsc_lib_jar], output: ['classes2.dex'], - command: ['dx', '--verbose', '--dex', '--min-sdk-version', '26', '--output='+join_paths(builddir_base, 'classes2.dex'), hax_arsc_lib_jar.full_path()]) - # hax.dex (named as classes.dex so it works inside a jar) subdir('src/api-impl') hax_dex = custom_target('hax.dex', build_by_default: true, input: [hax_jar], output: ['classes.dex'], command: ['dx', '--verbose', '--dex', '--output='+join_paths(builddir_base, 'classes.dex'), hax_jar.full_path()]) # api-impl.jar -custom_target('api-impl.jar', build_by_default: true, input: [hax_dex, hax_arsc_lib_dex], output: ['api-impl.jar'], +custom_target('api-impl.jar', build_by_default: true, input: [hax_dex], output: ['api-impl.jar'], install: true, install_dir : get_option('libdir') / 'java/dex/android_translation_layer', - command: ['jar', '-cvf', join_paths(builddir_base, 'api-impl.jar'), '-C', builddir_base, hax_dex, '-C', builddir_base, hax_arsc_lib_dex]) + command: ['jar', '-cvf', join_paths(builddir_base, 'api-impl.jar'), '-C', builddir_base, hax_dex]) #framework-res.apk subdir('res') diff --git a/src/ARSCLib/LICENSE b/src/ARSCLib/LICENSE deleted file mode 100644 index a84d2702..00000000 --- a/src/ARSCLib/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright (C) 2022 github.com/REAndroid - - 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. diff --git a/src/ARSCLib/README.md b/src/ARSCLib/README.md deleted file mode 100644 index cf06edc4..00000000 --- a/src/ARSCLib/README.md +++ /dev/null @@ -1,6 +0,0 @@ -taken from https://github.com/REAndroid/ARSCLib -licensed under Apache 2.0 - -# ARSCLib -A tool for decoding Android resources.arsc file using java, for decoding binary XML resources from apk files. - diff --git a/src/ARSCLib/android/content/res/XmlResourceParser.java b/src/ARSCLib/android/content/res/XmlResourceParser.java deleted file mode 100644 index 55ac439a..00000000 --- a/src/ARSCLib/android/content/res/XmlResourceParser.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2006 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. - */ - -package android.content.res; - -import android.util.AttributeSet; -import org.xmlpull.v1.XmlPullParser; - -public interface XmlResourceParser extends XmlPullParser, AttributeSet, AutoCloseable { - String getAttributeNamespace (int index); - public void close(); -} - diff --git a/src/ARSCLib/android/util/AttributeSet.java b/src/ARSCLib/android/util/AttributeSet.java deleted file mode 100644 index 9c66f2ab..00000000 --- a/src/ARSCLib/android/util/AttributeSet.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2006 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. - */ - -package android.util; - -public interface AttributeSet { - public int getAttributeCount(); - /*default*/ String getAttributeNamespace (int index); /* { - return null; - }*/ - public String getAttributeName(int index); - public String getAttributeValue(int index); - public String getAttributeValue(String namespace, String name); - public String getPositionDescription(); - public int getAttributeNameResource(int index); - public int getAttributeListValue(String namespace, String attribute, String[] options, int defaultValue); - public boolean getAttributeBooleanValue(String namespace, String attribute, boolean defaultValue); - public int getAttributeResourceValue(String namespace, String attribute, int defaultValue); - public int getAttributeIntValue(String namespace, String attribute, int defaultValue); - public int getAttributeUnsignedIntValue(String namespace, String attribute, int defaultValue); - public float getAttributeFloatValue(String namespace, String attribute, float defaultValue); - public int getAttributeListValue(int index, String[] options, int defaultValue); - public boolean getAttributeBooleanValue(int index, boolean defaultValue); - public int getAttributeResourceValue(int index, int defaultValue); - public int getAttributeIntValue(int index, int defaultValue); - public int getAttributeUnsignedIntValue(int index, int defaultValue); - public float getAttributeFloatValue(int index, float defaultValue); - public String getIdAttribute(); - public String getClassAttribute(); - public int getIdAttributeResourceValue(int defaultValue); - public int getStyleAttribute(); -} diff --git a/src/ARSCLib/com/android/org/kxml2/io/KXmlParser.java b/src/ARSCLib/com/android/org/kxml2/io/KXmlParser.java deleted file mode 100644 index c8d6d137..00000000 --- a/src/ARSCLib/com/android/org/kxml2/io/KXmlParser.java +++ /dev/null @@ -1,2137 +0,0 @@ -/* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. */ - -// Contributors: Paul Hackenberger (unterminated entity handling in relaxed mode) - -package com.android.org.kxml2.io; - -import java.io.Closeable; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.util.HashMap; -import java.util.Map; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - - -public class KXmlParser implements XmlPullParser, Closeable { - - private static final String PROPERTY_XMLDECL_VERSION - = "http://xmlpull.org/v1/doc/properties.html#xmldecl-version"; - private static final String PROPERTY_XMLDECL_STANDALONE - = "http://xmlpull.org/v1/doc/properties.html#xmldecl-standalone"; - private static final String PROPERTY_LOCATION = "http://xmlpull.org/v1/doc/properties.html#location"; - private static final String FEATURE_RELAXED = "http://xmlpull.org/v1/doc/features.html#relaxed"; - - private static final Map DEFAULT_ENTITIES = new HashMap(); - static { - DEFAULT_ENTITIES.put("lt", "<"); - DEFAULT_ENTITIES.put("gt", ">"); - DEFAULT_ENTITIES.put("amp", "&"); - DEFAULT_ENTITIES.put("apos", "'"); - DEFAULT_ENTITIES.put("quot", "\""); - } - - private static final int ELEMENTDECL = 11; - private static final int ENTITYDECL = 12; - private static final int ATTLISTDECL = 13; - private static final int NOTATIONDECL = 14; - private static final int PARAMETER_ENTITY_REF = 15; - private static final char[] START_COMMENT = { '<', '!', '-', '-' }; - private static final char[] END_COMMENT = { '-', '-', '>' }; - private static final char[] COMMENT_DOUBLE_DASH = { '-', '-' }; - private static final char[] START_CDATA = { '<', '!', '[', 'C', 'D', 'A', 'T', 'A', '[' }; - private static final char[] END_CDATA = { ']', ']', '>' }; - private static final char[] START_PROCESSING_INSTRUCTION = { '<', '?' }; - private static final char[] END_PROCESSING_INSTRUCTION = { '?', '>' }; - private static final char[] START_DOCTYPE = { '<', '!', 'D', 'O', 'C', 'T', 'Y', 'P', 'E' }; - private static final char[] SYSTEM = { 'S', 'Y', 'S', 'T', 'E', 'M' }; - private static final char[] PUBLIC = { 'P', 'U', 'B', 'L', 'I', 'C' }; - private static final char[] START_ELEMENT = { '<', '!', 'E', 'L', 'E', 'M', 'E', 'N', 'T' }; - private static final char[] START_ATTLIST = { '<', '!', 'A', 'T', 'T', 'L', 'I', 'S', 'T' }; - private static final char[] START_ENTITY = { '<', '!', 'E', 'N', 'T', 'I', 'T', 'Y' }; - private static final char[] START_NOTATION = { '<', '!', 'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N' }; - private static final char[] EMPTY = new char[] { 'E', 'M', 'P', 'T', 'Y' }; - private static final char[] ANY = new char[]{ 'A', 'N', 'Y' }; - private static final char[] NDATA = new char[]{ 'N', 'D', 'A', 'T', 'A' }; - private static final char[] NOTATION = new char[]{ 'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N' }; - private static final char[] REQUIRED = new char[] { 'R', 'E', 'Q', 'U', 'I', 'R', 'E', 'D' }; - private static final char[] IMPLIED = new char[] { 'I', 'M', 'P', 'L', 'I', 'E', 'D' }; - private static final char[] FIXED = new char[] { 'F', 'I', 'X', 'E', 'D' }; - - static final private String UNEXPECTED_EOF = "Unexpected EOF"; - static final private String ILLEGAL_TYPE = "Wrong event type"; - static final private int XML_DECLARATION = 998; - - // general - private String location; - - private String version; - private Boolean standalone; - private String rootElementName; - private String systemId; - private String publicId; - - /** - * True if the {@code } contents are handled. The DTD defines - * entity values and default attribute values. These values are parsed at - * inclusion time and may contain both tags and entity references. - * - *

If this is false, the user must {@link #defineEntityReplacementText - * define entity values manually}. Such entity values are literal strings - * and will not be parsed. There is no API to define default attributes - * manually. - */ - private boolean processDocDecl; - private boolean processNsp; - private boolean relaxed; - private boolean keepNamespaceAttributes; - - /** - * If non-null, the contents of the read buffer must be copied into this - * string builder before the read buffer is overwritten. This is used to - * capture the raw DTD text while parsing the DTD. - */ - private StringBuilder bufferCapture; - - /** - * Entities defined in or for this document. This map is created lazily. - */ - private Map documentEntities; - - /** - * Default attributes in this document. The outer map's key is the element - * name; the inner map's key is the attribute name. Both keys should be - * without namespace adjustments. This map is created lazily. - */ - private Map> defaultAttributes; - - - private int depth; - private String[] elementStack = new String[16]; - private String[] nspStack = new String[8]; - private int[] nspCounts = new int[4]; - - // source - - private Reader reader; - private String encoding; - private ContentSource nextContentSource; - private char[] buffer = new char[8192]; - private int position = 0; - private int limit = 0; - - /* - * Track the number of newlines and columns preceding the current buffer. To - * compute the line and column of a position in the buffer, compute the line - * and column in the buffer and add the preceding values. - */ - private int bufferStartLine; - private int bufferStartColumn; - - // the current token - - private int type; - private boolean isWhitespace; - private String namespace; - private String prefix; - private String name; - private String text; - - private boolean degenerated; - private int attributeCount; - - // true iff. we've encountered the START_TAG of an XML element at depth == 0; - private boolean parsedTopLevelStartTag; - - /* - * The current element's attributes arranged in groups of 4: - * i + 0 = attribute namespace URI - * i + 1 = attribute namespace prefix - * i + 2 = attribute qualified name (may contain ":", as in "html:h1") - * i + 3 = attribute value - */ - private String[] attributes = new String[16]; - - private String error; - - private boolean unresolved; - - - /** - * Retains namespace attributes like {@code xmlns="http://foo"} or {@code xmlns:foo="http:foo"} - * in pulled elements. Most applications will only be interested in the effective namespaces of - * their elements, so these attributes aren't useful. But for structure preserving wrappers like - * DOM, it is necessary to keep the namespace data around. - */ - public void keepNamespaceAttributes() { - this.keepNamespaceAttributes = true; - } - - private boolean adjustNsp() throws XmlPullParserException { - boolean any = false; - - for (int i = 0; i < attributeCount << 2; i += 4) { - String attrName = attributes[i + 2]; - int cut = attrName.indexOf(':'); - String prefix; - - if (cut != -1) { - prefix = attrName.substring(0, cut); - attrName = attrName.substring(cut + 1); - } else if (attrName.equals("xmlns")) { - prefix = attrName; - attrName = null; - } else { - continue; - } - - if (!prefix.equals("xmlns")) { - any = true; - } else { - int j = (nspCounts[depth]++) << 1; - - nspStack = ensureCapacity(nspStack, j + 2); - nspStack[j] = attrName; - nspStack[j + 1] = attributes[i + 3]; - - if (attrName != null && attributes[i + 3].isEmpty()) { - checkRelaxed("illegal empty namespace"); - } - - if (keepNamespaceAttributes) { - // explicitly set the namespace for unprefixed attributes - // such as xmlns="http://foo" - attributes[i] = "http://www.w3.org/2000/xmlns/"; - any = true; - } else { - System.arraycopy( - attributes, - i + 4, - attributes, - i, - ((--attributeCount) << 2) - i); - - i -= 4; - } - } - } - - if (any) { - for (int i = (attributeCount << 2) - 4; i >= 0; i -= 4) { - - String attrName = attributes[i + 2]; - int cut = attrName.indexOf(':'); - - if (cut == 0 && !relaxed) { - throw new RuntimeException( - "illegal attribute name: " + attrName + " at " + this); - } else if (cut != -1) { - String attrPrefix = attrName.substring(0, cut); - - attrName = attrName.substring(cut + 1); - - String attrNs = getNamespace(attrPrefix); - - if (attrNs == null && !relaxed) { - throw new RuntimeException( - "Undefined Prefix: " + attrPrefix + " in " + this); - } - - attributes[i] = attrNs; - attributes[i + 1] = attrPrefix; - attributes[i + 2] = attrName; - } - } - } - - int cut = name.indexOf(':'); - - if (cut == 0) { - checkRelaxed("illegal tag name: " + name); - } - - if (cut != -1) { - prefix = name.substring(0, cut); - name = name.substring(cut + 1); - } - - this.namespace = getNamespace(prefix); - - if (this.namespace == null) { - if (prefix != null) { - checkRelaxed("undefined prefix: " + prefix); - } - this.namespace = NO_NAMESPACE; - } - - return any; - } - - private String[] ensureCapacity(String[] arr, int required) { - if (arr.length >= required) { - return arr; - } - String[] bigger = new String[required + 16]; - System.arraycopy(arr, 0, bigger, 0, arr.length); - return bigger; - } - - private void checkRelaxed(String errorMessage) throws XmlPullParserException { - if (!relaxed) { - throw new XmlPullParserException(errorMessage, this, null); - } - if (error == null) { - error = "Error: " + errorMessage; - } - } - - public int next() throws XmlPullParserException, IOException { - return next(false); - } - - public int nextToken() throws XmlPullParserException, IOException { - return next(true); - } - - private int next(boolean justOneToken) throws IOException, XmlPullParserException { - if (reader == null) { - throw new XmlPullParserException("setInput() must be called first.", this, null); - } - - if (type == END_TAG) { - depth--; - } - - // degenerated needs to be handled before error because of possible - // processor expectations(!) - - if (degenerated) { - degenerated = false; - type = END_TAG; - return type; - } - - if (error != null) { - if (justOneToken) { - text = error; - type = COMMENT; - error = null; - return type; - } else { - error = null; - } - } - - type = peekType(false); - - if (type == XML_DECLARATION) { - readXmlDeclaration(); - type = peekType(false); - } - - text = null; - isWhitespace = true; - prefix = null; - name = null; - namespace = null; - attributeCount = -1; - boolean throwOnResolveFailure = !justOneToken; - - while (true) { - switch (type) { - - /* - * Return immediately after encountering a start tag, end tag, or - * the end of the document. - */ - case START_TAG: - parseStartTag(false, throwOnResolveFailure); - return type; - case END_TAG: - readEndTag(); - return type; - case END_DOCUMENT: - return type; - - /* - * Return after any text token when we're looking for a single - * token. Otherwise concatenate all text between tags. - */ - case ENTITY_REF: - if (justOneToken) { - StringBuilder entityTextBuilder = new StringBuilder(); - readEntity(entityTextBuilder, true, throwOnResolveFailure, ValueContext.TEXT); - text = entityTextBuilder.toString(); - break; - } - // fall-through - case TEXT: - text = readValue('<', !justOneToken, throwOnResolveFailure, ValueContext.TEXT); - if (depth == 0 && isWhitespace) { - type = IGNORABLE_WHITESPACE; - } - break; - case CDSECT: - read(START_CDATA); - text = readUntil(END_CDATA, true); - break; - - /* - * Comments, processing instructions and declarations are returned - * when we're looking for a single token. Otherwise they're skipped. - */ - case COMMENT: - String commentText = readComment(justOneToken); - if (justOneToken) { - text = commentText; - } - break; - case PROCESSING_INSTRUCTION: - read(START_PROCESSING_INSTRUCTION); - String processingInstruction = readUntil(END_PROCESSING_INSTRUCTION, justOneToken); - if (justOneToken) { - text = processingInstruction; - } - break; - case DOCDECL: - readDoctype(justOneToken); - if (parsedTopLevelStartTag) { - throw new XmlPullParserException("Unexpected token", this, null); - } - break; - - default: - throw new XmlPullParserException("Unexpected token", this, null); - } - - if (depth == 0 && (type == ENTITY_REF || type == TEXT || type == CDSECT)) { - throw new XmlPullParserException("Unexpected token", this, null); - } - - if (justOneToken) { - return type; - } - - if (type == IGNORABLE_WHITESPACE) { - text = null; - } - - /* - * We've read all that we can of a non-empty text block. Always - * report this as text, even if it was a CDATA block or entity - * reference. - */ - int peek = peekType(false); - if (text != null && !text.isEmpty() && peek < TEXT) { - type = TEXT; - return type; - } - - type = peek; - } - } - - /** - * Reads text until the specified delimiter is encountered. Consumes the - * text and the delimiter. - * - * @param returnText true to return the read text excluding the delimiter; - * false to return null. - */ - private String readUntil(char[] delimiter, boolean returnText) - throws IOException, XmlPullParserException { - int start = position; - StringBuilder result = null; - - if (returnText && text != null) { - result = new StringBuilder(); - result.append(text); - } - - search: - while (true) { - if (position + delimiter.length > limit) { - if (start < position && returnText) { - if (result == null) { - result = new StringBuilder(); - } - result.append(buffer, start, position - start); - } - if (!fillBuffer(delimiter.length)) { - checkRelaxed(UNEXPECTED_EOF); - type = COMMENT; - return null; - } - start = position; - } - - // TODO: replace with Arrays.equals(buffer, position, delimiter, 0, delimiter.length) - // when the VM has better method inlining - for (int i = 0; i < delimiter.length; i++) { - if (buffer[position + i] != delimiter[i]) { - position++; - continue search; - } - } - - break; - } - - int end = position; - position += delimiter.length; - - if (!returnText) { - return null; - } else if (result == null) { - return new String(buffer, start, end - start); - } else { - result.append(buffer, start, end - start); - return result.toString(); - } - } - - /** - * Returns true if an XML declaration was read. - */ - private void readXmlDeclaration() throws IOException, XmlPullParserException { - if (bufferStartLine != 0 || bufferStartColumn != 0 || position != 0) { - checkRelaxed("processing instructions must not start with xml"); - } - - read(START_PROCESSING_INSTRUCTION); - parseStartTag(true, true); - - if (attributeCount < 1 || !"version".equals(attributes[2])) { - checkRelaxed("version expected"); - } - - version = attributes[3]; - - int pos = 1; - - if (pos < attributeCount && "encoding".equals(attributes[2 + 4])) { - encoding = attributes[3 + 4]; - pos++; - } - - if (pos < attributeCount && "standalone".equals(attributes[4 * pos + 2])) { - String st = attributes[3 + 4 * pos]; - if ("yes".equals(st)) { - standalone = Boolean.TRUE; - } else if ("no".equals(st)) { - standalone = Boolean.FALSE; - } else { - checkRelaxed("illegal standalone value: " + st); - } - pos++; - } - - if (pos != attributeCount) { - checkRelaxed("unexpected attributes in XML declaration"); - } - - isWhitespace = true; - text = null; - } - - private String readComment(boolean returnText) throws IOException, XmlPullParserException { - read(START_COMMENT); - - if (relaxed) { - return readUntil(END_COMMENT, returnText); - } - - String commentText = readUntil(COMMENT_DOUBLE_DASH, returnText); - if (peekCharacter() != '>') { - throw new XmlPullParserException("Comments may not contain --", this, null); - } - position++; - return commentText; - } - - /** - * Read the document's DTD. Although this parser is non-validating, the DTD - * must be parsed to capture entity values and default attribute values. - */ - private void readDoctype(boolean saveDtdText) throws IOException, XmlPullParserException { - read(START_DOCTYPE); - - int startPosition = -1; - if (saveDtdText) { - bufferCapture = new StringBuilder(); - startPosition = position; - } - try { - skip(); - rootElementName = readName(); - readExternalId(true, true); - skip(); - if (peekCharacter() == '[') { - readInternalSubset(); - } - skip(); - } finally { - if (saveDtdText) { - bufferCapture.append(buffer, 0, position); - bufferCapture.delete(0, startPosition); - text = bufferCapture.toString(); - bufferCapture = null; - } - } - - read('>'); - skip(); - } - - /** - * Reads an external ID of one of these two forms: - * SYSTEM "quoted system name" - * PUBLIC "quoted public id" "quoted system name" - * - * If the system name is not required, this also supports lone public IDs of - * this form: - * PUBLIC "quoted public id" - * - * Returns true if any ID was read. - */ - private boolean readExternalId(boolean requireSystemName, boolean assignFields) - throws IOException, XmlPullParserException { - skip(); - int c = peekCharacter(); - - if (c == 'S') { - read(SYSTEM); - } else if (c == 'P') { - read(PUBLIC); - skip(); - if (assignFields) { - publicId = readQuotedId(true); - } else { - readQuotedId(false); - } - } else { - return false; - } - - skip(); - - if (!requireSystemName) { - int delimiter = peekCharacter(); - if (delimiter != '"' && delimiter != '\'') { - return true; // no system name! - } - } - - if (assignFields) { - systemId = readQuotedId(true); - } else { - readQuotedId(false); - } - return true; - } - - private static final char[] SINGLE_QUOTE = new char[] { '\'' }; - private static final char[] DOUBLE_QUOTE = new char[] { '"' }; - - /** - * Reads a quoted string, performing no entity escaping of the contents. - */ - private String readQuotedId(boolean returnText) throws IOException, XmlPullParserException { - int quote = peekCharacter(); - char[] delimiter; - if (quote == '"') { - delimiter = DOUBLE_QUOTE; - } else if (quote == '\'') { - delimiter = SINGLE_QUOTE; - } else { - throw new XmlPullParserException("Expected a quoted string", this, null); - } - position++; - return readUntil(delimiter, returnText); - } - - private void readInternalSubset() throws IOException, XmlPullParserException { - read('['); - - while (true) { - skip(); - if (peekCharacter() == ']') { - position++; - return; - } - - int declarationType = peekType(true); - switch (declarationType) { - case ELEMENTDECL: - readElementDeclaration(); - break; - - case ATTLISTDECL: - readAttributeListDeclaration(); - break; - - case ENTITYDECL: - readEntityDeclaration(); - break; - - case NOTATIONDECL: - readNotationDeclaration(); - break; - - case PROCESSING_INSTRUCTION: - read(START_PROCESSING_INSTRUCTION); - readUntil(END_PROCESSING_INSTRUCTION, false); - break; - - case COMMENT: - readComment(false); - break; - - case PARAMETER_ENTITY_REF: - throw new XmlPullParserException( - "Parameter entity references are not supported", this, null); - - default: - throw new XmlPullParserException("Unexpected token", this, null); - } - } - } - - /** - * Read an element declaration. This contains a name and a content spec. - * - * - * - */ - private void readElementDeclaration() throws IOException, XmlPullParserException { - read(START_ELEMENT); - skip(); - readName(); - readContentSpec(); - skip(); - read('>'); - } - - /** - * Read an element content spec. This is a regular expression-like pattern - * of names or other content specs. The following operators are supported: - * sequence: (a,b,c) - * choice: (a|b|c) - * optional: a? - * one or more: a+ - * any number: a* - * - * The special name '#PCDATA' is permitted but only if it is the first - * element of the first group: - * (#PCDATA|a|b) - * - * The top-level element must be either a choice, a sequence, or one of the - * special names EMPTY and ANY. - */ - private void readContentSpec() throws IOException, XmlPullParserException { - // this implementation is very lenient; it scans for balanced parens only - skip(); - int c = peekCharacter(); - if (c == '(') { - int depth = 0; - do { - if (c == '(') { - depth++; - } else if (c == ')') { - depth--; - } else if (c == -1) { - throw new XmlPullParserException( - "Unterminated element content spec", this, null); - } - position++; - c = peekCharacter(); - } while (depth > 0); - - if (c == '*' || c == '?' || c == '+') { - position++; - } - } else if (c == EMPTY[0]) { - read(EMPTY); - } else if (c == ANY[0]) { - read(ANY); - } else { - throw new XmlPullParserException("Expected element content spec", this, null); - } - } - - /** - * Reads an attribute list declaration such as the following: - * - * - * Each attribute has a name, type and default. - * - * Types are one of the built-in types (CDATA, ID, IDREF, IDREFS, ENTITY, - * ENTITIES, NMTOKEN, or NMTOKENS), an enumerated type "(list|of|options)" - * or NOTATION followed by an enumerated type. - * - * The default is either #REQUIRED, #IMPLIED, #FIXED, a quoted value, or - * #FIXED with a quoted value. - */ - private void readAttributeListDeclaration() throws IOException, XmlPullParserException { - read(START_ATTLIST); - skip(); - String elementName = readName(); - - while (true) { - skip(); - int c = peekCharacter(); - if (c == '>') { - position++; - return; - } - - // attribute name - String attributeName = readName(); - - // attribute type - skip(); - if (position + 1 >= limit && !fillBuffer(2)) { - throw new XmlPullParserException("Malformed attribute list", this, null); - } - if (buffer[position] == NOTATION[0] && buffer[position + 1] == NOTATION[1]) { - read(NOTATION); - skip(); - } - c = peekCharacter(); - if (c == '(') { - position++; - while (true) { - skip(); - readName(); - skip(); - c = peekCharacter(); - if (c == ')') { - position++; - break; - } else if (c == '|') { - position++; - } else { - throw new XmlPullParserException("Malformed attribute type", this, null); - } - } - } else { - readName(); - } - - // default value - skip(); - c = peekCharacter(); - if (c == '#') { - position++; - c = peekCharacter(); - if (c == 'R') { - read(REQUIRED); - } else if (c == 'I') { - read(IMPLIED); - } else if (c == 'F') { - read(FIXED); - } else { - throw new XmlPullParserException("Malformed attribute type", this, null); - } - skip(); - c = peekCharacter(); - } - if (c == '"' || c == '\'') { - position++; - // TODO: does this do escaping correctly? - String value = readValue((char) c, true, true, ValueContext.ATTRIBUTE); - if (peekCharacter() == c) { - position++; - } - defineAttributeDefault(elementName, attributeName, value); - } - } - } - - private void defineAttributeDefault(String elementName, String attributeName, String value) { - if (defaultAttributes == null) { - defaultAttributes = new HashMap>(); - } - Map elementAttributes = defaultAttributes.get(elementName); - if (elementAttributes == null) { - elementAttributes = new HashMap(); - defaultAttributes.put(elementName, elementAttributes); - } - elementAttributes.put(attributeName, value); - } - - /** - * Read an entity declaration. The value of internal entities are inline: - * - * - * The values of external entities must be retrieved by URL or path: - * - * - * - * - * Entities may be general or parameterized. Parameterized entities are - * marked by a percent sign. Such entities may only be used in the DTD: - * - */ - private void readEntityDeclaration() throws IOException, XmlPullParserException { - read(START_ENTITY); - boolean generalEntity = true; - - skip(); - if (peekCharacter() == '%') { - generalEntity = false; - position++; - skip(); - } - - String name = readName(); - - skip(); - int quote = peekCharacter(); - String entityValue; - if (quote == '"' || quote == '\'') { - position++; - entityValue = readValue((char) quote, true, false, ValueContext.ENTITY_DECLARATION); - if (peekCharacter() == quote) { - position++; - } - } else if (readExternalId(true, false)) { - /* - * Map external entities to the empty string. This is dishonest, - * but it's consistent with Android's Expat pull parser. - */ - entityValue = ""; - skip(); - if (peekCharacter() == NDATA[0]) { - read(NDATA); - skip(); - readName(); - } - } else { - throw new XmlPullParserException("Expected entity value or external ID", this, null); - } - - if (generalEntity && processDocDecl) { - if (documentEntities == null) { - documentEntities = new HashMap(); - } - documentEntities.put(name, entityValue.toCharArray()); - } - - skip(); - read('>'); - } - - private void readNotationDeclaration() throws IOException, XmlPullParserException { - read(START_NOTATION); - skip(); - readName(); - if (!readExternalId(false, false)) { - throw new XmlPullParserException( - "Expected external ID or public ID for notation", this, null); - } - skip(); - read('>'); - } - - private void readEndTag() throws IOException, XmlPullParserException { - read('<'); - read('/'); - name = readName(); // TODO: pass the expected name in as a hint? - skip(); - read('>'); - - int sp = (depth - 1) * 4; - - if (depth == 0) { - checkRelaxed("read end tag " + name + " with no tags open"); - type = COMMENT; - return; - } - - if (name.equals(elementStack[sp + 3])) { - namespace = elementStack[sp]; - prefix = elementStack[sp + 1]; - name = elementStack[sp + 2]; - } else if (!relaxed) { - throw new XmlPullParserException( - "expected: /" + elementStack[sp + 3] + " read: " + name, this, null); - } - } - - /** - * Returns the type of the next token. - */ - private int peekType(boolean inDeclaration) throws IOException, XmlPullParserException { - if (position >= limit && !fillBuffer(1)) { - return END_DOCUMENT; - } - - switch (buffer[position]) { - case '&': - return ENTITY_REF; // & - case '<': - if (position + 3 >= limit && !fillBuffer(4)) { - throw new XmlPullParserException("Dangling <", this, null); - } - - switch (buffer[position + 1]) { - case '/': - return END_TAG; // = limit && !fillBuffer(1)) { - checkRelaxed(UNEXPECTED_EOF); - return; - } - - int c = buffer[position]; - - if (xmldecl) { - if (c == '?') { - position++; - read('>'); - return; - } - } else { - if (c == '/') { - degenerated = true; - position++; - skip(); - read('>'); - break; - } else if (c == '>') { - position++; - break; - } - } - - String attrName = readName(); - - int i = (attributeCount++) * 4; - attributes = ensureCapacity(attributes, i + 4); - attributes[i] = ""; - attributes[i + 1] = null; - attributes[i + 2] = attrName; - - skip(); - if (position >= limit && !fillBuffer(1)) { - checkRelaxed(UNEXPECTED_EOF); - return; - } - - if (buffer[position] == '=') { - position++; - - skip(); - if (position >= limit && !fillBuffer(1)) { - checkRelaxed(UNEXPECTED_EOF); - return; - } - char delimiter = buffer[position]; - - if (delimiter == '\'' || delimiter == '"') { - position++; - } else if (relaxed) { - delimiter = ' '; - } else { - throw new XmlPullParserException("attr value delimiter missing!", this, null); - } - - attributes[i + 3] = readValue(delimiter, true, throwOnResolveFailure, - ValueContext.ATTRIBUTE); - - if (delimiter != ' ' && peekCharacter() == delimiter) { - position++; // end quote - } - } else if (relaxed) { - attributes[i + 3] = attrName; - } else { - checkRelaxed("Attr.value missing f. " + attrName); - attributes[i + 3] = attrName; - } - } - - int sp = depth++ * 4; - if (depth == 1) { - parsedTopLevelStartTag = true; - } - elementStack = ensureCapacity(elementStack, sp + 4); - elementStack[sp + 3] = name; - - if (depth >= nspCounts.length) { - int[] bigger = new int[depth + 4]; - System.arraycopy(nspCounts, 0, bigger, 0, nspCounts.length); - nspCounts = bigger; - } - - nspCounts[depth] = nspCounts[depth - 1]; - - if (processNsp) { - adjustNsp(); - } else { - namespace = ""; - } - - // For consistency with Expat, add default attributes after fixing namespaces. - if (defaultAttributes != null) { - Map elementDefaultAttributes = defaultAttributes.get(name); - if (elementDefaultAttributes != null) { - for (Map.Entry entry : elementDefaultAttributes.entrySet()) { - if (getAttributeValue(null, entry.getKey()) != null) { - continue; // an explicit value overrides the default - } - - int i = (attributeCount++) * 4; - attributes = ensureCapacity(attributes, i + 4); - attributes[i] = ""; - attributes[i + 1] = null; - attributes[i + 2] = entry.getKey(); - attributes[i + 3] = entry.getValue(); - } - } - } - - elementStack[sp] = namespace; - elementStack[sp + 1] = prefix; - elementStack[sp + 2] = name; - } - - /** - * Reads an entity reference from the buffer, resolves it, and writes the - * resolved entity to {@code out}. If the entity cannot be read or resolved, - * {@code out} will contain the partial entity reference. - */ - private void readEntity(StringBuilder out, boolean isEntityToken, boolean throwOnResolveFailure, - ValueContext valueContext) throws IOException, XmlPullParserException { - int start = out.length(); - - if (buffer[position++] != '&') { - throw new AssertionError(); - } - - out.append('&'); - - while (true) { - int c = peekCharacter(); - - if (c == ';') { - out.append(';'); - position++; - break; - - } else if (c >= 128 - || (c >= '0' && c <= '9') - || (c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || c == '_' - || c == '-' - || c == '#') { - position++; - out.append((char) c); - - } else if (relaxed) { - // intentionally leave the partial reference in 'out' - return; - - } else { - throw new XmlPullParserException("unterminated entity ref", this, null); - } - } - - String code = out.substring(start + 1, out.length() - 1); - - if (isEntityToken) { - name = code; - } - - if (code.startsWith("#")) { - try { - int c = code.startsWith("#x") - ? Integer.parseInt(code.substring(2), 16) - : Integer.parseInt(code.substring(1)); - out.delete(start, out.length()); - out.appendCodePoint(c); - unresolved = false; - return; - } catch (NumberFormatException notANumber) { - throw new XmlPullParserException("Invalid character reference: &" + code); - } catch (IllegalArgumentException invalidCodePoint) { - throw new XmlPullParserException("Invalid character reference: &" + code); - } - } - - if (valueContext == ValueContext.ENTITY_DECLARATION) { - // keep the unresolved &code; in the text to resolve later - return; - } - - String defaultEntity = DEFAULT_ENTITIES.get(code); - if (defaultEntity != null) { - out.delete(start, out.length()); - unresolved = false; - out.append(defaultEntity); - return; - } - - char[] resolved; - if (documentEntities != null && (resolved = documentEntities.get(code)) != null) { - out.delete(start, out.length()); - unresolved = false; - if (processDocDecl) { - pushContentSource(resolved); // parse the entity as XML - } else { - out.append(resolved); // include the entity value as text - } - return; - } - - /* - * The parser skipped an external DTD, and now we've encountered an - * unknown entity that could have been declared there. Map it to the - * empty string. This is dishonest, but it's consistent with Android's - * old ExpatPullParser. - */ - if (systemId != null) { - out.delete(start, out.length()); - return; - } - - // keep the unresolved entity "&code;" in the text for relaxed clients - unresolved = true; - if (throwOnResolveFailure) { - checkRelaxed("unresolved: &" + code + ";"); - } - } - - /** - * Where a value is found impacts how that value is interpreted. For - * example, in attributes, "\n" must be replaced with a space character. In - * text, "]]>" is forbidden. In entity declarations, named references are - * not resolved. - */ - enum ValueContext { - ATTRIBUTE, - TEXT, - ENTITY_DECLARATION - } - - /** - * Returns the current text or attribute value. This also has the side - * effect of setting isWhitespace to false if a non-whitespace character is - * encountered. - * - * @param delimiter {@code <} for text, {@code "} and {@code '} for quoted - * attributes, or a space for unquoted attributes. - */ - private String readValue(char delimiter, boolean resolveEntities, boolean throwOnResolveFailure, - ValueContext valueContext) throws IOException, XmlPullParserException { - - /* - * This method returns all of the characters from the current position - * through to an appropriate delimiter. - * - * If we're lucky (which we usually are), we'll return a single slice of - * the buffer. This fast path avoids allocating a string builder. - * - * There are 6 unlucky characters we could encounter: - * - "&": entities must be resolved. - * - "%": parameter entities are unsupported in entity values. - * - "<": this isn't permitted in attributes unless relaxed. - * - "]": this requires a lookahead to defend against the forbidden - * CDATA section delimiter "]]>". - * - "\r": If a "\r" is followed by a "\n", we discard the "\r". If it - * isn't followed by "\n", we replace "\r" with either a "\n" - * in text nodes or a space in attribute values. - * - "\n": In attribute values, "\n" must be replaced with a space. - * - * We could also get unlucky by needing to refill the buffer midway - * through the text. - */ - - int start = position; - StringBuilder result = null; - - // if a text section was already started, prefix the start - if (valueContext == ValueContext.TEXT && text != null) { - result = new StringBuilder(); - result.append(text); - } - - while (true) { - - /* - * Make sure we have at least a single character to read from the - * buffer. This mutates the buffer, so save the partial result - * to the slow path string builder first. - */ - if (position >= limit) { - if (start < position) { - if (result == null) { - result = new StringBuilder(); - } - result.append(buffer, start, position - start); - } - if (!fillBuffer(1)) { - return result != null ? result.toString() : ""; - } - start = position; - } - - char c = buffer[position]; - - if (c == delimiter - || (delimiter == ' ' && (c <= ' ' || c == '>')) - || c == '&' && !resolveEntities) { - break; - } - - if (c != '\r' - && (c != '\n' || valueContext != ValueContext.ATTRIBUTE) - && c != '&' - && c != '<' - && (c != ']' || valueContext != ValueContext.TEXT) - && (c != '%' || valueContext != ValueContext.ENTITY_DECLARATION)) { - isWhitespace &= (c <= ' '); - position++; - continue; - } - - /* - * We've encountered an unlucky character! Convert from fast - * path to slow path if we haven't done so already. - */ - if (result == null) { - result = new StringBuilder(); - } - result.append(buffer, start, position - start); - - if (c == '\r') { - if ((position + 1 < limit || fillBuffer(2)) && buffer[position + 1] == '\n') { - position++; - } - c = (valueContext == ValueContext.ATTRIBUTE) ? ' ' : '\n'; - - } else if (c == '\n') { - c = ' '; - - } else if (c == '&') { - isWhitespace = false; // TODO: what if the entity resolves to whitespace? - readEntity(result, false, throwOnResolveFailure, valueContext); - start = position; - continue; - - } else if (c == '<') { - if (valueContext == ValueContext.ATTRIBUTE) { - checkRelaxed("Illegal: \"<\" inside attribute value"); - } - isWhitespace = false; - - } else if (c == ']') { - if ((position + 2 < limit || fillBuffer(3)) - && buffer[position + 1] == ']' && buffer[position + 2] == '>') { - checkRelaxed("Illegal: \"]]>\" outside CDATA section"); - } - isWhitespace = false; - - } else if (c == '%') { - throw new XmlPullParserException("This parser doesn't support parameter entities", - this, null); - - } else { - throw new AssertionError(); - } - - position++; - result.append(c); - start = position; - } - - if (result == null) { - return new String(buffer, start, position - start); - } else { - result.append(buffer, start, position - start); - return result.toString(); - } - } - - private void read(char expected) throws IOException, XmlPullParserException { - int c = peekCharacter(); - if (c != expected) { - checkRelaxed("expected: '" + expected + "' actual: '" + ((char) c) + "'"); - if (c == -1) { - return; // On EOF, don't move position beyond limit - } - } - position++; - } - - private void read(char[] chars) throws IOException, XmlPullParserException { - if (position + chars.length > limit && !fillBuffer(chars.length)) { - checkRelaxed("expected: '" + new String(chars) + "' but was EOF"); - return; - } - - // TODO: replace with Arrays.equals(buffer, position, delimiter, 0, delimiter.length) - // when the VM has better method inlining - for (int i = 0; i < chars.length; i++) { - if (buffer[position + i] != chars[i]) { - checkRelaxed("expected: \"" + new String(chars) + "\" but was \"" - + new String(buffer, position, chars.length) + "...\""); - } - } - - position += chars.length; - } - - private int peekCharacter() throws IOException, XmlPullParserException { - if (position < limit || fillBuffer(1)) { - return buffer[position]; - } - return -1; - } - - /** - * Returns true once {@code limit - position >= minimum}. If the data is - * exhausted before that many characters are available, this returns - * false. - */ - private boolean fillBuffer(int minimum) throws IOException, XmlPullParserException { - // If we've exhausted the current content source, remove it - while (nextContentSource != null) { - if (position < limit) { - throw new XmlPullParserException("Unbalanced entity!", this, null); - } - popContentSource(); - if (limit - position >= minimum) { - return true; - } - } - - // Before clobbering the old characters, update where buffer starts - for (int i = 0; i < position; i++) { - if (buffer[i] == '\n') { - bufferStartLine++; - bufferStartColumn = 0; - } else { - bufferStartColumn++; - } - } - - if (bufferCapture != null) { - bufferCapture.append(buffer, 0, position); - } - - if (limit != position) { - limit -= position; - System.arraycopy(buffer, position, buffer, 0, limit); - } else { - limit = 0; - } - - position = 0; - int total; - while ((total = reader.read(buffer, limit, buffer.length - limit)) != -1) { - limit += total; - if (limit >= minimum) { - return true; - } - } - return false; - } - - /** - * Returns an element or attribute name. This is always non-empty for - * non-relaxed parsers. - */ - private String readName() throws IOException, XmlPullParserException { - if (position >= limit && !fillBuffer(1)) { - checkRelaxed("name expected"); - return ""; - } - - int start = position; - StringBuilder result = null; - - // read the first character - char c = buffer[position]; - if ((c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || c == '_' - || c == ':' - || c >= '\u00c0' // TODO: check the XML spec - || relaxed) { - position++; - } else { - checkRelaxed("name expected"); - return ""; - } - - while (true) { - /* - * Make sure we have at least a single character to read from the - * buffer. This mutates the buffer, so save the partial result - * to the slow path string builder first. - */ - if (position >= limit) { - if (result == null) { - result = new StringBuilder(); - } - result.append(buffer, start, position - start); - if (!fillBuffer(1)) { - return result.toString(); - } - start = position; - } - - // read another character - c = buffer[position]; - if ((c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || (c >= '0' && c <= '9') - || c == '_' - || c == '-' - || c == ':' - || c == '.' - || c >= '\u00b7') { // TODO: check the XML spec - position++; - continue; - } - - // we encountered a non-name character. done! - if (result == null) { - return new String(buffer, start, position - start); - } else { - result.append(buffer, start, position - start); - return result.toString(); - } - } - } - - private void skip() throws IOException, XmlPullParserException { - while (position < limit || fillBuffer(1)) { - int c = buffer[position]; - if (c > ' ') { - break; - } - position++; - } - } - - // public part starts here... - - public void setInput(Reader reader) throws XmlPullParserException { - this.reader = reader; - - type = START_DOCUMENT; - parsedTopLevelStartTag = false; - name = null; - namespace = null; - degenerated = false; - attributeCount = -1; - encoding = null; - version = null; - standalone = null; - - if (reader == null) { - return; - } - - position = 0; - limit = 0; - bufferStartLine = 0; - bufferStartColumn = 0; - depth = 0; - documentEntities = null; - } - - public void setInput(InputStream is, String charset) throws XmlPullParserException { - position = 0; - limit = 0; - boolean detectCharset = (charset == null); - - if (is == null) { - throw new IllegalArgumentException("is == null"); - } - - try { - if (detectCharset) { - // read the four bytes looking for an indication of the encoding in use - int firstFourBytes = 0; - while (limit < 4) { - int i = is.read(); - if (i == -1) { - break; - } - firstFourBytes = (firstFourBytes << 8) | i; - buffer[limit++] = (char) i; - } - - if (limit == 4) { - switch (firstFourBytes) { - case 0x00000FEFF: // UTF-32BE BOM - charset = "UTF-32BE"; - limit = 0; - break; - - case 0x0FFFE0000: // UTF-32LE BOM - charset = "UTF-32LE"; - limit = 0; - break; - - case 0x0000003c: // '<' in UTF-32BE - charset = "UTF-32BE"; - buffer[0] = '<'; - limit = 1; - break; - - case 0x03c000000: // '<' in UTF-32LE - charset = "UTF-32LE"; - buffer[0] = '<'; - limit = 1; - break; - - case 0x0003c003f: // "') { - String s = new String(buffer, 0, limit); - int i0 = s.indexOf("encoding"); - if (i0 != -1) { - while (s.charAt(i0) != '"' && s.charAt(i0) != '\'') { - i0++; - } - char deli = s.charAt(i0++); - int i1 = s.indexOf(deli, i0); - charset = s.substring(i0, i1); - } - break; - } - } - break; - - default: - // handle a byte order mark followed by something other than - * is still at character 0. - */ - if (!detectCharset && peekCharacter() == 0xfeff) { - limit--; - System.arraycopy(buffer, 1, buffer, 0, limit); - } - } catch (Exception e) { - throw new XmlPullParserException("Invalid stream or encoding: " + e, this, e); - } - } - - public void close() throws IOException { - if (reader != null) { - reader.close(); - } - } - - public boolean getFeature(String feature) { - if (XmlPullParser.FEATURE_PROCESS_NAMESPACES.equals(feature)) { - return processNsp; - } else if (FEATURE_RELAXED.equals(feature)) { - return relaxed; - } else if (FEATURE_PROCESS_DOCDECL.equals(feature)) { - return processDocDecl; - } else { - return false; - } - } - - public String getInputEncoding() { - return encoding; - } - - public void defineEntityReplacementText(String entity, String value) - throws XmlPullParserException { - if (processDocDecl) { - throw new IllegalStateException( - "Entity replacement text may not be defined with DOCTYPE processing enabled."); - } - if (reader == null) { - throw new IllegalStateException( - "Entity replacement text must be defined after setInput()"); - } - if (documentEntities == null) { - documentEntities = new HashMap(); - } - documentEntities.put(entity, value.toCharArray()); - } - - public Object getProperty(String property) { - if (property.equals(PROPERTY_XMLDECL_VERSION)) { - return version; - } else if (property.equals(PROPERTY_XMLDECL_STANDALONE)) { - return standalone; - } else if (property.equals(PROPERTY_LOCATION)) { - return location != null ? location : reader.toString(); - } else { - return null; - } - } - - /** - * Returns the root element's name if it was declared in the DTD. This - * equals the first tag's name for valid documents. - */ - public String getRootElementName() { - return rootElementName; - } - - /** - * Returns the document's system ID if it was declared. This is typically a - * string like {@code http://www.w3.org/TR/html4/strict.dtd}. - */ - public String getSystemId() { - return systemId; - } - - /** - * Returns the document's public ID if it was declared. This is typically a - * string like {@code -//W3C//DTD HTML 4.01//EN}. - */ - public String getPublicId() { - return publicId; - } - - public int getNamespaceCount(int depth) { - if (depth > this.depth) { - throw new IndexOutOfBoundsException(); - } - return nspCounts[depth]; - } - - public String getNamespacePrefix(int pos) { - return nspStack[pos * 2]; - } - - public String getNamespaceUri(int pos) { - return nspStack[(pos * 2) + 1]; - } - - public String getNamespace(String prefix) { - if ("xml".equals(prefix)) { - return "http://www.w3.org/XML/1998/namespace"; - } - if ("xmlns".equals(prefix)) { - return "http://www.w3.org/2000/xmlns/"; - } - - for (int i = (getNamespaceCount(depth) << 1) - 2; i >= 0; i -= 2) { - if (prefix == null) { - if (nspStack[i] == null) { - return nspStack[i + 1]; - } - } else if (prefix.equals(nspStack[i])) { - return nspStack[i + 1]; - } - } - return null; - } - - public int getDepth() { - return depth; - } - - public String getPositionDescription() { - StringBuilder buf = new StringBuilder(type < TYPES.length ? TYPES[type] : "unknown"); - buf.append(' '); - - if (type == START_TAG || type == END_TAG) { - if (degenerated) { - buf.append("(empty) "); - } - buf.append('<'); - if (type == END_TAG) { - buf.append('/'); - } - - if (prefix != null) { - buf.append("{" + namespace + "}" + prefix + ":"); - } - buf.append(name); - - int cnt = attributeCount * 4; - for (int i = 0; i < cnt; i += 4) { - buf.append(' '); - if (attributes[i + 1] != null) { - buf.append("{" + attributes[i] + "}" + attributes[i + 1] + ":"); - } - buf.append(attributes[i + 2] + "='" + attributes[i + 3] + "'"); - } - - buf.append('>'); - } else if (type == IGNORABLE_WHITESPACE) { - ; - } else if (type != TEXT) { - buf.append(getText()); - } else if (isWhitespace) { - buf.append("(whitespace)"); - } else { - String text = getText(); - if (text.length() > 16) { - text = text.substring(0, 16) + "..."; - } - buf.append(text); - } - - buf.append("@" + getLineNumber() + ":" + getColumnNumber()); - if (location != null) { - buf.append(" in "); - buf.append(location); - } else if (reader != null) { - buf.append(" in "); - buf.append(reader.toString()); - } - return buf.toString(); - } - - public int getLineNumber() { - int result = bufferStartLine; - for (int i = 0; i < position; i++) { - if (buffer[i] == '\n') { - result++; - } - } - return result + 1; // the first line is '1' - } - - public int getColumnNumber() { - int result = bufferStartColumn; - for (int i = 0; i < position; i++) { - if (buffer[i] == '\n') { - result = 0; - } else { - result++; - } - } - return result + 1; // the first column is '1' - } - - public boolean isWhitespace() throws XmlPullParserException { - if (type != TEXT && type != IGNORABLE_WHITESPACE && type != CDSECT) { - throw new XmlPullParserException(ILLEGAL_TYPE, this, null); - } - return isWhitespace; - } - - public String getText() { - if (type < TEXT || (type == ENTITY_REF && unresolved)) { - return null; - } else if (text == null) { - return ""; - } else { - return text; - } - } - - public char[] getTextCharacters(int[] poslen) { - String text = getText(); - if (text == null) { - poslen[0] = -1; - poslen[1] = -1; - return null; - } - char[] result = text.toCharArray(); - poslen[0] = 0; - poslen[1] = result.length; - return result; - } - - public String getNamespace() { - return namespace; - } - - public String getName() { - return name; - } - - public String getPrefix() { - return prefix; - } - - public boolean isEmptyElementTag() throws XmlPullParserException { - if (type != START_TAG) { - throw new XmlPullParserException(ILLEGAL_TYPE, this, null); - } - return degenerated; - } - - public int getAttributeCount() { - return attributeCount; - } - - public String getAttributeType(int index) { - return "CDATA"; - } - - public boolean isAttributeDefault(int index) { - return false; - } - - public String getAttributeNamespace(int index) { - if (index >= attributeCount) { - throw new IndexOutOfBoundsException(); - } - return attributes[index * 4]; - } - - public String getAttributeName(int index) { - if (index >= attributeCount) { - throw new IndexOutOfBoundsException(); - } - return attributes[(index * 4) + 2]; - } - - public String getAttributePrefix(int index) { - if (index >= attributeCount) { - throw new IndexOutOfBoundsException(); - } - return attributes[(index * 4) + 1]; - } - - public String getAttributeValue(int index) { - if (index >= attributeCount) { - throw new IndexOutOfBoundsException(); - } - return attributes[(index * 4) + 3]; - } - - public String getAttributeValue(String namespace, String name) { - for (int i = (attributeCount * 4) - 4; i >= 0; i -= 4) { - if (attributes[i + 2].equals(name) - && (namespace == null || attributes[i].equals(namespace))) { - return attributes[i + 3]; - } - } - - return null; - } - - public int getEventType() throws XmlPullParserException { - return type; - } - - // utility methods to make XML parsing easier ... - - public int nextTag() throws XmlPullParserException, IOException { - next(); - if (type == TEXT && isWhitespace) { - next(); - } - - if (type != END_TAG && type != START_TAG) { - throw new XmlPullParserException("unexpected type", this, null); - } - - return type; - } - - public void require(int type, String namespace, String name) - throws XmlPullParserException, IOException { - if (type != this.type - || (namespace != null && !namespace.equals(getNamespace())) - || (name != null && !name.equals(getName()))) { - throw new XmlPullParserException( - "expected: " + TYPES[type] + " {" + namespace + "}" + name, this, null); - } - } - - public String nextText() throws XmlPullParserException, IOException { - if (type != START_TAG) { - throw new XmlPullParserException("precondition: START_TAG", this, null); - } - - next(); - - String result; - if (type == TEXT) { - result = getText(); - next(); - } else { - result = ""; - } - - if (type != END_TAG) { - throw new XmlPullParserException("END_TAG expected", this, null); - } - - return result; - } - - public void setFeature(String feature, boolean value) throws XmlPullParserException { - if (XmlPullParser.FEATURE_PROCESS_NAMESPACES.equals(feature)) { - processNsp = value; - } else if (XmlPullParser.FEATURE_PROCESS_DOCDECL.equals(feature)) { - processDocDecl = value; - } else if (FEATURE_RELAXED.equals(feature)) { - relaxed = value; - } else { - throw new XmlPullParserException("unsupported feature: " + feature, this, null); - } - } - - public void setProperty(String property, Object value) throws XmlPullParserException { - if (property.equals(PROPERTY_LOCATION)) { - location = String.valueOf(value); - } else { - throw new XmlPullParserException("unsupported property: " + property); - } - } - static class ContentSource { - private final ContentSource next; - private final char[] buffer; - private final int position; - private final int limit; - ContentSource(ContentSource next, char[] buffer, int position, int limit) { - this.next = next; - this.buffer = buffer; - this.position = position; - this.limit = limit; - } - } - private void pushContentSource(char[] newBuffer) { - nextContentSource = new ContentSource(nextContentSource, buffer, position, limit); - buffer = newBuffer; - position = 0; - limit = newBuffer.length; - } - - /** - * Replaces the current exhausted buffer with the next buffer in the chain. - */ - private void popContentSource() { - buffer = nextContentSource.buffer; - position = nextContentSource.position; - limit = nextContentSource.limit; - nextContentSource = nextContentSource.next; - } -} diff --git a/src/ARSCLib/com/android/org/kxml2/io/KXmlSerializer.java b/src/ARSCLib/com/android/org/kxml2/io/KXmlSerializer.java deleted file mode 100644 index 53aa6f69..00000000 --- a/src/ARSCLib/com/android/org/kxml2/io/KXmlSerializer.java +++ /dev/null @@ -1,565 +0,0 @@ -/* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. */ - -package com.android.org.kxml2.io; - -import java.io.*; -import java.util.Arrays; -import java.util.Locale; -import org.xmlpull.v1.*; - -public class KXmlSerializer implements XmlSerializer { - - private static final int BUFFER_LEN = 8192; - private final char[] mText = new char[BUFFER_LEN]; - private int mPos; - private Writer writer; - private boolean pending; - private int auto; - private int depth; - private String[] elementStack = new String[12]; - private int[] nspCounts = new int[4]; - private String[] nspStack = new String[8]; - private boolean[] indent = new boolean[4]; - private boolean firstAttributeWritten; - private int indentAttributeReference; - private boolean unicode; - private String encoding; - - private void append(char c) throws IOException { - if(mPos >= BUFFER_LEN){ - flushBuffer(); - } - mText[mPos++] = c; - } - - private void append(String str, int i, int length) throws IOException { - while (length > 0){ - if(mPos == BUFFER_LEN){ - flushBuffer(); - } - int batch = BUFFER_LEN - mPos; - if(batch > length){ - batch = length; - } - str.getChars(i, i + batch, mText, mPos); - i += batch; - length -= batch; - mPos += batch; - } - } - - private void appendSpace(int length) throws IOException { - while (length > 0){ - if(mPos == BUFFER_LEN){ - flushBuffer(); - } - int batch = BUFFER_LEN - mPos; - if(batch > length){ - batch = length; - } - Arrays.fill(mText, mPos, mPos + batch, ' '); - length -= batch; - mPos += batch; - } - } - - private void append(String str) throws IOException { - append(str, 0, str.length()); - } - - private void flushBuffer() throws IOException { - if(mPos > 0){ - writer.write(mText, 0, mPos); - writer.flush(); - mPos = 0; - } - } - - private void check(boolean close) throws IOException { - if(!pending) - return; - - depth++; - pending = false; - - if(indent.length <= depth){ - boolean[] hlp = new boolean[depth + 4]; - System.arraycopy(indent, 0, hlp, 0, depth); - indent = hlp; - } - indent[depth] = indent[depth - 1]; - - for (int i = nspCounts[depth - 1]; i < nspCounts[depth]; i++){ - append(" xmlns"); - if(!nspStack[i * 2].isEmpty()){ - append(':'); - append(nspStack[i * 2]); - } - else if(getNamespace().isEmpty() && !nspStack[i * 2 + 1].isEmpty()) - throw new IllegalStateException("Cannot set default namespace for elements in no namespace"); - append("=\""); - writeEscaped(nspStack[i * 2 + 1], '"'); - append('"'); - } - - if(nspCounts.length <= depth + 1){ - int[] hlp = new int[depth + 8]; - System.arraycopy(nspCounts, 0, hlp, 0, depth + 1); - nspCounts = hlp; - } - - nspCounts[depth + 1] = nspCounts[depth]; - if(close){ - append(" />"); - } else { - append('>'); - } - } - - private void writeEscaped(String s, int quot) throws IOException { - for (int i = 0; i < s.length(); i++){ - char c = s.charAt(i); - switch (c){ - case '\n': - case '\r': - case '\t': - if(quot == -1) - append(c); - else - append("&#"+((int) c)+';'); - break; - case '&' : - append("&"); - break; - case '>' : - append(">"); - break; - case '<' : - append("<"); - break; - default: - if(c == quot){ - append(c == '"' ? """ : "'"); - break; - } - boolean allowedInXml = (c >= 0x20 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xfffd); - if(allowedInXml){ - if(unicode || c < 127){ - append(c); - } else { - append("&#" + ((int) c) + ";"); - } - } else if(Character.isHighSurrogate(c) && i < s.length() - 1){ - writeSurrogate(c, s.charAt(i + 1)); - ++i; - } else { - reportInvalidCharacter(c); - } - } - } - } - private static void reportInvalidCharacter(char ch){ - throw new IllegalArgumentException("Illegal character (U+" + Integer.toHexString((int) ch) + ")"); - } - @Override - public void docdecl(String dd) throws IOException { - append("'); - } - @Override - public void endDocument() throws IOException { - while (depth > 0){ - endTag(elementStack[depth * 3 - 3], elementStack[depth * 3 - 1]); - } - flush(); - } - @Override - public void entityRef(String name) throws IOException { - check(false); - append('&'); - append(name); - append(';'); - } - @Override - public boolean getFeature(String name){ - return "http://xmlpull.org/v1/doc/features.html#indent-output" - .equals(name) && indent[depth]; - } - @Override - public String getPrefix(String namespace, boolean create){ - try { - return getPrefix(namespace, false, create); - } - catch (IOException e){ - throw new RuntimeException(e.toString()); - } - } - private String getPrefix(String namespace, boolean includeDefault, boolean create) - throws IOException { - int[] nspCounts = this.nspCounts; - int depth = this.depth; - String[] nspStack = this.nspStack; - - for (int i = nspCounts[depth + 1] * 2 - 2; i >= 0;i -= 2){ - if(nspStack[i + 1].equals(namespace) - && (includeDefault - || !nspStack[i].isEmpty())){ - String cand = nspStack[i]; - for (int j = i + 2; j < nspCounts[depth + 1] * 2; j++){ - if(nspStack[j].equals(cand)){ - cand = null; - break; - } - } - if(cand != null){ - return cand; - } - } - } - if(!create){ - return null; - } - - String prefix; - - if(namespace.isEmpty()) { - prefix = ""; - }else { - do { - prefix = "n" + (auto++); - for (int i = nspCounts[depth + 1] * 2 - 2;i >= 0;i -= 2){ - if(prefix.equals(nspStack[i])){ - prefix = null; - break; - } - } - } - while (prefix == null); - } - - boolean p = pending; - pending = false; - setPrefix(prefix, namespace); - pending = p; - return prefix; - } - - @Override - public Object getProperty(String name){ - throw new RuntimeException("Unsupported property: "+name); - } - @Override - public void ignorableWhitespace(String s) throws IOException { - text(s); - } - @Override - public void setFeature(String name, boolean value){ - if("http://xmlpull.org/v1/doc/features.html#indent-output".equals(name)){ - indent[depth] = value; - firstAttributeWritten = false; - }else { - throw new RuntimeException("Unsupported Feature: "+name); - } - } - @Override - public void setProperty(String name, Object value){ - throw new RuntimeException("Unsupported Property:" + value); - } - @Override - public void setPrefix(String prefix, String namespace) - throws IOException { - - check(false); - if(prefix == null) { - prefix = ""; - } - if(namespace == null) { - namespace = ""; - } - String defined = getPrefix(namespace, true, false); - if(prefix.equals(defined)) { - return; - } - - int pos = (nspCounts[depth + 1]++) << 1; - - if(nspStack.length < pos + 1){ - String[] hlp = new String[nspStack.length + 16]; - System.arraycopy(nspStack, 0, hlp, 0, pos); - nspStack = hlp; - } - - nspStack[pos++] = prefix; - nspStack[pos] = namespace; - } - - public void setOutput(Writer writer){ - this.writer = writer; - nspCounts[0] = 2; - nspCounts[1] = 2; - nspStack[0] = ""; - nspStack[1] = ""; - nspStack[2] = "xml"; - nspStack[3] = "http://www.w3.org/XML/1998/namespace"; - pending = false; - auto = 0; - depth = 0; - - unicode = false; - } - @Override - public void setOutput(OutputStream os, String encoding) - throws IOException { - if(os == null) { - throw new IllegalArgumentException("os == null"); - } - setOutput(encoding == null - ? new OutputStreamWriter(os) - : new OutputStreamWriter(os, encoding)); - this.encoding = encoding; - if(encoding != null && encoding.toLowerCase(Locale.US).startsWith("utf")){ - unicode = true; - } - } - @Override - public void startDocument(String encoding, Boolean standalone) throws IOException { - append(""); - } - @Override - public XmlSerializer startTag(String namespace, String name) - throws IOException { - check(false); - firstAttributeWritten = false; - indentAttributeReference = 0; - if(indent[depth]){ - append('\r'); - append('\n'); - int spaceLength = 2 * depth; - appendSpace(spaceLength); - indentAttributeReference = spaceLength; - } - int esp = depth * 3; - if(elementStack.length < esp + 3){ - String[] hlp = new String[elementStack.length + 12]; - System.arraycopy(elementStack, 0, hlp, 0, esp); - elementStack = hlp; - } - String prefix = namespace == null? - "" : getPrefix(namespace, true, true); - - if(namespace != null && namespace.isEmpty()){ - for (int i = nspCounts[depth]; i < nspCounts[depth + 1]; i++){ - if(nspStack[i * 2].isEmpty() && !nspStack[i * 2 + 1].isEmpty()){ - throw new IllegalStateException("Cannot set default namespace for elements in no namespace"); - } - } - } - elementStack[esp++] = namespace; - elementStack[esp++] = prefix; - elementStack[esp] = name; - append('<'); - indentAttributeReference += 1; - if(!prefix.isEmpty()){ - append(prefix); - append(':'); - indentAttributeReference += prefix.length() + 1; - } - append(name); - int len = name.length(); - if(len > 20){ - len = 20; - } - indentAttributeReference += len; - pending = true; - return this; - } - @Override - public XmlSerializer attribute(String namespace, String name, String value) - throws IOException { - if(!pending) { - throw new IllegalStateException("illegal position for attribute"); - } - if(namespace == null) { - namespace = ""; - } - String prefix = namespace.isEmpty() ? - "" : getPrefix(namespace, false, true); - attributeIndent(); - append(' '); - if(!prefix.isEmpty()){ - append(prefix); - append(':'); - } - append(name); - append('='); - char q = value.indexOf('"') == -1 ? '"' : '\''; - append(q); - writeEscaped(value, q); - append(q); - firstAttributeWritten = true; - return this; - } - @Override - public void flush() throws IOException { - check(false); - flushBuffer(); - } - @Override - public XmlSerializer endTag(String namespace, String name)throws IOException { - if(!pending) { - depth--; - } - if((namespace == null - && elementStack[depth * 3] != null) - || (namespace != null - && !namespace.equals(elementStack[depth * 3])) - || !elementStack[depth * 3 + 2].equals(name)) { - throw new IllegalArgumentException(" does not match start"); - } - - if(pending){ - check(true); - depth--; - } - else { - if(indent[depth + 1]){ - append('\r'); - append('\n'); - appendSpace(2 * depth); - } - append("'); - } - - nspCounts[depth + 1] = nspCounts[depth]; - return this; - } - @Override - public String getNamespace(){ - return getDepth() == 0 ? null : elementStack[getDepth() * 3 - 3]; - } - @Override - public String getName(){ - return getDepth() == 0 ? null : elementStack[getDepth() * 3 - 1]; - } - @Override - public int getDepth(){ - return pending ? depth + 1 : depth; - } - @Override - public XmlSerializer text(String text) throws IOException { - check(false); - indent[depth] = false; - writeEscaped(text, -1); - return this; - } - @Override - public XmlSerializer text(char[] text, int start, int len) - throws IOException { - text(new String(text, start, len)); - return this; - } - @Override - public void cdsect(String data) throws IOException { - check(false); - data = data.replace("]]>", "]]]]>"); - append("= 0x20 && ch <= 0xd7ff) || - (ch == '\t' || ch == '\n' || ch == '\r') || - (ch >= 0xe000 && ch <= 0xfffd); - if(allowedInCdata){ - append(ch); - } else if(Character.isHighSurrogate(ch) && i < data.length() - 1){ - // Character entities aren't valid in CDATA, so break out for this. - append("]]>"); - writeSurrogate(ch, data.charAt(++i)); - append(""); - } - - private void writeSurrogate(char high, char low) throws IOException { - if(!Character.isLowSurrogate(low)){ - throw new IllegalArgumentException("Bad surrogate pair (U+" + Integer.toHexString((int) high) + - " U+" + Integer.toHexString((int) low) + ")"); - } - int codePoint = Character.toCodePoint(high, low); - append("&#" + codePoint + ";"); - } - @Override - public void comment(String comment) throws IOException { - check(false); - append(""); - } - @Override - public void processingInstruction(String pi) - throws IOException { - check(false); - append(""); - } - - private void attributeIndent() throws IOException { - if(!firstAttributeWritten || !indent[depth]){ - return; - } - int length = this.indentAttributeReference; - if(length <= 0){ - return; - } - append('\r'); - append('\n'); - appendSpace(length); - } -} diff --git a/src/ARSCLib/com/android/org/kxml2/io/LibCoreStringPool.java b/src/ARSCLib/com/android/org/kxml2/io/LibCoreStringPool.java deleted file mode 100644 index 715df45c..00000000 --- a/src/ARSCLib/com/android/org/kxml2/io/LibCoreStringPool.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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. - */ - -package com.android.org.kxml2.io; - -// Taken from libcore.internal.StringPool - -class LibCoreStringPool { - - private final String[] pool = new String[512]; - - public LibCoreStringPool() { - } - - private static boolean contentEquals(String s, char[] chars, int start, int length) { - if (s.length() != length) { - return false; - } - for (int i = 0; i < length; i++) { - if (chars[start + i] != s.charAt(i)) { - return false; - } - } - return true; - } - - /** - * Returns a string equal to {@code new String(array, start, length)}. - */ - public String get(char[] array, int start, int length) { - // Compute an arbitrary hash of the content - int hashCode = 0; - for (int i = start; i < start + length; i++) { - hashCode = (hashCode * 31) + array[i]; - } - - // Pick a bucket using Doug Lea's supplemental secondaryHash function (from HashMap) - hashCode ^= (hashCode >>> 20) ^ (hashCode >>> 12); - hashCode ^= (hashCode >>> 7) ^ (hashCode >>> 4); - int index = hashCode & (pool.length - 1); - - String pooled = pool[index]; - if (pooled != null && contentEquals(pooled, array, start, length)) { - return pooled; - } - - String result = new String(array, start, length); - pool[index] = result; - return result; - } - -} diff --git a/src/ARSCLib/com/reandroid/apk/APKLogger.java b/src/ARSCLib/com/reandroid/apk/APKLogger.java deleted file mode 100644 index 2ad571ee..00000000 --- a/src/ARSCLib/com/reandroid/apk/APKLogger.java +++ /dev/null @@ -1,22 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -public interface APKLogger { - void logMessage(String msg); - void logError(String msg, Throwable tr); - void logVerbose(String msg); -} diff --git a/src/ARSCLib/com/reandroid/apk/AndroidFrameworks.java b/src/ARSCLib/com/reandroid/apk/AndroidFrameworks.java deleted file mode 100644 index e05cf98d..00000000 --- a/src/ARSCLib/com/reandroid/apk/AndroidFrameworks.java +++ /dev/null @@ -1,219 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; - -public class AndroidFrameworks { - private static Map resource_paths; - private static FrameworkApk mCurrent; - - public static void setCurrent(FrameworkApk current){ - synchronized (AndroidFrameworks.class){ - mCurrent = current; - } - } - public static FrameworkApk getCurrent(){ - FrameworkApk current = mCurrent; - if(current==null){ - return null; - } - if(current.isDestroyed()){ - mCurrent = null; - return null; - } - return current; - } - public static FrameworkApk getLatest() throws IOException { - Map pathMap = getResourcePaths(); - synchronized (AndroidFrameworks.class){ - int latest = getHighestVersion(); - FrameworkApk current = getCurrent(); - if(current!=null && latest==current.getVersionCode()){ - return current; - } - String path = pathMap.get(latest); - if(path == null){ - throw new IOException("Could not get latest framework"); - } - return loadResource(latest); - } - } - public static FrameworkApk getBestMatch(int version) throws IOException { - Map pathMap = getResourcePaths(); - synchronized (AndroidFrameworks.class){ - int best = getBestMatchVersion(version); - FrameworkApk current = getCurrent(); - if(current!=null && best==current.getVersionCode()){ - return current; - } - String path = pathMap.get(best); - if(path == null){ - throw new IOException("Could not get framework for version = "+version); - } - return loadResource(best); - } - } - public static void destroyCurrent(){ - synchronized (AndroidFrameworks.class){ - FrameworkApk current = mCurrent; - if(current==null){ - return; - } - current.destroy(); - } - } - private static int getHighestVersion() { - Map pathMap = getResourcePaths(); - int highest = 0; - for(int id:pathMap.keySet()){ - if(highest==0){ - highest = id; - continue; - } - if(id>highest){ - highest = id; - } - } - return highest; - } - private static int getBestMatchVersion(int version) { - Map pathMap = getResourcePaths(); - if(pathMap.containsKey(version)){ - return version; - } - int highest = 0; - int best = 0; - int prevDifference = 0; - for(int id:pathMap.keySet()){ - if(highest==0){ - highest = id; - best = id; - prevDifference = version*2 + 1000; - continue; - } - if(id>highest){ - highest = id; - } - int diff = id-version; - if(diff<0){ - diff=-diff; - } - if(diffbest)){ - best = id; - prevDifference = diff; - } - } - return best; - } - public static FrameworkApk loadResource(int version) throws IOException { - String path = getResourcePath(version); - if(path == null){ - throw new IOException("No resource found for version: "+version); - } - String simpleName = toSimpleName(path); - return FrameworkApk.loadApkBuffer(simpleName, AndroidFrameworks.class.getResourceAsStream(path)); - } - private static String getResourcePath(int version){ - return getResourcePaths().get(version); - } - private static Map getResourcePaths(){ - if(resource_paths!=null){ - return resource_paths; - } - synchronized (AndroidFrameworks.class){ - resource_paths = scanAvailableResourcePaths(); - return resource_paths; - } - } - private static Map scanAvailableResourcePaths(){ - Map results = new HashMap<>(); - int maxSearch = 50; - for(int version=20; version0){ - i++; - path = path.substring(i); - } - i = path.lastIndexOf('.'); - if(i>=0){ - path = path.substring(0, i); - } - return path; - } - private static int parseVersion(String name){ - int i = name.lastIndexOf('/'); - if(i<0){ - i = name.lastIndexOf(File.separatorChar); - } - if(i>0){ - i++; - name = name.substring(i); - } - i = name.lastIndexOf('-'); - if(i>=0){ - i++; - name = name.substring(i); - } - i = name.indexOf('.'); - if(i>=0){ - name = name.substring(0, i); - } - return Integer.parseInt(name); - } - private static boolean isAvailable(String path){ - InputStream inputStream = AndroidFrameworks.class.getResourceAsStream(path); - if(inputStream==null){ - return false; - } - closeQuietly(inputStream); - return true; - } - private static void closeQuietly(InputStream stream){ - if(stream == null){ - return; - } - try { - stream.close(); - } catch (IOException ignored) { - } - } - private static String toResourcePath(int version){ - return ANDROID_RESOURCE_DIRECTORY + ANDROID_PACKAGE - + '-' + version - +FRAMEWORK_EXTENSION; - } - private static final String ANDROID_RESOURCE_DIRECTORY = "/frameworks/android/"; - private static final String ANDROID_PACKAGE = "android"; - private static final String FRAMEWORK_EXTENSION = ".apk"; -} diff --git a/src/ARSCLib/com/reandroid/apk/ApkBundle.java b/src/ARSCLib/com/reandroid/apk/ApkBundle.java deleted file mode 100644 index 8550c52f..00000000 --- a/src/ARSCLib/com/reandroid/apk/ApkBundle.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.archive.APKArchive; -import com.reandroid.archive2.block.ApkSignatureBlock; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.pool.TableStringPool; -import com.reandroid.arsc.pool.builder.StringPoolMerger; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.*; - -public class ApkBundle { - private final Map mModulesMap; - private APKLogger apkLogger; - public ApkBundle(){ - this.mModulesMap=new HashMap<>(); - } - - public ApkModule mergeModules() throws IOException { - List moduleList=getApkModuleList(); - if(moduleList.size()==0){ - throw new FileNotFoundException("Nothing to merge, empty modules"); - } - ApkModule result = new ApkModule(generateMergedModuleName(), new APKArchive()); - result.setAPKLogger(apkLogger); - result.setLoadDefaultFramework(false); - - mergeStringPools(result); - - ApkModule base=getBaseModule(); - if(base==null){ - base=getLargestTableModule(); - } - result.merge(base); - ApkSignatureBlock signatureBlock = null; - for(ApkModule module:moduleList){ - ApkSignatureBlock asb = module.getApkSignatureBlock(); - if(module==base){ - if(asb != null){ - signatureBlock = asb; - } - continue; - } - if(signatureBlock == null){ - signatureBlock = asb; - } - result.merge(module); - } - - result.setApkSignatureBlock(signatureBlock); - - if(result.hasTableBlock()){ - TableBlock tableBlock=result.getTableBlock(); - tableBlock.sortPackages(); - tableBlock.refresh(); - } - result.getApkArchive().autoSortApkFiles(); - return result; - } - private void mergeStringPools(ApkModule mergedModule) throws IOException { - if(!hasOneTableBlock() || mergedModule.hasTableBlock()){ - return; - } - logMessage("Merging string pools ... "); - TableBlock createdTable = new TableBlock(); - BlockInputSource inputSource= - new BlockInputSource<>(TableBlock.FILE_NAME, createdTable); - mergedModule.getApkArchive().add(inputSource); - - StringPoolMerger poolMerger = new StringPoolMerger(); - - for(ApkModule apkModule:getModules()){ - if(!apkModule.hasTableBlock()){ - continue; - } - TableStringPool stringPool = apkModule.getVolatileTableStringPool(); - poolMerger.add(stringPool); - } - - poolMerger.mergeTo(createdTable.getTableStringPool()); - - logMessage("Merged string pools="+poolMerger.getMergedPools() - +", style="+poolMerger.getMergedStyleStrings() - +", strings="+poolMerger.getMergedStrings()); - } - private String generateMergedModuleName(){ - Set moduleNames=mModulesMap.keySet(); - String merged="merged"; - int i=1; - String name=merged; - while (moduleNames.contains(name)){ - name=merged+"_"+i; - i++; - } - return name; - } - private ApkModule getLargestTableModule(){ - ApkModule apkModule=null; - int chunkSize=0; - for(ApkModule module:getApkModuleList()){ - if(!module.hasTableBlock()){ - continue; - } - TableBlock tableBlock=module.getTableBlock(); - int size=tableBlock.getHeaderBlock().getChunkSize(); - if(apkModule==null || size>chunkSize){ - chunkSize=size; - apkModule=module; - } - } - return apkModule; - } - public ApkModule getBaseModule(){ - for(ApkModule module:getApkModuleList()){ - if(module.isBaseModule()){ - return module; - } - } - return null; - } - public List getApkModuleList(){ - return new ArrayList<>(mModulesMap.values()); - } - public void loadApkDirectory(File dir) throws IOException{ - loadApkDirectory(dir, false); - } - public void loadApkDirectory(File dir, boolean recursive) throws IOException { - if(!dir.isDirectory()){ - throw new FileNotFoundException("No such directory: "+dir); - } - List apkList; - if(recursive){ - apkList = ApkUtil.recursiveFiles(dir, ".apk"); - }else { - apkList = ApkUtil.listFiles(dir, ".apk"); - } - if(apkList.size()==0){ - throw new FileNotFoundException("No '*.apk' files in directory: "+dir); - } - logMessage("Found apk files: "+apkList.size()); - for(File file:apkList){ - logVerbose("Loading: "+file.getName()); - String name = ApkUtil.toModuleName(file); - ApkModule module = ApkModule.loadApkFile(file, name); - module.setAPKLogger(apkLogger); - addModule(module); - } - } - public void addModule(ApkModule apkModule){ - apkModule.setLoadDefaultFramework(false); - String name = apkModule.getModuleName(); - mModulesMap.remove(name); - mModulesMap.put(name, apkModule); - } - public boolean containsApkModule(String moduleName){ - return mModulesMap.containsKey(moduleName); - } - public ApkModule removeApkModule(String moduleName){ - return mModulesMap.remove(moduleName); - } - public ApkModule getApkModule(String moduleName){ - return mModulesMap.get(moduleName); - } - public List listModuleNames(){ - return new ArrayList<>(mModulesMap.keySet()); - } - public int countModules(){ - return mModulesMap.size(); - } - public Collection getModules(){ - return mModulesMap.values(); - } - private boolean hasOneTableBlock(){ - for(ApkModule apkModule:getModules()){ - if(apkModule.hasTableBlock()){ - return true; - } - } - return false; - } - public void setAPKLogger(APKLogger logger) { - this.apkLogger = logger; - } - private void logMessage(String msg) { - if(apkLogger!=null){ - apkLogger.logMessage(msg); - } - } - private void logError(String msg, Throwable tr) { - if(apkLogger!=null){ - apkLogger.logError(msg, tr); - } - } - private void logVerbose(String msg) { - if(apkLogger!=null){ - apkLogger.logVerbose(msg); - } - } -} diff --git a/src/ARSCLib/com/reandroid/apk/ApkDecoder.java b/src/ARSCLib/com/reandroid/apk/ApkDecoder.java deleted file mode 100644 index 02fbc2a0..00000000 --- a/src/ARSCLib/com/reandroid/apk/ApkDecoder.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.archive.InputSource; -import com.reandroid.archive2.block.ApkSignatureBlock; - -import java.io.File; -import java.io.IOException; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -public abstract class ApkDecoder { - private final Set mDecodedPaths; - private APKLogger apkLogger; - private boolean mLogErrors; - - public ApkDecoder(){ - mDecodedPaths = new HashSet<>(); - } - public final void decodeTo(File outDir) throws IOException{ - reset(); - onDecodeTo(outDir); - } - abstract void onDecodeTo(File outDir) throws IOException; - - boolean containsDecodedPath(String path){ - return mDecodedPaths.contains(path); - } - void addDecodedPath(String path){ - mDecodedPaths.add(path); - } - void writePathMap(File dir, Collection sourceList) throws IOException { - PathMap pathMap = new PathMap(); - pathMap.add(sourceList); - File file = new File(dir, PathMap.JSON_FILE); - pathMap.toJson().write(file); - } - void dumpSignatures(File outDir, ApkSignatureBlock signatureBlock) throws IOException { - if(signatureBlock == null){ - return; - } - logMessage("Dumping signatures ..."); - File dir = new File(outDir, ApkUtil.SIGNATURE_DIR_NAME); - signatureBlock.writeSplitRawToDirectory(dir); - } - void logOrThrow(String message, IOException exception) throws IOException{ - if(isLogErrors()){ - logError(message, exception); - return; - } - if(message == null && exception == null){ - return; - } - if(exception == null){ - exception = new IOException(message); - } - throw exception; - } - private void reset(){ - mDecodedPaths.clear(); - } - - public boolean isLogErrors() { - return mLogErrors; - } - public void setLogErrors(boolean logErrors) { - this.mLogErrors = logErrors; - } - - public void setApkLogger(APKLogger apkLogger) { - this.apkLogger = apkLogger; - } - APKLogger getApkLogger() { - return apkLogger; - } - void logMessage(String msg) { - APKLogger apkLogger = this.apkLogger; - if(apkLogger!=null){ - apkLogger.logMessage(msg); - } - } - void logError(String msg, Throwable tr) { - APKLogger apkLogger = this.apkLogger; - if(apkLogger == null || (msg == null && tr == null)){ - return; - } - apkLogger.logError(msg, tr); - } - void logVerbose(String msg) { - APKLogger apkLogger = this.apkLogger; - if(apkLogger!=null){ - apkLogger.logVerbose(msg); - } - } -} diff --git a/src/ARSCLib/com/reandroid/apk/ApkJsonDecoder.java b/src/ARSCLib/com/reandroid/apk/ApkJsonDecoder.java deleted file mode 100644 index d146cfa7..00000000 --- a/src/ARSCLib/com/reandroid/apk/ApkJsonDecoder.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.archive.InputSource; -import com.reandroid.archive2.block.ApkSignatureBlock; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.chunk.xml.AndroidManifestBlock; -import com.reandroid.arsc.chunk.xml.ResXmlDocument; -import com.reandroid.json.JSONObject; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; - -public class ApkJsonDecoder { - private final ApkModule apkModule; - private final Set decodedPaths; - private final boolean splitTypes; - public ApkJsonDecoder(ApkModule apkModule, boolean splitTypes){ - this.apkModule = apkModule; - this.splitTypes = splitTypes; - this.decodedPaths = new HashSet<>(); - } - public ApkJsonDecoder(ApkModule apkModule){ - this(apkModule, false); - } - public void sanitizeFilePaths(){ - PathSanitizer sanitizer = PathSanitizer.create(apkModule); - sanitizer.sanitize(); - } - public File writeToDirectory(File dir) throws IOException { - this.decodedPaths.clear(); - writeUncompressed(dir); - writeManifest(dir); - writeTable(dir); - //writeResourceIds(dir); - //writePublicXml(dir); - writeResources(dir); - writeRootFiles(dir); - writePathMap(dir); - dumpSignatures(dir); - return new File(dir, apkModule.getModuleName()); - } - private void dumpSignatures(File outDir) throws IOException { - ApkSignatureBlock signatureBlock = apkModule.getApkSignatureBlock(); - if(signatureBlock == null){ - return; - } - apkModule.logMessage("Dumping signatures ..."); - File dir = toSignatureDir(outDir); - signatureBlock.writeSplitRawToDirectory(dir); - } - private void writePathMap(File dir) throws IOException { - PathMap pathMap = new PathMap(); - pathMap.add(apkModule.getApkArchive()); - File file = toPathMapJsonFile(dir); - pathMap.toJson().write(file); - } - private void writeUncompressed(File dir) throws IOException { - File file=toUncompressedJsonFile(dir); - UncompressedFiles uncompressedFiles=new UncompressedFiles(); - uncompressedFiles.addCommonExtensions(); - uncompressedFiles.addPath(apkModule.getApkArchive()); - uncompressedFiles.toJson().write(file); - } - private void writeResources(File dir) throws IOException { - for(ResFile resFile:apkModule.listResFiles()){ - writeResource(dir, resFile); - } - } - private void writeResource(File dir, ResFile resFile) throws IOException { - if(resFile.isBinaryXml()){ - writeResourceJson(dir, resFile); - } - } - private void writeResourceJson(File dir, ResFile resFile) throws IOException { - InputSource inputSource= resFile.getInputSource(); - String path=inputSource.getAlias(); - File file=toResJson(dir, path); - ResXmlDocument resXmlDocument =new ResXmlDocument(); - resXmlDocument.readBytes(inputSource.openStream()); - JSONObject jsonObject= resXmlDocument.toJson(); - jsonObject.write(file); - addDecoded(path); - } - private void writeRootFiles(File dir) throws IOException { - for(InputSource inputSource:apkModule.getApkArchive().listInputSources()){ - writeRootFile(dir, inputSource); - } - } - private void writeRootFile(File dir, InputSource inputSource) throws IOException { - String path=inputSource.getAlias(); - if(hasDecoded(path)){ - return; - } - File file=toRootFile(dir, path); - File parent=file.getParentFile(); - if(parent!=null && !parent.exists()){ - parent.mkdirs(); - } - FileOutputStream outputStream=new FileOutputStream(file); - inputSource.write(outputStream); - outputStream.close(); - addDecoded(path); - } - private void writeTable(File dir) throws IOException { - if(!splitTypes){ - writeTableSingle(dir); - return; - } - writeTableSplit(dir); - } - private void writeTableSplit(File dir) throws IOException { - if(!apkModule.hasTableBlock()){ - return; - } - TableBlock tableBlock = apkModule.getTableBlock(); - File splitDir= toJsonTableSplitDir(dir); - TableBlockJson tableBlockJson=new TableBlockJson(tableBlock); - tableBlockJson.writeJsonFiles(splitDir); - addDecoded(TableBlock.FILE_NAME); - } - private void writeTableSingle(File dir) throws IOException { - if(!apkModule.hasTableBlock()){ - return; - } - TableBlock tableBlock = apkModule.getTableBlock(); - File file= toJsonTableFile(dir); - tableBlock.toJson().write(file); - addDecoded(TableBlock.FILE_NAME); - } - private void writeResourceIds(File dir) throws IOException { - if(!apkModule.hasTableBlock()){ - return; - } - TableBlock tableBlock = apkModule.getTableBlock(); - ResourceIds resourceIds=new ResourceIds(); - resourceIds.loadTableBlock(tableBlock); - JSONObject jsonObject= resourceIds.toJson(); - File file=toResourceIds(dir); - jsonObject.write(file); - } - private void writePublicXml(File dir) throws IOException { - if(!apkModule.hasTableBlock()){ - return; - } - TableBlock tableBlock = apkModule.getTableBlock(); - ResourceIds resourceIds=new ResourceIds(); - resourceIds.loadTableBlock(tableBlock); - File file=toResourceIdsXml(dir); - resourceIds.writeXml(file); - } - private void writeManifest(File dir) throws IOException { - if(!apkModule.hasAndroidManifestBlock()){ - return; - } - AndroidManifestBlock manifestBlock = apkModule.getAndroidManifestBlock(); - File file = toJsonManifestFile(dir); - manifestBlock.toJson().write(file); - addDecoded(AndroidManifestBlock.FILE_NAME); - } - private boolean hasDecoded(String path){ - return decodedPaths.contains(path); - } - private void addDecoded(String path){ - this.decodedPaths.add(path); - } - private File toJsonTableFile(File dir){ - File file=new File(dir, apkModule.getModuleName()); - String name = TableBlock.FILE_NAME + ApkUtil.JSON_FILE_EXTENSION; - return new File(file, name); - } - private File toJsonTableSplitDir(File dir){ - File file=new File(dir, apkModule.getModuleName()); - return new File(file, ApkUtil.SPLIT_JSON_DIRECTORY); - } - private File toResourceIds(File dir){ - File file=new File(dir, apkModule.getModuleName()); - String name = "resource-ids.json"; - return new File(file, name); - } - private File toResourceIdsXml(File dir){ - File file=new File(dir, apkModule.getModuleName()); - String name = "public.xml"; - return new File(file, name); - } - private File toSignatureDir(File dir){ - dir = new File(dir, apkModule.getModuleName()); - return new File(dir, ApkUtil.SIGNATURE_DIR_NAME); - } - private File toPathMapJsonFile(File dir){ - File file = new File(dir, apkModule.getModuleName()); - return new File(file, PathMap.JSON_FILE); - } - private File toUncompressedJsonFile(File dir){ - File file = new File(dir, apkModule.getModuleName()); - return new File(file, UncompressedFiles.JSON_FILE); - } - private File toJsonManifestFile(File dir){ - File file=new File(dir, apkModule.getModuleName()); - String name = AndroidManifestBlock.FILE_NAME + ApkUtil.JSON_FILE_EXTENSION; - return new File(file, name); - } - private File toResJson(File dir, String path){ - File file=new File(dir, apkModule.getModuleName()); - file=new File(file, ApkUtil.RES_JSON_NAME); - path=path + ApkUtil.JSON_FILE_EXTENSION; - path=path.replace('/', File.separatorChar); - return new File(file, path); - } - private File toRootFile(File dir, String path){ - File file=new File(dir, apkModule.getModuleName()); - file=new File(file, ApkUtil.ROOT_NAME); - path=path.replace('/', File.separatorChar); - return new File(file, path); - } -} diff --git a/src/ARSCLib/com/reandroid/apk/ApkJsonEncoder.java b/src/ARSCLib/com/reandroid/apk/ApkJsonEncoder.java deleted file mode 100644 index 1adb0f80..00000000 --- a/src/ARSCLib/com/reandroid/apk/ApkJsonEncoder.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.archive.APKArchive; -import com.reandroid.archive.FileInputSource; -import com.reandroid.archive2.block.ApkSignatureBlock; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.chunk.xml.AndroidManifestBlock; -import com.reandroid.json.JSONArray; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.List; - -public class ApkJsonEncoder { - private APKArchive apkArchive; - private APKLogger apkLogger; - public ApkJsonEncoder(){ - } - public ApkModule scanDirectory(File moduleDir){ - this.apkArchive=new APKArchive(); - String moduleName=moduleDir.getName(); - scanManifest(moduleDir); - scanTable(moduleDir); - scanResJsonDirs(moduleDir); - scanRootDirs(moduleDir); - ApkModule module=new ApkModule(moduleName, apkArchive); - module.setLoadDefaultFramework(false); - module.setAPKLogger(apkLogger); - loadUncompressed(module, moduleDir); - //applyResourceId(module, moduleDir); - restorePathMap(moduleDir, module); - restoreSignatures(moduleDir, module); - return module; - } - private void restoreSignatures(File dir, ApkModule apkModule){ - File sigDir = new File(dir, ApkUtil.SIGNATURE_DIR_NAME); - if(!sigDir.isDirectory()){ - return; - } - logMessage("Loading signatures ..."); - ApkSignatureBlock signatureBlock = new ApkSignatureBlock(); - try { - signatureBlock.scanSplitFiles(sigDir); - apkModule.setApkSignatureBlock(signatureBlock); - } catch (IOException exception){ - logError("Failed to load signatures: ", exception); - } - } - private void restorePathMap(File dir, ApkModule apkModule){ - File file = new File(dir, PathMap.JSON_FILE); - if(!file.isFile()){ - return; - } - logMessage("Restoring file path ..."); - PathMap pathMap = new PathMap(); - FileInputStream inputStream = null; - try { - inputStream = new FileInputStream(file); - } catch (FileNotFoundException exception) { - logError("Failed to load path-map", exception); - return; - } - JSONArray jsonArray = new JSONArray(inputStream); - pathMap.fromJson(jsonArray); - pathMap.restore(apkModule); - } - private void applyResourceId(ApkModule apkModule, File moduleDir) { - if(!apkModule.hasTableBlock()){ - return; - } - File pubXml=toResourceIdsXml(moduleDir); - if(!pubXml.isFile()){ - return; - } - ResourceIds resourceIds=new ResourceIds(); - try { - resourceIds.fromXml(pubXml); - resourceIds.applyTo(apkModule.getTableBlock()); - } catch (IOException exception) { - throw new IllegalArgumentException(exception.getMessage()); - } - } - private void loadUncompressed(ApkModule module, File moduleDir){ - File jsonFile=toUncompressedJsonFile(moduleDir); - UncompressedFiles uf= module.getUncompressedFiles(); - try { - uf.fromJson(jsonFile); - } catch (IOException ignored) { - } - } - private void scanRootDirs(File moduleDir){ - File rootDir=toRootDir(moduleDir); - List jsonFileList=ApkUtil.recursiveFiles(rootDir); - for(File file:jsonFileList){ - scanRootFile(rootDir, file); - } - } - private void scanRootFile(File rootDir, File file){ - String path=ApkUtil.toArchivePath(rootDir, file); - FileInputSource inputSource=new FileInputSource(file, path); - apkArchive.add(inputSource); - } - private void scanResJsonDirs(File moduleDir){ - File resJsonDir=toResJsonDir(moduleDir); - List jsonFileList=ApkUtil.recursiveFiles(resJsonDir); - for(File file:jsonFileList){ - scanResJsonFile(resJsonDir, file); - } - } - private void scanResJsonFile(File resJsonDir, File file){ - JsonXmlInputSource inputSource=JsonXmlInputSource.fromFile(resJsonDir, file); - apkArchive.add(inputSource); - } - private void scanManifest(File moduleDir){ - File file=toJsonManifestFile(moduleDir); - if(!file.isFile()){ - return; - } - JsonManifestInputSource inputSource=JsonManifestInputSource.fromFile(moduleDir, file); - inputSource.setAPKLogger(apkLogger); - apkArchive.add(inputSource); - } - private void scanTable(File moduleDir) { - boolean splitFound=scanTableSplitJson(moduleDir); - if(splitFound){ - return; - } - scanTableSingleJson(moduleDir); - } - private boolean scanTableSplitJson(File moduleDir) { - File dir=toJsonTableSplitDir(moduleDir); - if(!dir.isDirectory()){ - return false; - } - SplitJsonTableInputSource inputSource=new SplitJsonTableInputSource(dir); - inputSource.setAPKLogger(apkLogger); - apkArchive.add(inputSource); - return true; - } - private void scanTableSingleJson(File moduleDir) { - File file=toJsonTableFile(moduleDir); - if(!file.isFile()){ - return; - } - SingleJsonTableInputSource inputSource= SingleJsonTableInputSource.fromFile(moduleDir, file); - inputSource.setAPKLogger(apkLogger); - apkArchive.add(inputSource); - } - private File toJsonTableFile(File dir){ - String name = TableBlock.FILE_NAME + ApkUtil.JSON_FILE_EXTENSION; - return new File(dir, name); - } - private File toJsonManifestFile(File dir){ - String name = AndroidManifestBlock.FILE_NAME + ApkUtil.JSON_FILE_EXTENSION; - return new File(dir, name); - } - private File toResourceIdsXml(File dir){ - String name = "public.xml"; - return new File(dir, name); - } - private File toUncompressedJsonFile(File dir){ - return new File(dir, UncompressedFiles.JSON_FILE); - } - private File toJsonTableSplitDir(File dir){ - return new File(dir, ApkUtil.SPLIT_JSON_DIRECTORY); - } - private File toResJsonDir(File dir){ - return new File(dir, ApkUtil.RES_JSON_NAME); - } - private File toRootDir(File dir){ - return new File(dir, ApkUtil.ROOT_NAME); - } - - public void setAPKLogger(APKLogger logger) { - this.apkLogger = logger; - } - private void logMessage(String msg) { - if(apkLogger!=null){ - apkLogger.logMessage(msg); - } - } - private void logError(String msg, Throwable tr) { - if(apkLogger!=null){ - apkLogger.logError(msg, tr); - } - } - private void logVerbose(String msg) { - if(apkLogger!=null){ - apkLogger.logVerbose(msg); - } - } -} diff --git a/src/ARSCLib/com/reandroid/apk/ApkModule.java b/src/ARSCLib/com/reandroid/apk/ApkModule.java deleted file mode 100644 index 14a98765..00000000 --- a/src/ARSCLib/com/reandroid/apk/ApkModule.java +++ /dev/null @@ -1,838 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.archive.*; -import com.reandroid.archive2.Archive; -import com.reandroid.archive2.block.ApkSignatureBlock; -import com.reandroid.archive2.writer.ApkWriter; -import com.reandroid.arsc.ApkFile; -import com.reandroid.arsc.array.PackageArray; -import com.reandroid.arsc.chunk.Chunk; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.chunk.xml.AndroidManifestBlock; -import com.reandroid.arsc.chunk.xml.ResXmlDocument; -import com.reandroid.arsc.container.SpecTypePair; -import com.reandroid.arsc.decoder.Decoder; -import com.reandroid.arsc.group.StringGroup; -import com.reandroid.arsc.item.TableString; -import com.reandroid.arsc.pool.TableStringPool; -import com.reandroid.arsc.util.FrameworkTable; -import com.reandroid.arsc.value.Entry; -import com.reandroid.arsc.value.ResConfig; -import com.reandroid.xml.XMLDocument; -import com.reandroid.xml.XMLElement; -import com.reandroid.xml.XMLException; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.util.*; -import java.util.zip.ZipEntry; - -public class ApkModule implements ApkFile { - private final String moduleName; - private final APKArchive apkArchive; - private boolean loadDefaultFramework = true; - private boolean mDisableLoadFramework = false; - private TableBlock mTableBlock; - private AndroidManifestBlock mManifestBlock; - private final UncompressedFiles mUncompressedFiles; - private APKLogger apkLogger; - private Decoder mDecoder; - private ApkType mApkType; - private ApkSignatureBlock apkSignatureBlock; - private Integer preferredFramework; - - public ApkModule(String moduleName, APKArchive apkArchive){ - this.moduleName=moduleName; - this.apkArchive=apkArchive; - this.mUncompressedFiles=new UncompressedFiles(); - this.mUncompressedFiles.addPath(apkArchive); - } - - public ApkSignatureBlock getApkSignatureBlock() { - return apkSignatureBlock; - } - public void setApkSignatureBlock(ApkSignatureBlock apkSignatureBlock) { - this.apkSignatureBlock = apkSignatureBlock; - } - - public boolean hasSignatureBlock(){ - return getApkSignatureBlock() != null; - } - - public void dumpSignatureInfoFiles(File directory) throws IOException{ - ApkSignatureBlock apkSignatureBlock = getApkSignatureBlock(); - if(apkSignatureBlock == null){ - throw new IOException("Don't have signature block"); - } - apkSignatureBlock.writeSplitRawToDirectory(directory); - } - public void dumpSignatureBlock(File file) throws IOException{ - ApkSignatureBlock apkSignatureBlock = getApkSignatureBlock(); - if(apkSignatureBlock == null){ - throw new IOException("Don't have signature block"); - } - apkSignatureBlock.writeRaw(file); - } - - public void scanSignatureInfoFiles(File directory) throws IOException{ - if(!directory.isDirectory()){ - throw new IOException("No such directory: " + directory); - } - ApkSignatureBlock apkSignatureBlock = this.apkSignatureBlock; - if(apkSignatureBlock == null){ - apkSignatureBlock = new ApkSignatureBlock(); - } - apkSignatureBlock.scanSplitFiles(directory); - setApkSignatureBlock(apkSignatureBlock); - } - public void loadSignatureBlock(File file) throws IOException{ - if(!file.isFile()){ - throw new IOException("No such file: " + file); - } - ApkSignatureBlock apkSignatureBlock = this.apkSignatureBlock; - if(apkSignatureBlock == null){ - apkSignatureBlock = new ApkSignatureBlock(); - } - apkSignatureBlock.read(file); - setApkSignatureBlock(apkSignatureBlock); - } - - public String getSplit(){ - if(!hasAndroidManifestBlock()){ - return null; - } - return getAndroidManifestBlock().getSplit(); - } - public FrameworkApk initializeAndroidFramework(TableBlock tableBlock, Integer version) throws IOException { - if(tableBlock == null || isAndroid(tableBlock)){ - return null; - } - List frameWorkList = tableBlock.getFrameWorks(); - for(TableBlock frameWork:frameWorkList){ - if(isAndroid(frameWork)){ - ApkFile apkFile = frameWork.getApkFile(); - if(apkFile instanceof FrameworkApk){ - return (FrameworkApk) apkFile; - } - return null; - } - } - logMessage("Initializing android framework ..."); - FrameworkApk frameworkApk; - if(version==null){ - logMessage("Can not read framework version, loading latest"); - frameworkApk = AndroidFrameworks.getLatest(); - }else { - logMessage("Loading android framework for version: " + version); - frameworkApk = AndroidFrameworks.getBestMatch(version); - } - FrameworkTable frameworkTable = frameworkApk.getTableBlock(); - tableBlock.addFramework(frameworkTable); - logMessage("Initialized framework: "+frameworkApk.getName()); - return frameworkApk; - } - private boolean isAndroid(TableBlock tableBlock){ - if(tableBlock instanceof FrameworkTable){ - FrameworkTable frameworkTable = (FrameworkTable) tableBlock; - return frameworkTable.isAndroid(); - } - return false; - } - - public FrameworkApk initializeAndroidFramework(XmlPullParser parser) throws IOException { - Map manifestAttributes; - try { - manifestAttributes = XmlHelper.readAttributes(parser, AndroidManifestBlock.TAG_manifest); - } catch (XmlPullParserException ex) { - throw new IOException(ex); - } - if(manifestAttributes == null){ - throw new IOException("Invalid AndroidManifest, missing element: '" - + AndroidManifestBlock.TAG_manifest + "'"); - } - return initializeAndroidFramework(manifestAttributes); - } - public FrameworkApk initializeAndroidFramework(Map manifestAttributes) throws IOException { - String coreApp = manifestAttributes.get(AndroidManifestBlock.NAME_coreApp); - String packageName = manifestAttributes.get(AndroidManifestBlock.NAME_PACKAGE); - if("true".equals(coreApp) && "android".equals(packageName)){ - logMessage("Looks framework itself, skip loading frameworks"); - return null; - } - String compileSdkVersion = manifestAttributes.get(AndroidManifestBlock.NAME_compileSdkVersion); - if(compileSdkVersion == null){ - logMessage("Missing attribute: '" + AndroidManifestBlock.NAME_compileSdkVersion + "', skip loading frameworks"); - return null; - } - int version; - try{ - version = Integer.parseInt(compileSdkVersion); - }catch (NumberFormatException exception){ - logMessage("NumberFormatException on reading: '" - + AndroidManifestBlock.NAME_compileSdkVersion + "=\"" - + compileSdkVersion +"\"' : " + exception.getMessage()); - return null; - } - TableBlock tableBlock = getTableBlock(false); - return initializeAndroidFramework(tableBlock, version); - } - public FrameworkApk initializeAndroidFramework(XMLDocument xmlDocument) throws IOException { - TableBlock tableBlock = getTableBlock(false); - if(isAndroidCoreApp(xmlDocument)){ - logMessage("Looks framework itself, skip loading frameworks"); - return null; - } - Integer version = readCompileVersionCode(xmlDocument); - return initializeAndroidFramework(tableBlock, version); - } - private boolean isAndroidCoreApp(XMLDocument manifestDocument){ - XMLElement root = manifestDocument.getDocumentElement(); - if(root == null){ - return false; - } - if(!"android".equals(root.getAttributeValue("package"))){ - return false; - } - String coreApp = root.getAttributeValue("coreApp"); - return "true".equals(coreApp); - } - private Integer readCompileVersionCode(XMLDocument manifestDocument) { - XMLElement root = manifestDocument.getDocumentElement(); - String versionString = readVersionCodeString(root); - if(versionString==null){ - return null; - } - try{ - return Integer.parseInt(versionString); - }catch (NumberFormatException exception){ - logMessage("NumberFormatException on manifest version reading: '" - +versionString+"': "+exception.getMessage()); - return null; - } - } - private String readVersionCodeString(XMLElement manifestRoot){ - String versionString = manifestRoot.getAttributeValue("android:compileSdkVersion"); - if(versionString!=null){ - return versionString; - } - versionString = manifestRoot.getAttributeValue("platformBuildVersionCode"); - if(versionString!=null){ - return versionString; - } - for(XMLElement element:manifestRoot.listChildElements()){ - if(AndroidManifestBlock.TAG_uses_sdk.equals(element.getTagName())){ - versionString = element.getAttributeValue("android:targetSdkVersion"); - if(versionString!=null){ - return versionString; - } - } - } - return null; - } - - public void setPreferredFramework(Integer version) throws IOException { - if(version!=null && version.equals(preferredFramework)){ - return; - } - this.preferredFramework = version; - if(version == null || mTableBlock==null){ - return; - } - logMessage("Initializing preferred framework: " + version); - mTableBlock.clearFrameworks(); - FrameworkApk frameworkApk = AndroidFrameworks.getBestMatch(version); - AndroidFrameworks.setCurrent(frameworkApk); - mTableBlock.addFramework(frameworkApk.getTableBlock()); - logMessage("Initialized framework: " + frameworkApk.getVersionCode()); - } - - public Integer getAndroidFrameworkVersion(){ - if(preferredFramework != null){ - return preferredFramework; - } - if(!hasAndroidManifestBlock()){ - return null; - } - AndroidManifestBlock manifestBlock = getAndroidManifestBlock(); - Integer version = manifestBlock.getCompileSdkVersion(); - if(version == null){ - version = manifestBlock.getPlatformBuildVersionCode(); - } - if(version == null){ - version = manifestBlock.getTargetSdkVersion(); - } - return version; - } - public void removeResFilesWithEntry(int resourceId) { - removeResFilesWithEntry(resourceId, null, true); - } - public void removeResFilesWithEntry(int resourceId, ResConfig resConfig, boolean trimEntryArray) { - List removedList = removeResFiles(resourceId, resConfig); - SpecTypePair specTypePair = null; - for(Entry entry:removedList){ - if(entry == null || entry.isNull()){ - continue; - } - if(trimEntryArray && specTypePair==null){ - specTypePair = entry.getTypeBlock().getParentSpecTypePair(); - } - entry.setNull(true); - } - if(specTypePair!=null){ - specTypePair.removeNullEntries(resourceId); - } - } - public List removeResFiles(int resourceId) { - return removeResFiles(resourceId, null); - } - public List removeResFiles(int resourceId, ResConfig resConfig) { - List results = new ArrayList<>(); - if(resourceId == 0 && resConfig==null){ - return results; - } - List resFileList = listResFiles(resourceId, resConfig); - APKArchive archive = getApkArchive(); - for(ResFile resFile:resFileList){ - results.addAll(resFile.getEntryList()); - String path = resFile.getFilePath(); - archive.remove(path); - } - return results; - } - public XMLDocument decodeXMLFile(String path) throws IOException, XMLException { - ResXmlDocument resXmlDocument = loadResXmlDocument(path); - AndroidManifestBlock manifestBlock = getAndroidManifestBlock(); - int pkgId = manifestBlock.guessCurrentPackageId(); - return resXmlDocument.decodeToXml(getTableBlock(), pkgId); - } - public List listDexFiles(){ - List results=new ArrayList<>(); - for(InputSource source:getApkArchive().listInputSources()){ - if(DexFileInputSource.isDexName(source.getAlias())){ - results.add(new DexFileInputSource(source.getAlias(), source)); - } - } - DexFileInputSource.sort(results); - return results; - } - public boolean isBaseModule(){ - if(!hasAndroidManifestBlock()){ - return false; - } - AndroidManifestBlock manifestBlock; - try { - manifestBlock=getAndroidManifestBlock(); - return manifestBlock.getMainActivity()!=null; - } catch (Exception ignored) { - return false; - } - } - public String getModuleName(){ - return moduleName; - } - public void writeApk(File file) throws IOException { - writeApk(file, null); - } - public void writeApk(File file, WriteProgress progress) throws IOException { - writeApk(file, progress, null); - } - public void writeApk(File file, WriteProgress progress, WriteInterceptor interceptor) throws IOException { - APKArchive archive = getApkArchive(); - UncompressedFiles uf = getUncompressedFiles(); - uf.apply(archive); - ApkWriter apkWriter = new ApkWriter(file, archive.listInputSources()); - apkWriter.setAPKLogger(getApkLogger()); - apkWriter.setWriteProgress(progress); - apkWriter.setApkSignatureBlock(getApkSignatureBlock()); - apkWriter.write(); - apkWriter.close(); - } - public void uncompressNonXmlResFiles() { - for(ResFile resFile:listResFiles()){ - if(resFile.isBinaryXml()){ - continue; - } - resFile.getInputSource().setMethod(ZipEntry.STORED); - } - } - public UncompressedFiles getUncompressedFiles(){ - return mUncompressedFiles; - } - public void removeDir(String dirName){ - getApkArchive().removeDir(dirName); - } - public void validateResourcesDir() { - List resFileList = listResFiles(); - Set existPaths=new HashSet<>(); - List sourceList = getApkArchive().listInputSources(); - for(InputSource inputSource:sourceList){ - existPaths.add(inputSource.getAlias()); - } - for(ResFile resFile:resFileList){ - String path=resFile.getFilePath(); - String pathNew=resFile.validateTypeDirectoryName(); - if(pathNew==null || pathNew.equals(path)){ - continue; - } - if(existPaths.contains(pathNew)){ - continue; - } - existPaths.remove(path); - existPaths.add(pathNew); - resFile.setFilePath(pathNew); - if(resFile.getInputSource().getMethod() == ZipEntry.STORED){ - getUncompressedFiles().replacePath(path, pathNew); - } - logVerbose("Dir validated: '"+path+"' -> '"+pathNew+"'"); - } - TableStringPool stringPool= getTableBlock().getStringPool(); - stringPool.refreshUniqueIdMap(); - getTableBlock().refresh(); - } - public void setResourcesRootDir(String dirName) { - List resFileList = listResFiles(); - Set existPaths=new HashSet<>(); - List sourceList = getApkArchive().listInputSources(); - for(InputSource inputSource:sourceList){ - existPaths.add(inputSource.getAlias()); - } - for(ResFile resFile:resFileList){ - String path=resFile.getFilePath(); - String pathNew=ApkUtil.replaceRootDir(path, dirName); - if(existPaths.contains(pathNew)){ - continue; - } - existPaths.remove(path); - existPaths.add(pathNew); - resFile.setFilePath(pathNew); - if(resFile.getInputSource().getMethod() == ZipEntry.STORED){ - getUncompressedFiles().replacePath(path, pathNew); - } - logVerbose("Root changed: '"+path+"' -> '"+pathNew+"'"); - } - TableStringPool stringPool= getTableBlock().getStringPool(); - stringPool.refreshUniqueIdMap(); - getTableBlock().refresh(); - } - public List listResFiles() { - return listResFiles(0, null); - } - public List listResFiles(int resourceId, ResConfig resConfig) { - List results=new ArrayList<>(); - TableBlock tableBlock=getTableBlock(); - if (tableBlock==null){ - return results; - } - TableStringPool stringPool= tableBlock.getStringPool(); - for(InputSource inputSource:getApkArchive().listInputSources()){ - String name=inputSource.getAlias(); - StringGroup groupTableString = stringPool.get(name); - if(groupTableString==null){ - continue; - } - for(TableString tableString:groupTableString.listItems()){ - List entryList = filterResFileEntries( - tableString.listReferencedResValueEntries(), resourceId, resConfig); - if(entryList.size()==0){ - continue; - } - ResFile resFile = new ResFile(inputSource, entryList); - results.add(resFile); - } - } - return results; - } - private List filterResFileEntries(List entryList, int resourceId, ResConfig resConfig){ - if(resourceId == 0 && resConfig == null || entryList.size()==0){ - return entryList; - } - List results = new ArrayList<>(); - for(Entry entry:entryList){ - if(entry==null || entry.isNull()){ - continue; - } - if(resourceId!=0 && resourceId!=entry.getResourceId()){ - continue; - } - if(resConfig!=null && !resConfig.equals(entry.getResConfig())){ - continue; - } - results.add(entry); - } - return results; - } - public String getPackageName(){ - if(hasAndroidManifestBlock()){ - return getAndroidManifestBlock().getPackageName(); - } - if(!hasTableBlock()){ - return null; - } - TableBlock tableBlock=getTableBlock(); - PackageArray pkgArray = tableBlock.getPackageArray(); - PackageBlock pkg = pkgArray.get(0); - if(pkg==null){ - return null; - } - return pkg.getName(); - } - public void setPackageName(String name) { - String old=getPackageName(); - if(hasAndroidManifestBlock()){ - getAndroidManifestBlock().setPackageName(name); - } - if(!hasTableBlock()){ - return; - } - TableBlock tableBlock=getTableBlock(); - PackageArray pkgArray = tableBlock.getPackageArray(); - for(PackageBlock pkg:pkgArray.listItems()){ - if(pkgArray.childesCount()==1){ - pkg.setName(name); - continue; - } - String pkgName=pkg.getName(); - if(pkgName.startsWith(old)){ - pkgName=pkgName.replace(old, name); - pkg.setName(pkgName); - } - } - } - public boolean hasAndroidManifestBlock(){ - return mManifestBlock!=null - || getApkArchive().getInputSource(AndroidManifestBlock.FILE_NAME)!=null; - } - public boolean hasTableBlock(){ - return mTableBlock!=null - || getApkArchive().getInputSource(TableBlock.FILE_NAME)!=null; - } - public void destroy(){ - getApkArchive().clear(); - AndroidManifestBlock manifestBlock = this.mManifestBlock; - if(manifestBlock!=null){ - manifestBlock.destroy(); - this.mManifestBlock = null; - } - TableBlock tableBlock = this.mTableBlock; - if(tableBlock!=null){ - tableBlock.destroy(); - this.mTableBlock = null; - } - } - public void setManifest(AndroidManifestBlock manifestBlock){ - APKArchive archive = getApkArchive(); - if(manifestBlock==null){ - mManifestBlock = null; - archive.remove(AndroidManifestBlock.FILE_NAME); - return; - } - manifestBlock.setApkFile(this); - BlockInputSource source = - new BlockInputSource<>(AndroidManifestBlock.FILE_NAME, manifestBlock); - archive.add(source); - mManifestBlock = manifestBlock; - } - public void setTableBlock(TableBlock tableBlock){ - APKArchive archive = getApkArchive(); - if(tableBlock == null){ - mTableBlock = null; - archive.remove(TableBlock.FILE_NAME); - return; - } - tableBlock.setApkFile(this); - BlockInputSource source = - new BlockInputSource<>(TableBlock.FILE_NAME, tableBlock); - archive.add(source); - source.setMethod(ZipEntry.STORED); - getUncompressedFiles().addPath(source); - mTableBlock = tableBlock; - } - @Override - public AndroidManifestBlock getAndroidManifestBlock() { - if(mManifestBlock!=null){ - return mManifestBlock; - } - APKArchive archive=getApkArchive(); - InputSource inputSource = archive.getInputSource(AndroidManifestBlock.FILE_NAME); - if(inputSource==null){ - return null; - } - InputStream inputStream = null; - try { - inputStream = inputSource.openStream(); - AndroidManifestBlock manifestBlock=AndroidManifestBlock.load(inputStream); - inputStream.close(); - BlockInputSource blockInputSource=new BlockInputSource<>(inputSource.getName(),manifestBlock); - blockInputSource.setSort(inputSource.getSort()); - blockInputSource.setMethod(inputSource.getMethod()); - archive.add(blockInputSource); - manifestBlock.setApkFile(this); - TableBlock tableBlock = this.mTableBlock; - if(tableBlock != null){ - int packageId = manifestBlock.guessCurrentPackageId(); - if(packageId != 0){ - manifestBlock.setPackageBlock(tableBlock.pickOne(packageId)); - }else { - manifestBlock.setPackageBlock(tableBlock.pickOne()); - } - } - mManifestBlock = manifestBlock; - onManifestBlockLoaded(manifestBlock); - } catch (IOException exception) { - throw new IllegalArgumentException(exception); - } - return mManifestBlock; - } - private void onManifestBlockLoaded(AndroidManifestBlock manifestBlock){ - initializeApkType(manifestBlock); - } - public TableBlock getTableBlock(boolean initFramework) { - if(mTableBlock==null){ - if(!hasTableBlock()){ - return null; - } - try { - mTableBlock = loadTableBlock(); - if(initFramework && loadDefaultFramework){ - Integer version = getAndroidFrameworkVersion(); - initializeAndroidFramework(mTableBlock, version); - } - } catch (IOException exception) { - throw new IllegalArgumentException(exception); - } - } - return mTableBlock; - } - @Override - public TableBlock getTableBlock() { - return getTableBlock(!mDisableLoadFramework); - } - @Override - public ResXmlDocument loadResXmlDocument(String path) throws IOException{ - InputSource inputSource = getApkArchive().getInputSource(path); - if(inputSource==null){ - throw new FileNotFoundException("No such file in apk: " + path); - } - return loadResXmlDocument(inputSource); - } - public ResXmlDocument loadResXmlDocument(InputSource inputSource) throws IOException{ - ResXmlDocument resXmlDocument = new ResXmlDocument(); - resXmlDocument.setApkFile(this); - resXmlDocument.readBytes(inputSource.openStream()); - return resXmlDocument; - } - @Override - public Decoder getDecoder(){ - return mDecoder; - } - @Override - public void setDecoder(Decoder decoder){ - this.mDecoder = decoder; - } - public ApkType getApkType(){ - if(mApkType!=null){ - return mApkType; - } - return initializeApkType(mManifestBlock); - } - public void setApkType(ApkType apkType){ - this.mApkType = apkType; - } - private ApkType initializeApkType(AndroidManifestBlock manifestBlock){ - if(mApkType!=null){ - return mApkType; - } - ApkType apkType = null; - if(manifestBlock!=null){ - apkType = manifestBlock.guessApkType(); - } - if(apkType != null){ - mApkType = apkType; - }else { - apkType = ApkType.UNKNOWN; - } - return apkType; - } - - // If we need TableStringPool only, this loads pool without - // loading packages and other chunk blocks for faster and less memory usage - public TableStringPool getVolatileTableStringPool() throws IOException{ - if(mTableBlock!=null){ - return mTableBlock.getStringPool(); - } - InputSource inputSource = getApkArchive() - .getInputSource(TableBlock.FILE_NAME); - if(inputSource==null){ - throw new IOException("Module don't have: "+TableBlock.FILE_NAME); - } - if((inputSource instanceof ZipEntrySource) - ||(inputSource instanceof FileInputSource)){ - InputStream inputStream = inputSource.openStream(); - TableStringPool stringPool = TableStringPool.readFromTable(inputStream); - inputStream.close(); - return stringPool; - } - return getTableBlock().getStringPool(); - } - TableBlock loadTableBlock() throws IOException { - APKArchive archive=getApkArchive(); - InputSource inputSource = archive.getInputSource(TableBlock.FILE_NAME); - if(inputSource==null){ - throw new IOException("Entry not found: "+TableBlock.FILE_NAME); - } - TableBlock tableBlock; - if(inputSource instanceof SplitJsonTableInputSource){ - tableBlock=((SplitJsonTableInputSource)inputSource).getTableBlock(); - }else if(inputSource instanceof SingleJsonTableInputSource){ - tableBlock=((SingleJsonTableInputSource)inputSource).getTableBlock(); - }else if(inputSource instanceof BlockInputSource){ - Chunk block = ((BlockInputSource) inputSource).getBlock(); - tableBlock = (TableBlock) block; - }else { - InputStream inputStream = inputSource.openStream(); - tableBlock = TableBlock.load(inputStream); - inputStream.close(); - } - BlockInputSource blockInputSource=new BlockInputSource<>(inputSource.getName(), tableBlock); - blockInputSource.setMethod(inputSource.getMethod()); - blockInputSource.setSort(inputSource.getSort()); - archive.add(blockInputSource); - tableBlock.setApkFile(this); - return tableBlock; - } - public APKArchive getApkArchive() { - return apkArchive; - } - public void setLoadDefaultFramework(boolean loadDefaultFramework) { - this.loadDefaultFramework = loadDefaultFramework; - this.mDisableLoadFramework = !loadDefaultFramework; - } - - public void merge(ApkModule module) throws IOException { - if(module==null||module==this){ - return; - } - logMessage("Merging: "+module.getModuleName()); - mergeDexFiles(module); - mergeTable(module); - mergeFiles(module); - getUncompressedFiles().merge(module.getUncompressedFiles()); - } - private void mergeTable(ApkModule module) { - if(!module.hasTableBlock()){ - return; - } - logMessage("Merging resource table: "+module.getModuleName()); - TableBlock exist; - if(!hasTableBlock()){ - exist=new TableBlock(); - BlockInputSource inputSource=new BlockInputSource<>(TableBlock.FILE_NAME, exist); - getApkArchive().add(inputSource); - }else{ - exist=getTableBlock(); - } - TableBlock coming=module.getTableBlock(); - exist.merge(coming); - } - private void mergeFiles(ApkModule module) { - APKArchive archiveExist = getApkArchive(); - APKArchive archiveComing = module.getApkArchive(); - Map comingAlias=ApkUtil.toAliasMap(archiveComing.listInputSources()); - Map existAlias=ApkUtil.toAliasMap(archiveExist.listInputSources()); - UncompressedFiles uncompressedFiles = module.getUncompressedFiles(); - for(InputSource inputSource:comingAlias.values()){ - if(existAlias.containsKey(inputSource.getAlias())||existAlias.containsKey(inputSource.getName())){ - continue; - } - if(DexFileInputSource.isDexName(inputSource.getName())){ - continue; - } - if (inputSource.getAlias().startsWith("lib/")){ - uncompressedFiles.removePath(inputSource.getAlias()); - } - logVerbose("Added: "+inputSource.getAlias()); - archiveExist.add(inputSource); - } - } - private void mergeDexFiles(ApkModule module){ - UncompressedFiles uncompressedFiles=module.getUncompressedFiles(); - List existList=listDexFiles(); - List comingList=module.listDexFiles(); - APKArchive archive=getApkArchive(); - int index=0; - if(existList.size()>0){ - index=existList.get(existList.size()-1).getDexNumber(); - if(index==0){ - index=2; - }else { - index++; - } - } - for(DexFileInputSource source:comingList){ - uncompressedFiles.removePath(source.getAlias()); - String name= DexFileInputSource.getDexName(index); - DexFileInputSource add=new DexFileInputSource(name, source.getInputSource()); - archive.add(add); - logMessage("Added ["+module.getModuleName()+"] " - +source.getAlias()+" -> "+name); - index++; - if(index==1){ - index=2; - } - } - } - APKLogger getApkLogger(){ - return apkLogger; - } - public void setAPKLogger(APKLogger logger) { - this.apkLogger = logger; - } - void logMessage(String msg) { - if(apkLogger!=null){ - apkLogger.logMessage(msg); - } - } - private void logError(String msg, Throwable tr) { - if(apkLogger!=null){ - apkLogger.logError(msg, tr); - } - } - private void logVerbose(String msg) { - if(apkLogger!=null){ - apkLogger.logVerbose(msg); - } - } - @Override - public String toString(){ - return getModuleName(); - } - public static ApkModule loadApkFile(File apkFile) throws IOException { - return loadApkFile(apkFile, ApkUtil.DEF_MODULE_NAME); - } - public static ApkModule loadApkFile(File apkFile, String moduleName) throws IOException { - Archive archive = new Archive(apkFile); - ApkModule apkModule = new ApkModule(moduleName, archive.createAPKArchive()); - apkModule.setApkSignatureBlock(archive.getApkSignatureBlock()); - return apkModule; - } -} diff --git a/src/ARSCLib/com/reandroid/apk/ApkModuleXmlDecoder.java b/src/ARSCLib/com/reandroid/apk/ApkModuleXmlDecoder.java deleted file mode 100644 index 1881bfdd..00000000 --- a/src/ARSCLib/com/reandroid/apk/ApkModuleXmlDecoder.java +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.apk.xmldecoder.*; -import com.reandroid.archive.InputSource; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.chunk.xml.AndroidManifestBlock; -import com.reandroid.arsc.chunk.xml.ResXmlDocument; -import com.reandroid.arsc.container.SpecTypePair; -import com.reandroid.arsc.value.*; -import com.reandroid.identifiers.PackageIdentifier; -import com.reandroid.json.JSONObject; -import com.reandroid.xml.XMLDocument; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.*; -import java.util.function.Predicate; - -public class ApkModuleXmlDecoder extends ApkDecoder implements Predicate { - private final ApkModule apkModule; - private final Map> decodedEntries; - - private ResXmlDocumentSerializer documentSerializer; - private XMLEntryDecoderSerializer entrySerializer; - - - public ApkModuleXmlDecoder(ApkModule apkModule){ - super(); - this.apkModule = apkModule; - this.decodedEntries = new HashMap<>(); - super.setApkLogger(apkModule.getApkLogger()); - } - public void sanitizeFilePaths(){ - PathSanitizer sanitizer = PathSanitizer.create(apkModule); - sanitizer.sanitize(); - } - @Override - void onDecodeTo(File outDir) throws IOException{ - this.decodedEntries.clear(); - logMessage("Decoding ..."); - - if(!apkModule.hasTableBlock()){ - logOrThrow(null, new IOException("Don't have resource table")); - return; - } - - decodeUncompressedFiles(outDir); - - TableBlock tableBlock = apkModule.getTableBlock(); - - this.entrySerializer = new XMLEntryDecoderSerializer(tableBlock); - this.entrySerializer.setDecodedEntries(this); - - decodeAndroidManifest(outDir, apkModule.getAndroidManifestBlock()); - decodeTableBlock(outDir, tableBlock); - - logMessage("Decoding resource files ..."); - List resFileList = apkModule.listResFiles(); - for(ResFile resFile:resFileList){ - decodeResFile(outDir, resFile); - } - decodeValues(outDir, tableBlock); - - extractRootFiles(outDir); - - writePathMap(outDir, apkModule.getApkArchive().listInputSources()); - - dumpSignatures(outDir, apkModule.getApkSignatureBlock()); - } - private void decodeTableBlock(File outDir, TableBlock tableBlock) throws IOException { - try{ - decodePackageInfo(outDir, tableBlock); - decodePublicXml(tableBlock, outDir); - addDecodedPath(TableBlock.FILE_NAME); - }catch (IOException exception){ - logOrThrow("Error decoding resource table", exception); - } - } - private void decodePackageInfo(File outDir, TableBlock tableBlock) throws IOException { - for(PackageBlock packageBlock:tableBlock.listPackages()){ - decodePackageInfo(outDir, packageBlock); - } - } - private void decodePackageInfo(File outDir, PackageBlock packageBlock) throws IOException { - File pkgDir = new File(outDir, getPackageDirName(packageBlock)); - File packageJsonFile = new File(pkgDir, PackageBlock.JSON_FILE_NAME); - JSONObject jsonObject = packageBlock.toJson(false); - jsonObject.write(packageJsonFile); - } - private void decodeUncompressedFiles(File outDir) - throws IOException { - File file=new File(outDir, UncompressedFiles.JSON_FILE); - UncompressedFiles uncompressedFiles = apkModule.getUncompressedFiles(); - uncompressedFiles.toJson().write(file); - } - private void decodeResFile(File outDir, ResFile resFile) - throws IOException{ - if(resFile.isBinaryXml()){ - decodeResXml(outDir, resFile); - }else { - decodeResRaw(outDir, resFile); - } - addDecodedPath(resFile.getFilePath()); - } - private void decodeResRaw(File outDir, ResFile resFile) - throws IOException { - Entry entry = resFile.pickOne(); - PackageBlock packageBlock= entry.getPackageBlock(); - - File pkgDir=new File(outDir, getPackageDirName(packageBlock)); - String alias = resFile.buildPath(ApkUtil.RES_DIR_NAME); - String path = alias.replace('/', File.separatorChar); - File file=new File(pkgDir, path); - File dir=file.getParentFile(); - if(!dir.exists()){ - dir.mkdirs(); - } - FileOutputStream outputStream=new FileOutputStream(file); - resFile.getInputSource().write(outputStream); - outputStream.close(); - resFile.setFilePath(alias); - - addDecodedEntry(entry); - } - private void decodeResXml(File outDir, ResFile resFile) - throws IOException{ - Entry entry = resFile.pickOne(); - PackageBlock packageBlock = entry.getPackageBlock(); - - File pkgDir = new File(outDir, getPackageDirName(packageBlock)); - String alias = resFile.buildPath(ApkUtil.RES_DIR_NAME); - String path = alias.replace('/', File.separatorChar); - path = path.replace('/', File.separatorChar); - File file = new File(pkgDir, path); - - logVerbose("Decoding: " + path); - serializeXml(packageBlock.getId(), resFile.getInputSource(), file); - - resFile.setFilePath(alias); - addDecodedEntry(entry); - } - private ResXmlDocumentSerializer getDocumentSerializer(){ - if(documentSerializer == null){ - documentSerializer = new ResXmlDocumentSerializer(apkModule); - documentSerializer.setValidateXmlNamespace(true); - } - return documentSerializer; - } - private void decodePublicXml(TableBlock tableBlock, File outDir) - throws IOException{ - for(PackageBlock packageBlock:tableBlock.listPackages()){ - decodePublicXml(packageBlock, outDir); - } - if(tableBlock.getPackageArray().childesCount()==0){ - decodeEmptyTable(outDir); - } - } - private void decodeEmptyTable(File outDir) throws IOException { - logMessage("Decoding empty table ..."); - String pkgName = apkModule.getPackageName(); - if(pkgName==null){ - return; - } - File pkgDir = new File(outDir, "0-"+pkgName); - File resDir = new File(pkgDir, ApkUtil.RES_DIR_NAME); - File values = new File(resDir, "values"); - File pubXml = new File(values, ApkUtil.FILE_NAME_PUBLIC_XML); - XMLDocument xmlDocument = new XMLDocument("resources"); - xmlDocument.save(pubXml, false); - } - private void decodePublicXml(PackageBlock packageBlock, File outDir) - throws IOException { - String packageDirName=getPackageDirName(packageBlock); - logMessage("Decoding public.xml: "+packageDirName); - File file=new File(outDir, packageDirName); - file=new File(file, ApkUtil.RES_DIR_NAME); - file=new File(file, "values"); - file=new File(file, ApkUtil.FILE_NAME_PUBLIC_XML); - PackageIdentifier packageIdentifier = new PackageIdentifier(); - packageIdentifier.load(packageBlock); - packageIdentifier.writePublicXml(file); - } - private void decodeAndroidManifest(File outDir, AndroidManifestBlock manifestBlock) - throws IOException { - if(!apkModule.hasAndroidManifestBlock()){ - logMessage("Don't have: "+ AndroidManifestBlock.FILE_NAME); - return; - } - File file=new File(outDir, AndroidManifestBlock.FILE_NAME); - logMessage("Decoding: "+file.getName()); - int currentPackageId = manifestBlock.guessCurrentPackageId(); - serializeXml(currentPackageId, manifestBlock, file); - addDecodedPath(AndroidManifestBlock.FILE_NAME); - } - private void serializeXml(int currentPackageId, ResXmlDocument document, File outFile) - throws IOException { - XMLNamespaceValidator.validateNamespaces(document); - ResXmlDocumentSerializer serializer = getDocumentSerializer(); - if(currentPackageId != 0){ - serializer.getDecoder().setCurrentPackageId(currentPackageId); - } - try { - serializer.write(document, outFile); - } catch (XmlPullParserException ex) { - throw new IOException("Error: "+outFile.getName(), ex); - } - } - private void serializeXml(int currentPackageId, InputSource inputSource, File outFile) - throws IOException { - ResXmlDocumentSerializer serializer = getDocumentSerializer(); - if(currentPackageId != 0){ - serializer.getDecoder().setCurrentPackageId(currentPackageId); - } - try { - serializer.write(inputSource, outFile); - } catch (XmlPullParserException ex) { - throw new IOException("Error: "+outFile.getName(), ex); - } - } - private void addDecodedEntry(Entry entry){ - if(entry.isNull()){ - return; - } - int resourceId= entry.getResourceId(); - Set resConfigSet=decodedEntries.get(resourceId); - if(resConfigSet==null){ - resConfigSet=new HashSet<>(); - decodedEntries.put(resourceId, resConfigSet); - } - resConfigSet.add(entry.getResConfig()); - } - private boolean containsDecodedEntry(Entry entry){ - Set resConfigSet=decodedEntries.get(entry.getResourceId()); - if(resConfigSet==null){ - return false; - } - return resConfigSet.contains(entry.getResConfig()); - } - private void decodeValues(File outDir, TableBlock tableBlock) throws IOException { - for(PackageBlock packageBlock:tableBlock.listPackages()){ - decodeValues(outDir, packageBlock); - } - } - private void decodeValues(File outDir, PackageBlock packageBlock) throws IOException { - logMessage("Decoding values: " - + getPackageDirName(packageBlock)); - - packageBlock.sortTypes(); - - File pkgDir = new File(outDir, getPackageDirName(packageBlock)); - File resDir = new File(pkgDir, ApkUtil.RES_DIR_NAME); - - for(SpecTypePair specTypePair : packageBlock.listSpecTypePairs()){ - decodeValues(resDir, specTypePair); - } - } - private void decodeValues(File outDir, SpecTypePair specTypePair) throws IOException { - entrySerializer.decode(outDir, specTypePair); - } - private String getPackageDirName(PackageBlock packageBlock){ - String name = ApkUtil.sanitizeForFileName(packageBlock.getName()); - if(name==null){ - name="package"; - } - TableBlock tableBlock = packageBlock.getTableBlock(); - int index = packageBlock.getIndex(); - String prefix; - if(index < 10 && tableBlock.countPackages() > 10){ - prefix = "0" + index; - }else { - prefix = Integer.toString(index); - } - return prefix + "-" + name; - } - private void extractRootFiles(File outDir) throws IOException { - logMessage("Extracting root files"); - File rootDir = new File(outDir, "root"); - for(InputSource inputSource:apkModule.getApkArchive().listInputSources()){ - if(containsDecodedPath(inputSource.getAlias())){ - continue; - } - extractRootFiles(rootDir, inputSource); - addDecodedPath(inputSource.getAlias()); - } - } - private void extractRootFiles(File rootDir, InputSource inputSource) throws IOException { - String path=inputSource.getAlias(); - path=path.replace(File.separatorChar, '/'); - File file=new File(rootDir, path); - File dir=file.getParentFile(); - if(!dir.exists()){ - dir.mkdirs(); - } - FileOutputStream outputStream=new FileOutputStream(file); - inputSource.write(outputStream); - outputStream.close(); - } - @Override - public boolean test(Entry entry) { - return !containsDecodedEntry(entry); - } -} diff --git a/src/ARSCLib/com/reandroid/apk/ApkModuleXmlEncoder.java b/src/ARSCLib/com/reandroid/apk/ApkModuleXmlEncoder.java deleted file mode 100644 index f4be9b7e..00000000 --- a/src/ARSCLib/com/reandroid/apk/ApkModuleXmlEncoder.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.archive.APKArchive; -import com.reandroid.archive.FileInputSource; -import com.reandroid.apk.xmlencoder.RESEncoder; -import com.reandroid.archive2.block.ApkSignatureBlock; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.pool.TableStringPool; -import com.reandroid.json.JSONArray; -import com.reandroid.xml.XMLException; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.List; - -public class ApkModuleXmlEncoder { - private final RESEncoder resEncoder; - public ApkModuleXmlEncoder(){ - this.resEncoder = new RESEncoder(); - } - public ApkModuleXmlEncoder(ApkModule module, TableBlock tableBlock){ - this.resEncoder = new RESEncoder(module, tableBlock); - } - public void scanDirectory(File mainDirectory) throws IOException, XMLException { - loadUncompressedFiles(mainDirectory); - resEncoder.scanDirectory(mainDirectory); - File rootDir=new File(mainDirectory, "root"); - scanRootDir(rootDir); - restorePathMap(mainDirectory); - restoreSignatures(mainDirectory); - sortFiles(); - TableStringPool tableStringPool = getApkModule().getTableBlock().getTableStringPool(); - tableStringPool.removeUnusedStrings(); - } - private void restoreSignatures(File dir) throws IOException { - File sigDir = new File(dir, ApkUtil.SIGNATURE_DIR_NAME); - if(!sigDir.isDirectory()){ - return; - } - ApkModule apkModule = getApkModule(); - apkModule.logMessage("Loading signatures ..."); - ApkSignatureBlock signatureBlock = new ApkSignatureBlock(); - signatureBlock.scanSplitFiles(sigDir); - apkModule.setApkSignatureBlock(signatureBlock); - } - private void restorePathMap(File dir) throws IOException{ - File file = new File(dir, PathMap.JSON_FILE); - if(!file.isFile()){ - return; - } - PathMap pathMap = new PathMap(); - JSONArray jsonArray = new JSONArray(file); - pathMap.fromJson(jsonArray); - pathMap.restore(getApkModule()); - } - public ApkModule getApkModule(){ - return resEncoder.getApkModule(); - } - - private void scanRootDir(File rootDir){ - APKArchive archive=getApkModule().getApkArchive(); - List rootFileList=ApkUtil.recursiveFiles(rootDir); - for(File file:rootFileList){ - String path=ApkUtil.toArchivePath(rootDir, file); - FileInputSource inputSource=new FileInputSource(file, path); - archive.add(inputSource); - } - } - private void sortFiles(){ - APKArchive archive = getApkModule().getApkArchive(); - archive.autoSortApkFiles(); - } - private void loadUncompressedFiles(File mainDirectory) throws IOException { - File file=new File(mainDirectory, UncompressedFiles.JSON_FILE); - UncompressedFiles uncompressedFiles = getApkModule().getUncompressedFiles(); - uncompressedFiles.fromJson(file); - } - public void setApkLogger(APKLogger apkLogger) { - this.resEncoder.setAPKLogger(apkLogger); - } -} diff --git a/src/ARSCLib/com/reandroid/apk/ApkUtil.java b/src/ARSCLib/com/reandroid/apk/ApkUtil.java deleted file mode 100644 index d01bec3a..00000000 --- a/src/ARSCLib/com/reandroid/apk/ApkUtil.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.archive.InputSource; -import com.reandroid.archive2.block.ApkSignatureBlock; - -import java.io.File; -import java.util.*; - -public class ApkUtil { - public static String sanitizeForFileName(String name){ - if(name==null){ - return null; - } - StringBuilder builder = new StringBuilder(); - char[] chars = name.toCharArray(); - boolean skipNext = true; - int length = 0; - int lengthMax = MAX_FILE_NAME_LENGTH; - for(int i=0;i=lengthMax){ - break; - } - char ch = chars[i]; - if(isGoodFileNameSymbol(ch)){ - if(!skipNext){ - builder.append(ch); - length++; - } - skipNext=true; - continue; - } - if(!isGoodFileNameChar(ch)){ - skipNext = true; - continue; - } - builder.append(ch); - length++; - skipNext=false; - } - if(length==0){ - return null; - } - return builder.toString(); - } - private static boolean isGoodFileNameSymbol(char ch){ - return ch == '.' - || ch == '+' - || ch == '-' - || ch == '_' - || ch == '#'; - } - private static boolean isGoodFileNameChar(char ch){ - return (ch >= '0' && ch <= '9') - || (ch >= 'A' && ch <= 'Z') - || (ch >= 'a' && ch <= 'z'); - } - public static int parseHex(String hex){ - long l=Long.decode(hex); - return (int) l; - } - public static String replaceRootDir(String path, String dirName){ - int i=path.indexOf('/')+1; - path=path.substring(i); - if(dirName != null && dirName.length()>0){ - if(!dirName.endsWith("/")){ - dirName=dirName+"/"; - } - path=dirName+path; - } - return path; - } - public static String toArchiveResourcePath(File dir, File file){ - String path = toArchivePath(dir, file); - if(path.endsWith(ApkUtil.JSON_FILE_EXTENSION)){ - int i2=path.length()- ApkUtil.JSON_FILE_EXTENSION.length(); - path=path.substring(0, i2); - } - return path; - } - public static String toArchivePath(File dir, File file){ - String dirPath = dir.getAbsolutePath()+File.separator; - String path = file.getAbsolutePath().substring(dirPath.length()); - path=path.replace(File.separatorChar, '/'); - return path; - } - public static List recursiveFiles(File dir, String ext){ - List results=new ArrayList<>(); - if(dir.isFile()){ - if(hasExtension(dir, ext)){ - results.add(dir); - } - return results; - } - if(!dir.isDirectory()){ - return results; - } - File[] files=dir.listFiles(); - if(files==null){ - return results; - } - for(File file:files){ - if(file.isFile()){ - if(!hasExtension(file, ext)){ - continue; - } - results.add(file); - continue; - } - results.addAll(recursiveFiles(file, ext)); - } - return results; - } - public static List recursiveFiles(File dir){ - return recursiveFiles(dir, null); - } - public static List listDirectories(File dir){ - List results=new ArrayList<>(); - File[] files=dir.listFiles(); - if(files==null){ - return results; - } - for(File file:files){ - if(file.isDirectory()){ - results.add(file); - } - } - return results; - } - public static List listFiles(File dir, String ext){ - List results=new ArrayList<>(); - File[] files=dir.listFiles(); - if(files==null){ - return results; - } - for(File file:files){ - if(file.isFile()){ - if(!hasExtension(file, ext)){ - continue; - } - results.add(file); - } - } - return results; - } - private static boolean hasExtension(File file, String ext){ - if(ext==null){ - return true; - } - String name=file.getName().toLowerCase(); - ext=ext.toLowerCase(); - return name.endsWith(ext); - } - public static String toModuleName(File file){ - String name=file.getName(); - int i=name.lastIndexOf('.'); - if(i>0){ - name=name.substring(0,i); - } - return name; - } - public static Map toAliasMap(Collection sourceList){ - Map results=new HashMap<>(); - for(InputSource inputSource:sourceList){ - results.put(inputSource.getAlias(), inputSource); - } - return results; - } - public static final String JSON_FILE_EXTENSION=".json"; - public static final String RES_JSON_NAME="res-json"; - public static final String ROOT_NAME="root"; - public static final String SPLIT_JSON_DIRECTORY="resources"; - public static final String DEF_MODULE_NAME="base"; - public static final String NAME_value_type="value_type"; - public static final String NAME_data="data"; - public static final String RES_DIR_NAME="res"; - public static final String FILE_NAME_PUBLIC_XML ="public.xml"; - - public static final String TAG_STRING_ARRAY = "string-array"; - public static final String TAG_INTEGER_ARRAY = "integer-array"; - - public static final String SIGNATURE_FILE_NAME = "signatures" + ApkSignatureBlock.FILE_EXT; - public static final String SIGNATURE_DIR_NAME = "signatures"; - - private static final int MAX_FILE_NAME_LENGTH = 50; -} diff --git a/src/ARSCLib/com/reandroid/apk/BlockInputSource.java b/src/ARSCLib/com/reandroid/apk/BlockInputSource.java deleted file mode 100644 index c5018c9a..00000000 --- a/src/ARSCLib/com/reandroid/apk/BlockInputSource.java +++ /dev/null @@ -1,55 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.archive.ByteInputSource; -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.chunk.Chunk; - -import java.io.IOException; -import java.io.OutputStream; - -public class BlockInputSource> extends ByteInputSource{ - private final T mBlock; - public BlockInputSource(String name, T block) { - super(new byte[0], name); - this.mBlock=block; - } - public T getBlock() { - mBlock.refresh(); - return mBlock; - } - @Override - public long getLength() throws IOException{ - Block block = getBlock(); - return block.countBytes(); - } - @Override - public long getCrc() throws IOException{ - Block block = getBlock(); - CrcOutputStream outputStream=new CrcOutputStream(); - block.writeBytes(outputStream); - return outputStream.getCrcValue(); - } - @Override - public long write(OutputStream outputStream) throws IOException { - return getBlock().writeBytes(outputStream); - } - @Override - public byte[] getBytes() { - return getBlock().getBytes(); - } -} diff --git a/src/ARSCLib/com/reandroid/apk/CrcOutputStream.java b/src/ARSCLib/com/reandroid/apk/CrcOutputStream.java deleted file mode 100644 index b99d5f3f..00000000 --- a/src/ARSCLib/com/reandroid/apk/CrcOutputStream.java +++ /dev/null @@ -1,53 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.zip.CRC32; - -public class CrcOutputStream extends OutputStream { - private final CRC32 crc; - private long length; - private long mCheckSum; - public CrcOutputStream() { - super(); - this.crc = new CRC32(); - } - public long getLength(){ - return length; - } - public long getCrcValue(){ - if(mCheckSum==0){ - mCheckSum=crc.getValue(); - } - return mCheckSum; - } - @Override - public void write(int b) throws IOException { - this.crc.update(b); - length=length+1; - } - @Override - public void write(byte[] b) throws IOException { - this.write(b, 0, b.length); - } - @Override - public void write(byte[] b, int off, int len) throws IOException { - this.crc.update(b, off, len); - length=length+len; - } -} diff --git a/src/ARSCLib/com/reandroid/apk/DexFileInputSource.java b/src/ARSCLib/com/reandroid/apk/DexFileInputSource.java deleted file mode 100644 index 195d6990..00000000 --- a/src/ARSCLib/com/reandroid/apk/DexFileInputSource.java +++ /dev/null @@ -1,66 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.archive.InputSource; - -import java.util.Comparator; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class DexFileInputSource extends RenamedInputSource implements Comparable{ - public DexFileInputSource(String name, InputSource inputSource){ - super(name, inputSource); - } - public int getDexNumber(){ - return getDexNumber(getAlias()); - } - @Override - public int compareTo(DexFileInputSource source) { - return Integer.compare(getDexNumber(), source.getDexNumber()); - } - public static void sort(List sourceList){ - sourceList.sort(new Comparator() { - @Override - public int compare(DexFileInputSource s1, DexFileInputSource s2) { - return s1.compareTo(s2); - } - }); - } - public static boolean isDexName(String name){ - return getDexNumber(name)>=0; - } - static String getDexName(int i){ - if(i==0){ - return "classes.dex"; - } - return "classes"+i+".dex"; - } - static int getDexNumber(String name){ - Matcher matcher=PATTERN.matcher(name); - if(!matcher.find()){ - return -1; - } - String num=matcher.group(1); - if(num.length()==0){ - return 0; - } - return Integer.parseInt(num); - } - private static final Pattern PATTERN=Pattern.compile("^classes([0-9]*)\\.dex$"); - -} diff --git a/src/ARSCLib/com/reandroid/apk/FileMagic.java b/src/ARSCLib/com/reandroid/apk/FileMagic.java deleted file mode 100644 index f8acba2f..00000000 --- a/src/ARSCLib/com/reandroid/apk/FileMagic.java +++ /dev/null @@ -1,96 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.archive.InputSource; - -import java.io.IOException; -import java.io.InputStream; - -public class FileMagic { - - public static String getExtensionFromMagic(InputSource inputSource) throws IOException { - byte[] magic=readFileMagic(inputSource); - if(magic==null){ - return null; - } - if(isPng(magic)){ - return ".png"; - } - if(isJpeg(magic)){ - return ".jpg"; - } - if(isWebp(magic)){ - return ".webp"; - } - if(isTtf(magic)){ - return ".ttf"; - } - return null; - } - - private static boolean isJpeg(byte[] magic){ - return compareMagic(MAGIC_JPG, magic); - } - private static boolean isPng(byte[] magic){ - return compareMagic(MAGIC_PNG, magic); - } - private static boolean isWebp(byte[] magic){ - return compareMagic(MAGIC_WEBP, magic); - } - private static boolean isTtf(byte[] magic){ - return compareMagic(MAGIC_TTF, magic); - } - private static boolean compareMagic(byte[] magic, byte[] readMagic){ - if(magic==null || readMagic==null){ - return false; - } - int max=magic.length; - if(max>readMagic.length){ - max=readMagic.length; - } - if(max==0){ - return false; - } - for(int i=0;i blockInputSource=new BlockInputSource<>(inputSource.getName(), frameworkTable); - blockInputSource.setMethod(inputSource.getMethod()); - blockInputSource.setSort(inputSource.getSort()); - archive.add(blockInputSource); - return frameworkTable; - } - public void optimize(){ - synchronized (mLock){ - if(mOptimizing){ - return; - } - if(!hasTableBlock()){ - mOptimizing = false; - return; - } - FrameworkTable frameworkTable = getTableBlock(); - if(frameworkTable.isOptimized()){ - mOptimizing = false; - return; - } - FrameworkOptimizer optimizer = new FrameworkOptimizer(this); - optimizer.optimize(); - mOptimizing = false; - } - } - public String getName(){ - if(isDestroyed()){ - return "destroyed"; - } - String pkg = getPackageName(); - if(pkg==null){ - return ""; - } - return pkg + "-" + getVersionCode(); - } - @Override - public int hashCode(){ - return Objects.hash(getClass(), getName()); - } - @Override - public boolean equals(Object obj){ - if(obj==this){ - return true; - } - if(getClass()!=obj.getClass()){ - return false; - } - FrameworkApk other = (FrameworkApk) obj; - return getName().equals(other.getName()); - } - @Override - public String toString(){ - return getName(); - } - public static FrameworkApk loadApkFile(File apkFile) throws IOException { - Archive archive = new Archive(apkFile); - APKArchive apkArchive = new APKArchive(archive.mapEntrySource()); - return new FrameworkApk(apkArchive); - } - public static FrameworkApk loadApkFile(File apkFile, String moduleName) throws IOException { - Archive archive = new Archive(apkFile); - APKArchive apkArchive = new APKArchive(archive.mapEntrySource()); - return new FrameworkApk(moduleName, apkArchive); - } - public static boolean isFramework(ApkModule apkModule) { - if(!apkModule.hasAndroidManifestBlock()){ - return false; - } - return isFramework(apkModule.getAndroidManifestBlock()); - } - public static boolean isFramework(AndroidManifestBlock manifestBlock){ - ResXmlElement root = manifestBlock.getManifestElement(); - ResXmlAttribute attribute = root.getStartElement() - .searchAttributeByName(AndroidManifestBlock.NAME_coreApp); - if(attribute==null || attribute.getValueType()!= ValueType.INT_BOOLEAN){ - return false; - } - return attribute.getValueAsBoolean(); - } - public static FrameworkApk loadApkBuffer(InputStream inputStream) throws IOException{ - return loadApkBuffer("framework", inputStream); - } - public static FrameworkApk loadApkBuffer(String moduleName, InputStream inputStream) throws IOException { - APKArchive archive = new APKArchive(); - FrameworkApk frameworkApk = new FrameworkApk(moduleName, archive); - Map inputSourceMap = InputSourceUtil.mapInputStreamAsBuffer(inputStream); - ByteInputSource source = inputSourceMap.get(TableBlock.FILE_NAME); - FrameworkTable tableBlock = new FrameworkTable(); - if(source!=null){ - tableBlock.readBytes(source.openStream()); - } - frameworkApk.setTableBlock(tableBlock); - - AndroidManifestBlock manifestBlock = new AndroidManifestBlock(); - source = inputSourceMap.get(AndroidManifestBlock.FILE_NAME); - if(source!=null){ - manifestBlock.readBytes(source.openStream()); - } - frameworkApk.setManifest(manifestBlock); - archive.addAll(inputSourceMap.values()); - return frameworkApk; - } - public static void optimize(File in, File out, APKLogger apkLogger) throws IOException{ - FrameworkApk frameworkApk = FrameworkApk.loadApkFile(in); - frameworkApk.setAPKLogger(apkLogger); - frameworkApk.optimize(); - frameworkApk.writeApk(out); - } -} diff --git a/src/ARSCLib/com/reandroid/apk/FrameworkOptimizer.java b/src/ARSCLib/com/reandroid/apk/FrameworkOptimizer.java deleted file mode 100644 index a02f7ccc..00000000 --- a/src/ARSCLib/com/reandroid/apk/FrameworkOptimizer.java +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.archive.APKArchive; -import com.reandroid.archive.InputSource; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.chunk.xml.AndroidManifestBlock; -import com.reandroid.arsc.chunk.xml.ResXmlAttribute; -import com.reandroid.arsc.chunk.xml.ResXmlElement; -import com.reandroid.arsc.chunk.xml.ResXmlNode; -import com.reandroid.arsc.group.EntryGroup; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.pool.ResXmlStringPool; -import com.reandroid.arsc.util.FrameworkTable; -import com.reandroid.arsc.value.*; - -import java.io.IOException; -import java.util.*; -import java.util.zip.ZipEntry; - - public class FrameworkOptimizer { - private final ApkModule frameworkApk; - private APKLogger apkLogger; - private boolean mOptimizing; - public FrameworkOptimizer(ApkModule frameworkApk){ - this.frameworkApk = frameworkApk; - this.apkLogger = frameworkApk.getApkLogger(); - } - public void optimize(){ - if(mOptimizing){ - return; - } - mOptimizing = true; - if(!frameworkApk.hasTableBlock()){ - logMessage("Don't have: "+TableBlock.FILE_NAME); - mOptimizing = false; - return; - } - FrameworkTable frameworkTable = getFrameworkTable(); - AndroidManifestBlock manifestBlock = null; - if(frameworkApk.hasAndroidManifestBlock()){ - manifestBlock = frameworkApk.getAndroidManifestBlock(); - } - optimizeTable(frameworkTable, manifestBlock); - UncompressedFiles uncompressedFiles = frameworkApk.getUncompressedFiles(); - uncompressedFiles.clearExtensions(); - uncompressedFiles.clearPaths(); - clearFiles(frameworkApk.getApkArchive()); - logMessage("Optimized"); - } - private void clearFiles(APKArchive archive){ - int count = archive.entriesCount(); - if(count==2){ - return; - } - logMessage("Removing files from: "+count); - InputSource tableSource = archive.getInputSource(TableBlock.FILE_NAME); - InputSource manifestSource = archive.getInputSource(AndroidManifestBlock.FILE_NAME); - archive.clear(); - if(tableSource!=null){ - tableSource.setMethod(ZipEntry.DEFLATED); - } - if(manifestSource!=null){ - manifestSource.setMethod(ZipEntry.DEFLATED); - } - archive.add(tableSource); - archive.add(manifestSource); - count = count - archive.entriesCount(); - logMessage("Removed files: "+count); - } - private void optimizeTable(FrameworkTable table, AndroidManifestBlock manifestBlock){ - if(table.isOptimized()){ - return; - } - logMessage("Optimizing ..."); - int prev = table.countBytes(); - int version = 0; - String name = "framework"; - if(manifestBlock !=null){ - Integer code = manifestBlock.getVersionCode(); - if(code!=null){ - version = code; - } - name = manifestBlock.getPackageName(); - compressManifest(manifestBlock); - backupManifestValue(manifestBlock, table); - } - logMessage("Optimizing table ..."); - table.optimize(name, version); - long diff=prev - table.countBytes(); - long percent=(diff*100L)/prev; - logMessage("Table size reduced by: "+percent+" %"); - mOptimizing = false; - } - - private FrameworkTable getFrameworkTable(){ - TableBlock tableBlock = frameworkApk.getTableBlock(); - if(tableBlock instanceof FrameworkTable){ - return (FrameworkTable) tableBlock; - } - FrameworkTable frameworkTable = toFramework(tableBlock); - frameworkApk.setTableBlock(frameworkTable); - return frameworkTable; - } - private FrameworkTable toFramework(TableBlock tableBlock){ - logMessage("Converting to framework ..."); - BlockReader reader = new BlockReader(tableBlock.getBytes()); - FrameworkTable frameworkTable = new FrameworkTable(); - try { - frameworkTable.readBytes(reader); - } catch (IOException exception) { - logError("Error re-loading framework: ", exception); - } - return frameworkTable; - } - private void compressManifest(AndroidManifestBlock manifestBlock){ - logMessage("Compressing manifest ..."); - int prev = manifestBlock.countBytes(); - ResXmlElement manifest = manifestBlock.getResXmlElement(); - List removeList = getManifestElementToRemove(manifest); - for(ResXmlNode node:removeList){ - manifest.removeNode(node); - } - ResXmlElement application = manifestBlock.getApplicationElement(); - if(application!=null){ - removeList = application.listXmlNodes(); - for(ResXmlNode node:removeList){ - application.removeNode(node); - } - } - ResXmlStringPool stringPool = manifestBlock.getStringPool(); - stringPool.removeUnusedStrings(); - manifestBlock.refresh(); - long diff=prev - manifestBlock.countBytes(); - long percent=(diff*100L)/prev; - logMessage("Manifest size reduced by: "+percent+" %"); - } - private List getManifestElementToRemove(ResXmlElement manifest){ - List results = new ArrayList<>(); - for(ResXmlNode node:manifest.listXmlNodes()){ - if(!(node instanceof ResXmlElement)){ - continue; - } - ResXmlElement element = (ResXmlElement)node; - if(AndroidManifestBlock.TAG_application.equals(element.getTag())){ - continue; - } - results.add(element); - } - return results; - } - private void backupManifestValue(AndroidManifestBlock manifestBlock, TableBlock tableBlock){ - logMessage("Backup manifest values ..."); - ResXmlElement application = manifestBlock.getApplicationElement(); - ResXmlAttribute iconAttribute = null; - int iconReference = 0; - if(application!=null){ - ResXmlAttribute attribute = application - .searchAttributeByResourceId(AndroidManifestBlock.ID_icon); - if(attribute!=null && attribute.getValueType()==ValueType.REFERENCE){ - iconAttribute = attribute; - iconReference = attribute.getData(); - } - } - - ResXmlElement element = manifestBlock.getResXmlElement(); - backupAttributeValues(tableBlock, element); - - if(iconAttribute!=null){ - iconAttribute.setTypeAndData(ValueType.REFERENCE, iconReference); - } - } - private void backupAttributeValues(TableBlock tableBlock, ResXmlElement element){ - if(element==null){ - return; - } - for(ResXmlAttribute attribute: element.listAttributes()){ - backupAttributeValues(tableBlock, attribute); - } - for(ResXmlElement child: element.listElements()){ - backupAttributeValues(tableBlock, child); - } - } - private void backupAttributeValues(TableBlock tableBlock, ResXmlAttribute attribute){ - if(attribute==null){ - return; - } - ValueType valueType = attribute.getValueType(); - if(valueType!=ValueType.REFERENCE && valueType!=ValueType.ATTRIBUTE){ - return; - } - int reference = attribute.getData(); - Entry entry = getEntryWithValue(tableBlock, reference); - if(entry == null || isReferenceEntry(entry) || entry.isComplex()){ - return; - } - ResTableEntry resTableEntry = (ResTableEntry) entry.getTableEntry(); - ResValue resValue = resTableEntry.getValue(); - valueType = resValue.getValueType(); - if(valueType==ValueType.STRING){ - String value = resValue.getValueAsString(); - attribute.setValueAsString(value); - }else { - int data = resValue.getData(); - attribute.setTypeAndData(valueType, data); - } - } - private Entry getEntryWithValue(TableBlock tableBlock, int resourceId){ - Set circularReference = new HashSet<>(); - return getEntryWithValue(tableBlock, resourceId, circularReference); - } - private Entry getEntryWithValue(TableBlock tableBlock, int resourceId, Set circularReference){ - if(circularReference.contains(resourceId)){ - return null; - } - circularReference.add(resourceId); - EntryGroup entryGroup = tableBlock.getEntryGroup(resourceId); - Entry entry = entryGroup.pickOne(); - if(entry==null){ - return null; - } - if(isReferenceEntry(entry)){ - return getEntryWithValue( - tableBlock, - ((ResValue)entry.getTableEntry().getValue()).getData(), - circularReference); - } - if(!entry.isNull()){ - return entry; - } - Iterator itr = entryGroup.iterator(true); - while (itr.hasNext()){ - entry = itr.next(); - if(!isReferenceEntry(entry)){ - if(!entry.isNull()){ - return entry; - } - } - } - return null; - } - private boolean isReferenceEntry(Entry entry){ - if(entry==null || entry.isNull()){ - return false; - } - TableEntry tableEntry = entry.getTableEntry(); - if(tableEntry instanceof CompoundEntry){ - return false; - } - if(!(tableEntry instanceof ResTableEntry)){ - return false; - } - ResTableEntry resTableEntry = (ResTableEntry) tableEntry; - ResValue resValue = resTableEntry.getValue(); - - ValueType valueType = resValue.getValueType(); - - return valueType == ValueType.REFERENCE - || valueType == ValueType.ATTRIBUTE; - } - - APKLogger getApkLogger(){ - return apkLogger; - } - public void setAPKLogger(APKLogger logger) { - this.apkLogger = logger; - } - void logMessage(String msg) { - if(apkLogger!=null){ - apkLogger.logMessage(msg); - } - } - private void logError(String msg, Throwable tr) { - if(apkLogger!=null){ - apkLogger.logError(msg, tr); - } - } - private void logVerbose(String msg) { - if(apkLogger!=null){ - apkLogger.logVerbose(msg); - } - } -} diff --git a/src/ARSCLib/com/reandroid/apk/JsonManifestInputSource.java b/src/ARSCLib/com/reandroid/apk/JsonManifestInputSource.java deleted file mode 100644 index 31731063..00000000 --- a/src/ARSCLib/com/reandroid/apk/JsonManifestInputSource.java +++ /dev/null @@ -1,36 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.archive.FileInputSource; -import com.reandroid.archive.InputSource; -import com.reandroid.arsc.chunk.xml.AndroidManifestBlock; - -import java.io.File; - -public class JsonManifestInputSource extends JsonXmlInputSource { - public JsonManifestInputSource(InputSource inputSource) { - super(inputSource); - } - AndroidManifestBlock newInstance(){ - return new AndroidManifestBlock(); - } - public static JsonManifestInputSource fromFile(File rootDir, File jsonFile){ - String path=ApkUtil.toArchiveResourcePath(rootDir, jsonFile); - FileInputSource fileInputSource=new FileInputSource(jsonFile, path); - return new JsonManifestInputSource(fileInputSource); - } -} diff --git a/src/ARSCLib/com/reandroid/apk/JsonXmlInputSource.java b/src/ARSCLib/com/reandroid/apk/JsonXmlInputSource.java deleted file mode 100644 index 7989744e..00000000 --- a/src/ARSCLib/com/reandroid/apk/JsonXmlInputSource.java +++ /dev/null @@ -1,86 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.archive.FileInputSource; -import com.reandroid.archive.InputSource; -import com.reandroid.arsc.chunk.xml.ResXmlDocument; -import com.reandroid.json.JSONException; -import com.reandroid.json.JSONObject; - -import java.io.*; - -public class JsonXmlInputSource extends InputSource { - private final InputSource inputSource; - private APKLogger apkLogger; - public JsonXmlInputSource(InputSource inputSource) { - super(inputSource.getAlias()); - this.inputSource=inputSource; - } - @Override - public long write(OutputStream outputStream) throws IOException { - return getResXmlBlock().writeBytes(outputStream); - } - @Override - public InputStream openStream() throws IOException { - ResXmlDocument resXmlDocument = getResXmlBlock(); - return new ByteArrayInputStream(resXmlDocument.getBytes()); - } - @Override - public long getLength() throws IOException{ - ResXmlDocument resXmlDocument = getResXmlBlock(); - return resXmlDocument.countBytes(); - } - private ResXmlDocument getResXmlBlock() throws IOException{ - logVerbose("From json: "+getAlias()); - ResXmlDocument resXmlDocument =newInstance(); - InputStream inputStream=inputSource.openStream(); - try{ - JSONObject jsonObject=new JSONObject(inputStream); - resXmlDocument.fromJson(jsonObject); - }catch (JSONException ex){ - throw new IOException(inputSource.getAlias()+": "+ex.getMessage(), ex); - } - return resXmlDocument; - } - ResXmlDocument newInstance(){ - return new ResXmlDocument(); - } - void setAPKLogger(APKLogger logger) { - this.apkLogger = logger; - } - void logMessage(String msg) { - if(apkLogger!=null){ - apkLogger.logMessage(msg); - } - } - private void logError(String msg, Throwable tr) { - if(apkLogger!=null){ - apkLogger.logError(msg, tr); - } - } - private void logVerbose(String msg) { - if(apkLogger!=null){ - apkLogger.logVerbose(msg); - } - } - - public static JsonXmlInputSource fromFile(File rootDir, File jsonFile){ - String path=ApkUtil.toArchiveResourcePath(rootDir, jsonFile); - FileInputSource fileInputSource=new FileInputSource(jsonFile, path); - return new JsonXmlInputSource(fileInputSource); - } -} diff --git a/src/ARSCLib/com/reandroid/apk/PathMap.java b/src/ARSCLib/com/reandroid/apk/PathMap.java deleted file mode 100644 index 36b86ba9..00000000 --- a/src/ARSCLib/com/reandroid/apk/PathMap.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.archive.InputSource; -import com.reandroid.archive.ZipArchive; -import com.reandroid.json.JSONArray; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONObject; - -import java.util.*; - -public class PathMap implements JSONConvert { - private final Object mLock = new Object(); - private final Map mNameAliasMap; - private final Map mAliasNameMap; - - public PathMap(){ - this.mNameAliasMap = new HashMap<>(); - this.mAliasNameMap = new HashMap<>(); - } - - public void restore(ApkModule apkModule){ - restoreResFile(apkModule.listResFiles()); - restore(apkModule.getApkArchive().listInputSources()); - } - public List restoreResFile(Collection files){ - List results = new ArrayList<>(); - if(files == null){ - return results; - } - for(ResFile resFile:files){ - String alias = restoreResFile(resFile); - if(alias==null){ - continue; - } - results.add(alias); - } - return results; - } - public String restoreResFile(ResFile resFile){ - InputSource inputSource = resFile.getInputSource(); - String alias = restore(inputSource); - if(alias==null){ - return null; - } - resFile.setFilePath(alias); - return alias; - } - public List restore(Collection sources){ - List results = new ArrayList<>(); - if(sources == null){ - return results; - } - for(InputSource inputSource:sources){ - String alias = restore(inputSource); - if(alias==null){ - continue; - } - results.add(alias); - } - return results; - } - public String restore(InputSource inputSource){ - if(inputSource==null){ - return null; - } - String name = inputSource.getName(); - String alias = getName(name); - if(alias==null){ - name = inputSource.getAlias(); - alias = getName(name); - } - if(alias==null || alias.equals(inputSource.getAlias())){ - return null; - } - inputSource.setAlias(alias); - return alias; - } - - public String getAlias(String name){ - synchronized (mLock){ - return mNameAliasMap.get(name); - } - } - public String getName(String alias){ - synchronized (mLock){ - return mAliasNameMap.get(alias); - } - } - public int size(){ - synchronized (mLock){ - return mNameAliasMap.size(); - } - } - public void clear(){ - synchronized (mLock){ - mNameAliasMap.clear(); - mAliasNameMap.clear(); - } - } - public void add(ZipArchive archive){ - if(archive == null){ - return; - } - add(archive.listInputSources()); - } - public void add(Collection sources){ - if(sources==null){ - return; - } - for(InputSource inputSource:sources){ - add(inputSource); - } - } - public void add(InputSource inputSource){ - if(inputSource==null){ - return; - } - add(inputSource.getName(), inputSource.getAlias()); - } - public void add(String name, String alias){ - if(name==null || alias==null){ - return; - } - if(name.equals(alias)){ - return; - } - synchronized (mLock){ - mNameAliasMap.remove(name); - mNameAliasMap.put(name, alias); - mAliasNameMap.remove(alias); - mAliasNameMap.put(alias, name); - } - } - - private void add(JSONObject json){ - if(json==null){ - return; - } - add(json.optString(NAME_name), json.optString(NAME_alias)); - } - - @Override - public JSONArray toJson() { - JSONArray jsonArray = new JSONArray(); - Map nameMap = this.mNameAliasMap; - List nameList = toSortedList(nameMap.keySet()); - for(String name:nameList){ - JSONObject jsonObject = new JSONObject(); - jsonObject.put(NAME_name, name); - jsonObject.put(NAME_alias, nameMap.get(name)); - jsonArray.put(jsonObject); - } - return jsonArray; - } - @Override - public void fromJson(JSONArray json) { - clear(); - if(json==null){ - return; - } - int length = json.length(); - for(int i=0;i sourceList; - private final boolean sanitizeResourceFiles; - private Collection resFileList; - private APKLogger apkLogger; - private final Set mSanitizedPaths; - public PathSanitizer(Collection sourceList, boolean sanitizeResourceFiles){ - this.sourceList = sourceList; - this.mSanitizedPaths = new HashSet<>(); - this.sanitizeResourceFiles = sanitizeResourceFiles; - } - public PathSanitizer(Collection sourceList){ - this(sourceList, false); - } - public void sanitize(){ - mSanitizedPaths.clear(); - logMessage("Sanitizing paths ..."); - sanitizeResFiles(); - for(InputSource inputSource:sourceList){ - sanitize(inputSource, 1, false); - } - logMessage("DONE = "+mSanitizedPaths.size()); - } - public void setResourceFileList(Collection resFileList){ - this.resFileList = resFileList; - } - private void sanitizeResFiles(){ - Collection resFileList = this.resFileList; - if(resFileList == null){ - return; - } - boolean sanitizeRes = this.sanitizeResourceFiles; - Set sanitizedPaths = this.mSanitizedPaths; - if(sanitizeRes){ - logMessage("Sanitizing resource files ..."); - } - for(ResFile resFile:resFileList){ - if(sanitizeRes){ - sanitize(resFile); - }else { - sanitizedPaths.add(resFile.getFilePath()); - } - } - } - private void sanitize(ResFile resFile){ - InputSource inputSource = resFile.getInputSource(); - String replace = sanitize(inputSource, 3, true); - if(replace==null){ - return; - } - resFile.setFilePath(replace); - } - private String sanitize(InputSource inputSource, int depth, boolean fixedDepth){ - String name = inputSource.getName(); - if(mSanitizedPaths.contains(name)){ - return null; - } - mSanitizedPaths.add(name); - String alias = inputSource.getAlias(); - if(shouldIgnore(alias)){ - return null; - } - String replace = sanitize(alias, depth, fixedDepth); - if(alias.equals(replace)){ - return null; - } - inputSource.setAlias(replace); - logVerbose("REN: '"+alias+"' -> '"+replace+"'"); - return replace; - } - - private String sanitize(String name, int depth, boolean fixedDepth){ - StringBuilder builder = new StringBuilder(); - String[] nameSplit = name.split("/"); - - boolean pathIsLong = name.length() >= MAX_PATH_LENGTH; - int length = nameSplit.length; - for(int i=0;i=depth)){ - split = createUniqueName(name); - appendPathName(builder, split); - break; - } - if(fixedDepth && i>=(depth-1)){ - if(i < length-1){ - split = createUniqueName(name); - } - appendPathName(builder, split); - break; - } - appendPathName(builder, split); - } - return builder.toString(); - } - private boolean shouldIgnore(String path){ - return path.startsWith("lib/") && path.endsWith(".so"); - } - - public void setApkLogger(APKLogger apkLogger) { - this.apkLogger = apkLogger; - } - private String getLogTag(){ - return "[SANITIZE]: "; - } - void logMessage(String msg){ - APKLogger logger = this.apkLogger; - if(logger!=null){ - logger.logMessage(getLogTag()+msg); - } - } - void logVerbose(String msg){ - APKLogger logger = this.apkLogger; - if(logger!=null){ - logger.logVerbose(getLogTag()+msg); - } - } - - private static void appendPathName(StringBuilder builder, String name){ - if(builder.length()>0){ - builder.append('/'); - } - builder.append(name); - } - private static String createUniqueName(String name){ - int hash = name.hashCode(); - return "alias_" + HexUtil.toHexNoPrefix8(hash); - } - private static boolean isGoodSimpleName(String name){ - if(name==null){ - return false; - } - String alias = sanitizeSimpleName(name); - return name.equals(alias); - } - public static String sanitizeSimpleName(String name){ - if(name==null){ - return null; - } - StringBuilder builder = new StringBuilder(); - char[] chars = name.toCharArray(); - boolean skipNext = true; - int length = 0; - int lengthMax = MAX_NAME_LENGTH; - for(int i=0;i=lengthMax){ - break; - } - char ch = chars[i]; - if(isGoodFileNameSymbol(ch)){ - if(!skipNext){ - builder.append(ch); - length++; - } - skipNext=true; - continue; - } - if(!isGoodFileNameChar(ch)){ - skipNext = true; - continue; - } - builder.append(ch); - length++; - skipNext=false; - } - if(length==0){ - return null; - } - return builder.toString(); - } - - private static boolean isGoodFileNameSymbol(char ch){ - return ch == '.' - || ch == '+' - || ch == '-' - || ch == '#'; - } - private static boolean isGoodFileNameChar(char ch){ - return ch == '_' - || (ch >= '0' && ch <= '9') - || (ch >= 'A' && ch <= 'Z') - || (ch >= 'a' && ch <= 'z'); - } - - public static PathSanitizer create(ApkModule apkModule){ - PathSanitizer pathSanitizer = new PathSanitizer( - apkModule.getApkArchive().listInputSources()); - pathSanitizer.setApkLogger(apkModule.getApkLogger()); - pathSanitizer.setResourceFileList(apkModule.listResFiles()); - return pathSanitizer; - } - - private static final int MAX_NAME_LENGTH = 75; - private static final int MAX_PATH_LENGTH = 100; -} diff --git a/src/ARSCLib/com/reandroid/apk/RenamedInputSource.java b/src/ARSCLib/com/reandroid/apk/RenamedInputSource.java deleted file mode 100644 index 8e1545c4..00000000 --- a/src/ARSCLib/com/reandroid/apk/RenamedInputSource.java +++ /dev/null @@ -1,55 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.archive.InputSource; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -public class RenamedInputSource extends InputSource { - private final T inputSource; - public RenamedInputSource(String name, T input){ - super(name); - this.inputSource=input; - super.setMethod(input.getMethod()); - super.setSort(input.getSort()); - } - public T getInputSource() { - return inputSource; - } - @Override - public void close(InputStream inputStream) throws IOException { - getInputSource().close(inputStream); - } - @Override - public long getLength() throws IOException { - return getInputSource().getLength(); - } - @Override - public long getCrc() throws IOException { - return getInputSource().getCrc(); - } - @Override - public long write(OutputStream outputStream) throws IOException { - return getInputSource().write(outputStream); - } - @Override - public InputStream openStream() throws IOException { - return getInputSource().openStream(); - } -} diff --git a/src/ARSCLib/com/reandroid/apk/ResFile.java b/src/ARSCLib/com/reandroid/apk/ResFile.java deleted file mode 100644 index 8ba6435b..00000000 --- a/src/ARSCLib/com/reandroid/apk/ResFile.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.archive.InputSource; -import com.reandroid.apk.xmlencoder.XMLEncodeSource; -import com.reandroid.arsc.chunk.TypeBlock; -import com.reandroid.arsc.chunk.xml.ResXmlDocument; -import com.reandroid.arsc.header.InfoHeader; -import com.reandroid.arsc.value.*; -import com.reandroid.json.JSONObject; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; - -public class ResFile { - private final List entryList; - private final InputSource inputSource; - private boolean mBinXml; - private boolean mBinXmlChecked; - private String mFileExtension; - private boolean mFileExtensionChecked; - private Entry mSelectedEntry; - public ResFile(InputSource inputSource, List entryList){ - this.inputSource=inputSource; - this.entryList = entryList; - } - public List getEntryList(){ - return entryList; - } - public String validateTypeDirectoryName(){ - Entry entry =pickOne(); - if(entry ==null){ - return null; - } - String path=getFilePath(); - String root=""; - int i=path.indexOf('/'); - if(i>0){ - i++; - root=path.substring(0, i); - path=path.substring(i); - } - String name=path; - i=path.lastIndexOf('/'); - if(i>0){ - i++; - name=path.substring(i); - } - TypeBlock typeBlock= entry.getTypeBlock(); - String typeName=typeBlock.getTypeName()+typeBlock.getResConfig().getQualifiers(); - return root+typeName+"/"+name; - } - public Entry pickOne(){ - if(mSelectedEntry ==null){ - mSelectedEntry =selectOne(); - } - return mSelectedEntry; - } - private Entry selectOne(){ - List entryList = this.entryList; - if(entryList.size()==0){ - return null; - } - for(Entry entry :entryList){ - if(!entry.isNull() && entry.isDefault()){ - return entry; - } - } - for(Entry entry :entryList){ - if(!entry.isNull()){ - return entry; - } - } - for(Entry entry :entryList){ - if(entry.isDefault()){ - return entry; - } - } - return entryList.get(0); - } - public String getFilePath(){ - return getInputSource().getAlias(); - } - public void setFilePath(String filePath){ - getInputSource().setAlias(filePath); - for(Entry entry : entryList){ - TableEntry tableEntry = entry.getTableEntry(); - if(!(tableEntry instanceof ResTableEntry)){ - continue; - } - ResValue resValue = ((ResTableEntry) tableEntry).getValue(); - resValue.setValueAsString(filePath); - } - } - public InputSource getInputSource() { - return inputSource; - } - public boolean isBinaryXml(){ - if(mBinXmlChecked){ - return mBinXml; - } - mBinXmlChecked = true; - InputSource inputSource = getInputSource(); - if((inputSource instanceof XMLEncodeSource) - || (inputSource instanceof JsonXmlInputSource)){ - mBinXml=true; - }else{ - try { - mBinXml = ResXmlDocument.isResXmlBlock(inputSource.getBytes(InfoHeader.INFO_MIN_SIZE)); - } catch (IOException ignored) { - } - } - return mBinXml; - } - public File buildOutFile(File dir){ - String path=getFilePath(); - path=path.replace('/', File.separatorChar); - return new File(dir, path); - } - public String buildPath(){ - return buildPath(null); - } - public String buildPath(String parent){ - Entry entry = pickOne(); - StringBuilder builder = new StringBuilder(); - if(parent!=null){ - builder.append(parent); - if(!parent.endsWith("/")){ - builder.append('/'); - } - } - TypeBlock typeBlock = entry.getTypeBlock(); - builder.append(typeBlock.getTypeName()); - builder.append(typeBlock.getQualifiers()); - builder.append('/'); - builder.append(entry.getName()); - String ext = getFileExtension(); - if(ext!=null){ - builder.append(ext); - } - return builder.toString(); - } - private String getFileExtension(){ - if(!mFileExtensionChecked){ - mFileExtensionChecked=true; - mFileExtension=readFileExtension(); - } - return mFileExtension; - } - private String readFileExtension(){ - if(isBinaryXml()){ - return ".xml"; - } - String path=getFilePath(); - int i=path.lastIndexOf('.'); - if(i>0){ - return path.substring(i); - } - try { - String magicExt=FileMagic.getExtensionFromMagic(getInputSource()); - if(magicExt!=null){ - return magicExt; - } - } catch (IOException ignored) { - } - return null; - } - @Override - public String toString(){ - return getFilePath(); - } -} diff --git a/src/ARSCLib/com/reandroid/apk/ResourceIds.java b/src/ARSCLib/com/reandroid/apk/ResourceIds.java deleted file mode 100644 index 7b43723f..00000000 --- a/src/ARSCLib/com/reandroid/apk/ResourceIds.java +++ /dev/null @@ -1,845 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.group.EntryGroup; -import com.reandroid.arsc.pool.SpecStringPool; -import com.reandroid.arsc.util.HexUtil; -import com.reandroid.arsc.util.ResNameMap; -import com.reandroid.json.JSONArray; -import com.reandroid.json.JSONObject; -import com.reandroid.xml.*; - -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.util.*; - -/**Use {@link com.reandroid.identifiers.TableIdentifier} */ -@Deprecated - public class ResourceIds { - private final Table mTable; - public ResourceIds(Table table){ - this.mTable=table; - } - public ResourceIds(){ - this(new Table()); - } - public Table getTable(){ - return mTable; - } - public int applyTo(TableBlock tableBlock){ - return mTable.applyTo(tableBlock); - } - public void fromJson(JSONObject jsonObject){ - mTable.fromJson(jsonObject); - } - public JSONObject toJson(){ - return mTable.toJson(); - } - public void loadTableBlock(TableBlock tableBlock){ - for(PackageBlock packageBlock:tableBlock.listPackages()){ - loadPackageBlock(packageBlock); - } - } - public void loadPackageBlock(PackageBlock packageBlock){ - Collection entryGroupList = packageBlock.listEntryGroup(); - String name= packageBlock.getName(); - for(EntryGroup entryGroup:entryGroupList){ - Table.Package.Type.Entry entry= Table.Package.Type.Entry.fromEntryGroup(entryGroup); - mTable.add(entry); - if(name==null){ - continue; - } - Table.Package.Type type=entry.type; - if(type!=null && type.mPackage!=null){ - type.mPackage.name=name; - name=null; - } - } - } - - public void writeXml(File file) throws IOException { - mTable.writeXml(file); - } - public void writeXml(OutputStream outputStream) throws IOException { - mTable.writeXml(outputStream); - } - public void fromXml(File file) throws IOException { - mTable.fromXml(file); - } - public void fromXml(InputStream inputStream) throws IOException { - mTable.fromXml(inputStream); - } - public void fromXml(XMLDocument xmlDocument) throws IOException { - mTable.fromXml(xmlDocument); - } - - public XMLDocument toXMLDocument(){ - return mTable.toXMLDocument(); - } - - public static class Table implements Comparator{ - public final Map packageMap; - public Table(){ - this.packageMap = new HashMap<>(); - } - public int applyTo(TableBlock tableBlock){ - int renameCount=0; - for(PackageBlock packageBlock : tableBlock.listPackages()){ - Package pkg=getPackage((byte) packageBlock.getId()); - if(pkg!=null){ - renameCount+=pkg.applyTo(packageBlock); - } - } - if(renameCount>0){ - tableBlock.refresh(); - } - return renameCount; - } - public void add(Package pkg){ - Package exist=this.packageMap.get(pkg.id); - if(exist!=null){ - exist.merge(pkg); - return; - } - this.packageMap.put(pkg.id, pkg); - } - public Package add(Package.Type.Entry entry){ - if(entry==null){ - return null; - } - byte pkgId=entry.getPackageId(); - Package pkg = packageMap.get(pkgId); - if(pkg==null){ - pkg=new Package(pkgId); - packageMap.put(pkgId, pkg); - } - pkg.add(entry); - return pkg; - } - public Package.Type.Entry getEntry(int resourceId){ - byte packageId = (byte) ((resourceId>>24) & 0xff); - byte typeId = (byte) ((resourceId>>16) & 0xff); - short entryId = (short) (resourceId & 0xff); - Package pkg = getPackage(packageId); - if(pkg == null){ - return null; - } - return getEntry(packageId, typeId, entryId); - } - public Package getPackage(byte packageId){ - return packageMap.get(packageId); - } - public Package.Type getType(byte packageId, byte typeId){ - Package pkg=getPackage(packageId); - if(pkg==null){ - return null; - } - return pkg.getType(typeId); - } - public Package.Type.Entry getEntry(byte packageId, byte typeId, short entryId){ - Package pkg=getPackage(packageId); - if(pkg==null){ - return null; - } - return pkg.getEntry(typeId, entryId); - } - public List listPackages(){ - List results=new ArrayList<>(packageMap.values()); - results.sort(this); - return results; - } - public List listEntries(){ - List results=new ArrayList<>(countEntries()); - for(Package pkg:packageMap.values()){ - results.addAll(pkg.listEntries()); - } - return results; - } - int countEntries(){ - int result=0; - for(Package pkg:packageMap.values()){ - result+=pkg.countEntries(); - } - return result; - } - public JSONObject toJson(){ - JSONObject jsonObject=new JSONObject(); - JSONArray jsonArray=new JSONArray(); - for(Package pkg: packageMap.values()){ - jsonArray.put(pkg.toJson()); - } - jsonObject.put("packages", jsonArray); - return jsonObject; - } - public void fromJson(JSONObject jsonObject){ - JSONArray jsonArray= jsonObject.optJSONArray("packages"); - if(jsonArray!=null){ - int length= jsonArray.length(); - for(int i=0;i"); - writer.write('\n'); - writer.write(""); - } - private void writeEnd(Writer writer) throws IOException{ - writer.write('\n'); - writer.write(""); - } - public void fromXml(File file) throws IOException { - FileInputStream inputStream=new FileInputStream(file); - fromXml(inputStream); - inputStream.close(); - } - public void fromXml(InputStream inputStream) throws IOException { - try { - fromXml(XMLDocument.load(inputStream)); - } catch (XMLException ex) { - throw new IOException(ex.getMessage(), ex); - } - } - public void fromXml(XMLDocument xmlDocument) { - XMLElement documentElement = xmlDocument.getDocumentElement(); - int count=documentElement.getChildesCount(); - for(int i=0;i, Comparator{ - public final byte id; - public String name; - public final Map typeMap; - private final ResNameMap mEntryNameMap; - public Package(byte id){ - this.id = id; - this.typeMap = new HashMap<>(); - this.mEntryNameMap = new ResNameMap<>(); - } - public void loadEntryMap(){ - mEntryNameMap.clear(); - for(Type type:typeMap.values()){ - String typeName=type.getName(); - for(Type.Entry entry: type.entryMap.values()){ - mEntryNameMap.add(typeName, entry.getName(), entry.getResourceId()); - } - } - } - public Integer getResourceId(String typeName, String name){ - return mEntryNameMap.get(typeName, name); - } - public Type.Entry getEntry(String typeName, String name){ - Type type=getType(typeName); - if(type==null){ - return null; - } - return type.getEntry(name); - } - private Type getType(String typeName){ - for(Type type:typeMap.values()){ - if(type.getName().equals(typeName)){ - return type; - } - } - return null; - } - public int getIdInt(){ - return 0xff & id; - } - public int applyTo(PackageBlock packageBlock){ - int renameCount=0; - Map map = packageBlock.getEntriesGroupMap(); - for(Map.Entry entry:map.entrySet()){ - byte typeId=Table.toTypeId(entry.getKey()); - Type type=typeMap.get(typeId); - if(type==null){ - continue; - } - EntryGroup entryGroup=entry.getValue(); - if(type.applyTo(entryGroup)){ - renameCount++; - } - } - if(renameCount>0){ - cleanSpecStringPool(packageBlock); - } - return renameCount; - } - private void cleanSpecStringPool(PackageBlock packageBlock){ - SpecStringPool specStringPool = packageBlock.getSpecStringPool(); - specStringPool.refreshUniqueIdMap(); - specStringPool.removeUnusedStrings(); - packageBlock.refresh(); - } - public void merge(Package pkg){ - if(pkg==this||pkg==null){ - return; - } - if(pkg.id!=this.id){ - throw new DuplicateException("Different package id: "+this.id+"!="+pkg.id); - } - if(pkg.name!=null){ - this.name = pkg.name; - } - for(Type type:pkg.typeMap.values()){ - add(type); - } - } - public Type getType(byte typeId){ - return typeMap.get(typeId); - } - public void add(Type type){ - Byte typeId= type.id;; - Type exist=this.typeMap.get(typeId); - if(exist!=null){ - exist.merge(type); - return; - } - type.mPackage=this; - this.typeMap.put(typeId, type); - } - public Package.Type.Entry getEntry(byte typeId, short entryId){ - Package.Type type=getType(typeId); - if(type==null){ - return null; - } - return type.getEntry(entryId); - } - public void add(Type.Entry entry){ - if(entry==null){ - return; - } - if(entry.getPackageId()!=this.id){ - throw new DuplicateException("Different package id: "+entry); - } - byte typeId=entry.getTypeId(); - Type type=typeMap.get(typeId); - if(type==null){ - type=new Type(typeId); - type.mPackage=this; - typeMap.put(typeId, type); - } - type.add(entry); - } - public String getHexId(){ - return HexUtil.toHex2(id); - } - public JSONObject toJson(){ - JSONObject jsonObject=new JSONObject(); - jsonObject.put("id", this.getIdInt()); - if(this.name!=null){ - jsonObject.put("name", this.name); - } - JSONArray jsonArray=new JSONArray(); - for(Type type:typeMap.values()){ - jsonArray.put(type.toJson()); - } - jsonObject.put("types", jsonArray); - return jsonObject; - } - @Override - public int compareTo(Package pkg) { - return Integer.compare(getIdInt(), pkg.getIdInt()); - } - @Override - public int compare(Type t1, Type t2) { - return t1.compareTo(t2); - } - public void toXMLElements(XMLElement documentElement){ - int count = documentElement.getChildesCount(); - for(Type type:listTypes()){ - type.toXMLElements(documentElement); - } - XMLElement firstElement = documentElement.getChildAt(count); - if(firstElement!=null){ - XMLComment comment = new XMLComment( - "packageName=\""+this.name+"\""); - firstElement.addComment(comment); - } - } - void setPackageName(XMLComment xmlComment){ - if(xmlComment==null){ - return; - } - String pkgName = xmlComment.getCommentText(); - if(pkgName==null || !pkgName.contains("packageName")){ - return; - } - int i = pkgName.indexOf('"'); - if(i>0){ - i++; - pkgName=pkgName.substring(i); - }else { - return; - } - i = pkgName.indexOf('"'); - if(i>0){ - pkgName=pkgName.substring(0, i); - }else { - return; - } - this.name=pkgName.trim(); - } - public List listEntries(){ - List results=new ArrayList<>(countEntries()); - for(Package.Type type:typeMap.values()){ - results.addAll(type.listEntries()); - } - return results; - } - public List listTypes(){ - List results=new ArrayList<>(typeMap.values()); - results.sort(this); - return results; - } - int countEntries(){ - int results=0; - for(Type type:typeMap.values()){ - results+=type.countEntries(); - } - return results; - } - public void writeXml(String indent, Writer writer) throws IOException{ - writeComment(indent, writer); - for(Type type:listTypes()){ - type.writeXml(indent, writer); - } - } - private void writeComment(String indent, Writer writer) throws IOException{ - String name = this.name; - if(name == null){ - return; - } - writer.write('\n'); - writer.write(indent); - writer.write(""); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Package aPackage = (Package) o; - return id == aPackage.id; - } - @Override - public int hashCode() { - return Objects.hash(id); - } - @Override - public String toString(){ - return getHexId() + ", types=" + typeMap.size(); - } - - public static Package fromJson(JSONObject jsonObject){ - Package pkg=new Package((byte) jsonObject.getInt("id")); - pkg.name = jsonObject.optString("name", null); - JSONArray jsonArray = jsonObject.optJSONArray("types"); - int length = jsonArray.length(); - for(int i=0;i, Comparator{ - public final byte id; - public String name; - public String nameAlias; - public Package mPackage; - public final Map entryMap; - public Type(byte id){ - this.id = id; - this.entryMap = new HashMap<>(); - } - public Entry getEntry(String entryName){ - for(Entry entry:entryMap.values()){ - if(entry.getName().equals(entryName)){ - return entry; - } - } - return null; - } - public int getIdInt(){ - return 0xff & id; - } - public boolean applyTo(EntryGroup entryGroup){ - boolean renamed=false; - Entry entry=entryMap.get(entryGroup.getEntryId()); - if(entry!=null){ - if(entry.applyTo(entryGroup)){ - renamed=true; - } - } - return renamed; - } - public String getName() { - if(nameAlias!=null){ - return nameAlias; - } - return name; - } - - public byte getId(){ - return id; - } - public byte getPackageId(){ - if(mPackage!=null){ - return mPackage.id; - } - return 0; - } - public void merge(Type type){ - if(type==this||type==null){ - return; - } - if(this.id!= type.id){ - throw new DuplicateException("Different type ids: "+id+"!="+type.id); - } - String n=type.getName(); - if(n!=null){ - this.name=n; - } - for(Entry entry:type.entryMap.values()){ - Short entryId=entry.getEntryId(); - Entry existEntry=this.entryMap.get(entryId); - if(existEntry != null && Objects.equals(existEntry.getName(), entry.getName())){ - continue; - } - this.entryMap.remove(entryId); - entry.type=this; - this.entryMap.put(entryId, entry); - } - } - public Entry getEntry(short entryId){ - return entryMap.get(entryId); - } - public String getHexId(){ - return HexUtil.toHex2(id); - } - public void add(Entry entry){ - if(entry==null){ - return; - } - if(entry.getTypeId()!=this.id){ - throw new DuplicateException("Different type id: "+entry); - } - short key=entry.getEntryId(); - Entry exist=entryMap.get(key); - if(exist!=null){ - if(Objects.equals(exist.getName(), entry.getName())){ - return; - } - /* Developer may have a reason adding duplicate - resource ids , lets ignore rather than throw - */ - // throw new DuplicateException("Duplicate entry exist: "+exist+", entry: "+entry); - return; - } - if(getName() == null){ - this.name = entry.getTypeName(); - } - entry.type=this; - entryMap.put(key, entry); - } - - public JSONObject toJson(){ - JSONObject jsonObject=new JSONObject(); - jsonObject.put("id", getIdInt()); - jsonObject.put("name", getName()); - JSONArray jsonArray=new JSONArray(); - for(Entry entry: entryMap.values()){ - jsonArray.put(entry.toJson()); - } - jsonObject.put("entries", jsonArray); - return jsonObject; - } - public void toXMLElements(XMLElement documentElement){ - for(Entry entry:listEntries()){ - documentElement.addChild(entry.toXMLElement()); - } - } - public List listEntries(){ - List results=new ArrayList<>(entryMap.values()); - results.sort(this); - return results; - } - int countEntries(){ - return entryMap.size(); - } - public void writeXml(String indent, Writer writer) throws IOException{ - for(Entry entry:listEntries()){ - entry.writeXml(indent, writer); - } - } - @Override - public int compareTo(Type type) { - return Integer.compare(getIdInt(), type.getIdInt()); - } - @Override - public int compare(Entry entry1, Entry entry2) { - return entry1.compareTo(entry2); - } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Type that = (Type) o; - return id == that.id; - } - @Override - public int hashCode() { - return Objects.hash(id); - } - @Override - public String toString(){ - StringBuilder builder=new StringBuilder(); - builder.append(getHexId()); - String n=getName(); - if(n !=null){ - builder.append(" ").append(n); - } - builder.append(", entries=").append(entryMap.size()); - return builder.toString(); - } - - public static Type fromJson(JSONObject jsonObject){ - Type type = new Type((byte) jsonObject.getInt("id")); - type.name = jsonObject.optString("name", null); - JSONArray jsonArray = jsonObject.optJSONArray("entries"); - if(jsonArray!=null){ - int length=jsonArray.length(); - for(int i=0;i{ - public int resourceId; - public String typeName; - public String name; - public String nameAlias; - public Type type; - public Entry(int resourceId, String typeName, String name){ - this.resourceId = resourceId; - this.typeName = typeName; - this.name = name; - } - public Entry(int resourceId, String name){ - this(resourceId, null, name); - } - public boolean applyTo(EntryGroup entryGroup){ - return entryGroup.renameSpec(this.getName()); - } - public String getName() { - if(nameAlias!=null){ - return nameAlias; - } - return name; - } - public String getTypeName(){ - if(this.type!=null){ - return this.type.getName(); - } - return this.typeName; - } - public byte getPackageId(){ - if(this.type!=null){ - Package pkg=this.type.mPackage; - if(pkg!=null){ - return pkg.id; - } - } - return (byte) ((resourceId>>24) & 0xff); - } - public byte getTypeId(){ - if(this.type!=null){ - return this.type.id; - } - return (byte) ((resourceId>>16) & 0xff); - } - public short getEntryId(){ - return (short) (resourceId & 0xffff); - } - public int getEntryIdInt(){ - return resourceId & 0xffff; - } - public int getResourceId(){ - return ((getPackageId() & 0xff)<<24) - | ((getTypeId() & 0xff)<<16) - | (getEntryId() & 0xffff); - } - public String getHexId(){ - return HexUtil.toHex8(getResourceId()); - } - - public void writeXml(String indent, Writer writer) throws IOException{ - writer.write('\n'); - writer.write(indent); - writer.write(""); - } - @Override - public int compareTo(Entry entry) { - return Integer.compare(getEntryIdInt(), entry.getEntryIdInt()); - } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Entry that = (Entry) o; - return getResourceId() == that.getResourceId(); - } - @Override - public int hashCode() { - return Objects.hash(getResourceId()); - } - public JSONObject toJson(){ - JSONObject jsonObject=new JSONObject(); - jsonObject.put("id", getResourceId()); - jsonObject.put("name", getName()); - return jsonObject; - } - public XMLElement toXMLElement(){ - XMLElement element=new XMLElement("public"); - element.setResourceId(getResourceId()); - element.addAttribute(new XMLAttribute("id", getHexId())); - element.addAttribute(new XMLAttribute("type", getTypeName())); - element.addAttribute(new XMLAttribute("name", getName())); - return element; - } - @Override - public String toString(){ - return toXMLElement().toText(false); - } - public static Entry fromEntryGroup(EntryGroup entryGroup){ - return new Entry(entryGroup.getResourceId(), - entryGroup.getTypeName(), - entryGroup.getSpecName()); - } - public static Entry fromJson(JSONObject jsonObject){ - return new Entry(jsonObject.getInt("id"), - jsonObject.optString("type", null), - jsonObject.getString("name")); - } - public static Entry fromXml(XMLElement element){ - return new Entry( - ApkUtil.parseHex(element.getAttributeValue("id")), - element.getAttributeValue("type"), - element.getAttributeValue("name")); - } - } - } - - } - private static short toEntryId(int resourceId){ - int i=resourceId&0xffff; - return (short) i; - } - static byte toTypeId(int resourceId){ - int i=resourceId>>16; - i=i&0xff; - return (byte) i; - } - static byte toPackageId(int resourceId){ - int i=resourceId>>24; - i=i&0xff; - return (byte) i; - } - static int toResourceId(byte pkgId, byte typeId, short entryId){ - return (pkgId & 0xff)<<24 - | (typeId & 0xff)<<16 - | (entryId & 0xffff); - } - } - public static class DuplicateException extends IllegalArgumentException{ - public DuplicateException(String message){ - super(message); - } - public DuplicateException(String message, final Throwable cause) { - super(message, cause); - } - public DuplicateException(Throwable cause) { - super(cause.getMessage(), cause); - } - } - - public static final String JSON_FILE_NAME ="resource-ids.json"; -} diff --git a/src/ARSCLib/com/reandroid/apk/SingleJsonTableInputSource.java b/src/ARSCLib/com/reandroid/apk/SingleJsonTableInputSource.java deleted file mode 100644 index 1cc1129c..00000000 --- a/src/ARSCLib/com/reandroid/apk/SingleJsonTableInputSource.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.archive.FileInputSource; -import com.reandroid.archive.InputSource; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.json.JSONException; -import com.reandroid.json.JSONObject; - -import java.io.*; - -public class SingleJsonTableInputSource extends InputSource { - private final InputSource inputSource; - private TableBlock mCache; - private APKLogger apkLogger; - public SingleJsonTableInputSource(InputSource inputSource) { - super(inputSource.getAlias()); - this.inputSource=inputSource; - } - @Override - public long write(OutputStream outputStream) throws IOException { - return getTableBlock().writeBytes(outputStream); - } - @Override - public InputStream openStream() throws IOException { - TableBlock tableBlock = getTableBlock(); - return new ByteArrayInputStream(tableBlock.getBytes()); - } - @Override - public long getLength() throws IOException{ - TableBlock tableBlock = getTableBlock(); - return tableBlock.countBytes(); - } - @Override - public long getCrc() throws IOException { - CrcOutputStream outputStream=new CrcOutputStream(); - this.write(outputStream); - return outputStream.getCrcValue(); - } - public TableBlock getTableBlock() throws IOException{ - if(mCache != null){ - return mCache; - } - logMessage("Building resources table: " + inputSource.getAlias()); - TableBlock tableBlock=newInstance(); - InputStream inputStream = inputSource.openStream(); - try{ - StringPoolBuilder poolBuilder = new StringPoolBuilder(); - JSONObject jsonObject = new JSONObject(inputStream); - poolBuilder.build(jsonObject); - poolBuilder.apply(tableBlock); - tableBlock.fromJson(jsonObject); - }catch (JSONException ex){ - throw new IOException(inputSource.getAlias(), ex); - } - mCache = tableBlock; - return tableBlock; - } - TableBlock newInstance(){ - return new TableBlock(); - } - public static SingleJsonTableInputSource fromFile(File rootDir, File jsonFile){ - String path=ApkUtil.toArchiveResourcePath(rootDir, jsonFile); - FileInputSource fileInputSource=new FileInputSource(jsonFile, path); - return new SingleJsonTableInputSource(fileInputSource); - } - void setAPKLogger(APKLogger logger) { - this.apkLogger = logger; - } - private void logMessage(String msg) { - if(apkLogger!=null){ - apkLogger.logMessage(msg); - } - } - private void logError(String msg, Throwable tr) { - if(apkLogger!=null){ - apkLogger.logError(msg, tr); - } - } - private void logVerbose(String msg) { - if(apkLogger!=null){ - apkLogger.logVerbose(msg); - } - } -} diff --git a/src/ARSCLib/com/reandroid/apk/SplitJsonTableInputSource.java b/src/ARSCLib/com/reandroid/apk/SplitJsonTableInputSource.java deleted file mode 100644 index 0f8618b6..00000000 --- a/src/ARSCLib/com/reandroid/apk/SplitJsonTableInputSource.java +++ /dev/null @@ -1,78 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.archive.InputSource; -import com.reandroid.arsc.chunk.TableBlock; - -import java.io.*; - -public class SplitJsonTableInputSource extends InputSource { - private final File dir; - private TableBlock mCache; - private APKLogger apkLogger; - public SplitJsonTableInputSource(File dir) { - super(TableBlock.FILE_NAME); - this.dir=dir; - } - @Override - public long write(OutputStream outputStream) throws IOException { - return getTableBlock().writeBytes(outputStream); - } - @Override - public InputStream openStream() throws IOException { - TableBlock tableBlock = getTableBlock(); - return new ByteArrayInputStream(tableBlock.getBytes()); - } - @Override - public long getLength() throws IOException{ - TableBlock tableBlock = getTableBlock(); - return tableBlock.countBytes(); - } - @Override - public long getCrc() throws IOException { - CrcOutputStream outputStream=new CrcOutputStream(); - this.write(outputStream); - return outputStream.getCrcValue(); - } - public TableBlock getTableBlock() throws IOException { - if(mCache!=null){ - return mCache; - } - TableBlockJsonBuilder builder=new TableBlockJsonBuilder(); - TableBlock tableBlock=builder.scanDirectory(dir); - mCache=tableBlock; - return tableBlock; - } - void setAPKLogger(APKLogger logger) { - this.apkLogger = logger; - } - void logMessage(String msg) { - if(apkLogger!=null){ - apkLogger.logMessage(msg); - } - } - private void logError(String msg, Throwable tr) { - if(apkLogger!=null){ - apkLogger.logError(msg, tr); - } - } - private void logVerbose(String msg) { - if(apkLogger!=null){ - apkLogger.logVerbose(msg); - } - } -} diff --git a/src/ARSCLib/com/reandroid/apk/StringPoolBuilder.java b/src/ARSCLib/com/reandroid/apk/StringPoolBuilder.java deleted file mode 100644 index 21825824..00000000 --- a/src/ARSCLib/com/reandroid/apk/StringPoolBuilder.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.pool.SpecStringPool; -import com.reandroid.arsc.pool.TableStringPool; -import com.reandroid.arsc.value.ValueHeader; -import com.reandroid.arsc.value.ValueType; -import com.reandroid.json.JSONArray; -import com.reandroid.json.JSONException; -import com.reandroid.json.JSONObject; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.*; - -public class StringPoolBuilder { - private final Map> mSpecNameMap; - private final Set mTableStrings; - private int mCurrentPackageId; - private JSONArray mStyledStrings; - public StringPoolBuilder(){ - this.mSpecNameMap = new HashMap<>(); - this.mTableStrings = new HashSet<>(); - } - public void apply(TableBlock tableBlock){ - applyTableString(tableBlock.getTableStringPool()); - for(int pkgId:mSpecNameMap.keySet()){ - PackageBlock packageBlock=tableBlock.getPackageArray().getOrCreate(pkgId); - applySpecString(packageBlock.getSpecStringPool()); - } - } - private void applyTableString(TableStringPool stringPool){ - stringPool.fromJson(mStyledStrings); - stringPool.addStrings(getTableString()); - stringPool.refresh(); - } - private void applySpecString(SpecStringPool stringPool){ - int pkgId = stringPool.getPackageBlock().getId(); - stringPool.addStrings(getSpecString(pkgId)); - stringPool.refresh(); - } - public void scanDirectory(File resourcesDir) throws IOException { - mCurrentPackageId=0; - List pkgDirList=ApkUtil.listDirectories(resourcesDir); - for(File dir:pkgDirList){ - File pkgFile=new File(dir, PackageBlock.JSON_FILE_NAME); - scanFile(pkgFile); - List jsonFileList=ApkUtil.recursiveFiles(dir, ".json"); - for(File file:jsonFileList){ - if(file.equals(pkgFile)){ - continue; - } - scanFile(file); - } - } - } - public void scanFile(File jsonFile) throws IOException { - try{ - FileInputStream inputStream=new FileInputStream(jsonFile); - JSONObject jsonObject=new JSONObject(inputStream); - build(jsonObject); - }catch (JSONException ex){ - throw new IOException(jsonFile+": "+ex.getMessage()); - } - } - public void build(JSONObject jsonObject){ - scan(jsonObject); - } - public Set getTableString(){ - return mTableStrings; - } - public Set getSpecString(int pkgId){ - return mSpecNameMap.get(pkgId); - } - private void scan(JSONObject jsonObject){ - if(jsonObject.has(ValueHeader.NAME_entry_name)){ - addSpecName(jsonObject.optString(ValueHeader.NAME_entry_name)); - } - if(jsonObject.has(ApkUtil.NAME_value_type)){ - if(ValueType.STRING.name().equals(jsonObject.getString(ApkUtil.NAME_value_type))){ - String data= jsonObject.optString(ApkUtil.NAME_data, ""); - addTableString(data); - } - return; - }else if(jsonObject.has(PackageBlock.NAME_package_id)){ - mCurrentPackageId = jsonObject.getInt(PackageBlock.NAME_package_id); - } - Set keyList = jsonObject.keySet(); - for(String key:keyList){ - Object obj=jsonObject.get(key); - if(obj instanceof JSONObject){ - scan((JSONObject) obj); - continue; - } - if(obj instanceof JSONArray){ - JSONArray jsonArray = (JSONArray) obj; - if(TableBlock.NAME_styled_strings.equals(key)){ - this.mStyledStrings = jsonArray; - }else { - scan(jsonArray); - } - } - } - } - private void scan(JSONArray jsonArray){ - if(jsonArray==null){ - return; - } - for(Object obj:jsonArray.getArrayList()){ - if(obj instanceof JSONObject){ - scan((JSONObject) obj); - continue; - } - if(obj instanceof JSONArray){ - scan((JSONArray) obj); - } - } - } - private void addTableString(String name){ - if(name==null){ - return; - } - mTableStrings.add(name); - } - private void addSpecName(String name){ - if(name==null){ - return; - } - int pkgId=mCurrentPackageId; - if(pkgId==0){ - throw new IllegalArgumentException("Current package id is 0"); - } - Set specNames=mSpecNameMap.get(pkgId); - if(specNames==null){ - specNames=new HashSet<>(); - mSpecNameMap.put(pkgId, specNames); - } - specNames.add(name); - } -} diff --git a/src/ARSCLib/com/reandroid/apk/TableBlockJson.java b/src/ARSCLib/com/reandroid/apk/TableBlockJson.java deleted file mode 100644 index bf48d615..00000000 --- a/src/ARSCLib/com/reandroid/apk/TableBlockJson.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.arsc.BuildInfo; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.StagedAlias; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.chunk.TypeBlock; -import com.reandroid.arsc.container.SpecTypePair; -import com.reandroid.arsc.util.HexUtil; -import com.reandroid.json.JSONObject; - -import java.io.File; -import java.io.IOException; - -public class TableBlockJson { - private final TableBlock tableBlock; - public TableBlockJson(TableBlock tableBlock){ - this.tableBlock=tableBlock; - } - public void writeJsonFiles(File outDir) throws IOException { - for(PackageBlock packageBlock: tableBlock.listPackages()){ - writePackageJsonFiles(outDir, packageBlock); - } - } - private void writePackageJsonFiles(File rootDir, PackageBlock packageBlock) throws IOException { - File pkgDir = new File(rootDir, getDirName(packageBlock)); - - writePackageJson(pkgDir, packageBlock); - - for(SpecTypePair specTypePair: packageBlock.listSpecTypePairs()){ - for(TypeBlock typeBlock:specTypePair.getTypeBlockArray().listItems()){ - writeTypeJsonFiles(pkgDir, typeBlock); - } - } - } - private void writePackageJson(File packageDirectory, PackageBlock packageBlock) throws IOException { - JSONObject jsonObject = new JSONObject(); - - jsonObject.put(BuildInfo.NAME_arsc_lib_version, BuildInfo.getVersion()); - - jsonObject.put(PackageBlock.NAME_package_id, packageBlock.getId()); - jsonObject.put(PackageBlock.NAME_package_name, packageBlock.getName()); - StagedAlias stagedAlias=StagedAlias - .mergeAll(packageBlock.getStagedAliasList().getChildes()); - if(stagedAlias!=null){ - jsonObject.put(PackageBlock.NAME_staged_aliases, - stagedAlias.getStagedAliasEntryArray().toJson()); - } - - File packageFile = new File(packageDirectory, PackageBlock.JSON_FILE_NAME); - jsonObject.write(packageFile); - } - private void writeTypeJsonFiles(File packageDirectory, TypeBlock typeBlock) throws IOException { - File file=new File(packageDirectory, - getFileName(typeBlock) + ApkUtil.JSON_FILE_EXTENSION); - JSONObject jsonObject = typeBlock.toJson(); - jsonObject.write(file); - } - private String getFileName(TypeBlock typeBlock){ - StringBuilder builder=new StringBuilder(); - builder.append(String.format("%03d-", typeBlock.getIndex())); - builder.append(HexUtil.toHex2(typeBlock.getTypeId())); - String name= typeBlock.getTypeName(); - builder.append('-').append(name); - builder.append(typeBlock.getResConfig().getQualifiers()); - return builder.toString(); - } - private String getDirName(PackageBlock packageBlock){ - StringBuilder builder=new StringBuilder(); - builder.append(HexUtil.toHex2((byte) packageBlock.getId())); - builder.append("-"); - builder.append(packageBlock.getIndex()); - String name= ApkUtil.sanitizeForFileName(packageBlock.getName()); - if(name!=null){ - builder.append('-'); - builder.append(name); - } - return builder.toString(); - } -} diff --git a/src/ARSCLib/com/reandroid/apk/TableBlockJsonBuilder.java b/src/ARSCLib/com/reandroid/apk/TableBlockJsonBuilder.java deleted file mode 100644 index 1880496f..00000000 --- a/src/ARSCLib/com/reandroid/apk/TableBlockJsonBuilder.java +++ /dev/null @@ -1,89 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.StagedAlias; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.chunk.TypeBlock; -import com.reandroid.arsc.value.ResConfig; -import com.reandroid.json.JSONArray; -import com.reandroid.json.JSONObject; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.List; - -public class TableBlockJsonBuilder { - private final StringPoolBuilder poolBuilder; - public TableBlockJsonBuilder(){ - poolBuilder=new StringPoolBuilder(); - } - public TableBlock scanDirectory(File resourcesDir) throws IOException { - if(!resourcesDir.isDirectory()){ - throw new IOException("No such directory: "+resourcesDir); - } - List pkgDirList=ApkUtil.listDirectories(resourcesDir); - if(pkgDirList.size()==0){ - throw new IOException("No package sub directory found in : "+resourcesDir); - } - TableBlock tableBlock=new TableBlock(); - poolBuilder.scanDirectory(resourcesDir); - poolBuilder.apply(tableBlock); - for(File pkgDir:pkgDirList){ - scanPackageDirectory(tableBlock, pkgDir); - } - tableBlock.sortPackages(); - tableBlock.refresh(); - return tableBlock; - } - private void scanPackageDirectory(TableBlock tableBlock, File pkgDir) throws IOException{ - File pkgFile=new File(pkgDir, PackageBlock.JSON_FILE_NAME); - if(!pkgFile.isFile()){ - throw new IOException("Invalid package directory! Package file missing: "+pkgFile); - } - FileInputStream inputStream=new FileInputStream(pkgFile); - JSONObject jsonObject=new JSONObject(inputStream); - PackageBlock pkg=tableBlock.getPackageArray() - .getOrCreate(jsonObject.getInt(PackageBlock.NAME_package_id)); - pkg.setName(jsonObject.optString(PackageBlock.NAME_package_name)); - if(jsonObject.has(PackageBlock.NAME_staged_aliases)){ - JSONArray stagedJson = jsonObject.getJSONArray(PackageBlock.NAME_staged_aliases); - StagedAlias stagedAlias = new StagedAlias(); - stagedAlias.getStagedAliasEntryArray().fromJson(stagedJson); - pkg.getStagedAliasList().add(stagedAlias); - } - List typeFileList = ApkUtil.listFiles(pkgDir, ApkUtil.JSON_FILE_EXTENSION); - typeFileList.remove(pkgFile); - for(File typeFile:typeFileList){ - loadType(pkg, typeFile); - } - pkg.sortTypes(); - } - private void loadType(PackageBlock packageBlock, File typeJsonFile) throws IOException{ - FileInputStream inputStream=new FileInputStream(typeJsonFile); - JSONObject jsonObject=new JSONObject(inputStream); - JSONObject configObj=jsonObject.getJSONObject(TypeBlock.NAME_config); - ResConfig resConfig=new ResConfig(); - resConfig.fromJson(configObj); - TypeBlock typeBlock=packageBlock.getSpecTypePairArray() - .getOrCreate( - ((byte)(0xff & jsonObject.getInt(TypeBlock.NAME_id))) - , resConfig); - typeBlock.fromJson(jsonObject); - } -} diff --git a/src/ARSCLib/com/reandroid/apk/UncompressedFiles.java b/src/ARSCLib/com/reandroid/apk/UncompressedFiles.java deleted file mode 100644 index cdc3422c..00000000 --- a/src/ARSCLib/com/reandroid/apk/UncompressedFiles.java +++ /dev/null @@ -1,232 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.archive.InputSource; -import com.reandroid.archive.ZipArchive; -import com.reandroid.json.JSONArray; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONObject; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; -import java.util.zip.ZipEntry; - -public class UncompressedFiles implements JSONConvert { - private final Set mPathList; - private final Set mExtensionList; - private String mResRawDir; - public UncompressedFiles(){ - this.mPathList=new HashSet<>(); - this.mExtensionList=new HashSet<>(); - } - public void setResRawDir(String resRawDir){ - this.mResRawDir=resRawDir; - } - public void apply(ZipArchive archive){ - for(InputSource inputSource:archive.listInputSources()){ - apply(inputSource); - } - } - public void apply(InputSource inputSource){ - if(isUncompressed(inputSource.getAlias()) || isUncompressed(inputSource.getName())){ - inputSource.setMethod(ZipEntry.STORED); - }else { - inputSource.setMethod(ZipEntry.DEFLATED); - } - } - public boolean isUncompressed(String path){ - if(path==null){ - return false; - } - if(containsPath(path)||containsExtension(path)||isResRawDir(path)){ - return true; - } - String extension=getExtension(path); - return containsExtension(extension); - } - private boolean isResRawDir(String path){ - String dir=mResRawDir; - if(dir==null||dir.length()==0){ - return false; - } - return path.startsWith(dir); - } - public boolean containsExtension(String extension){ - if(extension==null){ - return false; - } - if(mExtensionList.contains(extension)){ - return true; - } - if(!extension.startsWith(".")){ - return mExtensionList.contains("."+extension); - } - return mExtensionList.contains(extension.substring(1)); - } - public boolean containsPath(String path){ - path=sanitizePath(path); - if(path==null){ - return false; - } - return mPathList.contains(path); - } - public void addPath(ZipArchive zipArchive){ - for(InputSource inputSource: zipArchive.listInputSources()){ - addPath(inputSource); - } - } - public void addPath(InputSource inputSource){ - if(inputSource.getMethod()!=ZipEntry.STORED){ - return; - } - addPath(inputSource.getAlias()); - } - public void addPath(String path){ - path=sanitizePath(path); - if(path==null){ - return; - } - mPathList.add(path); - } - public void removePath(String path){ - path=sanitizePath(path); - if(path==null){ - return; - } - mPathList.remove(path); - } - public void replacePath(String path, String rep){ - path=sanitizePath(path); - rep=sanitizePath(rep); - if(path==null||rep==null){ - return; - } - if(!mPathList.contains(path)){ - return; - } - mPathList.remove(path); - mPathList.add(rep); - } - public void addCommonExtensions(){ - for(String ext:COMMON_EXTENSIONS){ - addExtension(ext); - } - } - public void addExtension(String extension){ - if(extension==null || extension.length()==0){ - return; - } - mExtensionList.add(extension); - } - public void clearPaths(){ - mPathList.clear(); - } - public void clearExtensions(){ - mExtensionList.clear(); - } - @Override - public JSONObject toJson() { - JSONObject jsonObject = new JSONObject(); - jsonObject.put(NAME_extensions, new JSONArray(mExtensionList)); - jsonObject.put(NAME_paths, new JSONArray(mPathList)); - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - clearExtensions(); - clearPaths(); - if(json==null){ - return; - } - JSONArray extensions = json.optJSONArray(NAME_extensions); - if(extensions!=null){ - int length = extensions.length(); - for(int i=0;i0){ - i++; - path=path.substring(i); - } - i = path.lastIndexOf('.'); - if(i>0){ - return path.substring(i); - } - return null; - } - - public static final String JSON_FILE = "uncompressed-files.json"; - public static final String NAME_paths = "paths"; - public static final String NAME_extensions = "extensions"; - public static String[] COMMON_EXTENSIONS=new String[]{ - ".png", - ".jpg", - ".mp3", - ".mp4", - ".wav", - ".webp", - }; -} diff --git a/src/ARSCLib/com/reandroid/apk/XmlHelper.java b/src/ARSCLib/com/reandroid/apk/XmlHelper.java deleted file mode 100644 index 4f2c2e08..00000000 --- a/src/ARSCLib/com/reandroid/apk/XmlHelper.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk; - -import com.reandroid.arsc.item.StringItem; -import com.reandroid.xml.*; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.Closeable; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -public class XmlHelper { - - public static Map readAttributes(XmlPullParser parser, String elementName) throws IOException, XmlPullParserException { - if(!findElement(parser, elementName)){ - return null; - } - return mapAttributes(parser); - } - public static Map mapAttributes(XmlPullParser parser){ - Map map = new HashMap<>(); - int count = parser.getAttributeCount(); - for(int i = 0; i < count; i++){ - String name = parser.getAttributeName(i); - int index = name.indexOf(':'); - if(index > 0 && index < name.length() && !name.startsWith("xmlns:")){ - index++; - name = name.substring(index); - } - map.put(name, - parser.getAttributeValue(i)); - } - return map; - } - private static boolean findElement(XmlPullParser parser, String elementName) throws IOException, XmlPullParserException { - int event; - while ((event = parser.next()) != XmlPullParser.END_DOCUMENT){ - if(event != XmlPullParser.START_TAG){ - continue; - } - if(elementName.equals(parser.getName())){ - return true; - } - } - return false; - } - - public static void setTextContent(XMLElement element, StringItem stringItem){ - if(stringItem==null){ - element.clearChildNodes(); - return; - } - if(!stringItem.hasStyle()){ - element.setTextContent(stringItem.get()); - }else { - element.setSpannableText(stringItem.getXml()); - } - } - public static String toXMLTagName(String typeName){ - // e.g ^attr-private - if(typeName.length()>0 && typeName.charAt(0)=='^'){ - typeName = typeName.substring(1); - } - return typeName; - } - - public static void closeSilent(Object obj){ - if(!(obj instanceof Closeable)){ - return; - } - Closeable closeable = (Closeable) obj; - try { - closeable.close(); - } catch (IOException ignored) { - } - } - - public static final String RESOURCES_TAG = "resources"; -} diff --git a/src/ARSCLib/com/reandroid/apk/xmldecoder/BagDecoder.java b/src/ARSCLib/com/reandroid/apk/xmldecoder/BagDecoder.java deleted file mode 100644 index ba597822..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmldecoder/BagDecoder.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmldecoder; - -import com.reandroid.arsc.value.ResTableMapEntry; -import com.reandroid.common.EntryStore; -import com.reandroid.xml.XMLElement; - -abstract class BagDecoder extends DecoderTableEntry { - public BagDecoder(EntryStore entryStore){ - super(entryStore); - } - public abstract boolean canDecode(ResTableMapEntry mapEntry); -} diff --git a/src/ARSCLib/com/reandroid/apk/xmldecoder/BagDecoderArray.java b/src/ARSCLib/com/reandroid/apk/xmldecoder/BagDecoderArray.java deleted file mode 100644 index 61d40a97..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmldecoder/BagDecoderArray.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmldecoder; - -import com.reandroid.apk.ApkUtil; -import com.reandroid.apk.XmlHelper; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.value.*; -import com.reandroid.common.EntryStore; - -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; - -class BagDecoderArray extends BagDecoder{ - public BagDecoderArray(EntryStore entryStore) { - super(entryStore); - } - - @Override - public OUTPUT decode(ResTableMapEntry mapEntry, EntryWriter writer) throws IOException { - Entry entry = mapEntry.getParentEntry(); - String tag = getTagName(mapEntry); - writer.enableIndent(true); - writer.startTag(tag); - writer.attribute("name", entry.getName()); - - PackageBlock packageBlock = entry.getPackageBlock(); - EntryStore entryStore = getEntryStore(); - ResValueMap[] resValueMaps = mapEntry.listResValueMap(); - boolean zero_name = isZeroNameArray(resValueMaps); - for(int i = 0; i < resValueMaps.length; i++){ - ResValueMap valueMap = resValueMaps[i]; - String childTag = "item"; - writer.enableIndent(true); - writer.startTag(childTag); - if(zero_name){ - String name = ValueDecoder.decodeAttributeName( - entryStore, packageBlock, valueMap.getName()); - writer.attribute("name", name); - } - writeText(writer, packageBlock, valueMap); - writer.endTag(childTag); - } - return writer.endTag(tag); - } - private String getTagName(ResTableMapEntry mapEntry){ - ResValueMap[] resValueMaps = mapEntry.listResValueMap(); - Set valueTypes = new HashSet<>(); - for(int i = 0; i < resValueMaps.length; i++){ - valueTypes.add(resValueMaps[i].getValueType()); - } - if(valueTypes.contains(ValueType.STRING)){ - return ApkUtil.TAG_STRING_ARRAY; - } - if(valueTypes.size() == 1 && valueTypes.contains(ValueType.INT_DEC)){ - return ApkUtil.TAG_INTEGER_ARRAY; - } - return XmlHelper.toXMLTagName(mapEntry.getParentEntry().getTypeName()); - } - @Override - public boolean canDecode(ResTableMapEntry mapEntry) { - return isArrayValue(mapEntry); - } - public static boolean isArrayValue(ResTableMapEntry mapEntry){ - int parentId=mapEntry.getParentId(); - if(parentId!=0){ - return false; - } - ResValueMap[] valueMapList = mapEntry.listResValueMap(); - if(valueMapList == null || valueMapList.length == 0){ - return false; - } - if(isIndexedArray(valueMapList)){ - return true; - } - return isZeroNameArray(valueMapList); - } - private static boolean isIndexedArray(ResValueMap[] resValueMapList){ - int length = resValueMapList.length; - for(int i = 0; i < length; i++){ - ResValueMap valueMap = resValueMapList[i]; - int name = valueMap.getName(); - int high = (name >> 16) & 0xffff; - if(high!=0x0100 && high!=0x0200){ - return false; - } - int low = name & 0xffff; - int id = low - 1; - if(id!=i){ - return false; - } - } - return true; - } - private static boolean isZeroNameArray(ResValueMap[] resValueMapList){ - int length = resValueMapList.length; - for(int i = 0; i < length; i++){ - if(!isZeroName(resValueMapList[i])){ - return false; - } - } - return true; - } - private static boolean isZeroName(ResValueMap resValueMap){ - return resValueMap.getName() == 0; - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmldecoder/BagDecoderAttr.java b/src/ARSCLib/com/reandroid/apk/xmldecoder/BagDecoderAttr.java deleted file mode 100644 index af2a0958..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmldecoder/BagDecoderAttr.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmldecoder; - -import com.reandroid.apk.XmlHelper; -import com.reandroid.arsc.array.CompoundItemArray; -import com.reandroid.arsc.util.HexUtil; -import com.reandroid.arsc.value.*; -import com.reandroid.arsc.value.attribute.AttributeBag; -import com.reandroid.arsc.value.attribute.AttributeBagItem; -import com.reandroid.common.EntryStore; - -import java.io.IOException; - -class BagDecoderAttr extends BagDecoder{ - public BagDecoderAttr(EntryStore entryStore){ - super(entryStore); - } - - @Override - public OUTPUT decode(ResTableMapEntry mapEntry, EntryWriter writer) throws IOException { - Entry entry = mapEntry.getParentEntry(); - String tag = XmlHelper.toXMLTagName(entry.getTypeName()); - writer.enableIndent(true); - writer.startTag(tag); - writer.attribute("name", entry.getName()); - writeParentAttributes(writer, mapEntry.getValue()); - ResValueMap formatsMap = mapEntry.getByType(AttributeType.FORMATS); - - AttributeDataFormat bagType = AttributeDataFormat.typeOfBag(formatsMap.getData()); - - ResValueMap[] bagItems = mapEntry.listResValueMap(); - - - for(int i = 0; i < bagItems.length; i++){ - ResValueMap item = bagItems[i]; - AttributeType attributeType = item.getAttributeType(); - if(attributeType != null){ - continue; - } - writer.enableIndent(true); - writer.startTag(bagType.getName()); - - String name = item.decodeName(); - writer.attribute("name", name); - int rawVal = item.getData(); - String value; - if(item.getValueType() == ValueType.INT_HEX){ - value = HexUtil.toHex8(rawVal); - }else { - value = Integer.toString(rawVal); - } - writer.text(value); - - writer.endTag(bagType.getName()); - } - return writer.endTag(tag); - } - - private void writeParentAttributes(EntryWriter writer, CompoundItemArray itemArray) throws IOException { - for(ResValueMap valueMap : itemArray.getChildes()){ - AttributeType type = valueMap.getAttributeType(); - if(type == null){ - continue; - } - String value; - if(type == AttributeType.FORMATS){ - value = AttributeDataFormat.toString( - AttributeDataFormat.decodeValueTypes(valueMap.getData())); - }else { - value = Integer.toString(valueMap.getData()); - } - if(value == null){ - continue; - } - writer.attribute(type.getName(), value); - } - } - @Override - public boolean canDecode(ResTableMapEntry mapEntry) { - return AttributeBag.isAttribute(mapEntry); - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmldecoder/BagDecoderCommon.java b/src/ARSCLib/com/reandroid/apk/xmldecoder/BagDecoderCommon.java deleted file mode 100644 index 232b2503..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmldecoder/BagDecoderCommon.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmldecoder; - -import com.reandroid.apk.XmlHelper; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.value.Entry; -import com.reandroid.arsc.value.ResTableMapEntry; -import com.reandroid.arsc.value.ResValueMap; -import com.reandroid.arsc.value.ValueType; -import com.reandroid.common.EntryStore; -import com.reandroid.xml.XMLElement; - -import java.io.IOException; - -class BagDecoderCommon extends BagDecoder{ - public BagDecoderCommon(EntryStore entryStore) { - super(entryStore); - } - - @Override - public OUTPUT decode(ResTableMapEntry mapEntry, EntryWriter writer) throws IOException { - Entry entry = mapEntry.getParentEntry(); - String tag = XmlHelper.toXMLTagName(entry.getTypeName()); - writer.enableIndent(true); - writer.startTag(tag); - writer.attribute("name", entry.getName()); - - PackageBlock packageBlock = entry.getPackageBlock(); - - int parentId = mapEntry.getParentId(); - String parent; - if(parentId != 0){ - parent = ValueDecoder.decodeEntryValue(getEntryStore(), - packageBlock, ValueType.REFERENCE, parentId); - }else { - parent = null; - } - if(parent != null){ - writer.attribute("parent", parent); - } - - EntryStore entryStore = getEntryStore(); - ResValueMap[] resValueMaps = mapEntry.listResValueMap(); - for(int i = 0; i < resValueMaps.length; i++){ - ResValueMap valueMap = resValueMaps[i]; - String childTag = "item"; - writer.enableIndent(true); - writer.startTag(childTag); - - String name = ValueDecoder.decodeAttributeName( - entryStore, packageBlock, valueMap.getName()); - writer.attribute("name", name); - - writeText(writer, valueMap); - - writer.endTag(childTag); - } - return writer.endTag(tag); - } - @Override - public boolean canDecode(ResTableMapEntry mapEntry) { - return mapEntry !=null; - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmldecoder/BagDecoderPlural.java b/src/ARSCLib/com/reandroid/apk/xmldecoder/BagDecoderPlural.java deleted file mode 100644 index 2831589d..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmldecoder/BagDecoderPlural.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmldecoder; - -import com.reandroid.apk.XmlHelper; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.value.*; -import com.reandroid.arsc.value.plurals.PluralsQuantity; -import com.reandroid.common.EntryStore; - -import java.io.IOException; - -class BagDecoderPlural extends BagDecoder{ - public BagDecoderPlural(EntryStore entryStore) { - super(entryStore); - } - - @Override - public OUTPUT decode(ResTableMapEntry mapEntry, EntryWriter writer) throws IOException { - Entry entry = mapEntry.getParentEntry(); - String tag = XmlHelper.toXMLTagName(entry.getTypeName()); - writer.enableIndent(true); - writer.startTag(tag); - writer.attribute("name", entry.getName()); - - ResValueMap[] resValueMaps = mapEntry.listResValueMap(); - PackageBlock packageBlock = entry.getPackageBlock(); - for(int i=0; i < resValueMaps.length; i++){ - ResValueMap valueMap = resValueMaps[i]; - String childTag = "item"; - writer.enableIndent(true); - writer.startTag(childTag); - - AttributeType quantity = valueMap.getAttributeType(); - if(quantity == null || !quantity.isPlural()){ - throw new IOException("Unknown plural quantity: " + valueMap); - } - writer.attribute("quantity", quantity.getName()); - - writeText(writer, packageBlock, valueMap); - - writer.endTag(childTag); - } - return writer.endTag(tag); - } - - @Override - public boolean canDecode(ResTableMapEntry mapEntry) { - return isResBagPluralsValue(mapEntry); - } - - public static boolean isResBagPluralsValue(ResTableMapEntry valueItem){ - int parentId=valueItem.getParentId(); - if(parentId!=0){ - return false; - } - ResValueMap[] bagItems = valueItem.listResValueMap(); - if(bagItems==null||bagItems.length==0){ - return false; - } - int len=bagItems.length; - for(int i=0;i> 16) & 0xffff; - if(high!=0x0100){ - return false; - } - int low = name & 0xffff; - PluralsQuantity pq=PluralsQuantity.valueOf((short) low); - if(pq==null){ - return false; - } - } - return true; - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmldecoder/DecoderResTableEntry.java b/src/ARSCLib/com/reandroid/apk/xmldecoder/DecoderResTableEntry.java deleted file mode 100644 index 45982a60..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmldecoder/DecoderResTableEntry.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmldecoder; - -import com.reandroid.apk.XmlHelper; -import com.reandroid.arsc.value.Entry; -import com.reandroid.arsc.value.ResTableEntry; -import com.reandroid.common.EntryStore; - -import java.io.IOException; - -public class DecoderResTableEntry extends DecoderTableEntry { - public DecoderResTableEntry(EntryStore entryStore){ - super(entryStore); - } - @Override - public OUTPUT decode(ResTableEntry tableEntry, EntryWriter writer) throws IOException{ - Entry entry = tableEntry.getParentEntry(); - String tag = XmlHelper.toXMLTagName(entry.getTypeName()); - writer.enableIndent(true); - writer.startTag(tag); - writer.attribute("name", entry.getName()); - if(!isId(tag)){ - writeText(writer, entry.getPackageBlock(), tableEntry.getValue()); - } - return writer.endTag(tag); - } - - private boolean isId(String tag){ - return "id".equals(tag); - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmldecoder/DecoderResTableEntryMap.java b/src/ARSCLib/com/reandroid/apk/xmldecoder/DecoderResTableEntryMap.java deleted file mode 100644 index f0e7cff2..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmldecoder/DecoderResTableEntryMap.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmldecoder; - -import com.reandroid.arsc.value.ResTableMapEntry; -import com.reandroid.common.EntryStore; - -import java.io.IOException; - -class DecoderResTableEntryMap extends DecoderTableEntry { - private final Object[] decoderList; - private final BagDecoderCommon bagDecoderCommon; - - public DecoderResTableEntryMap(EntryStore entryStore) { - super(entryStore); - this.decoderList = new Object[] { - new BagDecoderAttr<>(entryStore), - new BagDecoderPlural<>(entryStore), - new BagDecoderArray<>(entryStore) - }; - - this.bagDecoderCommon = new BagDecoderCommon<>(entryStore); - } - - @Override - public OUTPUT decode(ResTableMapEntry tableEntry, EntryWriter writer) throws IOException { - return getFor(tableEntry).decode(tableEntry, writer); - } - private BagDecoder getFor(ResTableMapEntry mapEntry){ - Object[] decoderList = this.decoderList; - for(int i = 0; i < decoderList.length; i++){ - BagDecoder bagDecoder = (BagDecoder) decoderList[i]; - if(bagDecoder.canDecode(mapEntry)){ - return bagDecoder; - } - } - return bagDecoderCommon; - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmldecoder/DecoderTableEntry.java b/src/ARSCLib/com/reandroid/apk/xmldecoder/DecoderTableEntry.java deleted file mode 100644 index 3255d716..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmldecoder/DecoderTableEntry.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmldecoder; - -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.value.*; -import com.reandroid.common.EntryStore; - -import java.io.IOException; - -abstract class DecoderTableEntry, OUTPUT> { - private final EntryStore entryStore; - public DecoderTableEntry(EntryStore entryStore){ - this.entryStore = entryStore; - } - public EntryStore getEntryStore() { - return entryStore; - } - public abstract OUTPUT decode(INPUT tableEntry, EntryWriter writer) throws IOException; - - void writeText(EntryWriter writer, PackageBlock packageBlock, ValueItem valueItem) - throws IOException { - - if(valueItem.getValueType() == ValueType.STRING){ - XMLDecodeHelper.writeTextContent(writer, valueItem.getDataAsPoolString()); - }else { - String value = ValueDecoder.decodeEntryValue( - getEntryStore(), - packageBlock, - valueItem.getValueType(), - valueItem.getData()); - writer.text(value); - } - } - void writeText(EntryWriter writer, ResValueMap attributeValue) - throws IOException { - if(attributeValue.getValueType() == ValueType.STRING){ - XMLDecodeHelper.writeTextContent(writer, attributeValue.getDataAsPoolString()); - }else { - String value = ValueDecoder.decode(getEntryStore(), - attributeValue.getPackageBlock().getId(), - attributeValue); - writer.text(value); - } - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmldecoder/EntryWriter.java b/src/ARSCLib/com/reandroid/apk/xmldecoder/EntryWriter.java deleted file mode 100644 index 20bd77c8..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmldecoder/EntryWriter.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmldecoder; - -import java.io.IOException; - -public interface EntryWriter{ - void setFeature(String name, Object value); - T startTag(String name) throws IOException; - T endTag(String name) throws IOException; - T attribute(String name, String value) throws IOException; - T text(String text) throws IOException; - void comment(String comment) throws IOException; - void flush() throws IOException; - void enableIndent(boolean enable); -} diff --git a/src/ARSCLib/com/reandroid/apk/xmldecoder/EntryWriterElement.java b/src/ARSCLib/com/reandroid/apk/xmldecoder/EntryWriterElement.java deleted file mode 100644 index ad14a221..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmldecoder/EntryWriterElement.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmldecoder; - -import com.reandroid.xml.XMLComment; -import com.reandroid.xml.XMLElement; - -import java.io.IOException; - -public class EntryWriterElement implements EntryWriter { - private XMLElement mCurrentElement; - private XMLElement mResult; - private boolean mEnableIndent; - - public EntryWriterElement(){ - } - - public XMLElement getElement() { - return mResult; - } - @Override - public void setFeature(String name, Object value) { - if(!FEATURE_INDENT.equals(name)){ - return; - } - boolean state = false; - if(value instanceof Boolean){ - state = (Boolean)value; - } - mEnableIndent = state; - } - @Override - public XMLElement startTag(String name) throws IOException { - XMLElement xmlElement = new XMLElement(name); - XMLElement current = mCurrentElement; - if(current != null){ - current.addChild(xmlElement); - }else { - mResult = null; - } - mCurrentElement = xmlElement; - if(mEnableIndent){ - xmlElement.setIndent(2); - xmlElement.setIndentScale(1.0f); - }else { - xmlElement.setIndent(0); - xmlElement.setIndentScale(0.0f); - } - return xmlElement; - } - @Override - public XMLElement endTag(String name) throws IOException { - XMLElement current = mCurrentElement; - if(current == null){ - throw new IOException("endTag called before startTag"); - } - if(!name.equals(current.getTagName())){ - throw new IOException("Mismatch endTag = " - + name + ", expect = " + current.getTagName()); - } - XMLElement parent = current.getParent(); - if(parent == null){ - mResult = current; - }else { - current = parent; - } - mCurrentElement = parent; - return current; - } - @Override - public XMLElement attribute(String name, String value) { - mCurrentElement.setAttribute(name, value); - return mCurrentElement; - } - @Override - public XMLElement text(String text) throws IOException { - mCurrentElement.setTextContent(text, false); - return mCurrentElement; - } - @Override - public void comment(String comment) throws IOException { - if(comment != null){ - mCurrentElement.addComment(new XMLComment(comment)); - } - } - @Override - public void flush() throws IOException { - } - @Override - public void enableIndent(boolean enable){ - setFeature(FEATURE_INDENT, enable); - } - - private static final String FEATURE_INDENT = "http://xmlpull.org/v1/doc/features.html#indent-output"; -} diff --git a/src/ARSCLib/com/reandroid/apk/xmldecoder/EntryWriterSerializer.java b/src/ARSCLib/com/reandroid/apk/xmldecoder/EntryWriterSerializer.java deleted file mode 100644 index 163688b2..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmldecoder/EntryWriterSerializer.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmldecoder; - -import org.xmlpull.v1.XmlSerializer; - -import java.io.IOException; - -public class EntryWriterSerializer implements EntryWriter { - private final XmlSerializer xmlSerializer; - public EntryWriterSerializer(XmlSerializer xmlSerializer){ - this.xmlSerializer = xmlSerializer; - } - - public XmlSerializer getXmlSerializer() { - return xmlSerializer; - } - - @Override - public void setFeature(String name, Object value) { - if(value == null){ - value = false; - }else if(!(value instanceof Boolean)){ - return; - } - xmlSerializer.setFeature(name, (Boolean)value); - } - @Override - public XmlSerializer startTag(String name) throws IOException { - return xmlSerializer.startTag(null, name); - } - @Override - public XmlSerializer endTag(String name) throws IOException { - return xmlSerializer.endTag(null, name); - } - @Override - public XmlSerializer attribute(String name, String value) throws IOException { - return xmlSerializer.attribute(null, name, value); - } - @Override - public XmlSerializer text(String text) throws IOException { - return xmlSerializer.text(text); - } - @Override - public void comment(String comment) throws IOException { - xmlSerializer.comment(comment); - } - @Override - public void flush() throws IOException { - xmlSerializer.flush(); - } - @Override - public void enableIndent(boolean enable){ - setFeature(FEATURE_INDENT, enable); - } - - private static final String FEATURE_INDENT = "http://xmlpull.org/v1/doc/features.html#indent-output"; -} diff --git a/src/ARSCLib/com/reandroid/apk/xmldecoder/ResXmlDocumentSerializer.java b/src/ARSCLib/com/reandroid/apk/xmldecoder/ResXmlDocumentSerializer.java deleted file mode 100644 index eb5db63c..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmldecoder/ResXmlDocumentSerializer.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmldecoder; - -import com.android.org.kxml2.io.KXmlSerializer; -import com.reandroid.apk.ApkModule; -import com.reandroid.archive.InputSource; -import com.reandroid.arsc.chunk.xml.ResXmlDocument; -import com.reandroid.arsc.chunk.xml.ResXmlPullParser; -import com.reandroid.arsc.decoder.Decoder; -import com.reandroid.xml.XmlParserToSerializer; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - -import java.io.*; -import java.nio.charset.StandardCharsets; - -public class ResXmlDocumentSerializer implements ResXmlPullParser.DocumentLoadedListener{ - private final Object mLock = new Object(); - private final ResXmlPullParser parser; - private final XmlSerializer serializer; - private final XmlParserToSerializer parserToSerializer; - private boolean validateXmlNamespace; - private String mCurrentPath; - public ResXmlDocumentSerializer(ResXmlPullParser parser){ - this.parser = parser; - this.serializer = new KXmlSerializer(); - this.parserToSerializer = new XmlParserToSerializer(parser, serializer); - this.parser.setDocumentLoadedListener(this); - } - public ResXmlDocumentSerializer(Decoder decoder){ - this(new ResXmlPullParser(decoder)); - } - public ResXmlDocumentSerializer(ApkModule apkModule){ - this(createDecoder(apkModule)); - } - - public void write(InputSource inputSource, File file) - throws IOException, XmlPullParserException { - write(inputSource.openStream(), file); - } - public void write(InputSource inputSource, OutputStream outputStream) - throws IOException, XmlPullParserException { - write(inputSource.openStream(), outputStream); - inputSource.disposeInputSource(); - } - public void write(InputStream inputStream, OutputStream outputStream) - throws IOException, XmlPullParserException { - synchronized (mLock){ - this.parser.setInput(inputStream, null); - OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8); - this.serializer.setOutput(writer); - try{ - this.parserToSerializer.write(); - }catch (Exception ex){ - throw getError(ex); - } - writer.close(); - outputStream.close(); - mCurrentPath = null; - } - } - public void write(InputStream inputStream, File file) - throws IOException, XmlPullParserException { - File dir = file.getParentFile(); - if(dir != null && !dir.exists()){ - dir.mkdirs(); - } - mCurrentPath = String.valueOf(file); - FileOutputStream outputStream = new FileOutputStream(file); - write(inputStream, outputStream); - } - public void write(ResXmlDocument xmlDocument, File file) - throws IOException, XmlPullParserException { - mCurrentPath = String.valueOf(file); - File dir = file.getParentFile(); - if(dir != null && !dir.exists()){ - dir.mkdirs(); - } - FileOutputStream outputStream = new FileOutputStream(file); - write(xmlDocument, outputStream); - } - public void write(ResXmlDocument xmlDocument, OutputStream outputStream) - throws IOException, XmlPullParserException { - OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8); - write(xmlDocument, writer); - writer.close(); - outputStream.close(); - } - public void write(ResXmlDocument xmlDocument, Writer writer) - throws IOException, XmlPullParserException { - synchronized (mLock){ - this.parser.setResXmlDocument(xmlDocument); - this.serializer.setOutput(writer); - this.parserToSerializer.write(); - writer.flush(); - } - } - public Decoder getDecoder(){ - return parser.getDecoder(); - } - - public void setValidateXmlNamespace(boolean validateXmlNamespace) { - this.validateXmlNamespace = validateXmlNamespace; - } - @Override - public ResXmlDocument onDocumentLoaded(ResXmlDocument resXmlDocument) { - if(!validateXmlNamespace){ - return resXmlDocument; - } - XMLNamespaceValidator.validateNamespaces(resXmlDocument); - return resXmlDocument; - } - private IOException getError(Exception exception){ - String path = mCurrentPath; - if(exception instanceof IOException){ - String msg = path + ":" + exception.getMessage(); - IOException ioException = new IOException(msg); - ioException.setStackTrace(exception.getStackTrace()); - Throwable cause = ioException.getCause(); - if(cause != null){ - ioException.initCause(cause); - } - return ioException; - } - String msg = path + ":" + exception.getClass() + ":" + exception.getMessage(); - IOException otherException = new IOException(msg); - otherException.setStackTrace(exception.getStackTrace()); - Throwable cause = otherException.getCause(); - if(cause != null){ - otherException.initCause(cause); - } - return otherException; - } - - private static Decoder createDecoder(ApkModule apkModule){ - Decoder decoder = Decoder.create(apkModule.getTableBlock()); - decoder.setApkFile(apkModule); - return decoder; - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmldecoder/XMLBagDecoder.java b/src/ARSCLib/com/reandroid/apk/xmldecoder/XMLBagDecoder.java deleted file mode 100644 index 688eaf87..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmldecoder/XMLBagDecoder.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmldecoder; - -import com.reandroid.arsc.value.ResTableMapEntry; -import com.reandroid.common.EntryStore; -import com.reandroid.xml.XMLElement; - -import java.io.IOException; - -@Deprecated -public class XMLBagDecoder { - private final DecoderResTableEntryMap mDocumentDecoder; - private final EntryWriterElement mWriter; - public XMLBagDecoder(EntryStore entryStore){ - mDocumentDecoder = new DecoderResTableEntryMap<>(entryStore); - mWriter = new EntryWriterElement(); - } - public void decode(ResTableMapEntry mapEntry, XMLElement parentElement){ - try { - XMLElement child = mDocumentDecoder.decode(mapEntry, mWriter); - parentElement.addChild(child); - } catch (IOException exception) { - } - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmldecoder/XMLDecodeHelper.java b/src/ARSCLib/com/reandroid/apk/xmldecoder/XMLDecodeHelper.java deleted file mode 100644 index 55a24f5a..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmldecoder/XMLDecodeHelper.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmldecoder; - -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.item.StringItem; -import com.reandroid.xml.*; -import com.reandroid.xml.parser.XMLSpanParser; - -import java.io.IOException; - -public class XMLDecodeHelper { - - public static void writeTextContent(EntryWriter writer, StringItem stringItem) throws IOException { - if(stringItem == null){ - return; - } - if(!stringItem.hasStyle()){ - String text = stringItem.get(); - text = ValueDecoder.escapeSpecialCharacter(text); - text = ValueDecoder.quoteWhitespace(text); - writer.text(text); - }else { - String xml = stringItem.getXml(); - XMLElement element = parseSpanSafe(xml); - if(element != null){ - writeParsedSpannable(writer, element); - }else { - // TODO: throw or investigate the reason - writer.text(xml); - } - } - } - public static void writeParsedSpannable(EntryWriter writer, XMLElement spannableParent) throws IOException { - for(XMLNode xmlNode : spannableParent.getChildNodes()){ - if(xmlNode instanceof XMLText){ - String text = ((XMLText)xmlNode).getText(true); - writer.enableIndent(false); - writer.text(ValueDecoder.escapeSpecialCharacter(text)); - }else if(xmlNode instanceof XMLElement){ - writeElement(writer, (XMLElement) xmlNode); - } - } - } - private static void writeElement(EntryWriter writer, XMLElement element) throws IOException { - writer.enableIndent(false); - writer.startTag(element.getTagName()); - for(XMLAttribute xmlAttribute : element.listAttributes()){ - writer.attribute(xmlAttribute.getName(), xmlAttribute.getValue()); - } - for(XMLNode xmlNode : element.getChildNodes()){ - if(xmlNode instanceof XMLText){ - String text = ((XMLText)xmlNode).getText(true); - writer.text(text); - }else if(xmlNode instanceof XMLElement){ - writeElement(writer, (XMLElement) xmlNode); - } - } - writer.endTag(element.getTagName()); - } - private static XMLElement parseSpanSafe(String spanText){ - if(spanText==null){ - return null; - } - try { - XMLSpanParser spanParser = new XMLSpanParser(); - return spanParser.parse(spanText); - } catch (XMLException ignored) { - return null; - } - } - -} diff --git a/src/ARSCLib/com/reandroid/apk/xmldecoder/XMLEntryDecoder.java b/src/ARSCLib/com/reandroid/apk/xmldecoder/XMLEntryDecoder.java deleted file mode 100644 index ad9fc1f0..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmldecoder/XMLEntryDecoder.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmldecoder; - -import com.reandroid.arsc.chunk.TypeBlock; -import com.reandroid.arsc.group.EntryGroup; -import com.reandroid.arsc.value.*; -import com.reandroid.common.EntryStore; - -import java.io.File; -import java.io.IOException; -import java.util.Collection; -import java.util.Iterator; -import java.util.function.Predicate; - -public class XMLEntryDecoder{ - private final Object mLock = new Object(); - private final DecoderResTableEntry decoderEntry; - private final DecoderResTableEntryMap decoderEntryMap; - private Predicate mDecodedEntries; - - public XMLEntryDecoder(EntryStore entryStore){ - this.decoderEntry = new DecoderResTableEntry<>(entryStore); - this.decoderEntryMap = new DecoderResTableEntryMap<>(entryStore); - } - - public void setDecodedEntries(Predicate decodedEntries) { - this.mDecodedEntries = decodedEntries; - } - - private boolean shouldDecode(Entry entry){ - if(entry == null || entry.isNull()){ - return false; - } - if(this.mDecodedEntries != null){ - return mDecodedEntries.test(entry); - } - return true; - } - - public OUTPUT decode(EntryWriter writer, Entry entry) throws IOException{ - if(!shouldDecode(entry)){ - return null; - } - synchronized (mLock){ - TableEntry tableEntry = entry.getTableEntry(); - if(tableEntry instanceof ResTableMapEntry){ - return decoderEntryMap.decode((ResTableMapEntry) tableEntry, writer); - } - return decoderEntry.decode((ResTableEntry) tableEntry, writer); - } - } - public int decode(EntryWriter writer, Collection entryList) throws IOException { - int count = 0; - for(Entry entry : entryList){ - OUTPUT output = decode(writer, entry); - if(output != null){ - count ++; - } - } - return count; - } - public int decode(EntryWriter writer, ResConfig resConfig, Collection entryGroupList) throws IOException { - int count = 0; - for(EntryGroup entryGroup : entryGroupList){ - OUTPUT output = decode(writer, entryGroup.getEntry(resConfig)); - if(output != null){ - count ++; - } - } - return count; - } - public int decode(EntryWriter writer, TypeBlock typeBlock) throws IOException { - Iterator iterator = typeBlock.getEntryArray() - .iterator(true); - int count = 0; - while (iterator.hasNext()){ - Entry entry = iterator.next(); - OUTPUT output = decode(writer, entry); - if(output != null){ - count++; - } - } - return count; - } - - void deleteIfZero(int decodeCount, File file){ - if(decodeCount > 0){ - return; - } - file.delete(); - File dir = file.getParentFile(); - if(isEmptyDirectory(dir)){ - dir.delete(); - } - } - private boolean isEmptyDirectory(File dir){ - if(dir == null || !dir.isDirectory()){ - return false; - } - File[] files = dir.listFiles(); - return files == null || files.length == 0; - } - File toOutXmlFile(File resDirectory, TypeBlock typeBlock){ - String path = toValuesXml(typeBlock); - return new File(resDirectory, path); - } - String toValuesXml(TypeBlock typeBlock){ - StringBuilder builder = new StringBuilder(); - char sepChar = File.separatorChar; - builder.append("values"); - builder.append(typeBlock.getQualifiers()); - builder.append(sepChar); - String type = typeBlock.getTypeName(); - builder.append(type); - if(!type.endsWith("s")){ - builder.append('s'); - } - builder.append(".xml"); - return builder.toString(); - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmldecoder/XMLEntryDecoderDocument.java b/src/ARSCLib/com/reandroid/apk/xmldecoder/XMLEntryDecoderDocument.java deleted file mode 100644 index 9313dbfc..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmldecoder/XMLEntryDecoderDocument.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmldecoder; - -import com.reandroid.apk.XmlHelper; -import com.reandroid.arsc.value.Entry; -import com.reandroid.common.EntryStore; -import com.reandroid.xml.XMLDocument; -import com.reandroid.xml.XMLElement; - -import java.io.IOException; -import java.util.Collection; - -public class XMLEntryDecoderDocument extends XMLEntryDecoder{ - private final EntryWriterElement entryWriterElement; - public XMLEntryDecoderDocument(EntryStore entryStore) { - super(entryStore); - this.entryWriterElement = new EntryWriterElement(); - } - - public XMLElement decode(Entry entry) throws IOException { - return super.decode(this.entryWriterElement, entry); - } - - public XMLDocument decode(XMLDocument xmlDocument, Collection entryList) - throws IOException { - - if(xmlDocument == null){ - xmlDocument = new XMLDocument(XmlHelper.RESOURCES_TAG); - } - XMLElement docElement = xmlDocument.getDocumentElement(); - - if(docElement == null){ - docElement = new XMLElement(XmlHelper.RESOURCES_TAG); - xmlDocument.setDocumentElement(docElement); - } - for(Entry entry : entryList){ - docElement.addChild(decode(entry)); - } - return xmlDocument; - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmldecoder/XMLEntryDecoderSerializer.java b/src/ARSCLib/com/reandroid/apk/xmldecoder/XMLEntryDecoderSerializer.java deleted file mode 100644 index 1286009c..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmldecoder/XMLEntryDecoderSerializer.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmldecoder; - -import com.android.org.kxml2.io.KXmlSerializer; -import com.reandroid.apk.XmlHelper; -import com.reandroid.arsc.chunk.TypeBlock; -import com.reandroid.arsc.container.SpecTypePair; -import com.reandroid.arsc.group.EntryGroup; -import com.reandroid.arsc.value.ResConfig; -import com.reandroid.common.EntryStore; -import org.xmlpull.v1.XmlSerializer; - -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - -public class XMLEntryDecoderSerializer extends XMLEntryDecoder implements Closeable { - private final EntryWriterSerializer entryWriterSerializer; - private Closeable mClosable; - private boolean mStart; - - public XMLEntryDecoderSerializer(EntryStore entryStore, XmlSerializer serializer) { - super(entryStore); - this.entryWriterSerializer = new EntryWriterSerializer(serializer); - } - public XMLEntryDecoderSerializer(EntryStore entryStore) { - this(entryStore, new KXmlSerializer()); - } - - public int decode(File resDirectory, SpecTypePair specTypePair) throws IOException { - int count; - if(specTypePair.hasDuplicateResConfig(true)){ - count = decodeDuplicateConfigs(resDirectory, specTypePair); - }else { - count = decodeUniqueConfigs(resDirectory, specTypePair); - } - return count; - } - private int decodeDuplicateConfigs(File resDirectory, SpecTypePair specTypePair) throws IOException { - List resConfigList = specTypePair.listResConfig(); - Collection entryGroupList = specTypePair - .createEntryGroups(true).values(); - int total = 0; - for(ResConfig resConfig : resConfigList){ - TypeBlock typeBlock = resConfig.getParentInstance(TypeBlock.class); - File outXml = toOutXmlFile(resDirectory, typeBlock); - total += decode(outXml, resConfig, entryGroupList); - } - return total; - } - private int decodeUniqueConfigs(File resDirectory, SpecTypePair specTypePair) throws IOException { - int total = 0; - Iterator itr = specTypePair.iteratorNonEmpty(); - while (itr.hasNext()){ - TypeBlock typeBlock = itr.next(); - File outXml = toOutXmlFile(resDirectory, typeBlock); - total += decode(outXml, typeBlock); - } - return total; - } - public int decode(File outXmlFile, ResConfig resConfig, Collection entryGroupList) throws IOException { - setOutput(outXmlFile); - int count = decode(resConfig, entryGroupList); - close(); - deleteIfZero(count, outXmlFile); - return count; - } - public int decode(File outXmlFile, TypeBlock typeBlock) throws IOException { - setOutput(outXmlFile); - int count = super.decode(entryWriterSerializer, typeBlock); - close(); - deleteIfZero(count, outXmlFile); - return count; - } - public int decode(ResConfig resConfig, Collection entryGroupList) throws IOException { - return super.decode(entryWriterSerializer, resConfig, entryGroupList); - } - public void setOutput(File file) throws IOException { - File dir = file.getParentFile(); - if(dir != null && !dir.exists()){ - dir.mkdirs(); - } - setOutput(new FileOutputStream(file)); - } - public void setOutput(OutputStream outputStream) throws IOException { - close(); - getXmlSerializer().setOutput(outputStream, StandardCharsets.UTF_8.name()); - this.mClosable = outputStream; - start(); - } - public void setOutput(Writer writer) throws IOException { - close(); - getXmlSerializer().setOutput(writer); - this.mClosable = writer; - start(); - } - - private void start() throws IOException { - if(!mStart){ - XmlSerializer xmlSerializer = getXmlSerializer(); - xmlSerializer.startDocument("utf-8", null); - xmlSerializer.startTag(null, XmlHelper.RESOURCES_TAG); - mStart = true; - } - } - private void end() throws IOException { - if(mStart){ - XmlSerializer xmlSerializer = getXmlSerializer(); - xmlSerializer.endTag(null, XmlHelper.RESOURCES_TAG); - xmlSerializer.endDocument(); - xmlSerializer.flush(); - mStart = false; - } - } - private XmlSerializer getXmlSerializer(){ - return entryWriterSerializer.getXmlSerializer(); - } - - @Override - public void close() throws IOException { - Closeable closeable = this.mClosable; - end(); - if(closeable != null){ - closeable.close(); - } - this.mClosable = null; - } - -} diff --git a/src/ARSCLib/com/reandroid/apk/xmldecoder/XMLNamespaceValidator.java b/src/ARSCLib/com/reandroid/apk/xmldecoder/XMLNamespaceValidator.java deleted file mode 100644 index 1f42220f..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmldecoder/XMLNamespaceValidator.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmldecoder; - -import com.reandroid.arsc.chunk.xml.*; - -import java.util.Collection; - -public class XMLNamespaceValidator { - private static final String URI_ANDROID = "http://schemas.android.com/apk/res/android"; - private static final String URI_APP = "http://schemas.android.com/apk/res-auto"; - private static final String PREFIX_ANDROID = "android"; - private static final String PREFIX_APP = "app"; - private final ResXmlDocument xmlBlock; - public XMLNamespaceValidator(ResXmlDocument xmlBlock){ - this.xmlBlock=xmlBlock; - } - public void validate(){ - validateNamespaces(xmlBlock); - } - - public static boolean isValid(ResXmlAttribute attribute){ - int resourceId = attribute.getNameResourceID(); - if(resourceId == 0){ - return attribute.getUri() == null; - } - if(isAndroid(toPackageId(resourceId))){ - return isValidAndroidNamespace(attribute); - }else { - return isValidAppNamespace(attribute); - } - } - public static void validateNamespaces(ResXmlDocument resXmlDocument){ - validateNamespaces(resXmlDocument.getResXmlElement()); - } - public static void validateNamespaces(ResXmlElement element){ - validateNamespaces(element.listAttributes()); - for(ResXmlElement child : element.listElements()){ - validateNamespaces(child); - } - } - - private static void validateNamespaces(Collection attributeList){ - for(ResXmlAttribute attribute : attributeList){ - validateNamespace(attribute); - } - } - private static void validateNamespace(ResXmlAttribute attribute){ - int resourceId = attribute.getNameResourceID(); - if(resourceId == 0){ - attribute.setNamespaceReference(-1); - return; - } - if(isAndroid(toPackageId(resourceId))){ - if(!isValidAndroidNamespace(attribute)){ - attribute.setNamespace(URI_ANDROID, PREFIX_ANDROID); - } - }else { - if(!isValidAppNamespace(attribute)){ - attribute.setNamespace(URI_APP, PREFIX_APP); - } - } - } - - private static boolean isValidAppNamespace(ResXmlAttribute attribute){ - String uri = attribute.getUri(); - String prefix = attribute.getNamePrefix(); - if(URI_ANDROID.equals(uri) || PREFIX_ANDROID.equals(prefix)){ - return false; - } - if(isEmpty(uri) || isEmpty(prefix)){ - return false; - } - return true; - } - private static boolean isValidAndroidNamespace(ResXmlAttribute attribute){ - return URI_ANDROID.equals(attribute.getUri()) - && PREFIX_ANDROID.equals(attribute.getNamePrefix()); - } - - private static boolean isAndroid(int pkgId){ - return pkgId==1; - } - private static int toPackageId(int resId){ - return (resId >> 24 & 0xFF); - } - private static boolean isEmpty(String str){ - if(str==null){ - return true; - } - str=str.trim(); - return str.length()==0; - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmlencoder/EncodeException.java b/src/ARSCLib/com/reandroid/apk/xmlencoder/EncodeException.java deleted file mode 100644 index c997bba6..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmlencoder/EncodeException.java +++ /dev/null @@ -1,25 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmlencoder; - -public class EncodeException extends IllegalArgumentException{ - public EncodeException(String message){ - super(message); - } - public EncodeException(String message, Throwable cause){ - super(message, cause); - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmlencoder/EncodeMaterials.java b/src/ARSCLib/com/reandroid/apk/xmlencoder/EncodeMaterials.java deleted file mode 100644 index 46f3ad47..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmlencoder/EncodeMaterials.java +++ /dev/null @@ -1,433 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmlencoder; - -import com.reandroid.apk.APKLogger; -import com.reandroid.apk.FrameworkApk; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.chunk.TypeBlock; -import com.reandroid.arsc.container.SpecTypePair; -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.group.EntryGroup; -import com.reandroid.arsc.item.SpecString; -import com.reandroid.arsc.util.FrameworkTable; -import com.reandroid.arsc.util.HexUtil; -import com.reandroid.arsc.util.ResNameMap; -import com.reandroid.arsc.value.Entry; -import com.reandroid.identifiers.PackageIdentifier; -import com.reandroid.identifiers.ResourceIdentifier; -import com.reandroid.identifiers.TableIdentifier; - -import java.util.HashSet; -import java.util.Set; -import java.util.regex.Matcher; - -public class EncodeMaterials { - private PackageBlock currentPackage; - private final Set frameworkTables = new HashSet<>(); - private APKLogger apkLogger; - private boolean mForceCreateNamespaces = true; - private Set mFrameworkPackageNames; - private final ResNameMap mLocalResNameMap = new ResNameMap<>(); - private final TableIdentifier tableIdentifier = new TableIdentifier(); - private PackageIdentifier currentPackageIdentifier; - private Integer mMainPackageId; - public EncodeMaterials(){ - } - public void setMainPackageId(Integer mainPackageId){ - this.mMainPackageId = mainPackageId; - } - public PackageBlock pickMainPackageBlock(TableBlock tableBlock){ - if(mMainPackageId != null){ - return tableBlock.pickOne(mMainPackageId); - } - return tableBlock.pickOne(); - } - public TableIdentifier getTableIdentifier(){ - return tableIdentifier; - } - public void setEntryName(Entry entry, String name){ - PackageBlock packageBlock = entry.getPackageBlock(); - SpecString specString = packageBlock - .getSpecStringPool().getOrCreate(name); - entry.setSpecReference(specString); - } - public SpecString getSpecString(String name){ - return currentPackage.getSpecStringPool() - .get(name) - .get(0); - } - public Entry getAttributeBlock(String refString){ - String type = "attr"; - Entry entry = getAttributeBlock(type, refString); - if(entry == null){ - type = "^attr-private"; - entry = getAttributeBlock(type, refString); - } - return entry; - } - private Entry getAttributeBlock(String type, String refString){ - String packageName = null; - String name = refString; - int i=refString.lastIndexOf(':'); - if(i>=0){ - packageName=refString.substring(0, i); - name=refString.substring(i+1); - } - if(EncodeUtil.isEmpty(packageName) - || packageName.equals(getCurrentPackageName()) - || !isFrameworkPackageName(packageName)){ - - return getLocalEntry(type, name); - } - return getFrameworkEntry(type, name); - } - public int resolveReference(String refString){ - if("@null".equals(refString)){ - return 0; - } - Matcher matcher = ValueDecoder.PATTERN_REFERENCE.matcher(refString); - if(!matcher.find()){ - ValueDecoder.EncodeResult ref = ValueDecoder.encodeHexReference(refString); - if(ref!=null){ - return ref.value; - } - ref = ValueDecoder.encodeNullReference(refString); - if(ref!=null){ - return ref.value; - } - throw new EncodeException( - "Not proper reference string: '"+refString+"'"); - } - String prefix=matcher.group(1); - String packageName = matcher.group(2); - if(packageName!=null && packageName.endsWith(":")){ - packageName=packageName.substring(0, packageName.length()-1); - } - String type = matcher.group(4); - String name = matcher.group(5); - if(isLocalPackageName(packageName)){ - return resolveLocalResourceId(packageName, type, name); - } - - if(EncodeUtil.isEmpty(packageName) - || packageName.equals(getCurrentPackageName()) - || !isFrameworkPackageName(packageName)){ - return resolveLocalResourceId(type, name); - } - return resolveFrameworkResourceId(packageName, type, name); - } - private int resolveLocalResourceId(String packageName, String type, String name){ - ResourceIdentifier ri = tableIdentifier.get(packageName, type, name); - if(ri != null){ - return ri.getResourceId(); - } - EntryGroup entryGroup=getLocalEntryGroup(type, name); - if(entryGroup!=null){ - return entryGroup.getResourceId(); - } - throw new EncodeException("Local entry not found: " + - "package=" + packageName + - ", type=" + type + - ", name=" + name); - } - public int resolveLocalResourceId(String type, String name){ - PackageIdentifier pi = this.currentPackageIdentifier; - if(pi != null){ - ResourceIdentifier ri = pi.getResourceIdentifier(type, name); - if(ri != null){ - return ri.getResourceId(); - } - } - EntryGroup entryGroup=getLocalEntryGroup(type, name); - if(entryGroup!=null){ - return entryGroup.getResourceId(); - } - throw new EncodeException("Local entry not found: " + - "type="+type+ - ", name="+name); - } - public int resolveFrameworkResourceId(String packageName, String type, String name){ - Entry entry = getFrameworkEntry(packageName, type, name); - if(entry !=null){ - return entry.getResourceId(); - } - throw new EncodeException("Framework entry not found: " + - "package="+packageName+ - ", type="+type+ - ", name="+name); - } - public int resolveFrameworkResourceId(int packageId, String type, String name){ - Entry entry = getFrameworkEntry(packageId, type, name); - if(entry !=null){ - return entry.getResourceId(); - } - throw new EncodeException("Framework entry not found: " + - "packageId=" + HexUtil.toHex2((byte) packageId)+ - ", type="+type+ - ", name="+name); - } - public EntryGroup getLocalEntryGroup(String type, String name){ - for(EntryGroup entryGroup : currentPackage.listEntryGroup()){ - if(type.equals(entryGroup.getTypeName()) && - name.equals(entryGroup.getSpecName())){ - return entryGroup; - } - } - for(PackageBlock packageBlock:currentPackage.getTableBlock().listPackages()){ - for(EntryGroup entryGroup : packageBlock.listEntryGroup()){ - if(type.equals(entryGroup.getTypeName()) && - name.equals(entryGroup.getSpecName())){ - return entryGroup; - } - } - } - return null; - } - public Entry getLocalEntry(String type, String name){ - Entry entry =mLocalResNameMap.get(type, name); - if(entry !=null){ - return entry; - } - loadLocalEntryMap(type); - entry =mLocalResNameMap.get(type, name); - if(entry !=null){ - return entry; - } - entry = searchLocalEntry(type, name); - if(entry !=null){ - mLocalResNameMap.add(type, name, entry); - } - return entry; - } - private Entry searchLocalEntry(String type, String name){ - for(EntryGroup entryGroup : currentPackage.listEntryGroup()){ - if(type.equals(entryGroup.getTypeName()) && - name.equals(entryGroup.getSpecName())){ - return entryGroup.pickOne(); - } - } - SpecTypePair specTypePair=currentPackage.getSpecTypePair(type); - if(specTypePair!=null){ - for(TypeBlock typeBlock:specTypePair.listTypeBlocks()){ - for(Entry entry :typeBlock.listEntries(true)){ - if(name.equals(entry.getName())){ - return entry; - } - } - break; - } - } - for(PackageBlock packageBlock:currentPackage.getTableBlock().listPackages()){ - if(packageBlock==currentPackage){ - continue; - } - specTypePair=packageBlock.getSpecTypePair(type); - if(specTypePair!=null){ - for(TypeBlock typeBlock:specTypePair.listTypeBlocks()){ - for(Entry entry :typeBlock.listEntries(true)){ - if(name.equals(entry.getName())){ - return entry; - } - } - break; - } - } - } - return null; - } - private void loadLocalEntryMap(String type){ - ResNameMap localMap = mLocalResNameMap; - for(PackageBlock packageBlock:currentPackage.getTableBlock().listPackages()){ - SpecTypePair specTypePair=packageBlock.getSpecTypePair(type); - if(specTypePair!=null){ - for(TypeBlock typeBlock:specTypePair.listTypeBlocks()){ - for(Entry entry :typeBlock.listEntries(true)){ - localMap.add(entry.getTypeName(), - entry.getName(), entry); - } - } - } - } - } - public Entry getFrameworkEntry(String type, String name){ - for(FrameworkTable table:frameworkTables){ - Entry entry = table.searchEntry(type, name); - if(entry !=null){ - return entry; - } - } - return null; - } - private boolean isFrameworkPackageName(String packageName){ - return getFrameworkPackageNames().contains(packageName); - } - private Set getFrameworkPackageNames(){ - if(mFrameworkPackageNames!=null){ - return mFrameworkPackageNames; - } - Set results=new HashSet<>(); - for(FrameworkTable table:frameworkTables){ - for(PackageBlock packageBlock:table.listPackages()){ - results.add(packageBlock.getName()); - } - } - mFrameworkPackageNames=results; - return results; - } - public Entry getFrameworkEntry(String packageName, String type, String name){ - for(FrameworkTable table:frameworkTables){ - for(PackageBlock packageBlock:table.listPackages()){ - if(packageName.equals(packageBlock.getName())){ - Entry entry = table.searchEntry(type, name); - if(entry !=null){ - return entry; - } - } - } - } - return null; - } - public Entry getFrameworkEntry(int packageId, String type, String name){ - for(FrameworkTable table:frameworkTables){ - for(PackageBlock packageBlock:table.listPackages()){ - if(packageId==packageBlock.getId()){ - Entry entry = table.searchEntry(type, name); - if(entry !=null){ - return entry; - } - } - } - } - return null; - } - public EncodeMaterials setForceCreateNamespaces(boolean force) { - this.mForceCreateNamespaces = force; - return this; - } - public EncodeMaterials setCurrentPackage(PackageBlock currentPackage) { - this.currentPackage = currentPackage; - onCurrentPackageChanged(currentPackage); - return this; - } - public EncodeMaterials setCurrentLocalPackage(PackageIdentifier packageIdentifier) { - this.currentPackageIdentifier = packageIdentifier; - return this; - } - private void onCurrentPackageChanged(PackageBlock currentPackage){ - if(currentPackage == null){ - return; - } - PackageIdentifier pi = tableIdentifier.getByPackage(currentPackage); - if(pi != null){ - this.currentPackageIdentifier = pi; - } - } - private boolean isLocalPackageName(String packageName){ - if(packageName == null){ - return false; - } - for(PackageIdentifier pi : tableIdentifier.getPackages()){ - if(packageName.equals(pi.getName())){ - return true; - } - } - return false; - } - private boolean isUniquePackageNames(){ - Set names = new HashSet<>(); - for(PackageIdentifier pi : tableIdentifier.getPackages()){ - names.add(pi.getName()); - } - return names.size() == tableIdentifier.getPackages().size(); - } - private boolean isUniquePackageIds(){ - Set ids = new HashSet<>(); - for(PackageIdentifier pi : tableIdentifier.getPackages()){ - ids.add(pi.getId()); - } - return ids.size() == tableIdentifier.getPackages().size(); - } - public EncodeMaterials addFramework(FrameworkApk frameworkApk) { - if(frameworkApk!=null){ - addFramework(frameworkApk.getTableBlock()); - } - return this; - } - public EncodeMaterials addFramework(FrameworkTable frameworkTable) { - frameworkTable.loadResourceNameMap(); - this.frameworkTables.add(frameworkTable); - this.mFrameworkPackageNames=null; - return this; - } - public EncodeMaterials setAPKLogger(APKLogger logger) { - this.apkLogger = logger; - return this; - } - - public PackageBlock getCurrentPackage() { - return currentPackage; - } - public boolean isForceCreateNamespaces() { - return mForceCreateNamespaces; - } - - public String getCurrentPackageName(){ - return currentPackage.getName(); - } - public int getCurrentPackageId(){ - return currentPackage.getId(); - } - - public void logMessage(String msg) { - if(apkLogger!=null){ - apkLogger.logMessage(msg); - } - } - public void logError(String msg, Throwable tr) { - if(apkLogger!=null){ - apkLogger.logError(msg, tr); - } - } - public void logVerbose(String msg) { - if(apkLogger!=null){ - apkLogger.logVerbose(msg); - } - } - public static EncodeMaterials create(TableBlock tableBlock){ - PackageBlock packageBlock = tableBlock.pickOne(); - if(packageBlock==null){ - throw new EncodeException("No packages found on table block"); - } - return create(packageBlock); - } - public static EncodeMaterials create(PackageBlock packageBlock){ - EncodeMaterials encodeMaterials = new EncodeMaterials(); - - TableBlock tableBlock = packageBlock.getTableBlock(); - encodeMaterials.getTableIdentifier().load(tableBlock); - encodeMaterials.setCurrentPackage(packageBlock); - - for(TableBlock frameworkTable:tableBlock.getFrameWorks()){ - if(frameworkTable instanceof FrameworkTable){ - encodeMaterials.addFramework((FrameworkTable) frameworkTable); - } - } - return encodeMaterials; - } - -} diff --git a/src/ARSCLib/com/reandroid/apk/xmlencoder/EncodeUtil.java b/src/ARSCLib/com/reandroid/apk/xmlencoder/EncodeUtil.java deleted file mode 100644 index 6c3724ad..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmlencoder/EncodeUtil.java +++ /dev/null @@ -1,156 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmlencoder; - - import com.reandroid.apk.ApkUtil; - - import java.io.File; - import java.util.Comparator; - import java.util.List; - import java.util.regex.Matcher; - import java.util.regex.Pattern; - - public class EncodeUtil { - public static void sortStrings(List stringList){ - Comparator cmp=new Comparator() { - @Override - public int compare(String s1, String s2) { - return s1.compareTo(s2); - } - }; - stringList.sort(cmp); - } - public static boolean isPublicXml(File file){ - if(!ApkUtil.FILE_NAME_PUBLIC_XML.equals(file.getName())){ - return false; - } - File dir = file.getParentFile(); - return dir!=null && dir.getName().equals("values"); - } - public static void sortPublicXml(List fileList){ - Comparator cmp=new Comparator() { - @Override - public int compare(File f1, File f2) { - String n1=f1.getAbsolutePath(); - String n2=f2.getAbsolutePath(); - return n1.compareTo(n2); - } - }; - fileList.sort(cmp); - } - public static void sortValuesXml(List fileList){ - Comparator cmp=new Comparator() { - @Override - public int compare(File f1, File f2) { - String n1=getValuesXmlCompare(f1); - String n2=getValuesXmlCompare(f2); - return n1.compareTo(n2); - } - }; - fileList.sort(cmp); - } - private static String getValuesXmlCompare(File file){ - String name=file.getName().toLowerCase(); - if(name.equals("public.xml")){ - return "0"; - } - if(name.equals("ids.xml")){ - return "1"; - } - if(name.contains("attr")){ - return "2"; - } - return "3 "+name; - } - public static boolean isEmpty(String text){ - if(text==null){ - return true; - } - text=text.trim(); - return text.length()==0; - } - public static String getQualifiersFromValuesXml(File valuesXml){ - String dirName=valuesXml.getParentFile().getName(); - int i=dirName.indexOf('-'); - if(i>0){ - return dirName.substring(i); - } - return ""; - } - public static String getEntryPathFromResFile(File resFile){ - File typeDir=resFile.getParentFile(); - File resDir=typeDir.getParentFile(); - return resDir.getName() - +"/"+typeDir.getName() - +"/"+resFile.getName(); - } - public static String getEntryNameFromResFile(File resFile){ - String name=resFile.getName(); - String ninePatch=".9.png"; - if(name.endsWith(ninePatch)){ - return name.substring(0, name.length()-ninePatch.length()); - } - int i=name.lastIndexOf('.'); - if(i>0){ - name = name.substring(0, i); - } - return name; - } - public static String getQualifiersFromResFile(File resFile){ - String name=resFile.getParentFile().getName(); - int i=name.indexOf('-'); - if(i>0){ - return name.substring(i); - } - return ""; - } - public static String getTypeNameFromResFile(File resFile){ - String name=resFile.getParentFile().getName(); - int i=name.indexOf('-'); - if(i>0){ - name=name.substring(0, i); - } - if(!name.equals("plurals") && name.endsWith("s")){ - name=name.substring(0, name.length()-1); - } - return name; - } - public static String getTypeNameFromValuesXml(File valuesXml){ - String name=valuesXml.getName(); - name=name.substring(0, name.length()-4); - if(!name.equals("plurals") && name.endsWith("s")){ - name=name.substring(0, name.length()-1); - } - return name; - } - public static String sanitizeType(String type){ - if(type.startsWith("^attr")){ - return type; - } - Matcher matcher=PATTERN_TYPE.matcher(type); - if(!matcher.find()){ - return ""; - } - return matcher.group(1); - } - public static final String NULL_PACKAGE_NAME = "NULL_PACKAGE_NAME"; - private static final Pattern PATTERN_TYPE=Pattern.compile("^([a-z]+)[^a-z]*.*$"); - - public static final String URI_ANDROID = "http://schemas.android.com/apk/res/android"; - public static final String URI_APP = "http://schemas.android.com/apk/res-auto"; - public static final String PREFIX_ANDROID = "android"; - public static final String PREFIX_APP = "app"; -} diff --git a/src/ARSCLib/com/reandroid/apk/xmlencoder/FilePathEncoder.java b/src/ARSCLib/com/reandroid/apk/xmlencoder/FilePathEncoder.java deleted file mode 100644 index 36bd1441..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmlencoder/FilePathEncoder.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmlencoder; - -import com.reandroid.archive.APKArchive; -import com.reandroid.archive.FileInputSource; -import com.reandroid.archive.InputSource; -import com.reandroid.apk.ApkUtil; -import com.reandroid.apk.UncompressedFiles; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.TypeBlock; -import com.reandroid.arsc.value.Entry; -import com.reandroid.xml.source.XMLFileSource; -import com.reandroid.xml.source.XMLSource; - -import java.io.File; -import java.util.List; - -public class FilePathEncoder { - private final EncodeMaterials materials; - private APKArchive apkArchive; - private UncompressedFiles uncompressedFiles; - public FilePathEncoder(EncodeMaterials encodeMaterials){ - this.materials =encodeMaterials; - } - - public void setApkArchive(APKArchive apkArchive) { - this.apkArchive = apkArchive; - } - public void setUncompressedFiles(UncompressedFiles uncompressedFiles){ - this.uncompressedFiles=uncompressedFiles; - } - public void encodeResDir(File resDir){ - materials.logVerbose("Scanning file list: " - +resDir.getParentFile().getName() - +File.separator+resDir.getName()); - List dirList = ApkUtil.listDirectories(resDir); - for(File dir:dirList){ - if(dir.getName().startsWith("values")){ - continue; - } - encodeTypeDir(dir); - } - } - public void encodeTypeDir(File dir){ - List fileList = ApkUtil.listFiles(dir, null); - for(File file:fileList){ - encodeFileEntry(file); - } - } - public InputSource encodeFileEntry(File resFile){ - String type = EncodeUtil.getTypeNameFromResFile(resFile); - PackageBlock packageBlock = materials.getCurrentPackage(); - int typeId=packageBlock - .getTypeStringPool().idOf(type); - String qualifiers = EncodeUtil.getQualifiersFromResFile(resFile); - TypeBlock typeBlock = packageBlock.getOrCreateTypeBlock((byte)typeId, qualifiers); - String name = EncodeUtil.getEntryNameFromResFile(resFile); - int resourceId=materials.resolveLocalResourceId(type, name); - - Entry entry = typeBlock - .getOrCreateEntry((short) (0xffff & resourceId)); - - String path = EncodeUtil.getEntryPathFromResFile(resFile); - entry.setValueAsString(path); - materials.setEntryName(entry, name); - InputSource inputSource=createInputSource(path, resFile); - if(inputSource instanceof XMLEncodeSource){ - ((XMLEncodeSource)inputSource).setEntry(entry); - } - addInputSource(inputSource); - return inputSource; - } - private InputSource createInputSource(String path, File resFile){ - if(isXmlFile(resFile)){ - return createXMLEncodeInputSource(path, resFile); - } - addUncompressedFiles(path); - return createRawFileInputSource(path, resFile); - } - private InputSource createRawFileInputSource(String path, File resFile){ - return new FileInputSource(resFile, path); - } - private InputSource createXMLEncodeInputSource(String path, File resFile){ - XMLSource xmlSource = new XMLFileSource(path, resFile); - return new XMLEncodeSource(materials, xmlSource); - } - private boolean isXmlFile(File resFile){ - String name=resFile.getName(); - if(!name.endsWith(".xml")){ - return false; - } - String type=EncodeUtil.getTypeNameFromResFile(resFile); - return !type.equals("raw"); - } - private void addInputSource(InputSource inputSource){ - if(inputSource!=null && this.apkArchive!=null){ - apkArchive.add(inputSource); - } - } - private void addUncompressedFiles(String path){ - if(uncompressedFiles!=null){ - uncompressedFiles.addPath(path); - } - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmlencoder/RESEncoder.java b/src/ARSCLib/com/reandroid/apk/xmlencoder/RESEncoder.java deleted file mode 100644 index 0b3417e9..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmlencoder/RESEncoder.java +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmlencoder; - -import com.reandroid.apk.*; -import com.reandroid.archive.APKArchive; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.chunk.xml.AndroidManifestBlock; -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.util.HexUtil; -import com.reandroid.identifiers.PackageIdentifier; -import com.reandroid.identifiers.ResourceIdentifier; -import com.reandroid.identifiers.TableIdentifier; -import com.reandroid.xml.XMLException; -import com.reandroid.xml.XMLParserFactory; -import com.reandroid.xml.source.XMLFileSource; -import com.reandroid.xml.source.XMLSource; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.File; -import java.io.IOException; -import java.util.*; -import java.util.zip.ZipEntry; - -public class RESEncoder { - private APKLogger apkLogger; - private final TableBlock tableBlock; - private final Set parsedFiles = new HashSet<>(); - private final ApkModule apkModule; - public RESEncoder(){ - this(new ApkModule("encoded", - new APKArchive()), new TableBlock()); - } - public RESEncoder(ApkModule module, TableBlock block){ - this.apkModule = module; - this.tableBlock = block; - if(!module.hasTableBlock()){ - module.setLoadDefaultFramework(false); - BlockInputSource inputSource = - new BlockInputSource<>(TableBlock.FILE_NAME, block); - inputSource.setMethod(ZipEntry.STORED); - this.apkModule.setTableBlock(tableBlock); - } - } - public TableBlock getTableBlock(){ - return tableBlock; - } - public ApkModule getApkModule(){ - return apkModule; - } - public void scanDirectory(File mainDir) throws IOException, XMLException { - scanResourceFiles(mainDir); - } - private void scanResourceFiles(File mainDir) throws IOException, XMLException { - List pubXmlFileList = searchPublicXmlFiles(mainDir); - if(pubXmlFileList.size()==0){ - throw new IOException("No .*/values/" - + ApkUtil.FILE_NAME_PUBLIC_XML+" file found in '"+mainDir); - } - preloadStringPool(pubXmlFileList); - EncodeMaterials encodeMaterials = new EncodeMaterials(); - encodeMaterials.setAPKLogger(apkLogger); - - TableIdentifier tableIdentifier = encodeMaterials.getTableIdentifier(); - tableIdentifier.loadPublicXml(pubXmlFileList); - tableIdentifier.initialize(this.tableBlock); - - excludeIds(pubXmlFileList); - File manifestFile = initializeFrameworkFromManifest(encodeMaterials, pubXmlFileList); - - encodeAttrs(encodeMaterials, pubXmlFileList); - - encodeValues(encodeMaterials, pubXmlFileList); - - tableBlock.refresh(); - - PackageBlock packageBlock = encodeMaterials.pickMainPackageBlock(this.tableBlock); - if(manifestFile != null){ - if(packageBlock != null){ - encodeMaterials.setCurrentPackage(packageBlock); - } - XMLSource xmlSource = - new XMLFileSource(AndroidManifestBlock.FILE_NAME, manifestFile); - XMLEncodeSource xmlEncodeSource = - new XMLEncodeSource(encodeMaterials, xmlSource); - getApkModule().getApkArchive().add(xmlEncodeSource); - } - } - private File initializeFrameworkFromManifest(EncodeMaterials encodeMaterials, List pubXmlFileList) throws IOException { - for(File pubXmlFile:pubXmlFileList){ - addParsedFiles(pubXmlFile); - File manifestFile = toAndroidManifest(pubXmlFile); - if(!manifestFile.isFile()){ - continue; - } - initializeFrameworkFromManifest(encodeMaterials, manifestFile); - return manifestFile; - } - return null; - } - private void encodeValues(EncodeMaterials encodeMaterials, List pubXmlFileList) throws XMLException, IOException { - logMessage("Encoding values ..."); - TableIdentifier tableIdentifier = encodeMaterials.getTableIdentifier(); - - for(File pubXmlFile:pubXmlFileList){ - addParsedFiles(pubXmlFile); - PackageIdentifier packageIdentifier = tableIdentifier.getByTag(pubXmlFile); - - PackageBlock packageBlock = packageIdentifier.getPackageBlock(); - - encodeMaterials.setCurrentPackage(packageBlock); - - File resDir=toResDirectory(pubXmlFile); - encodeResDir(encodeMaterials, resDir); - FilePathEncoder filePathEncoder = new FilePathEncoder(encodeMaterials); - filePathEncoder.setApkArchive(getApkModule().getApkArchive()); - filePathEncoder.setUncompressedFiles(getApkModule().getUncompressedFiles()); - filePathEncoder.encodeResDir(resDir); - - packageBlock.sortTypes(); - packageBlock.refresh(); - } - } - private void encodeAttrs(EncodeMaterials encodeMaterials, List pubXmlFileList) throws XMLException { - logMessage("Encoding attrs ..."); - TableIdentifier tableIdentifier = encodeMaterials.getTableIdentifier(); - - for(File pubXmlFile:pubXmlFileList){ - addParsedFiles(pubXmlFile); - PackageIdentifier packageIdentifier = tableIdentifier.getByTag(pubXmlFile); - - PackageBlock packageBlock = packageIdentifier.getPackageBlock(); - encodeMaterials.setCurrentPackage(packageBlock); - - ValuesEncoder valuesEncoder = new ValuesEncoder(encodeMaterials); - File fileAttrs = toAttr(pubXmlFile); - if(fileAttrs.isFile()){ - valuesEncoder.encodeValuesXml(fileAttrs); - packageBlock.sortTypes(); - packageBlock.refresh(); - addParsedFiles(fileAttrs); - } - } - } - private void excludeIds(List pubXmlFileList){ - for(File pubXmlFile:pubXmlFileList){ - addParsedFiles(pubXmlFile); - File fileIds = toId(pubXmlFile); - if(fileIds.isFile()){ - addParsedFiles(fileIds); - } - } - } - private void initializeFrameworkFromManifest(EncodeMaterials encodeMaterials, File manifestFile) throws IOException { - XmlPullParser parser; - try { - parser = XMLParserFactory.newPullParser(manifestFile); - } catch (XmlPullParserException ex) { - throw new IOException(ex); - } - FrameworkApk frameworkApk = getApkModule().initializeAndroidFramework(parser); - encodeMaterials.addFramework(frameworkApk); - initializeMainPackageId(encodeMaterials, parser); - XmlHelper.closeSilent(parser); - } - private void initializeMainPackageId(EncodeMaterials encodeMaterials, XmlPullParser parser) throws IOException { - Map applicationAttributes; - try { - applicationAttributes = XmlHelper.readAttributes(parser, AndroidManifestBlock.TAG_application); - } catch (XmlPullParserException ex) { - throw new IOException(ex); - } - if(applicationAttributes == null){ - return; - } - String iconReference = applicationAttributes.get(AndroidManifestBlock.NAME_icon); - if(iconReference == null){ - return; - } - logMessage("Set main package id from manifest: " + iconReference); - ValueDecoder.ReferenceString ref = ValueDecoder.parseReference(iconReference); - if(ref == null){ - logMessage("Something wrong on : " + AndroidManifestBlock.NAME_icon); - return; - } - TableIdentifier tableIdentifier = encodeMaterials.getTableIdentifier(); - ResourceIdentifier resourceIdentifier; - if(ref.packageName != null){ - resourceIdentifier = tableIdentifier.get(ref.packageName, ref.type, ref.name); - }else { - resourceIdentifier = tableIdentifier.get(ref.type, ref.name); - } - if(resourceIdentifier == null){ - logMessage("WARN: failed to resolve: " + ref); - return; - } - int packageId = resourceIdentifier.getPackageId(); - encodeMaterials.setMainPackageId(packageId); - logMessage("Main package id initialized: id = " - + HexUtil.toHex2((byte)packageId) + ", from: " + ref ); - } - private void preloadStringPool(List pubXmlFileList){ - logMessage("Loading string pool ..."); - ValuesStringPoolBuilder poolBuilder=new ValuesStringPoolBuilder(); - for(File pubXml:pubXmlFileList){ - File resDir=toResDirectory(pubXml); - List valuesDirList = listValuesDir(resDir); - for(File dir:valuesDirList){ - logVerbose(poolBuilder.size()+" building pool: "+dir.getName()); - poolBuilder.scanValuesDirectory(dir); - } - } - poolBuilder.addTo(tableBlock.getTableStringPool()); - } - - private void encodeResDir(EncodeMaterials materials, File resDir) throws XMLException { - - List valuesDirList = listValuesDir(resDir); - for(File valuesDir:valuesDirList){ - encodeValuesDir(materials, valuesDir); - } - } - private void encodeValuesDir(EncodeMaterials materials, File valuesDir) throws XMLException { - ValuesEncoder valuesEncoder = new ValuesEncoder(materials); - List xmlFiles = ApkUtil.listFiles(valuesDir, ".xml"); - EncodeUtil.sortValuesXml(xmlFiles); - for(File file:xmlFiles){ - if(isAlreadyParsed(file)){ - continue; - } - addParsedFiles(file); - valuesEncoder.encodeValuesXml(file); - } - } - private File toAndroidManifest(File pubXmlFile){ - File resDirectory = toResDirectory(pubXmlFile); - File packageDirectory = resDirectory.getParentFile(); - File root = packageDirectory.getParentFile(); - return new File(root, AndroidManifestBlock.FILE_NAME); - } - private File toPackageDirectory(File pubXmlFile){ - return toResDirectory(pubXmlFile) - .getParentFile(); - } - private File toResDirectory(File pubXmlFile){ - return pubXmlFile - .getParentFile() - .getParentFile(); - } - private File toId(File pubXmlFile){ - return new File(pubXmlFile.getParentFile(), "ids.xml"); - } - private File toAttr(File pubXmlFile){ - return new File(pubXmlFile.getParentFile(), "attrs.xml"); - } - private List listValuesDir(File resDir){ - List results=new ArrayList<>(); - File def=new File(resDir, "values"); - results.add(def); - File[] dirList=resDir.listFiles(); - if(dirList!=null){ - for(File dir:dirList){ - if(def.equals(dir) || !dir.isDirectory()){ - continue; - } - if(dir.getName().startsWith("values-")){ - results.add(dir); - } - } - } - return results; - } - private List searchPublicXmlFiles(File mainDir){ - logVerbose("Searching public.xml: "+mainDir); - List dirList=ApkUtil.listDirectories(mainDir); - List xmlFiles = new ArrayList<>(); - for(File dir:dirList){ - if(dir.getName().equals("root")){ - continue; - } - xmlFiles.addAll( - ApkUtil.recursiveFiles(dir, ApkUtil.FILE_NAME_PUBLIC_XML)); - } - List results = new ArrayList<>(); - for(File file:xmlFiles){ - if(!EncodeUtil.isPublicXml(file)){ - continue; - } - if(toAndroidManifest(file).isFile()){ - results.add(file); - } - } - EncodeUtil.sortPublicXml(results); - return results; - } - - private boolean isAlreadyParsed(File file){ - return parsedFiles.contains(file); - } - private void addParsedFiles(File file){ - parsedFiles.add(file); - } - public void setAPKLogger(APKLogger logger) { - this.apkLogger = logger; - this.apkModule.setAPKLogger(logger); - } - private void logMessage(String msg) { - if(apkLogger!=null){ - apkLogger.logMessage(msg); - } - } - private void logError(String msg, Throwable tr) { - if(apkLogger!=null){ - apkLogger.logError(msg, tr); - } - } - private void logVerbose(String msg) { - if(apkLogger!=null){ - apkLogger.logVerbose(msg); - } - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmlencoder/ValuesEncoder.java b/src/ARSCLib/com/reandroid/apk/xmlencoder/ValuesEncoder.java deleted file mode 100644 index 95e40929..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmlencoder/ValuesEncoder.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmlencoder; - -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.value.Entry; -import com.reandroid.xml.XMLDocument; -import com.reandroid.xml.XMLElement; -import com.reandroid.xml.XMLException; - -import java.io.File; -import java.util.HashMap; -import java.util.Map; - -public class ValuesEncoder { - private final EncodeMaterials materials; - private final Map xmlEncodersMap; - private final Map xmlBagEncodersMap; - private final XMLValuesEncoderCommon commonEncoder; - private final XMLValuesEncoderBag bagCommonEncoder; - public ValuesEncoder(EncodeMaterials materials){ - this.materials=materials; - Map map = new HashMap<>(); - map.put("id", new XMLValuesEncoderId(materials)); - map.put("string", new XMLValuesEncoderString(materials)); - XMLValuesEncoderDimen encoderDimen=new XMLValuesEncoderDimen(materials); - map.put("dimen", encoderDimen); - map.put("fraction", encoderDimen); - map.put("color", new XMLValuesEncoderColor(materials)); - map.put("integer", new XMLValuesEncoderInteger(materials)); - - this.xmlEncodersMap=map; - this.commonEncoder=new XMLValuesEncoderCommon(materials); - - Map mapBag=new HashMap<>(); - XMLValuesEncoderAttr encoderAttr = new XMLValuesEncoderAttr(materials); - mapBag.put("attr", encoderAttr); - mapBag.put("^attr-private", encoderAttr); - mapBag.put("plurals", new XMLValuesEncoderPlurals(materials)); - mapBag.put("array", new XMLValuesEncoderArray(materials)); - mapBag.put("style", new XMLValuesEncoderStyle(materials)); - this.xmlBagEncodersMap=mapBag; - this.bagCommonEncoder=new XMLValuesEncoderBag(materials); - - } - public void encodeValuesXml(File valuesXmlFile) throws XMLException { - if(valuesXmlFile.getName().equals("public.xml")){ - return; - } - String simpleName = valuesXmlFile.getParentFile().getName() - +File.separator+valuesXmlFile.getName(); - materials.logVerbose("Encoding: "+simpleName); - - String type = EncodeUtil.getTypeNameFromValuesXml(valuesXmlFile); - String qualifiers = EncodeUtil.getQualifiersFromValuesXml(valuesXmlFile); - XMLDocument xmlDocument = XMLDocument.load(valuesXmlFile); - encodeValuesXml(type, qualifiers, xmlDocument); - } - public void encodeValue(String qualifiers, XMLElement element){ - String type = getType(element, null); - if(type == null){ - throw new EncodeException("Can not determine type: " + element); - } - encodeValue(type, qualifiers, element); - } - public void encodeValue(String type, String qualifiers, XMLElement element){ - boolean is_bag = isBag(element); - encodeValue(is_bag, type, qualifiers, element); - } - public void encodeValue(boolean is_bag, String type, String qualifiers, XMLElement element){ - PackageBlock packageBlock = getEncodeMaterials().getCurrentPackage(); - Entry entry = packageBlock - .getOrCreate(qualifiers, type, element.getAttributeValue("name")); - encodeValue(is_bag, entry, element); - } - public void encodeValue(Entry entry, XMLElement element){ - boolean is_bag = isBag(element); - encodeValue(is_bag, entry, element); - } - public void encodeValue(boolean is_bag, Entry entry, XMLElement element){ - XMLValuesEncoder encoder; - String type = entry.getTypeName(); - if(is_bag){ - encoder = getBagEncoder(type); - }else{ - encoder = getEncoder(type); - } - encoder.encodeValue(entry, element); - } - public void encodeValues(String type, String qualifiers, XMLDocument xmlDocument){ - type = getType(xmlDocument, type); - boolean is_bag = isBag(xmlDocument, type); - encodeValues(is_bag, type, qualifiers, xmlDocument); - } - public void encodeValues(boolean is_bag, String type, String qualifiers, XMLDocument xmlDocument){ - XMLValuesEncoder encoder; - if(is_bag){ - encoder = getBagEncoder(type); - }else{ - encoder = getEncoder(type); - } - encoder.encode(type, qualifiers, xmlDocument); - } - public EncodeMaterials getEncodeMaterials(){ - return materials; - } - private void encodeValuesXml(String type, String qualifiers, XMLDocument xmlDocument) { - type=getType(xmlDocument, type); - XMLValuesEncoder encoder; - if(isBag(xmlDocument, type)){ - encoder = getBagEncoder(type); - }else{ - encoder=getEncoder(type); - } - encoder.encode(type, qualifiers, xmlDocument); - } - private boolean isBag(XMLElement element){ - if(element.hasChildElements()){ - return true; - } - return element.getAttributeCount() > 1; - } - private boolean isBag(XMLDocument xmlDocument, String type){ - if(type.startsWith("attr")){ - return true; - } - if(type.startsWith("^attr")){ - return true; - } - if(type.startsWith("style")){ - return true; - } - if(type.startsWith("plurals")){ - return true; - } - if(type.startsWith("array")){ - return true; - } - if(type.startsWith("string")){ - return false; - } - XMLElement documentElement=xmlDocument.getDocumentElement(); - int count=documentElement.getChildesCount(); - for(int i=0;i0){ - return true; - } - } - return false; - } - private boolean hasNameAttributes(XMLDocument xmlDocument){ - XMLElement documentElement=xmlDocument.getDocumentElement(); - int count=documentElement.getChildesCount(); - for(int i=0;i0){ - XMLElement child = element.getChildAt(0); - if(child.getAttributeValue("name") != null){ - return true; - } - } - } - return false; - } - private String getType(XMLDocument xmlDocument, String def){ - XMLElement documentElement=xmlDocument.getDocumentElement(); - if(documentElement.getChildesCount()==0){ - return def; - } - XMLElement first=documentElement.getChildAt(0); - String type=first.getAttributeValue("type"); - if(type==null){ - type=first.getTagName(); - } - if(type==null){ - return def; - } - if(type.endsWith("-array")){ - return "array"; - } - if(type.startsWith("attr-private")){ - return "^attr-private"; - } - if(type.equals("item")){ - return def; - } - return type; - } - private String getType(XMLElement first, String def){ - String type = first.getAttributeValue("type"); - if(type == null){ - type = first.getTagName(); - } - if(type == null){ - return def; - } - if(type.endsWith("-array")){ - return "array"; - } - if(type.startsWith("attr-private")){ - return "^attr-private"; - } - if(type.equals("item")){ - return def; - } - return type; - } - private XMLValuesEncoder getEncoder(String type){ - type=EncodeUtil.sanitizeType(type); - XMLValuesEncoder encoder=xmlEncodersMap.get(type); - if(encoder!=null){ - return encoder; - } - return commonEncoder; - } - private XMLValuesEncoderBag getBagEncoder(String type){ - type=EncodeUtil.sanitizeType(type); - XMLValuesEncoderBag encoder=xmlBagEncodersMap.get(type); - if(encoder!=null){ - return encoder; - } - return bagCommonEncoder; - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmlencoder/ValuesStringPoolBuilder.java b/src/ARSCLib/com/reandroid/apk/xmlencoder/ValuesStringPoolBuilder.java deleted file mode 100644 index 39ecbc66..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmlencoder/ValuesStringPoolBuilder.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmlencoder; - -import com.reandroid.arsc.array.StringArray; -import com.reandroid.arsc.array.StyleArray; -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.item.StyleItem; -import com.reandroid.arsc.item.TableString; -import com.reandroid.arsc.pool.TableStringPool; -import com.reandroid.xml.XMLDocument; -import com.reandroid.xml.XMLElement; -import com.reandroid.xml.XMLSpanInfo; -import com.reandroid.xml.XMLSpannable; - -import java.io.File; -import java.util.*; - -public class ValuesStringPoolBuilder { - private final Set stringList; - private final Set styleList; - public ValuesStringPoolBuilder(){ - this.stringList=new HashSet<>(); - this.styleList=new HashSet<>(); - } - public void addTo(TableStringPool stringPool){ - if(stringPool.getStringsArray().childesCount()==0){ - buildWithStyles(stringPool); - } - stringPool.addStrings(stringList); - stringList.clear(); - styleList.clear(); - stringPool.refresh(); - } - private void buildWithStyles(TableStringPool stringPool){ - List spannableList = buildSpannable(); - if(spannableList.size()==0){ - return; - } - StringArray stringsArray = stringPool.getStringsArray(); - StyleArray styleArray = stringPool.getStyleArray(); - - int stylesCount = spannableList.size(); - stringsArray.setChildesCount(stylesCount); - styleArray.setChildesCount(stylesCount); - - List tagList = - new ArrayList<>(XMLSpannable.tagList(spannableList)); - EncodeUtil.sortStrings(tagList); - Map tagsMap = - stringPool.insertStrings(tagList); - - List textList = XMLSpannable.toTextList(spannableList); - - for(int i=0;i buildSpannable(){ - List results=new ArrayList<>(); - Set removeList=new HashSet<>(); - for(String text:styleList){ - XMLSpannable spannable=XMLSpannable.parse(text); - if(spannable!=null){ - results.add(spannable); - removeList.add(text); - }else { - stringList.add(text); - } - } - stringList.removeAll(removeList); - XMLSpannable.sort(results); - return results; - } - public void scanValuesDirectory(File dir){ - addStringsFile(new File(dir, "strings.xml")); - addBagsFile(new File(dir, "plurals.xml")); - } - public int size(){ - return stringList.size(); - } - private void addStringsFile(File file) { - if(file==null||!file.isFile()){ - return; - } - try { - XMLDocument xmlDocument = XMLDocument.load(file); - addStrings(xmlDocument); - } catch (Exception ignored) { - } - } - private void addBagsFile(File file) { - if(file==null||!file.isFile()){ - return; - } - try { - XMLDocument xmlDocument = XMLDocument.load(file); - addBagStrings(xmlDocument); - } catch (Exception ignored) { - } - } - private void addBagStrings(XMLDocument xmlDocument){ - if(xmlDocument == null){ - return; - } - XMLElement documentElement = xmlDocument.getDocumentElement(); - if(documentElement==null){ - return; - } - int count = documentElement.getChildesCount(); - for(int i=0;i0 && text.charAt(0)!='@'){ - stringList.add(text); - } - } - private void addStyleElement(XMLElement element){ - styleList.add(element.buildTextContent(false)); - } - -} diff --git a/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLEncodeSource.java b/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLEncodeSource.java deleted file mode 100644 index 2c703b12..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLEncodeSource.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmlencoder; - -import com.reandroid.archive.ByteInputSource; -import com.reandroid.apk.CrcOutputStream; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.xml.ResXmlDocument; -import com.reandroid.arsc.value.Entry; -import com.reandroid.xml.XMLException; -import com.reandroid.xml.source.XMLSource; - -import java.io.IOException; -import java.io.OutputStream; - -public class XMLEncodeSource extends ByteInputSource { - private final EncodeMaterials encodeMaterials; - private final XMLSource xmlSource; - private ResXmlDocument resXmlDocument; - private Entry mEntry; - public XMLEncodeSource(EncodeMaterials encodeMaterials, XMLSource xmlSource, Entry entry){ - super(new byte[0], xmlSource.getPath()); - this.encodeMaterials = encodeMaterials; - this.xmlSource = xmlSource; - this.mEntry = entry; - } - public XMLEncodeSource(EncodeMaterials encodeMaterials, XMLSource xmlSource){ - this(encodeMaterials, xmlSource, null); - } - - public XMLSource getXmlSource() { - return xmlSource; - } - public Entry getEntry(){ - return mEntry; - } - public void setEntry(Entry entry) { - this.mEntry = entry; - } - - @Override - public long getLength() throws IOException{ - return getResXmlBlock().countBytes(); - } - @Override - public long getCrc() throws IOException{ - ResXmlDocument resXmlDocument = getResXmlBlock(); - CrcOutputStream outputStream=new CrcOutputStream(); - resXmlDocument.writeBytes(outputStream); - return outputStream.getCrcValue(); - } - @Override - public long write(OutputStream outputStream) throws IOException { - return getResXmlBlock().writeBytes(outputStream); - } - @Override - public byte[] getBytes() { - try { - return getResXmlBlock().getBytes(); - } catch (IOException ignored) { - } - //should not reach here - return new byte[0]; - } - public ResXmlDocument getResXmlBlock() throws IOException{ - if(resXmlDocument !=null){ - return resXmlDocument; - } - try { - XMLFileEncoder xmlFileEncoder=new XMLFileEncoder(encodeMaterials); - xmlFileEncoder.setCurrentPath(xmlSource.getPath()); - EncodeMaterials encodeMaterials = this.encodeMaterials; - encodeMaterials.logVerbose("Encoding xml: " + xmlSource.getPath()); - PackageBlock currentPackage = encodeMaterials.getCurrentPackage(); - PackageBlock packageBlock = getEntryPackageBlock(); - if(packageBlock != null && packageBlock != currentPackage){ - encodeMaterials.setCurrentPackage(packageBlock); - } - resXmlDocument = xmlFileEncoder.encode(xmlSource.getXMLDocument()); - } catch (XMLException ex) { - throw new EncodeException("XMLException on: '"+xmlSource.getPath() - +"'\n '"+ex.getMessage()+"'"); - } - return resXmlDocument; - } - private PackageBlock getEntryPackageBlock(){ - Entry entry = getEntry(); - if(entry != null){ - return entry.getPackageBlock(); - } - return null; - } - @Override - public void disposeInputSource(){ - this.xmlSource.disposeXml(); - if(this.resXmlDocument !=null){ - resXmlDocument =null; - } - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLFileEncoder.java b/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLFileEncoder.java deleted file mode 100644 index 442549f8..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLFileEncoder.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmlencoder; - -import com.reandroid.arsc.array.ResValueMapArray; -import com.reandroid.arsc.chunk.xml.*; -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.value.AttributeDataFormat; -import com.reandroid.arsc.value.Entry; -import com.reandroid.arsc.value.ValueType; -import com.reandroid.arsc.value.attribute.AttributeBag; -import com.reandroid.xml.*; - -import java.io.File; -import java.io.InputStream; - -public class XMLFileEncoder { - private final EncodeMaterials materials; - private ResXmlDocument resXmlDocument; - private String mCurrentPath; - public XMLFileEncoder(EncodeMaterials materials){ - this.materials=materials; - } - - // Just for logging purpose - public void setCurrentPath(String path) { - this.mCurrentPath = path; - } - public ResXmlDocument encode(String xmlString){ - try { - return encode(XMLDocument.load(xmlString)); - } catch (XMLException ex) { - materials.logMessage(ex.getMessage()); - } - return null; - } - public ResXmlDocument encode(InputStream inputStream){ - try { - return encode(XMLDocument.load(inputStream)); - } catch (XMLException ex) { - materials.logMessage(ex.getMessage()); - } - return null; - } - public ResXmlDocument encode(File xmlFile){ - setCurrentPath(xmlFile.getAbsolutePath()); - try { - return encode(XMLDocument.load(xmlFile)); - } catch (XMLException ex) { - materials.logMessage(ex.getMessage()); - } - return null; - } - public ResXmlDocument encode(XMLDocument xmlDocument){ - resXmlDocument = new ResXmlDocument(); - resXmlDocument.setPackageBlock(materials.getCurrentPackage()); - buildIdMap(xmlDocument); - buildElement(xmlDocument); - resXmlDocument.refresh(); - return resXmlDocument; - } - public ResXmlDocument getResXmlBlock(){ - return resXmlDocument; - } - private void buildElement(XMLDocument xmlDocument){ - XMLElement element = xmlDocument.getDocumentElement(); - ResXmlElement resXmlElement = resXmlDocument.createRootElement(element.getTagName()); - buildElement(element, resXmlElement); - } - private void buildElement(XMLElement element, ResXmlElement resXmlElement){ - ensureNamespaces(element, resXmlElement); - resXmlElement.setTag(element.getTagName()); - buildAttributes(element, resXmlElement); - for(XMLNode node:element.getChildNodes()){ - if(node instanceof XMLText){ - resXmlElement.addResXmlText(((XMLText)node).getText(true)); - }else if(node instanceof XMLComment){ - resXmlElement.setComment(((XMLComment)node).getCommentText()); - }else if(node instanceof XMLElement){ - XMLElement child=(XMLElement) node; - ResXmlElement childXml=resXmlElement.createChildElement(); - buildElement(child, childXml); - } - } - } - private void buildAttributes(XMLElement element, ResXmlElement resXmlElement){ - for(XMLAttribute attribute:element.listAttributes()){ - if(attribute instanceof SchemaAttr){ - continue; - } - if(SchemaAttr.looksSchema(attribute.getName(), attribute.getValue())){ - continue; - } - String name=attribute.getNameWoPrefix(); - int resourceId=decodeUnknownAttributeHex(name); - Entry entry =null; - if(resourceId==0){ - entry =getAttributeBlock(attribute); - if(entry !=null){ - resourceId= entry.getResourceId(); - }else if(attribute.getNamePrefix()!=null){ - throw new EncodeException("No resource found for attribute: " - + attribute.getName() + ", at file "+mCurrentPath); - } - } - ResXmlAttribute xmlAttribute = - resXmlElement.createAttribute(name, resourceId); - String prefix=attribute.getNamePrefix(); - if(prefix!=null){ - ResXmlStartNamespace ns = resXmlElement.getStartNamespaceByPrefix(prefix); - if(ns==null){ - ns=forceCreateNamespace(resXmlElement, resourceId, prefix); - } - if(ns==null){ - throw new EncodeException("Namespace not found: " - +attribute.toString() - +", path="+mCurrentPath); - } - xmlAttribute.setNamespaceReference(ns.getUriReference()); - } - - String valueText=attribute.getValue(); - - if(ValueDecoder.isReference(valueText)){ - if(valueText.startsWith("?")){ - xmlAttribute.setValueType(ValueType.ATTRIBUTE); - }else { - xmlAttribute.setValueType(ValueType.REFERENCE); - } - xmlAttribute.setData(materials.resolveReference(valueText)); - continue; - } - if(entry !=null){ - AttributeBag attributeBag=AttributeBag - .create((ResValueMapArray) entry.getTableEntry().getValue()); - - ValueDecoder.EncodeResult encodeResult = - attributeBag.encodeEnumOrFlagValue(valueText); - if(encodeResult!=null){ - xmlAttribute.setValueType(encodeResult.valueType); - xmlAttribute.setData(encodeResult.value); - continue; - } - if(attributeBag.isEqualType(AttributeDataFormat.STRING)) { - xmlAttribute.setValueAsString(ValueDecoder - .unEscapeSpecialCharacter(valueText)); - continue; - } - } - - if(EncodeUtil.isEmpty(valueText)) { - if(valueText == null){ - valueText = ""; - } - xmlAttribute.setValueAsString(valueText); - }else{ - ValueDecoder.EncodeResult encodeResult = - ValueDecoder.encodeGuessAny(valueText); - if(encodeResult!=null){ - xmlAttribute.setValueType(encodeResult.valueType); - xmlAttribute.setData(encodeResult.value); - }else { - xmlAttribute.setValueAsString(ValueDecoder - .unEscapeSpecialCharacter(valueText)); - } - } - } - resXmlElement.calculatePositions(); - } - private void ensureNamespaces(XMLElement element, ResXmlElement resXmlElement){ - for(XMLAttribute attribute:element.listAttributes()){ - String prefix = SchemaAttr.getPrefix(attribute.getName()); - if(prefix==null){ - continue; - } - String uri=attribute.getValue(); - resXmlElement.getOrCreateNamespace(uri, prefix); - } - } - private void buildIdMap(XMLDocument xmlDocument){ - ResIdBuilder idBuilder=new ResIdBuilder(); - XMLElement element= xmlDocument.getDocumentElement(); - searchResIds(idBuilder, element); - idBuilder.buildTo(resXmlDocument.getResXmlIDMap()); - } - private void searchResIds(ResIdBuilder idBuilder, XMLElement element){ - for(XMLAttribute attribute : element.listAttributes()){ - addResourceId(idBuilder, attribute); - } - int count=element.getChildesCount(); - for(int i=0;i>24) & 0xff; - String uri; - if(pkgId == 1){ - uri = EncodeUtil.URI_ANDROID; - }else { - uri=EncodeUtil.URI_APP; - } - ResXmlElement root = resXmlElement.getRootResXmlElement(); - ResXmlStartNamespace ns = root.getOrCreateNamespace(uri, prefix); - materials.logVerbose("Force created ns: "+prefix+":"+uri); - return ns; - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoder.java b/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoder.java deleted file mode 100644 index c3c07fad..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoder.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmlencoder; - -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.TypeBlock; -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.value.Entry; -import com.reandroid.arsc.value.ValueType; -import com.reandroid.xml.XMLDocument; -import com.reandroid.xml.XMLElement; - -class XMLValuesEncoder { - private final EncodeMaterials materials; - XMLValuesEncoder(EncodeMaterials materials){ - this.materials=materials; - } - public void encode(String type, String qualifiers, XMLDocument xmlDocument){ - XMLElement documentElement = xmlDocument.getDocumentElement(); - TypeBlock typeBlock = getTypeBlock(type, qualifiers); - - int count = documentElement.getChildesCount(); - - typeBlock.getEntryArray().ensureSize(count); - - for(int i=0;i 1){ - return false; - } - String text = element.getTextContent(); - if(!ValueDecoder.isReference(text)){ - return false; - } - encodeReferenceValue(entry, text); - return true; - } - void encodeChildes(XMLElement element, ResTableMapEntry mapEntry){ - throw new EncodeException("Unimplemented bag type encoder: " - +element.getTagName()); - - } - int getChildesCount(XMLElement element){ - return element.getChildesCount(); - } - - @Override - void encodeNullValue(Entry entry){ - // Nothing to do - } - - Integer decodeUnknownAttributeHex(String name){ - if(name.length() == 0 || (name.charAt(0) !='@' && name.charAt(0) != '?')){ - return null; - } - name = name.substring(1); - if(!ValueDecoder.isHex(name)){ - return null; - } - return ValueDecoder.parseHex(name); - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoderColor.java b/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoderColor.java deleted file mode 100644 index 88cb856a..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoderColor.java +++ /dev/null @@ -1,36 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmlencoder; - -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.value.Entry; - -class XMLValuesEncoderColor extends XMLValuesEncoder{ - XMLValuesEncoderColor(EncodeMaterials materials) { - super(materials); - } - @Override - void encodeStringValue(Entry entry, String value){ - ValueDecoder.EncodeResult encodeResult=ValueDecoder.encodeColor(value); - if(encodeResult!=null){ - entry.setValueAsRaw(encodeResult.valueType, encodeResult.value); - }else { - // If reaches here the value might be - // file path e.g. res/color/something.xml - entry.setValueAsString(value); - } - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoderCommon.java b/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoderCommon.java deleted file mode 100644 index dc774f39..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoderCommon.java +++ /dev/null @@ -1,39 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmlencoder; - -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.value.Entry; - - class XMLValuesEncoderCommon extends XMLValuesEncoder{ - XMLValuesEncoderCommon(EncodeMaterials materials) { - super(materials); - } - @Override - void encodeStringValue(Entry entry, String value){ - if(ValueDecoder.isReference(value)){ - entry.setValueAsReference(getMaterials().resolveReference(value)); - }else { - ValueDecoder.EncodeResult encodeResult=ValueDecoder.encodeGuessAny(value); - if(encodeResult!=null){ - entry.setValueAsRaw(encodeResult.valueType, encodeResult.value); - }else { - entry.setValueAsString(ValueDecoder - .unEscapeSpecialCharacter(value)); - } - } - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoderDimen.java b/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoderDimen.java deleted file mode 100644 index 38cd6dcf..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoderDimen.java +++ /dev/null @@ -1,40 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmlencoder; - -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.value.Entry; - - class XMLValuesEncoderDimen extends XMLValuesEncoder{ - XMLValuesEncoderDimen(EncodeMaterials materials) { - super(materials); - } - @Override - void encodeStringValue(Entry entry, String value){ - ValueDecoder.EncodeResult encodeResult = - ValueDecoder.encodeDimensionOrFloat(value); - if(encodeResult==null){ - encodeResult=ValueDecoder.encodeHexOrInt(value); - } - if(encodeResult!=null){ - entry.setValueAsRaw(encodeResult.valueType, encodeResult.value); - }else { - getMaterials().logMessage("Encoding as string dimen value: "+value); - entry.setValueAsString(value); - } - - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoderId.java b/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoderId.java deleted file mode 100644 index 805d4e34..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoderId.java +++ /dev/null @@ -1,47 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmlencoder; - -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.value.ValueHeader; -import com.reandroid.arsc.value.Entry; - - class XMLValuesEncoderId extends XMLValuesEncoder{ - public XMLValuesEncoderId(EncodeMaterials materials) { - super(materials); - } - - @Override - void encodeStringValue(Entry entry, String value){ - entry.setValueAsBoolean(false); - setVisibility(entry); - } - @Override - void encodeNullValue(Entry entry){ - entry.setValueAsBoolean(false); - setVisibility(entry); - } - @Override - void encodeBooleanValue(Entry entry, String value){ - super.encodeBooleanValue(entry, value); - setVisibility(entry); - } - private void setVisibility(Entry entry){ - ValueHeader valueHeader = entry.getHeader(); - valueHeader.setWeak(true); - valueHeader.setPublic(true); - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoderInteger.java b/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoderInteger.java deleted file mode 100644 index d10080b8..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoderInteger.java +++ /dev/null @@ -1,42 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmlencoder; - -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.value.Entry; -import com.reandroid.arsc.value.ValueType; - -class XMLValuesEncoderInteger extends XMLValuesEncoder{ - XMLValuesEncoderInteger(EncodeMaterials materials) { - super(materials); - } - @Override - void encodeStringValue(Entry entry, String value){ - value=value.trim(); - if(ValueDecoder.isInteger(value)){ - entry.setValueAsRaw(ValueType.INT_DEC, ValueDecoder.parseInteger(value)); - }else if(ValueDecoder.isHex(value)){ - entry.setValueAsRaw(ValueType.INT_HEX, ValueDecoder.parseHex(value)); - }else { - ValueDecoder.EncodeResult encodeResult=ValueDecoder.encodeDimensionOrFloat(value); - if(encodeResult!=null){ - entry.setValueAsRaw(encodeResult.valueType, encodeResult.value); - }else { - throw new EncodeException("Unknown value for type : '"+value+"'"); - } - } - } -} diff --git a/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoderPlurals.java b/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoderPlurals.java deleted file mode 100644 index bbc9e8d8..00000000 --- a/src/ARSCLib/com/reandroid/apk/xmlencoder/XMLValuesEncoderPlurals.java +++ /dev/null @@ -1,59 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.apk.xmlencoder; - -import com.reandroid.arsc.array.ResValueMapArray; -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.value.AttributeType; -import com.reandroid.arsc.value.ResTableMapEntry; -import com.reandroid.arsc.value.ResValueMap; -import com.reandroid.arsc.value.ValueType; -import com.reandroid.arsc.value.plurals.PluralsQuantity; -import com.reandroid.xml.XMLElement; - -class XMLValuesEncoderPlurals extends XMLValuesEncoderBag{ - XMLValuesEncoderPlurals(EncodeMaterials materials) { - super(materials); - } - @Override - void encodeChildes(XMLElement parentElement, ResTableMapEntry resValueBag){ - int count = parentElement.getChildesCount(); - ResValueMapArray itemArray = resValueBag.getValue(); - for(int i=0;i entriesMap){ - super(entriesMap); - } - public APKArchive(){ - super(); - } - - public void refresh(){ - List inputSourceList = listInputSources(); - applySort(inputSourceList); - set(inputSourceList); - } - public void autoSortApkFiles(){ - List inputSourceList = listInputSources(); - autoSortApkFiles(inputSourceList); - set(inputSourceList); - } - public long writeApk(File outApk) throws IOException{ - ZipSerializer serializer=new ZipSerializer(listInputSources()); - return serializer.writeZip(outApk); - } - public long writeApk(OutputStream outputStream) throws IOException{ - ZipSerializer serializer=new ZipSerializer(listInputSources()); - return serializer.writeZip(outputStream); - } - public static APKArchive loadZippedApk(File zipFile) throws IOException { - return loadZippedApk(new ZipFile(zipFile)); - } - public static APKArchive loadZippedApk(ZipFile zipFile) { - Map entriesMap = InputSourceUtil.mapZipFileSources(zipFile); - return new APKArchive(entriesMap); - } - public static void repackApk(File apkFile) throws IOException{ - APKArchive apkArchive =loadZippedApk(apkFile); - apkArchive.writeApk(apkFile); - } - public static void applySort(List sourceList){ - Comparator cmp=new Comparator() { - @Override - public int compare(InputSource in1, InputSource in2) { - return Integer.compare(in1.getSort(), in2.getSort()); - } - }; - sourceList.sort(cmp); - } - public static void autoSortApkFiles(List sourceList){ - Comparator cmp=new Comparator() { - @Override - public int compare(InputSource in1, InputSource in2) { - return getSortName(in1).compareTo(getSortName(in2)); - } - }; - sourceList.sort(cmp); - int i=0; - for(InputSource inputSource:sourceList){ - inputSource.setSort(i); - i++; - } - } - private static String getSortName(InputSource inputSource){ - String name=inputSource.getAlias(); - StringBuilder builder=new StringBuilder(); - if(name.equals("AndroidManifest.xml")){ - builder.append("0 "); - }else if(name.startsWith("META-INF/")){ - builder.append("1 "); - }else if(name.equals("resources.arsc")){ - builder.append("2 "); - }else if(name.startsWith("classes")){ - builder.append("3 "); - }else if(name.startsWith("res/")){ - builder.append("4 "); - }else if(name.startsWith("lib/")){ - builder.append("5 "); - }else if(name.startsWith("assets/")){ - builder.append("6 "); - }else { - builder.append("7 "); - } - builder.append(name.toLowerCase()); - return builder.toString(); - } -} diff --git a/src/ARSCLib/com/reandroid/archive/ByteInputSource.java b/src/ARSCLib/com/reandroid/archive/ByteInputSource.java deleted file mode 100644 index 6acfe730..00000000 --- a/src/ARSCLib/com/reandroid/archive/ByteInputSource.java +++ /dev/null @@ -1,46 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -public class ByteInputSource extends InputSource { - private byte[] inBytes; - public ByteInputSource(byte[] inBytes, String name) { - super(name); - this.inBytes=inBytes; - } - @Override - public long write(OutputStream outputStream) throws IOException { - byte[] bts=getBytes(); - outputStream.write(bts); - return bts.length; - } - @Override - public InputStream openStream() throws IOException { - return new ByteArrayInputStream(getBytes()); - } - public byte[] getBytes() { - return inBytes; - } - @Override - public void disposeInputSource(){ - inBytes=new byte[0]; - } -} diff --git a/src/ARSCLib/com/reandroid/archive/FileInputSource.java b/src/ARSCLib/com/reandroid/archive/FileInputSource.java deleted file mode 100644 index bfb67796..00000000 --- a/src/ARSCLib/com/reandroid/archive/FileInputSource.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive; - -import com.reandroid.common.FileChannelInputStream; - -import java.io.*; - -public class FileInputSource extends InputSource { - private final File file; - public FileInputSource(File file, String name){ - super(name); - this.file=file; - } - @Override - public byte[] getBytes(int length) throws IOException{ - return FileChannelInputStream.read(getFile(), length); - } - @Override - public long getLength() { - return getFile().length(); - } - @Override - public void close(InputStream inputStream) throws IOException { - inputStream.close(); - } - @Override - public FileChannelInputStream openStream() throws IOException { - return new FileChannelInputStream(this.file); - } - public File getFile(){ - return file; - } - -} diff --git a/src/ARSCLib/com/reandroid/archive/InputSource.java b/src/ARSCLib/com/reandroid/archive/InputSource.java deleted file mode 100644 index e29d37c3..00000000 --- a/src/ARSCLib/com/reandroid/archive/InputSource.java +++ /dev/null @@ -1,132 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.zip.CRC32; -import java.util.zip.ZipEntry; - -public abstract class InputSource { - private final String name; - private String alias; - private long mCrc; - private long mLength; - private int method = ZipEntry.DEFLATED; - private int sort; - public InputSource(String name){ - this.name = name; - this.alias = InputSourceUtil.sanitize(name); - } - public byte[] getBytes(int length) throws IOException{ - InputStream inputStream = openStream(); - byte[] bytes = new byte[length]; - inputStream.read(bytes, 0, length); - close(inputStream); - return bytes; - } - public void disposeInputSource(){ - } - public int getSort() { - return sort; - } - public void setSort(int sort) { - this.sort = sort; - } - public int getMethod() { - return method; - } - public void setMethod(int method) { - this.method = method; - } - - public String getAlias(){ - if(alias!=null){ - return alias; - } - return getName(); - } - public void setAlias(String alias) { - this.alias = alias; - } - public void close(InputStream inputStream) throws IOException { - inputStream.close(); - } - public long write(OutputStream outputStream) throws IOException { - return write(outputStream, openStream()); - } - private long write(OutputStream outputStream, InputStream inputStream) throws IOException { - long result=0; - byte[] buffer=new byte[1024 * 1000]; - int len; - while ((len=inputStream.read(buffer))>0){ - outputStream.write(buffer, 0, len); - result+=len; - } - close(inputStream); - return result; - } - public String getName(){ - return name; - } - public long getLength() throws IOException{ - if(mLength==0){ - calculateCrc(); - } - return mLength; - } - public long getCrc() throws IOException{ - if(mCrc==0){ - calculateCrc(); - } - return mCrc; - } - public abstract InputStream openStream() throws IOException; - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof InputSource)) { - return false; - } - InputSource that = (InputSource) o; - return getName().equals(that.getName()); - } - @Override - public int hashCode() { - return getName().hashCode(); - } - @Override - public String toString(){ - return getClass().getSimpleName()+": "+getName(); - } - private void calculateCrc() throws IOException { - InputStream inputStream=openStream(); - long length=0; - CRC32 crc = new CRC32(); - int bytesRead; - byte[] buffer = new byte[1024*64]; - while((bytesRead = inputStream.read(buffer)) != -1) { - crc.update(buffer, 0, bytesRead); - length+=bytesRead; - } - close(inputStream); - mCrc=crc.getValue(); - mLength=length; - } -} diff --git a/src/ARSCLib/com/reandroid/archive/InputSourceUtil.java b/src/ARSCLib/com/reandroid/archive/InputSourceUtil.java deleted file mode 100644 index 49d283eb..00000000 --- a/src/ARSCLib/com/reandroid/archive/InputSourceUtil.java +++ /dev/null @@ -1,151 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive; - -import java.io.*; -import java.util.*; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; -import java.util.zip.ZipInputStream; - - public class InputSourceUtil { - - public static String toRelative(File rootDir, File file){ - int len=rootDir.getAbsolutePath().length(); - String path=file.getAbsolutePath(); - path=path.substring(len); - path=sanitize(path); - return path; - } - public static String sanitize(String path){ - path=path.replace('\\', '/'); - while (path.startsWith("./")){ - path=path.substring(2); - } - while (path.startsWith("/")){ - path=path.substring(1); - } - return path; - } - - public static Map mapZipFileSources(ZipFile zipFile){ - Map results=new LinkedHashMap<>(); - Enumeration entriesEnum = zipFile.entries(); - int i=0; - while (entriesEnum.hasMoreElements()){ - ZipEntry zipEntry = entriesEnum.nextElement(); - if(zipEntry.isDirectory()){ - continue; - } - ZipEntrySource source=new ZipEntrySource(zipFile, zipEntry); - source.setSort(i); - source.setMethod(zipEntry.getMethod()); - results.put(source.getName(), source); - i++; - } - return results; - } - public static Map mapInputStreamAsBuffer(InputStream inputStream) throws IOException { - Map results = new LinkedHashMap<>(); - ZipInputStream zin = new ZipInputStream(inputStream); - ZipEntry zipEntry; - int i=0; - while ((zipEntry=zin.getNextEntry())!=null){ - if(zipEntry.isDirectory()){ - continue; - } - byte[] buffer = loadBuffer(zin); - String name = sanitize(zipEntry.getName()); - ByteInputSource source = new ByteInputSource(buffer, name); - source.setSort(i); - source.setMethod(zipEntry.getMethod()); - results.put(name, source); - i++; - } - zin.close(); - return results; - } - private static byte[] loadBuffer(InputStream in) throws IOException { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - byte[] buff=new byte[40960]; - int len; - while((len=in.read(buff))>0){ - outputStream.write(buff, 0, len); - } - outputStream.close(); - return outputStream.toByteArray(); - } - public static List listZipFileSources(ZipFile zipFile){ - List results=new ArrayList<>(); - Enumeration entriesEnum = zipFile.entries(); - int i=0; - while (entriesEnum.hasMoreElements()){ - ZipEntry zipEntry = entriesEnum.nextElement(); - if(zipEntry.isDirectory()){ - continue; - } - ZipEntrySource source=new ZipEntrySource(zipFile, zipEntry); - source.setSort(i); - results.add(source); - } - return results; - } - public static List listDirectory(File dir){ - List results=new ArrayList<>(); - recursiveDirectory(results, dir, dir); - return results; - } - private static void recursiveDirectory(List results, File rootDir, File dir){ - if(dir.isFile()){ - String name; - if(rootDir.equals(dir)){ - name=dir.getName(); - }else { - name=toRelative(rootDir, dir); - } - results.add(new FileInputSource(dir, name)); - return; - } - File[] childFiles=dir.listFiles(); - if(childFiles==null){ - return; - } - for(File file:childFiles){ - recursiveDirectory(results, rootDir, file); - } - } - public static List sortString(List stringList){ - Comparator cmp=new Comparator() { - @Override - public int compare(String s1, String s2) { - return s1.compareTo(s2); - } - }; - stringList.sort(cmp); - return stringList; - } - - public static List sort(List sourceList){ - Comparator cmp=new Comparator() { - @Override - public int compare(InputSource in1, InputSource in2) { - return Integer.compare(in1.getSort(), in2.getSort()); - } - }; - sourceList.sort(cmp); - return sourceList; - } -} diff --git a/src/ARSCLib/com/reandroid/archive/WriteInterceptor.java b/src/ARSCLib/com/reandroid/archive/WriteInterceptor.java deleted file mode 100644 index ad80d55a..00000000 --- a/src/ARSCLib/com/reandroid/archive/WriteInterceptor.java +++ /dev/null @@ -1,20 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive; - -public interface WriteInterceptor { - InputSource onWriteArchive(InputSource inputSource); -} diff --git a/src/ARSCLib/com/reandroid/archive/WriteProgress.java b/src/ARSCLib/com/reandroid/archive/WriteProgress.java deleted file mode 100644 index 8c6438b4..00000000 --- a/src/ARSCLib/com/reandroid/archive/WriteProgress.java +++ /dev/null @@ -1,20 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive; - -public interface WriteProgress { - void onCompressFile(String path, int mode, long writtenBytes); -} diff --git a/src/ARSCLib/com/reandroid/archive/ZipAlign.java b/src/ARSCLib/com/reandroid/archive/ZipAlign.java deleted file mode 100644 index 8b687e04..00000000 --- a/src/ARSCLib/com/reandroid/archive/ZipAlign.java +++ /dev/null @@ -1,333 +0,0 @@ -/* - This class is copied from "apksigner" and I couldn't find the - original repo/author to credit here. - */ - -package com.reandroid.archive; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.RandomAccessFile; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.Enumeration; -import java.util.GregorianCalendar; -import java.util.List; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; -import java.util.zip.ZipOutputStream; - - -public class ZipAlign { - private static final int ZIP_ENTRY_HEADER_LEN = 30; - private static final int ZIP_ENTRY_VERSION = 20; - private static final int ZIP_ENTRY_USES_DATA_DESCR = 0x0008; - private static final int ZIP_ENTRY_DATA_DESCRIPTOR_LEN = 16; - private static final int ALIGNMENT_4 = 4; - private static final int ALIGNMENT_PAGE = 4096; - - private static class XEntry { - public final ZipEntry entry; - public final long headerOffset; - public final int flags; - public final int padding; - - public XEntry(ZipEntry entry, long headerOffset, int flags, int padding) { - this.entry = entry; - this.headerOffset = headerOffset; - this.flags = flags; - this.padding = padding; - } - } - - - private static class FilterOutputStreamEx extends FilterOutputStream { - private long totalWritten = 0; - public FilterOutputStreamEx(OutputStream out) { - super(out); - } - @Override - public void write(byte[] b) throws IOException { - out.write(b); - totalWritten += b.length; - } - @Override - public void write(byte[] b, int off, int len) throws IOException { - out.write(b, off, len); - totalWritten += len; - } - @Override - public void write(int b) throws IOException { - out.write(b); - totalWritten += 1; - } - @Override - public void close() throws IOException { - super.close(); - } - public void writeInt(long v) throws IOException { - write((int) (v & 0xff)); - write((int) ((v >>> 8) & 0xff)); - write((int) ((v >>> 16) & 0xff)); - write((int) ((v >>> 24) & 0xff)); - } - public void writeShort(int v) throws IOException { - write((v) & 0xff); - write((v >>> 8) & 0xff); - } - } - - private File mInputFile; - private int mAlignment; - private File mOutputFile; - private ZipFile mZipFile; - private RandomAccessFile mRafInput; - private FilterOutputStreamEx mOutputStream; - private final List mXEntries = new ArrayList<>(); - private long mInputFileOffset = 0; - private int mTotalPadding = 0; - - public void zipAlign(File input, File output) throws IOException { - zipAlign(input, output, ALIGNMENT_4); - } - public void zipAlign(File input, File output, int alignment) throws IOException { - mInputFile = input; - mAlignment = alignment; - mOutputFile = output; - openFiles(); - copyAllEntries(); - buildCentralDirectory(); - closeFiles(); - } - private void openFiles() throws IOException { - mZipFile = new ZipFile(mInputFile); - mRafInput = new RandomAccessFile(mInputFile, "r"); - mOutputStream = new FilterOutputStreamEx(new BufferedOutputStream(new FileOutputStream(mOutputFile), 32 * 1024)); - } - private void copyAllEntries() throws IOException { - final int entryCount = mZipFile.size(); - if (entryCount == 0) { - return; - } - final Enumeration entries = mZipFile.entries(); - while (entries.hasMoreElements()) { - final ZipEntry entry = (ZipEntry) entries.nextElement(); - final String name = entry.getName(); - - int flags = entry.getMethod() == ZipEntry.STORED ? 0 : 1 << 3; - flags |= 1 << 11; - - final long outputEntryHeaderOffset = mOutputStream.totalWritten; - - final int inputEntryHeaderSize = ZIP_ENTRY_HEADER_LEN + (entry.getExtra() != null ? entry.getExtra().length : 0) - + name.getBytes(StandardCharsets.UTF_8).length; - final long inputEntryDataOffset = mInputFileOffset + inputEntryHeaderSize; - - final int padding; - - if (entry.getMethod() != ZipEntry.STORED) { - padding = 0; - } else { - int alignment = mAlignment; - if (name.startsWith("lib/") && name.endsWith(".so")) { - alignment = ALIGNMENT_PAGE; - } - long newOffset = inputEntryDataOffset + mTotalPadding; - padding = (int) ((alignment - (newOffset % alignment)) % alignment); - mTotalPadding += padding; - } - - final XEntry xentry = new XEntry(entry, outputEntryHeaderOffset, flags, padding); - mXEntries.add(xentry); - byte[] extra = entry.getExtra(); - if (extra == null) { - extra = new byte[padding]; - } else { - byte[] newExtra = new byte[extra.length + padding]; - System.arraycopy(extra, 0, newExtra, 0, extra.length); - Arrays.fill(newExtra, extra.length, newExtra.length, (byte) 0); - extra = newExtra; - } - entry.setExtra(extra); - mOutputStream.writeInt(ZipOutputStream.LOCSIG); - mOutputStream.writeShort(ZIP_ENTRY_VERSION); - mOutputStream.writeShort(flags); - mOutputStream.writeShort(entry.getMethod()); - - int modDate; - int time; - GregorianCalendar cal = new GregorianCalendar(); - cal.setTime(new Date(entry.getTime())); - int year = cal.get(Calendar.YEAR); - if (year < 1980) { - modDate = 0x21; - time = 0; - } else { - modDate = cal.get(Calendar.DATE); - modDate = (cal.get(Calendar.MONTH) + 1 << 5) | modDate; - modDate = ((cal.get(Calendar.YEAR) - 1980) << 9) | modDate; - time = cal.get(Calendar.SECOND) >> 1; - time = (cal.get(Calendar.MINUTE) << 5) | time; - time = (cal.get(Calendar.HOUR_OF_DAY) << 11) | time; - } - - mOutputStream.writeShort(time); - mOutputStream.writeShort(modDate); - - mOutputStream.writeInt(entry.getCrc()); - mOutputStream.writeInt(entry.getCompressedSize()); - mOutputStream.writeInt(entry.getSize()); - - mOutputStream.writeShort(entry.getName().getBytes(StandardCharsets.UTF_8).length); - mOutputStream.writeShort(entry.getExtra().length); - mOutputStream.write(entry.getName().getBytes(StandardCharsets.UTF_8)); - mOutputStream.write(entry.getExtra(), 0, entry.getExtra().length); - - mInputFileOffset += inputEntryHeaderSize; - - final long sizeToCopy; - if ((flags & ZIP_ENTRY_USES_DATA_DESCR) != 0) { - sizeToCopy = (entry.isDirectory() ? 0 : entry.getCompressedSize()) + ZIP_ENTRY_DATA_DESCRIPTOR_LEN; - } else { - sizeToCopy = entry.isDirectory() ? 0 : entry.getCompressedSize(); - } - - if (sizeToCopy > 0) { - mRafInput.seek(mInputFileOffset); - - long totalSizeCopied = 0; - final byte[] buf = new byte[32 * 1024]; - while (totalSizeCopied < sizeToCopy) { - int read = mRafInput.read(buf, 0, (int) Math.min(32 * 1024, sizeToCopy - totalSizeCopied)); - if (read <= 0) { - break; - } - mOutputStream.write(buf, 0, read); - totalSizeCopied += read; - } - } - - mInputFileOffset += sizeToCopy; - } - } - - private void buildCentralDirectory() throws IOException { - final long centralDirOffset = mOutputStream.totalWritten; - final int entryCount = mXEntries.size(); - for (int i = 0; i < entryCount; i++) { - XEntry xentry = mXEntries.get(i); - final ZipEntry entry = xentry.entry; - int modDate; - int time; - GregorianCalendar cal = new GregorianCalendar(); - cal.setTime(new Date(entry.getTime())); - int year = cal.get(Calendar.YEAR); - if (year < 1980) { - modDate = 0x21; - time = 0; - } else { - modDate = cal.get(Calendar.DATE); - modDate = (cal.get(Calendar.MONTH) + 1 << 5) | modDate; - modDate = ((cal.get(Calendar.YEAR) - 1980) << 9) | modDate; - time = cal.get(Calendar.SECOND) >> 1; - time = (cal.get(Calendar.MINUTE) << 5) | time; - time = (cal.get(Calendar.HOUR_OF_DAY) << 11) | time; - } - - mOutputStream.writeInt(ZipFile.CENSIG); // CEN header signature - mOutputStream.writeShort(ZIP_ENTRY_VERSION); // version made by - mOutputStream.writeShort(ZIP_ENTRY_VERSION); // version needed to extract - mOutputStream.writeShort(xentry.flags); // general purpose bit flag - mOutputStream.writeShort(entry.getMethod()); // compression method - mOutputStream.writeShort(time); - mOutputStream.writeShort(modDate); - mOutputStream.writeInt(entry.getCrc()); // crc-32 - mOutputStream.writeInt(entry.getCompressedSize()); // compressed size - mOutputStream.writeInt(entry.getSize()); // uncompressed size - final byte[] nameBytes = entry.getName().getBytes(StandardCharsets.UTF_8); - mOutputStream.writeShort(nameBytes.length); - mOutputStream.writeShort(entry.getExtra() != null ? entry.getExtra().length - xentry.padding : 0); - final byte[] commentBytes; - if (entry.getComment() != null) { - commentBytes = entry.getComment().getBytes(StandardCharsets.UTF_8); - mOutputStream.writeShort(Math.min(commentBytes.length, 0xffff)); - } else { - commentBytes = null; - mOutputStream.writeShort(0); - } - mOutputStream.writeShort(0); // starting disk number - mOutputStream.writeShort(0); // internal file attributes (unused) - mOutputStream.writeInt(0); // external file attributes (unused) - mOutputStream.writeInt(xentry.headerOffset); // relative offset of local header - mOutputStream.write(nameBytes); - if (entry.getExtra() != null) { - mOutputStream.write(entry.getExtra(), 0, entry.getExtra().length - xentry.padding); - } - if (commentBytes != null) { - mOutputStream.write(commentBytes, 0, Math.min(commentBytes.length, 0xffff)); - } - } - final long centralDirSize = mOutputStream.totalWritten - centralDirOffset; - - mOutputStream.writeInt(ZipFile.ENDSIG); // END record signature - mOutputStream.writeShort(0); // number of this disk - mOutputStream.writeShort(0); // central directory start disk - mOutputStream.writeShort(entryCount); // number of directory entries on disk - mOutputStream.writeShort(entryCount); // total number of directory entries - mOutputStream.writeInt(centralDirSize); // length of central directory - mOutputStream.writeInt(centralDirOffset); // offset of central directory - mOutputStream.writeShort(0); - mOutputStream.flush(); - } - - private void closeFiles() throws IOException { - try { - mZipFile.close(); - } finally { - try { - mRafInput.close(); - } finally { - mOutputStream.close(); - } - } - - } - - public static void align4(File inFile) throws IOException{ - align(inFile, ALIGNMENT_4); - } - public static void align4(File inFile, File outFile) throws IOException{ - align(inFile, outFile, ALIGNMENT_4); - } - public static void align(File inFile, int alignment) throws IOException{ - File tmp=toTmpFile(inFile); - tmp.delete(); - align(inFile, tmp, alignment); - inFile.delete(); - tmp.renameTo(inFile); - } - public static void align(File inFile, File outFile, int alignment) throws IOException{ - ZipAlign zipAlign=new ZipAlign(); - File dir=outFile.getParentFile(); - if(dir!=null && !dir.exists()){ - dir.mkdirs(); - } - zipAlign.zipAlign(inFile, outFile, alignment); - } - private static File toTmpFile(File file){ - String name=file.getName()+".align.tmp"; - File dir=file.getParentFile(); - if(dir==null){ - return new File(name); - } - return new File(dir, name); - } -} - diff --git a/src/ARSCLib/com/reandroid/archive/ZipArchive.java b/src/ARSCLib/com/reandroid/archive/ZipArchive.java deleted file mode 100644 index 80cc6bd5..00000000 --- a/src/ARSCLib/com/reandroid/archive/ZipArchive.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.zip.ZipFile; - -public class ZipArchive { - private final Map mEntriesMap; - public ZipArchive(Map entriesMap){ - this.mEntriesMap=entriesMap; - } - public ZipArchive(){ - this(new LinkedHashMap<>()); - } - - public int size(){ - return mEntriesMap.size(); - } - public void extract(File outDir) throws IOException { - for(InputSource inputSource:listInputSources()){ - extract(outDir, inputSource); - } - } - private void extract(File outDir, InputSource inputSource) throws IOException { - File file=toOutFile(outDir, inputSource.getAlias()); - File dir=file.getParentFile(); - if(dir!=null && !dir.exists()){ - dir.mkdirs(); - } - FileOutputStream outputStream=new FileOutputStream(file); - inputSource.write(outputStream); - outputStream.close(); - inputSource.disposeInputSource(); - } - private File toOutFile(File outDir, String path){ - path=path.replace('/', File.separatorChar); - return new File(outDir, path); - } - public void removeDir(String dirName){ - if(!dirName.endsWith("/")){ - dirName=dirName+"/"; - } - for(InputSource inputSource:listInputSources()){ - if(inputSource.getName().startsWith(dirName)){ - remove(inputSource.getName()); - } - } - } - public void removeAll(Pattern patternAlias){ - for(InputSource inputSource:listInputSources()){ - Matcher matcher = patternAlias.matcher(inputSource.getAlias()); - if(matcher.matches()){ - mEntriesMap.remove(inputSource.getName()); - } - } - } - public void clear(){ - mEntriesMap.clear(); - } - public int entriesCount(){ - return mEntriesMap.size(); - } - public InputSource remove(String name){ - InputSource inputSource=mEntriesMap.remove(name); - if(inputSource==null){ - return null; - } - return inputSource; - } - public void addArchive(File archiveFile) throws IOException { - ZipFile zipFile=new ZipFile(archiveFile); - add(zipFile); - } - public void addDirectory(File dir){ - addAll(InputSourceUtil.listDirectory(dir)); - } - public void add(ZipFile zipFile){ - List sourceList = InputSourceUtil.listZipFileSources(zipFile); - this.addAll(sourceList); - } - public void set(Collection inputSourceList){ - clear(); - addAll(inputSourceList); - } - public void addAll(Collection inputSourceList){ - for(InputSource inputSource:inputSourceList){ - add(inputSource); - } - } - public void add(InputSource inputSource){ - if(inputSource==null){ - return; - } - String name=inputSource.getName(); - Map map=mEntriesMap; - map.remove(name); - map.put(name, inputSource); - } - public List listInputSources(){ - return new ArrayList<>(mEntriesMap.values()); - } - public InputSource getInputSource(String name){ - return mEntriesMap.get(name); - } -} diff --git a/src/ARSCLib/com/reandroid/archive/ZipEntrySource.java b/src/ARSCLib/com/reandroid/archive/ZipEntrySource.java deleted file mode 100644 index 41bc0967..00000000 --- a/src/ARSCLib/com/reandroid/archive/ZipEntrySource.java +++ /dev/null @@ -1,36 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive; - -import java.io.IOException; -import java.io.InputStream; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -public class ZipEntrySource extends InputSource { - private final ZipFile zipFile; - private final ZipEntry zipEntry; - public ZipEntrySource(ZipFile zipFile, ZipEntry zipEntry){ - super(zipEntry.getName()); - this.zipFile=zipFile; - this.zipEntry=zipEntry; - super.setMethod(zipEntry.getMethod()); - } - @Override - public InputStream openStream() throws IOException { - return zipFile.getInputStream(zipEntry); - } -} diff --git a/src/ARSCLib/com/reandroid/archive/ZipSerializer.java b/src/ARSCLib/com/reandroid/archive/ZipSerializer.java deleted file mode 100644 index f462ecba..00000000 --- a/src/ARSCLib/com/reandroid/archive/ZipSerializer.java +++ /dev/null @@ -1,97 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive; - -import java.io.*; -import java.util.List; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -public class ZipSerializer { - private final List mSourceList; - private WriteProgress writeProgress; - private WriteInterceptor writeInterceptor; - public ZipSerializer(List sourceList){ - this.mSourceList=sourceList; - } - - public void setWriteInterceptor(WriteInterceptor writeInterceptor) { - this.writeInterceptor = writeInterceptor; - } - public void setWriteProgress(WriteProgress writeProgress){ - this.writeProgress=writeProgress; - } - public long writeZip(File outZip) throws IOException{ - File dir=outZip.getParentFile(); - if(dir!=null && !dir.exists()){ - dir.mkdirs(); - } - File tmp=toTmpFile(outZip); - FileOutputStream fileOutputStream=new FileOutputStream(tmp); - long length= writeZip(fileOutputStream); - fileOutputStream.close(); - outZip.delete(); - tmp.renameTo(outZip); - return length; - } - private File toTmpFile(File file){ - File dir=file.getParentFile(); - String name=file.getName()+".tmp"; - return new File(dir, name); - } - public long writeZip(OutputStream outputStream) throws IOException{ - long length=0; - WriteProgress progress=writeProgress; - ZipOutputStream zipOutputStream=new ZipOutputStream(outputStream); - for(InputSource inputSource:mSourceList){ - inputSource = interceptWrite(inputSource); - if(inputSource==null){ - continue; - } - if(progress!=null){ - progress.onCompressFile(inputSource.getAlias(), inputSource.getMethod(), length); - } - length+=write(zipOutputStream, inputSource); - zipOutputStream.closeEntry(); - inputSource.disposeInputSource(); - } - zipOutputStream.close(); - return length; - } - private long write(ZipOutputStream zipOutputStream, InputSource inputSource) throws IOException{ - ZipEntry zipEntry=createZipEntry(inputSource); - zipOutputStream.putNextEntry(zipEntry); - return inputSource.write(zipOutputStream); - } - private ZipEntry createZipEntry(InputSource inputSource) throws IOException { - String name=inputSource.getAlias(); - ZipEntry zipEntry=new ZipEntry(name); - int method = inputSource.getMethod(); - zipEntry.setMethod(method); - if(method==ZipEntry.STORED){ - zipEntry.setCrc(inputSource.getCrc()); - zipEntry.setSize(inputSource.getLength()); - } - return zipEntry; - } - private InputSource interceptWrite(InputSource inputSource){ - WriteInterceptor interceptor=writeInterceptor; - if(interceptor!=null){ - return interceptor.onWriteArchive(inputSource); - } - return inputSource; - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/Archive.java b/src/ARSCLib/com/reandroid/archive2/Archive.java deleted file mode 100644 index 295fa15b..00000000 --- a/src/ARSCLib/com/reandroid/archive2/Archive.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2; - -import com.reandroid.archive.APKArchive; -import com.reandroid.archive.InputSource; -import com.reandroid.archive2.block.*; -import com.reandroid.archive2.io.ArchiveEntrySource; -import com.reandroid.archive2.io.ZipFileInput; -import com.reandroid.archive2.io.ArchiveUtil; -import com.reandroid.archive2.io.ZipInput; -import com.reandroid.archive2.model.LocalFileDirectory; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.zip.Inflater; -import java.util.zip.InflaterInputStream; -import java.util.zip.ZipEntry; - -public class Archive { - private final ZipInput zipInput; - private final List entryList; - private final EndRecord endRecord; - private final ApkSignatureBlock apkSignatureBlock; - public Archive(ZipInput zipInput) throws IOException { - this.zipInput = zipInput; - LocalFileDirectory lfd = new LocalFileDirectory(); - lfd.visit(zipInput); - List localFileHeaderList = lfd.getHeaderList(); - List centralEntryHeaderList = lfd.getCentralFileDirectory().getHeaderList(); - List entryList = new ArrayList<>(localFileHeaderList.size()); - for(int i=0;i mapEntrySource(){ - Map map = new LinkedHashMap<>(); - ZipInput zipInput = this.zipInput; - List entryList = this.entryList; - for(int i=0; i getEntryList() { - return entryList; - } - - public ApkSignatureBlock getApkSignatureBlock() { - return apkSignatureBlock; - } - public EndRecord getEndRecord() { - return endRecord; - } - - // for test - public void extract(File dir) throws IOException { - for(ArchiveEntry archiveEntry:getEntryList()){ - if(archiveEntry.isDirectory()){ - continue; - } - extract(dir, archiveEntry); - } - } - private void extract(File dir, ArchiveEntry archiveEntry) throws IOException{ - File out = toFile(dir, archiveEntry); - File parent = out.getParentFile(); - if(!parent.exists()){ - parent.mkdirs(); - } - FileOutputStream outputStream = new FileOutputStream(out); - ArchiveUtil.writeAll(openInputStream(archiveEntry), outputStream); - outputStream.close(); - } - private File toFile(File dir, ArchiveEntry archiveEntry){ - String name = archiveEntry.getName().replace('/', File.separatorChar); - return new File(dir, name); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/ArchiveEntry.java b/src/ARSCLib/com/reandroid/archive2/ArchiveEntry.java deleted file mode 100644 index e6856b55..00000000 --- a/src/ARSCLib/com/reandroid/archive2/ArchiveEntry.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2; - -import com.reandroid.archive2.block.CentralEntryHeader; -import com.reandroid.archive2.block.LocalFileHeader; -import com.reandroid.arsc.util.HexUtil; - -import java.util.zip.ZipEntry; - -public class ArchiveEntry extends ZipEntry { - private final CentralEntryHeader centralEntryHeader; - private final LocalFileHeader localFileHeader; - public ArchiveEntry(LocalFileHeader lfh, CentralEntryHeader ceh){ - super(lfh.getFileName()); - this.localFileHeader = lfh; - this.centralEntryHeader = ceh; - } - public ArchiveEntry(String name){ - this(new LocalFileHeader(name), new CentralEntryHeader(name)); - } - public ArchiveEntry(){ - this(new LocalFileHeader(), new CentralEntryHeader()); - } - - public long getDataSize(){ - if(getMethod() == ZipEntry.STORED){ - return getSize(); - } - return getCompressedSize(); - } - - @Override - public int getMethod(){ - return localFileHeader.getMethod(); - } - @Override - public void setMethod(int method){ - localFileHeader.setMethod(method); - centralEntryHeader.setMethod(method); - } - @Override - public long getSize() { - return centralEntryHeader.getSize(); - } - @Override - public void setSize(long size) { - centralEntryHeader.setSize(size); - localFileHeader.setSize(size); - } - @Override - public long getCrc() { - return centralEntryHeader.getCrc(); - } - @Override - public void setCrc(long crc) { - centralEntryHeader.setCrc(crc); - localFileHeader.setCrc(crc); - } - @Override - public long getCompressedSize() { - return centralEntryHeader.getCompressedSize(); - } - @Override - public void setCompressedSize(long csize) { - centralEntryHeader.setCompressedSize(csize); - localFileHeader.setCompressedSize(csize); - } - public long getFileOffset() { - return localFileHeader.getFileOffset(); - } - @Override - public String getName(){ - return centralEntryHeader.getFileName(); - } - public void setName(String name){ - centralEntryHeader.setFileName(name); - localFileHeader.setFileName(name); - } - @Override - public String getComment(){ - return centralEntryHeader.getComment(); - } - @Override - public void setComment(String name){ - centralEntryHeader.setComment(name); - } - @Override - public boolean isDirectory() { - return this.getName().endsWith("/"); - } - public CentralEntryHeader getCentralEntryHeader(){ - return centralEntryHeader; - } - public LocalFileHeader getLocalFileHeader() { - return localFileHeader; - } - public boolean matches(CentralEntryHeader centralEntryHeader){ - if(centralEntryHeader==null){ - return false; - } - return false; - } - - @Override - public String toString(){ - return "["+ getFileOffset()+"] " + getName() + getComment() - + HexUtil.toHex(" 0x", getCrc(), 8); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/ZipSignature.java b/src/ARSCLib/com/reandroid/archive2/ZipSignature.java deleted file mode 100644 index c9526dde..00000000 --- a/src/ARSCLib/com/reandroid/archive2/ZipSignature.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2; - -public enum ZipSignature { - CENTRAL_FILE(0X02014B50), - LOCAL_FILE(0X04034B50), - DATA_DESCRIPTOR(0X08074B50), - END_RECORD(0X06054B50); - - private final int value; - - ZipSignature(int value){ - this.value = value; - } - public int getValue() { - return value; - } - public static ZipSignature valueOf(int value){ - for(ZipSignature signature:VALUES){ - if(value == signature.getValue()){ - return signature; - } - } - return null; - } - private static final ZipSignature[] VALUES = values(); -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/ApkSignatureBlock.java b/src/ARSCLib/com/reandroid/archive2/block/ApkSignatureBlock.java deleted file mode 100644 index 4c2c2898..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/ApkSignatureBlock.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block; - - -import com.reandroid.archive2.block.pad.SchemePadding; -import com.reandroid.arsc.io.BlockReader; - -import java.io.File; -import java.io.FileFilter; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; - -public class ApkSignatureBlock extends LengthPrefixedList - implements Comparator { - public ApkSignatureBlock(SignatureFooter signatureFooter){ - super(true); - setBottomBlock(signatureFooter); - } - public ApkSignatureBlock(){ - this(new SignatureFooter()); - } - public List getSignatures(){ - return super.getElements(); - } - public int countSignatures(){ - return super.getElementsCount(); - } - public void sortSignatures(){ - sort(this); - } - public void updatePadding(){ - SchemePadding schemePadding = getOrCreateSchemePadding(); - schemePadding.setPadding(0); - sortSignatures(); - refresh(); - int size = countBytes(); - int alignment = 4096; - int padding = (alignment - (size % alignment)) % alignment; - schemePadding.setPadding(padding); - refresh(); - } - private SchemePadding getOrCreateSchemePadding(){ - SignatureInfo signatureInfo = getSignature(SignatureId.PADDING); - if(signatureInfo == null){ - signatureInfo = new SignatureInfo(); - signatureInfo.setId(SignatureId.PADDING); - signatureInfo.setSignatureScheme(new SchemePadding()); - add(signatureInfo); - } - SignatureScheme scheme = signatureInfo.getSignatureScheme(); - if(!(scheme instanceof SchemePadding)){ - scheme = new SchemePadding(); - signatureInfo.setSignatureScheme(scheme); - } - return (SchemePadding) scheme; - } - public SignatureInfo getSignature(SignatureId signatureId){ - for(SignatureInfo signatureInfo:getSignatures()){ - if(signatureInfo.getId().equals(signatureId)){ - return signatureInfo; - } - } - return null; - } - public SignatureFooter getSignatureFooter(){ - return (SignatureFooter) getBottomBlock(); - } - @Override - public SignatureInfo newInstance() { - return new SignatureInfo(); - } - @Override - protected void onRefreshed(){ - SignatureFooter footer = getSignatureFooter(); - footer.updateMagic(); - super.onRefreshed(); - footer.setSignatureSize(getDataSize()); - } - - public void writeRaw(File file) throws IOException{ - refresh(); - File dir = file.getParentFile(); - if(dir != null && !dir.exists()){ - dir.mkdirs(); - } - FileOutputStream outputStream = new FileOutputStream(file); - writeBytes(outputStream); - outputStream.close(); - } - public List writeSplitRawToDirectory(File dir) throws IOException{ - refresh(); - List signatureInfoList = getElements(); - List writtenFiles = new ArrayList<>(signatureInfoList.size()); - for(SignatureInfo signatureInfo:signatureInfoList){ - File file = signatureInfo.writeRawToDirectory(dir); - writtenFiles.add(file); - } - return writtenFiles; - } - public void read(File file) throws IOException { - super.readBytes(new BlockReader(file)); - } - public void scanSplitFiles(File dir) throws IOException { - if(!dir.isDirectory()){ - throw new IOException("No such directory"); - } - FileFilter filter = new FileFilter() { - @Override - public boolean accept(File file) { - if(!file.isFile()){ - return false; - } - String name = file.getName().toLowerCase(); - return name.endsWith(SignatureId.FILE_EXT_RAW); - } - }; - File[] files = dir.listFiles(filter); - if(files == null){ - return; - } - for(File file:files){ - addSplitRaw(file); - } - sortSignatures(); - } - public SignatureInfo addSplitRaw(File signatureInfoFile) throws IOException { - SignatureInfo signatureInfo = new SignatureInfo(); - signatureInfo.read(signatureInfoFile); - add(signatureInfo); - return signatureInfo; - } - @Override - public int compare(SignatureInfo info1, SignatureInfo info2) { - return info1.getId().compareTo(info2.getId()); - } - - public static final String FILE_EXT = ".sig"; -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/BottomBlock.java b/src/ARSCLib/com/reandroid/archive2/block/BottomBlock.java deleted file mode 100644 index 2ae5aeaf..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/BottomBlock.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block; - -import com.reandroid.arsc.container.BlockList; -import com.reandroid.arsc.io.BlockReader; - -import java.io.IOException; - -// General purpose block to consume the remaining bytes of BlockReader -public class BottomBlock extends BlockList { - public BottomBlock(){ - super(); - } - @Override - public void onReadBytes(BlockReader reader) throws IOException { - while (reader.isAvailable()){ - LengthPrefixedBytes prefixedBytes = new LengthPrefixedBytes(false); - prefixedBytes.readBytes(reader); - this.add(prefixedBytes); - } - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/CentralEntryHeader.java b/src/ARSCLib/com/reandroid/archive2/block/CentralEntryHeader.java deleted file mode 100644 index 1a6b7c07..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/CentralEntryHeader.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block; - -import com.reandroid.archive2.ZipSignature; -import com.reandroid.arsc.util.HexUtil; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Objects; - -public class CentralEntryHeader extends CommonHeader { - private String mComment; - public CentralEntryHeader(){ - super(OFFSET_fileName, ZipSignature.CENTRAL_FILE, OFFSET_general_purpose); - } - public CentralEntryHeader(String name){ - this(); - setFileName(name); - } - - @Override - int readComment(InputStream inputStream) throws IOException { - int commentLength = getCommentLength(); - if(commentLength==0){ - mComment = ""; - return 0; - } - setCommentLength(commentLength); - byte[] bytes = getBytesInternal(); - int read = inputStream.read(bytes, getOffsetComment(), commentLength); - if(read != commentLength){ - throw new IOException("Stream ended before reading comment: read=" - +read+", name length="+commentLength); - } - mComment = null; - return commentLength; - } - - public int getVersionExtract(){ - return getShortUnsigned(OFFSET_versionExtract); - } - public void setVersionExtract(int value){ - putShort(OFFSET_versionExtract, value); - } - public String getComment(){ - if(mComment == null){ - mComment = decodeComment(); - } - return mComment; - } - public void setComment(String comment){ - if(comment==null){ - comment=""; - } - byte[] strBytes = ZipStringEncoding.encodeString(isUtf8(), comment); - int length = strBytes.length; - setCommentLength(length); - if(length==0){ - mComment = comment; - return; - } - byte[] bytes = getBytesInternal(); - System.arraycopy(strBytes, 0, bytes, getOffsetComment(), length); - mComment = comment; - } - - - @Override - public int getCommentLength(){ - return getShortUnsigned(OFFSET_commentLength); - } - public void setCommentLength(int value){ - int length = getOffsetComment() + value; - setBytesLength(length, false); - putShort(OFFSET_commentLength, value); - } - public long getLocalRelativeOffset(){ - return getIntegerUnsigned(OFFSET_localRelativeOffset); - } - public void setLocalRelativeOffset(long offset){ - putInteger(OFFSET_localRelativeOffset, offset); - } - @Override - void onUtf8Changed(boolean oldValue){ - String str = mComment; - if(str != null){ - setComment(str); - } - } - - public boolean matches(LocalFileHeader localFileHeader){ - if(localFileHeader==null){ - return false; - } - return getCrc() == localFileHeader.getCrc() - && Objects.equals(getFileName(), localFileHeader.getFileName()); - } - - @Override - public String toString(){ - if(countBytes()0){ - builder.append("name=").append(str); - appendOnce = true; - } - str = getComment(); - if(str.length()>0){ - if(appendOnce){ - builder.append(", "); - } - builder.append("comment=").append(str); - appendOnce = true; - } - if(appendOnce){ - builder.append(", "); - } - builder.append("SIG=").append(getSignature()); - builder.append(", versionMadeBy=").append(HexUtil.toHex4((short) getVersionMadeBy())); - builder.append(", versionExtract=").append(HexUtil.toHex4((short) getVersionExtract())); - builder.append(", GP={").append(getGeneralPurposeFlag()).append("}"); - builder.append(", method=").append(getMethod()); - builder.append(", date=").append(getDate()); - builder.append(", crc=").append(HexUtil.toHex8(getCrc())); - builder.append(", cSize=").append(getCompressedSize()); - builder.append(", size=").append(getSize()); - builder.append(", fileNameLength=").append(getFileNameLength()); - builder.append(", extraLength=").append(getExtraLength()); - builder.append(", commentLength=").append(getCommentLength()); - builder.append(", offset=").append(getLocalRelativeOffset()); - return builder.toString(); - } - - - public static CentralEntryHeader fromLocalFileHeader(LocalFileHeader lfh){ - CentralEntryHeader ceh = new CentralEntryHeader(); - ceh.setSignature(ZipSignature.CENTRAL_FILE); - ceh.setVersionMadeBy(0x0300); - long offset = lfh.getFileOffset() - lfh.countBytes(); - ceh.setLocalRelativeOffset(offset); - ceh.getGeneralPurposeFlag().setValue(lfh.getGeneralPurposeFlag().getValue()); - ceh.setMethod(lfh.getMethod()); - ceh.setDosTime(lfh.getDosTime()); - ceh.setCrc(lfh.getCrc()); - ceh.setCompressedSize(lfh.getCompressedSize()); - ceh.setSize(lfh.getSize()); - ceh.setFileName(lfh.getFileName()); - ceh.setExtra(lfh.getExtra()); - return ceh; - } - private static final int OFFSET_signature = 0; - private static final int OFFSET_versionMadeBy = 4; - private static final int OFFSET_versionExtract = 6; - private static final int OFFSET_general_purpose = 8; - private static final int OFFSET_method = 10; - private static final int OFFSET_dos_time = 12; - private static final int OFFSET_dos_date = 14; - private static final int OFFSET_crc = 16; - private static final int OFFSET_compressed_size = 20; - private static final int OFFSET_size = 24; - private static final int OFFSET_fileNameLength = 28; - private static final int OFFSET_extraLength = 30; - private static final int OFFSET_commentLength = 32; - private static final int OFFSET_diskStart = 34; - private static final int OFFSET_internalFileAttributes = 36; - private static final int OFFSET_externalFileAttributes = 38; - private static final int OFFSET_localRelativeOffset = 42; - private static final int OFFSET_fileName = 46; - -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/CertificateBlock.java b/src/ARSCLib/com/reandroid/archive2/block/CertificateBlock.java deleted file mode 100644 index 1894f70e..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/CertificateBlock.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block; - -import java.io.ByteArrayInputStream; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; - -public class CertificateBlock extends LengthPrefixedBytes{ - public CertificateBlock() { - super(false); - } - - public X509Certificate getCertificate(){ - return generateCertificate(getByteArray().toArray()); - } - public static X509Certificate generateCertificate(byte[] encodedForm){ - CertificateFactory factory = getCertFactory(); - if(factory == null){ - return null; - } - try{ - // TODO: cert bytes could be in DER format ? - return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(encodedForm)); - }catch (CertificateException ignored){ - return null; - } - } - private static CertificateFactory getCertFactory() { - if (sCertFactory == null) { - try { - sCertFactory = CertificateFactory.getInstance("X.509"); - } catch (CertificateException ignored) { - } - } - return sCertFactory; - } - - private static CertificateFactory sCertFactory = null; -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/CertificateBlockList.java b/src/ARSCLib/com/reandroid/archive2/block/CertificateBlockList.java deleted file mode 100644 index 958cf13f..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/CertificateBlockList.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block; - - -public class CertificateBlockList extends LengthPrefixedList{ - public CertificateBlockList() { - super(false); - } - @Override - public CertificateBlock newInstance() { - return new CertificateBlock(); - } - -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/CommonHeader.java b/src/ARSCLib/com/reandroid/archive2/block/CommonHeader.java deleted file mode 100644 index db31b279..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/CommonHeader.java +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block; - -import com.reandroid.archive2.ZipSignature; -import com.reandroid.arsc.util.HexUtil; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.zip.ZipEntry; - -public abstract class CommonHeader extends ZipHeader { - private final int offsetFileName; - private final int offsetGeneralPurpose; - private final GeneralPurposeFlag generalPurposeFlag; - private String mFileName; - private long mFileOffset; - public CommonHeader(int offsetFileName, ZipSignature expectedSignature, int offsetGeneralPurpose){ - super(offsetFileName, expectedSignature); - this.offsetFileName = offsetFileName; - this.offsetGeneralPurpose = offsetGeneralPurpose; - this.generalPurposeFlag = new GeneralPurposeFlag(this, offsetGeneralPurpose); - } - public long getFileOffset() { - return mFileOffset; - } - public void setFileOffset(long fileOffset){ - this.mFileOffset = fileOffset; - } - public long getDataSize(){ - if(getMethod() == ZipEntry.STORED){ - return getSize(); - } - return getCompressedSize(); - } - public void setDataSize(long size){ - if(getMethod() == ZipEntry.STORED){ - setSize(size); - } - setCompressedSize(size); - } - - @Override - int readNext(InputStream inputStream) throws IOException { - int read = 0; - read += readFileName(inputStream); - read += readExtra(inputStream); - read += readComment(inputStream); - mFileName = null; - return read; - } - private int readFileName(InputStream inputStream) throws IOException { - int fileNameLength = getFileNameLength(); - if(fileNameLength==0){ - mFileName = ""; - return 0; - } - setFileNameLength(fileNameLength); - byte[] bytes = getBytesInternal(); - int read = inputStream.read(bytes, offsetFileName, fileNameLength); - if(read != fileNameLength){ - throw new IOException("Stream ended before reading file name: read=" - +read+", name length="+fileNameLength); - } - mFileName = null; - return fileNameLength; - } - private int readExtra(InputStream inputStream) throws IOException { - int extraLength = getExtraLength(); - if(extraLength==0){ - return 0; - } - setExtraLength(extraLength); - byte[] bytes = getBytesInternal(); - int offset = getOffsetExtra(); - int read = inputStream.read(bytes, offset, extraLength); - if(read != extraLength){ - throw new IOException("Stream ended before reading extra bytes: read=" - + read +", extra length="+extraLength); - } - return extraLength; - } - int readComment(InputStream inputStream) throws IOException { - return 0; - } - public int getVersionMadeBy(){ - return getShortUnsigned(OFFSET_versionMadeBy); - } - public void setVersionMadeBy(int value){ - putShort(OFFSET_versionMadeBy, value); - } - public int getPlatform(){ - return getByteUnsigned(OFFSET_platform); - } - public void setPlatform(int value){ - getBytesInternal()[OFFSET_platform] = (byte) value; - } - public GeneralPurposeFlag getGeneralPurposeFlag() { - return generalPurposeFlag; - } - public int getMethod(){ - return getShortUnsigned(offsetGeneralPurpose + 2); - } - public void setMethod(int value){ - putShort(offsetGeneralPurpose + 2, value); - GeneralPurposeFlag gpf = getGeneralPurposeFlag(); - //gpf.setHasDataDescriptor(value != ZipEntry.STORED); - } - public long getDosTime(){ - return getIntegerUnsigned(offsetGeneralPurpose + 4); - } - public void setDosTime(long value){ - putInteger(offsetGeneralPurpose + 4, value); - } - public Date getDate(){ - return dosToJavaDate(getDosTime()); - } - public void setDate(Date date){ - setDate(date==null ? 0L : date.getTime()); - } - public void setDate(long date){ - setDosTime(javaToDosTime(date)); - } - public long getCrc(){ - return getIntegerUnsigned(offsetGeneralPurpose + 8); - } - public void setCrc(long value){ - putInteger(offsetGeneralPurpose + 8, value); - } - public long getCompressedSize(){ - return getIntegerUnsigned(offsetGeneralPurpose + 12); - } - public void setCompressedSize(long value){ - putInteger(offsetGeneralPurpose + 12, value); - } - public long getSize(){ - return getIntegerUnsigned(offsetGeneralPurpose + 16); - } - public void setSize(long value){ - putInteger(offsetGeneralPurpose + 16, value); - } - public int getFileNameLength(){ - return getShortUnsigned(offsetGeneralPurpose + 20); - } - private void setFileNameLength(int value){ - int length = offsetFileName + value + getExtraLength() + getCommentLength(); - super.setBytesLength(length, false); - putShort(offsetGeneralPurpose + 20, value); - } - public int getExtraLength(){ - return getShortUnsigned(offsetGeneralPurpose + 22); - } - public void setExtraLength(int value){ - int length = offsetFileName + getFileNameLength() + value + getCommentLength(); - super.setBytesLength(length, false); - putShort(offsetGeneralPurpose + 22, value); - } - public byte[] getExtra(){ - int length = getExtraLength(); - byte[] result = new byte[length]; - if(length==0){ - return result; - } - byte[] bytes = getBytesInternal(); - int offset = getOffsetExtra(); - System.arraycopy(bytes, offset, result, 0, length); - return result; - } - public void setExtra(byte[] extra){ - if(extra == null){ - extra = new byte[0]; - } - int length = extra.length; - setExtraLength(length); - if(length == 0){ - return; - } - putBytes(extra, 0, getOffsetExtra(), length); - } - public int getCommentLength(){ - return 0; - } - int getOffsetComment(){ - return offsetFileName + getFileNameLength() + getExtraLength(); - } - private int getOffsetExtra(){ - return offsetFileName + getFileNameLength(); - } - - public String getFileName(){ - if(mFileName == null){ - mFileName = decodeFileName(); - } - return mFileName; - } - public void setFileName(String fileName){ - if(fileName==null){ - fileName=""; - } - byte[] nameBytes; - if(getGeneralPurposeFlag().getUtf8()){ - nameBytes = fileName.getBytes(StandardCharsets.UTF_8); - }else { - nameBytes = fileName.getBytes(); - } - int length = nameBytes.length; - setFileNameLength(length); - if(length==0){ - mFileName = fileName; - return; - } - byte[] bytes = getBytesInternal(); - System.arraycopy(nameBytes, 0, bytes, offsetFileName, length); - mFileName = fileName; - } - public boolean isUtf8(){ - return getGeneralPurposeFlag().getUtf8(); - } - public boolean hasDataDescriptor(){ - return getGeneralPurposeFlag().hasDataDescriptor(); - } - private String decodeFileName(){ - int length = getFileNameLength(); - byte[] bytes = getBytesInternal(); - int offset = offsetFileName; - int max = bytes.length - offset; - if(max<=0){ - return ""; - } - if(length>max){ - length = max; - } - return ZipStringEncoding.decode(getGeneralPurposeFlag().getUtf8(), - getBytesInternal(), offset, length); - } - public String decodeComment(){ - int length = getExtraLength(); - byte[] bytes = getBytesInternal(); - int offset = getOffsetExtra(); - int max = bytes.length - offset; - if(max<=0){ - return ""; - } - if(length>max){ - length = max; - } - return ZipStringEncoding.decode(getGeneralPurposeFlag().getUtf8(), - getBytesInternal(), offset, length); - } - void onUtf8Changed(boolean oldValue){ - String str = mFileName; - if(str != null){ - setFileName(str); - } - } - - @Override - public String toString(){ - if(countBytes()0){ - builder.append("name=").append(str); - appendOnce = true; - } - if(appendOnce){ - builder.append(", "); - } - builder.append("SIG=").append(getSignature()); - builder.append(", versionMadeBy=").append(HexUtil.toHex4((short) getVersionMadeBy())); - builder.append(", platform=").append(HexUtil.toHex2((byte) getPlatform())); - builder.append(", GP={").append(getGeneralPurposeFlag()).append("}"); - builder.append(", method=").append(getMethod()); - builder.append(", date=").append(getDate()); - builder.append(", crc=").append(HexUtil.toHex8(getCrc())); - builder.append(", cSize=").append(getCompressedSize()); - builder.append(", size=").append(getSize()); - builder.append(", fileNameLength=").append(getFileNameLength()); - builder.append(", extraLength=").append(getExtraLength()); - return builder.toString(); - } - - private static Date dosToJavaDate(final long dosTime) { - final Calendar cal = Calendar.getInstance(); - cal.set(Calendar.YEAR, (int) ((dosTime >> 25) & 0x7f) + 1980); - cal.set(Calendar.MONTH, (int) ((dosTime >> 21) & 0x0f) - 1); - cal.set(Calendar.DATE, (int) (dosTime >> 16) & 0x1f); - cal.set(Calendar.HOUR_OF_DAY, (int) (dosTime >> 11) & 0x1f); - cal.set(Calendar.MINUTE, (int) (dosTime >> 5) & 0x3f); - cal.set(Calendar.SECOND, (int) (dosTime << 1) & 0x3e); - cal.set(Calendar.MILLISECOND, 0); - return cal.getTime(); - } - private static long javaToDosTime(long javaTime) { - int date; - int time; - GregorianCalendar cal = new GregorianCalendar(); - cal.setTime(new Date(javaTime)); - int year = cal.get(Calendar.YEAR); - if (year < 1980) { - date = 0x21; - time = 0; - } else { - date = cal.get(Calendar.DATE); - date = (cal.get(Calendar.MONTH) + 1 << 5) | date; - date = ((cal.get(Calendar.YEAR) - 1980) << 9) | date; - time = cal.get(Calendar.SECOND) >> 1; - time = (cal.get(Calendar.MINUTE) << 5) | time; - time = (cal.get(Calendar.HOUR_OF_DAY) << 11) | time; - } - return ((long) date << 16) | time; - } - - public static class GeneralPurposeFlag { - private final CommonHeader localFileHeader; - private final int offset; - public GeneralPurposeFlag(CommonHeader commonHeader, int offset){ - this.localFileHeader = commonHeader; - this.offset = offset; - } - - public boolean getEncryption(){ - return this.localFileHeader.getBit(offset, 0); - } - public void setEncryption(boolean flag){ - this.localFileHeader.putBit(offset, 0, flag); - } - public boolean hasDataDescriptor(){ - return this.localFileHeader.getBit(offset, 3); - } - public void setHasDataDescriptor(boolean flag){ - this.localFileHeader.putBit(offset, 3, flag); - } - public boolean getStrongEncryption(){ - return this.localFileHeader.getBit(offset, 6); - } - public void setStrongEncryption(boolean flag){ - this.localFileHeader.putBit(offset, 6, flag); - } - public boolean getUtf8(){ - return this.localFileHeader.getBit(offset + 1, 3); - } - public void setUtf8(boolean flag){ - setUtf8(flag, true); - } - private void setUtf8(boolean flag, boolean notify){ - boolean oldUtf8 = getUtf8(); - if(oldUtf8 == flag){ - return; - } - this.localFileHeader.putBit(offset +1, 3, flag); - if(notify){ - this.localFileHeader.onUtf8Changed(oldUtf8); - } - } - - public int getValue(){ - return this.localFileHeader.getShortUnsigned(offset); - } - public void setValue(int value){ - if(value == getValue()){ - return; - } - boolean oldUtf8 = getUtf8(); - this.localFileHeader.putShort(offset, value); - if(oldUtf8 != getUtf8()){ - this.localFileHeader.onUtf8Changed(oldUtf8); - } - } - public void initDefault(){ - setUtf8(false, false); - } - - @Override - public String toString(){ - return "Enc="+ getEncryption() - +", Descriptor="+ hasDataDescriptor() - +", StrongEnc="+ getStrongEncryption() - +", UTF8="+ getUtf8(); - } - } - - private static final int OFFSET_versionMadeBy = 4; - private static final int OFFSET_platform = 5; - - private static final int OFFSET_general_purpose = 6; - - private static final int OFFSET_method = 8; - private static final int OFFSET_dos_time = 10; - private static final int OFFSET_crc = 14; - private static final int OFFSET_compressed_size = 18; - private static final int OFFSET_size = 22; - private static final int OFFSET_fileNameLength = 26; - private static final int OFFSET_extraLength = 28; - - private static final int OFFSET_fileName = 30; - -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/DataDescriptor.java b/src/ARSCLib/com/reandroid/archive2/block/DataDescriptor.java deleted file mode 100644 index 2aa0cf2a..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/DataDescriptor.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block; - -import com.reandroid.archive2.ZipSignature; -import com.reandroid.arsc.util.HexUtil; - -public class DataDescriptor extends ZipHeader{ - public DataDescriptor() { - super(MIN_LENGTH, ZipSignature.DATA_DESCRIPTOR); - } - public long getCrc(){ - return getIntegerUnsigned(OFFSET_crc); - } - public void setCrc(long value){ - putInteger(OFFSET_crc, value); - } - public long getCompressedSize(){ - return getIntegerUnsigned(OFFSET_compressed_size); - } - public void setCompressedSize(long value){ - putInteger(OFFSET_compressed_size, value); - } - public long getSize(){ - return getIntegerUnsigned(OFFSET_size); - } - public void setSize(long value){ - putInteger(OFFSET_size, value); - } - - @Override - public String toString(){ - StringBuilder builder = new StringBuilder(); - builder.append(getSignature()); - builder.append(", crc=").append(HexUtil.toHex8(getCrc())); - builder.append(", compressed=").append(getCompressedSize()); - builder.append(", size=").append(getSize()); - return builder.toString(); - } - public static DataDescriptor fromLocalFile(LocalFileHeader lfh){ - DataDescriptor dataDescriptor = new DataDescriptor(); - dataDescriptor.setSignature(ZipSignature.DATA_DESCRIPTOR); - dataDescriptor.setSize(lfh.getSize()); - dataDescriptor.setCompressedSize(lfh.getCompressedSize()); - dataDescriptor.setCrc(lfh.getCrc()); - return dataDescriptor; - } - - private static final int OFFSET_crc = 4; - private static final int OFFSET_compressed_size = 8; - private static final int OFFSET_size = 12; - - public static final int MIN_LENGTH = 16; -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/EndRecord.java b/src/ARSCLib/com/reandroid/archive2/block/EndRecord.java deleted file mode 100644 index 49a4c0ff..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/EndRecord.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block; - -import com.reandroid.archive2.ZipSignature; -import com.reandroid.arsc.util.HexUtil; - -public class EndRecord extends ZipHeader{ - public EndRecord() { - super(MIN_LENGTH, ZipSignature.END_RECORD); - } - public int getNumberOfDisk(){ - return getShortUnsigned(OFFSET_numberOfDisk); - } - public void setNumberOfDisk(int value){ - putShort(OFFSET_numberOfDisk, value); - } - public int getCentralDirectoryStartDisk(){ - return getShortUnsigned(OFFSET_centralDirectoryStartDisk); - } - public void setCentralDirectoryStartDisk(int value){ - putShort(OFFSET_centralDirectoryStartDisk, value); - } - public int getNumberOfDirectories(){ - return getShortUnsigned(OFFSET_numberOfDirectories); - } - public void setNumberOfDirectories(int value){ - putShort(OFFSET_numberOfDirectories, value); - } - public int getTotalNumberOfDirectories(){ - return getShortUnsigned(OFFSET_totalNumberOfDirectories); - } - public void setTotalNumberOfDirectories(int value){ - putShort(OFFSET_totalNumberOfDirectories, value); - } - public long getLengthOfCentralDirectory(){ - return getIntegerUnsigned(OFFSET_lengthOfCentralDirectory); - } - public void setLengthOfCentralDirectory(long value){ - putInteger(OFFSET_lengthOfCentralDirectory, value); - } - public long getOffsetOfCentralDirectory(){ - return getIntegerUnsigned(OFFSET_offsetOfCentralDirectory); - } - public void setOffsetOfCentralDirectory(int value){ - putInteger(OFFSET_offsetOfCentralDirectory, value); - } - public int getLastShort(){ - return getShortUnsigned(OFFSET_lastShort); - } - public void getLastShort(int value){ - putShort(OFFSET_lastShort, value); - } - - - @Override - public String toString(){ - if(countBytes() extends FixedBlockContainer - implements BlockCreator { - private final Block numberBlock; - private final BlockList elements; - private final SingleBlockContainer bottomContainer; - public LengthPrefixedList(boolean is_long){ - super(3); - Block numberBlock; - if(is_long){ - numberBlock = new LongItem(); - }else { - numberBlock = new IntegerItem(); - } - this.numberBlock = numberBlock; - this.elements = new BlockList<>(); - this.bottomContainer = new SingleBlockContainer<>(); - addChild(0, this.numberBlock); - addChild(1, this.elements); - addChild(2, this.bottomContainer); - } - public long getDataSize(){ - Block numberBlock = this.numberBlock; - if(numberBlock instanceof LongItem){ - return ((LongItem)numberBlock).get(); - } - return ((IntegerItem)numberBlock).get(); - } - public void setDataSize(long dataSize){ - Block numberBlock = this.numberBlock; - if(numberBlock instanceof LongItem){ - ((LongItem)numberBlock).set(dataSize); - }else { - ((IntegerItem)numberBlock).set((int) dataSize); - } - } - public int getElementsCount(){ - return getElements().size(); - } - public List getElements() { - return elements.getChildes(); - } - public T add(T element){ - this.elements.add(element); - return element; - } - public boolean remove(T element){ - return this.elements.remove(element); - } - public void sort(Comparator comparator){ - this.elements.sort(comparator); - } - @Override - public void onReadBytes(BlockReader reader) throws IOException{ - if(!reader.isAvailable()){ - return; - } - numberBlock.readBytes(reader); - int totalSize = (int) getDataSize(); - if(totalSize <= 0){ - return; - } - BlockReader chunkReader = reader.create(totalSize); - readElements(chunkReader); - bottomContainer.readBytes(chunkReader); - reader.offset(totalSize); - } - private void readElements(BlockReader reader) throws IOException{ - int preserve = bottomContainer.countBytes() + 4; - while (reader.available() > preserve){ - int position = reader.getPosition(); - T element = newInstance(); - element = add(element); - element.readBytes(reader); - if(position == reader.getPosition()){ - break; - } - } - } - @Override - protected void onRefreshed(){ - int size = countBytes() - numberBlock.countBytes(); - setDataSize(size); - } - public Block getBottomBlock(){ - return bottomContainer.getItem(); - } - public void setBottomBlock(Block block){ - bottomContainer.setItem(block); - } - - - @Override - public String toString(){ - return "size=" + numberBlock + ", count=" + getElementsCount(); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/LocalFileHeader.java b/src/ARSCLib/com/reandroid/archive2/block/LocalFileHeader.java deleted file mode 100644 index f7fa7c09..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/LocalFileHeader.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block; - -import com.reandroid.archive2.ZipSignature; - -import java.io.IOException; -import java.io.InputStream; - -public class LocalFileHeader extends CommonHeader { - private DataDescriptor dataDescriptor; - public LocalFileHeader(){ - super(OFFSET_fileName, ZipSignature.LOCAL_FILE, OFFSET_general_purpose); - } - public LocalFileHeader(String name){ - this(); - setFileName(name); - } - - public void mergeZeroValues(CentralEntryHeader ceh){ - if(getCrc()==0){ - setCrc(ceh.getCrc()); - } - if(getSize()==0){ - setSize(ceh.getSize()); - } - if(getCompressedSize()==0){ - setCompressedSize(ceh.getCompressedSize()); - } - if(getGeneralPurposeFlag().getValue()==0){ - getGeneralPurposeFlag().setValue(ceh.getGeneralPurposeFlag().getValue()); - } - } - - public DataDescriptor getDataDescriptor() { - return dataDescriptor; - } - public void setDataDescriptor(DataDescriptor dataDescriptor){ - this.dataDescriptor = dataDescriptor; - getGeneralPurposeFlag().setHasDataDescriptor(dataDescriptor!=null); - } - - public static LocalFileHeader fromCentralEntryHeader(CentralEntryHeader ceh){ - LocalFileHeader lfh = new LocalFileHeader(); - lfh.setSignature(ZipSignature.LOCAL_FILE); - lfh.setVersionMadeBy(ceh.getVersionMadeBy()); - lfh.getGeneralPurposeFlag().setValue(ceh.getGeneralPurposeFlag().getValue()); - lfh.setMethod(ceh.getMethod()); - lfh.setDosTime(ceh.getDosTime()); - lfh.setCrc(ceh.getCrc()); - lfh.setCompressedSize(ceh.getCompressedSize()); - lfh.setSize(ceh.getSize()); - lfh.setFileName(ceh.getFileName()); - lfh.setExtra(ceh.getExtra()); - return lfh; - } - - public static LocalFileHeader read(InputStream inputStream) throws IOException { - LocalFileHeader localFileHeader = new LocalFileHeader(); - localFileHeader.readBytes(inputStream); - if(localFileHeader.isValidSignature()){ - return localFileHeader; - } - return null; - } - private static final int OFFSET_signature = 0; - private static final int OFFSET_versionMadeBy = 4; - private static final int OFFSET_platform = 5; - private static final int OFFSET_general_purpose = 6; - private static final int OFFSET_method = 8; - private static final int OFFSET_dos_time = 10; - private static final int OFFSET_crc = 14; - private static final int OFFSET_compressed_size = 18; - private static final int OFFSET_size = 22; - private static final int OFFSET_fileNameLength = 26; - private static final int OFFSET_extraLength = 28; - - private static final int OFFSET_fileName = 30; - -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/SignatureFooter.java b/src/ARSCLib/com/reandroid/archive2/block/SignatureFooter.java deleted file mode 100644 index 3594021c..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/SignatureFooter.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block; - -import com.reandroid.arsc.item.ByteArray; - -import java.io.IOException; -import java.io.InputStream; - -public class SignatureFooter extends ZipBlock{ - public SignatureFooter() { - super(MIN_SIZE); - setMagic(APK_SIG_BLOCK_MAGIC); - } - @Override - public int readBytes(InputStream inputStream) throws IOException { - setBytesLength(MIN_SIZE, false); - byte[] bytes = getBytesInternal(); - return inputStream.read(bytes, 0, bytes.length); - } - public long getSignatureSize(){ - return getLong(OFFSET_size); - } - public void setSignatureSize(long size){ - int minLength = MIN_SIZE; - if(countBytes() < minLength){ - setBytesLength(minLength, false); - } - putLong(OFFSET_size, size); - } - public byte[] getMagic() { - return getBytes(OFFSET_magic, APK_SIG_BLOCK_MAGIC.length, false); - } - public void setMagic(byte[] magic){ - if(magic == null){ - magic = new byte[0]; - } - int length = OFFSET_magic + magic.length; - setBytesLength(length, false); - putBytes(magic, 0, OFFSET_magic, magic.length); - } - public boolean isValid(){ - return getSignatureSize() > MIN_SIZE - && ByteArray.equals(APK_SIG_BLOCK_MAGIC, getMagic()); - } - public void updateMagic(){ - setMagic(APK_SIG_BLOCK_MAGIC); - } - @Override - public String toString(){ - return getSignatureSize() + " ["+new String(getMagic())+"]"; - } - - public static final int MIN_SIZE = 24; - - private static final int OFFSET_size = 0; - private static final int OFFSET_magic = 8; - - private static final byte[] APK_SIG_BLOCK_MAGIC = - new byte[]{'A', 'P', 'K', ' ', 'S', 'i', 'g', ' ', 'B', 'l', 'o', 'c', 'k', ' ', '4', '2'}; -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/SignatureId.java b/src/ARSCLib/com/reandroid/archive2/block/SignatureId.java deleted file mode 100644 index 33560ef7..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/SignatureId.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block; - -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.util.HexUtil; - -import java.util.Objects; - -public class SignatureId implements Comparable{ - private final String name; - private final int id; - private final int sort; - - private SignatureId(String name, int id, int sort) { - this.name = name; - this.id = id; - this.sort = sort; - } - public String name() { - return name; - } - public int getId() { - return id; - } - public String toFileName() { - if (this.name != null) { - return name + FILE_EXT_RAW; - } - return HexUtil.toHex8(id) + FILE_EXT_RAW; - } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - SignatureId that = (SignatureId) obj; - return id == that.id; - } - @Override - public int compareTo(SignatureId signatureId) { - return Integer.compare(sort, signatureId.sort); - } - @Override - public int hashCode() { - return Objects.hash(id); - } - @Override - public String toString() { - String name = this.name; - if (name != null) { - return name; - } - return "UNKNOWN(" + HexUtil.toHex8(id) + ")"; - } - public static SignatureId valueOf(String name) { - if (name == null) { - return null; - } - String ext = FILE_EXT_RAW; - if (name.endsWith(ext)) { - name = name.substring(0, name.length() - ext.length()); - } - for (SignatureId signatureId : VALUES) { - if (name.equalsIgnoreCase(signatureId.name())) { - return signatureId; - } - } - if (ValueDecoder.isHex(name)) { - return new SignatureId(null, ValueDecoder.parseHex(name), 99); - } - return null; - } - public static SignatureId valueOf(int id) { - for (SignatureId signatureId : VALUES) { - if (id == signatureId.getId()) { - return signatureId; - } - } - return new SignatureId(null, id, 99); - } - - public static SignatureId[] values() { - return VALUES.clone(); - } - - public static final SignatureId V2 = new SignatureId("V2", 0x7109871A, 0); - public static final SignatureId V3 = new SignatureId("V3", 0xF05368C0, 1); - public static final SignatureId V31 = new SignatureId("V31", 0x1B93AD61, 2); - public static final SignatureId STAMP_V1 = new SignatureId("STAMP_V1", 0x2B09189E, 3); - public static final SignatureId STAMP_V2 = new SignatureId("STAMP_V2", 0x6DFF800D, 4); - public static final SignatureId PADDING = new SignatureId("PADDING", 0x42726577, 9999); - public static final SignatureId NULL = new SignatureId("NULL", 0x0, 999); - - private static final SignatureId[] VALUES = new SignatureId[]{ - V2, V3, V31, STAMP_V1, STAMP_V2, PADDING, NULL - }; - - public static final String FILE_EXT_RAW = ".signature.info.bin"; -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/SignatureInfo.java b/src/ARSCLib/com/reandroid/archive2/block/SignatureInfo.java deleted file mode 100644 index 94f59bac..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/SignatureInfo.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block; - -import com.reandroid.archive2.block.pad.SchemePadding; -import com.reandroid.archive2.block.stamp.SchemeStampV1; -import com.reandroid.archive2.block.stamp.SchemeStampV2; -import com.reandroid.archive2.block.v2.SchemeV2; -import com.reandroid.archive2.block.v3.SchemeV3; -import com.reandroid.archive2.block.v3.SchemeV31; -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.container.SingleBlockContainer; -import com.reandroid.arsc.io.BlockLoad; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.item.IntegerItem; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; - -public class SignatureInfo extends LengthPrefixedBlock implements BlockLoad { - private final IntegerItem idItem; - private final SingleBlockContainer schemeContainer; - public SignatureInfo() { - super(2, true); - this.idItem = new IntegerItem(); - this.schemeContainer = new SingleBlockContainer<>(); - addChild(this.idItem); - addChild(this.schemeContainer); - this.idItem.setBlockLoad(this); - } - public int getIdValue(){ - return idItem.get(); - } - public SignatureId getId(){ - return SignatureId.valueOf(getIdValue()); - } - public void setId(int id){ - idItem.set(id); - } - public void setId(SignatureId signatureId){ - setId(signatureId == null? 0 : signatureId.getId()); - } - public SignatureScheme getSignatureScheme(){ - return schemeContainer.getItem(); - } - public void setSignatureScheme(SignatureScheme signatureScheme){ - schemeContainer.setItem(signatureScheme); - } - - @Override - public void onBlockLoaded(BlockReader reader, Block sender) throws IOException { - if(sender == this.idItem){ - onIdLoaded(); - } - } - private void onIdLoaded(){ - SignatureId signatureId = getId(); - SignatureScheme scheme; - if(signatureId == SignatureId.V2){ - scheme = new SchemeV2(); - }else if(signatureId == SignatureId.V3){ - scheme = new SchemeV3(); - }else if(signatureId == SignatureId.V31){ - scheme = new SchemeV31(); - }else if(signatureId == SignatureId.STAMP_V1){ - scheme = new SchemeStampV1(); - }else if(signatureId == SignatureId.STAMP_V2){ - scheme = new SchemeStampV2(); - }else if(signatureId == SignatureId.PADDING){ - scheme = new SchemePadding(); - }else { - scheme = new UnknownScheme(signatureId); - } - schemeContainer.setItem(scheme); - } - public void writeRaw(File file) throws IOException{ - File dir = file.getParentFile(); - if(dir != null && !dir.exists()){ - dir.mkdirs(); - } - FileOutputStream outputStream = new FileOutputStream(file); - writeBytes(outputStream); - outputStream.close(); - } - public File writeRawToDirectory(File dir) throws IOException{ - String name = getIndex() + "_" + getId().toFileName(); - File file = new File(dir, name); - writeRaw(file); - return file; - } - public void read(File file) throws IOException { - super.readBytes(new BlockReader(file)); - } - @Override - public String toString() { - return getId() + ", scheme: " + getSignatureScheme(); - } - -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/SignatureScheme.java b/src/ARSCLib/com/reandroid/archive2/block/SignatureScheme.java deleted file mode 100644 index 555179a6..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/SignatureScheme.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block; - -import com.reandroid.arsc.container.ExpandableBlockContainer; - -public class SignatureScheme extends ExpandableBlockContainer { - private final SignatureId signatureId; - public SignatureScheme(int childesCount, SignatureId signatureId){ - super(childesCount); - this.signatureId = signatureId; - } - public SignatureId getSignatureId() { - return signatureId; - } - - public SignatureInfo getSignatureInfo(){ - return getParent(SignatureInfo.class); - } - @Override - public String toString(){ - return "id=" + getSignatureId(); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/UnknownScheme.java b/src/ARSCLib/com/reandroid/archive2/block/UnknownScheme.java deleted file mode 100644 index 172f8e45..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/UnknownScheme.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block; - -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.item.ByteArray; - -import java.io.IOException; - -// General purpose block to consume the specified bytes of BlockReader -// TODO: No class should override this, implement all like SchemeV2 -public class UnknownScheme extends SignatureScheme{ - private final ByteArray byteArray; - public UnknownScheme(SignatureId signatureId) { - super(1, signatureId); - this.byteArray = new ByteArray(); - addChild(byteArray); - } - @Override - public void onReadBytes(BlockReader reader) throws IOException { - SignatureInfo signatureInfo = getSignatureInfo(); - int size = (int) signatureInfo.getDataSize() - 4; - byteArray.setSize(size); - super.onReadBytes(reader); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/ZipBlock.java b/src/ARSCLib/com/reandroid/archive2/block/ZipBlock.java deleted file mode 100644 index 8669aad0..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/ZipBlock.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block; - -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.item.BlockItem; - -import java.io.IOException; -import java.io.InputStream; - -public abstract class ZipBlock extends BlockItem { - public ZipBlock(int bytesLength) { - super(bytesLength); - } - - public void putBytes(byte[] bytes, int offset, int putOffset, int length){ - if(length<=0 || bytes.length==0){ - return; - } - int size = putOffset + length; - setBytesLength(size, false); - System.arraycopy(bytes, offset, getBytesInternal(), putOffset, length); - } - @Override - public abstract int readBytes(InputStream inputStream) throws IOException; - - // should not use this method - @Override - public void onReadBytes(BlockReader blockReader) throws IOException { - this.readBytes((InputStream) blockReader); - } - - byte[] getBytes(int offset, int length, boolean strict){ - byte[] bytes = getBytesInternal(); - if(strict){ - if(offset<0 || offset>=bytes.length || (offset + length)>bytes.length){ - return null; - } - } - if(offset < 0){ - offset = 0; - } - int available = bytes.length - offset; - if(length<=0 || available <=0){ - return new byte[0]; - } - if(length > available){ - length = available; - } - byte[] result = new byte[length]; - System.arraycopy(getBytesInternal(), offset, result, 0, length); - return result; - } - long getLong(int offset){ - return getLong(getBytesInternal(), offset); - } - void putLong(int offset, long value){ - putLong(getBytesInternal(), offset, value); - } - long getIntegerUnsigned(int offset){ - return getInteger(offset) & 0x00000000ffffffffL; - } - void putBit(int offset, int bitIndex, boolean bit){ - putBit(getBytesInternal(), offset, bitIndex, bit); - } - boolean getBit(int offset, int bitIndex){ - return getBit(getBytesInternal(), offset, bitIndex); - } - int getByteUnsigned(int offset){ - return getBytesInternal()[offset] & 0xff; - } - int getShortUnsigned(int offset){ - return getShort(getBytesInternal(), offset) & 0xffff; - } - int getInteger(int offset){ - return getInteger(getBytesInternal(), offset); - } - void putInteger(int offset, int value){ - putInteger(getBytesInternal(), offset, value); - } - void putInteger(int offset, long value){ - putInteger(getBytesInternal(), offset, (int) value); - } - void putShort(int offset, int value){ - putShort(getBytesInternal(), offset, (short) value); - } - -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/ZipHeader.java b/src/ARSCLib/com/reandroid/archive2/block/ZipHeader.java deleted file mode 100644 index c6c89f29..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/ZipHeader.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block; - -import com.reandroid.archive2.ZipSignature; - -import java.io.IOException; -import java.io.InputStream; - -public class ZipHeader extends ZipBlock{ - private final ZipSignature expectedSignature; - private final int minByteLength; - public ZipHeader(int minByteLength, ZipSignature expectedSignature) { - super(minByteLength); - this.minByteLength = minByteLength; - this.expectedSignature = expectedSignature; - } - @Override - public int readBytes(InputStream inputStream) throws IOException { - int read = readBasic(inputStream); - ZipSignature sig=getSignature(); - if(sig != getExpectedSignature()){ - return read; - } - read += readNext(inputStream); - return read; - } - private int readBasic(InputStream inputStream) throws IOException { - setBytesLength(getMinByteLength(), false); - byte[] bytes = getBytesInternal(); - int beginLength = bytes.length; - int read = inputStream.read(bytes, 0, beginLength); - if(read != beginLength){ - setBytesLength(read, false); - if(getSignature()==expectedSignature){ - setSignature(0); - } - return read; - } - return read; - } - int readNext(InputStream inputStream) throws IOException { - return 0; - } - public boolean isValidSignature(){ - return getSignature() == getExpectedSignature(); - } - ZipSignature getExpectedSignature(){ - return expectedSignature; - } - int getMinByteLength() { - return minByteLength; - } - - public ZipSignature getSignature(){ - return ZipSignature.valueOf(getSignatureValue()); - } - public int getSignatureValue(){ - if(countBytes()<4){ - return 0; - } - return getInteger(OFFSET_signature); - } - public void setSignature(int value){ - if(countBytes()<4){ - return; - } - putInteger(OFFSET_signature, value); - } - public void setSignature(ZipSignature signature){ - setSignature(signature == null ? 0:signature.getValue()); - } - - private static final int OFFSET_signature = 0; -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/ZipStringEncoding.java b/src/ARSCLib/com/reandroid/archive2/block/ZipStringEncoding.java deleted file mode 100644 index 44296af9..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/ZipStringEncoding.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.*; - -import static java.nio.charset.StandardCharsets.UTF_8; - - -public class ZipStringEncoding { - - private static final char REPLACEMENT = '?'; - private static final byte[] REPLACEMENT_BYTES = { (byte) REPLACEMENT }; - private static final String REPLACEMENT_STRING = String.valueOf(REPLACEMENT); - private static final char[] HEX_CHARS = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' - }; - private static ByteBuffer encodeFully(final CharsetEncoder enc, final CharBuffer cb, final ByteBuffer out) { - ByteBuffer o = out; - while (cb.hasRemaining()) { - final CoderResult result = enc.encode(cb, o, false); - if (result.isOverflow()) { - final int increment = estimateIncrementalEncodingSize(enc, cb.remaining()); - o = growBufferBy(o, increment); - } - } - return o; - } - private static CharBuffer encodeSurrogate(final CharBuffer cb, final char c) { - cb.position(0).limit(6); - cb.put('%'); - cb.put('U'); - - cb.put(HEX_CHARS[(c >> 12) & 0x0f]); - cb.put(HEX_CHARS[(c >> 8) & 0x0f]); - cb.put(HEX_CHARS[(c >> 4) & 0x0f]); - cb.put(HEX_CHARS[c & 0x0f]); - cb.flip(); - return cb; - } - - private static int estimateIncrementalEncodingSize(final CharsetEncoder enc, final int charCount) { - return (int) Math.ceil(charCount * enc.averageBytesPerChar()); - } - private static int estimateInitialBufferSize(final CharsetEncoder enc, final int charChount) { - final float first = enc.maxBytesPerChar(); - final float rest = (charChount - 1) * enc.averageBytesPerChar(); - return (int) Math.ceil(first + rest); - } - - private final Charset charset; - private final boolean useReplacement; - private final CharsetEncoder mEncoder; - private final CharsetDecoder mDecoder; - - ZipStringEncoding(final Charset charset, final boolean useReplacement) { - this.charset = charset; - this.useReplacement = useReplacement; - mEncoder = newEncoder(); - mDecoder = newDecoder(); - } - - public boolean canEncode(final String name) { - final CharsetEncoder enc = newEncoder(); - return enc.canEncode(name); - } - public String decode(byte[] data, int offset, int length) throws IOException { - return mDecoder.decode(ByteBuffer.wrap(data, offset, length)).toString(); - } - public byte[] encode(final String text) { - final CharsetEncoder enc = mEncoder; - - final CharBuffer cb = CharBuffer.wrap(text); - CharBuffer tmp = null; - ByteBuffer out = ByteBuffer.allocate(estimateInitialBufferSize(enc, cb.remaining())); - - while (cb.hasRemaining()) { - final CoderResult res = enc.encode(cb, out, false); - - if (res.isUnmappable() || res.isMalformed()) { - final int spaceForSurrogate = estimateIncrementalEncodingSize(enc, 6 * res.length()); - if (spaceForSurrogate > out.remaining()) { - int charCount = 0; - for (int i = cb.position() ; i < cb.limit(); i++) { - charCount += !enc.canEncode(cb.get(i)) ? 6 : 1; - } - final int totalExtraSpace = estimateIncrementalEncodingSize(enc, charCount); - out = growBufferBy(out, totalExtraSpace - out.remaining()); - } - if (tmp == null) { - tmp = CharBuffer.allocate(6); - } - for (int i = 0; i < res.length(); ++i) { - out = encodeFully(enc, encodeSurrogate(tmp, cb.get()), out); - } - - } else if (res.isOverflow()) { - final int increment = estimateIncrementalEncodingSize(enc, cb.remaining()); - out = growBufferBy(out, increment); - - } else if (res.isUnderflow() || res.isError()) { - break; - } - } - // tell the encoder we are done - enc.encode(cb, out, true); - // may have caused underflow, but that's been ignored traditionally - - out.limit(out.position()); - out.rewind(); - return out.array(); - } - - public Charset getCharset() { - return charset; - } - - private CharsetDecoder newDecoder() { - if (!useReplacement) { - return this.charset.newDecoder() - .onMalformedInput(CodingErrorAction.REPORT) - .onUnmappableCharacter(CodingErrorAction.REPORT); - } - return charset.newDecoder() - .onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE) - .replaceWith(REPLACEMENT_STRING); - } - - private CharsetEncoder newEncoder() { - if (useReplacement) { - return charset.newEncoder() - .onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE) - .replaceWith(REPLACEMENT_BYTES); - } - return charset.newEncoder() - .onMalformedInput(CodingErrorAction.REPORT) - .onUnmappableCharacter(CodingErrorAction.REPORT); - } - - private static final String UTF8 = UTF_8.name(); - - - private static ZipStringEncoding getZipEncoding(final String name) { - Charset cs = Charset.defaultCharset(); - if (name != null) { - try { - cs = Charset.forName(name); - } catch (final UnsupportedCharsetException e) { - } - } - final boolean useReplacement = isUTF8(cs.name()); - return new ZipStringEncoding(cs, useReplacement); - } - - static ByteBuffer growBufferBy(final ByteBuffer buffer, final int increment) { - buffer.limit(buffer.position()); - buffer.rewind(); - - final ByteBuffer on = ByteBuffer.allocate(buffer.capacity() + increment); - - on.put(buffer); - return on; - } - - private static boolean isUTF8(final String charsetName) { - final String actual = charsetName != null ? charsetName : Charset.defaultCharset().name(); - if (UTF_8.name().equalsIgnoreCase(actual)) { - return true; - } - return UTF_8.aliases().stream().anyMatch(alias -> alias.equalsIgnoreCase(actual)); - } - - public static String decode(boolean isUtf8, byte[] bytes, int offset, int length){ - if(isUtf8){ - return decodeUtf8(bytes, offset, length); - } - return decodeDefault(bytes, offset, length); - } - private static String decodeUtf8(byte[] bytes, int offset, int length){ - try { - return UTF8_ENCODING.decode(bytes, offset, length); - } catch (IOException exception) { - return new String(bytes, offset, length); - } - } - private static String decodeDefault(byte[] bytes, int offset, int length){ - return new String(bytes, offset, length); - } - public static byte[] encodeString(boolean isUtf8, String text){ - if(text==null || text.length()==0){ - return new byte[0]; - } - if(isUtf8){ - return UTF8_ENCODING.encode(text); - } - return DEFAULT_ENCODING.encode(text); - } - - private static final ZipStringEncoding UTF8_ENCODING = getZipEncoding(UTF8); - private static final ZipStringEncoding DEFAULT_ENCODING = getZipEncoding(Charset.defaultCharset().name()); - -} - diff --git a/src/ARSCLib/com/reandroid/archive2/block/pad/SchemePadding.java b/src/ARSCLib/com/reandroid/archive2/block/pad/SchemePadding.java deleted file mode 100644 index f726ef33..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/pad/SchemePadding.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block.pad; - -import com.reandroid.archive2.block.SignatureId; -import com.reandroid.archive2.block.SignatureInfo; -import com.reandroid.archive2.block.SignatureScheme; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.item.ByteArray; - -import java.io.IOException; - -public class SchemePadding extends SignatureScheme { - private final ByteArray byteArray; - public SchemePadding() { - super(1, SignatureId.PADDING); - this.byteArray = new ByteArray(); - addChild(this.byteArray); - } - public int getPadding(){ - return byteArray.size(); - } - public void setPadding(int padding){ - byteArray.setSize(padding); - } - public byte[] getPaddingBytes() { - return byteArray.getBytes(); - } - public void setPadding(byte[] bytes){ - byteArray.set(bytes); - } - - @Override - public void onReadBytes(BlockReader reader) throws IOException{ - SignatureInfo signatureInfo = getSignatureInfo(); - int size = (int) signatureInfo.getDataSize() - 4; - byteArray.setSize(size); - super.onReadBytes(reader); - } - @Override - public String toString(){ - return "padding = " + getPadding(); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/stamp/SchemeStampV1.java b/src/ARSCLib/com/reandroid/archive2/block/stamp/SchemeStampV1.java deleted file mode 100644 index aa2b4f39..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/stamp/SchemeStampV1.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block.stamp; - -import com.reandroid.archive2.block.SignatureId; -import com.reandroid.archive2.block.UnknownScheme; - -// TODO: implement structure -public class SchemeStampV1 extends UnknownScheme { - public SchemeStampV1() { - super(SignatureId.STAMP_V1); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/stamp/SchemeStampV2.java b/src/ARSCLib/com/reandroid/archive2/block/stamp/SchemeStampV2.java deleted file mode 100644 index ceb8504c..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/stamp/SchemeStampV2.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block.stamp; - -import com.reandroid.archive2.block.SignatureId; -import com.reandroid.archive2.block.UnknownScheme; - -// TODO: implement structure -public class SchemeStampV2 extends UnknownScheme { - public SchemeStampV2() { - super(SignatureId.STAMP_V2); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/v2/SchemeV2.java b/src/ARSCLib/com/reandroid/archive2/block/v2/SchemeV2.java deleted file mode 100644 index c7e4c235..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/v2/SchemeV2.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block.v2; - -import com.reandroid.archive2.block.SignatureId; -import com.reandroid.archive2.block.SignatureScheme; - -public class SchemeV2 extends SignatureScheme { - private final V2SignedDataList signedDataList; - public SchemeV2(){ - super(1, SignatureId.V2); - this.signedDataList = new V2SignedDataList(); - addChild(this.signedDataList); - } - -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/v2/V2Signature.java b/src/ARSCLib/com/reandroid/archive2/block/v2/V2Signature.java deleted file mode 100644 index f73ee339..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/v2/V2Signature.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block.v2; - -import com.reandroid.archive2.block.LengthPrefixedBytes; - -public class V2Signature extends LengthPrefixedBytes { - public V2Signature() { - super(false); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/v2/V2SignedData.java b/src/ARSCLib/com/reandroid/archive2/block/v2/V2SignedData.java deleted file mode 100644 index 8eb53f1f..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/v2/V2SignedData.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block.v2; - -import com.reandroid.archive2.block.BottomBlock; -import com.reandroid.archive2.block.LengthPrefixedBlock; -import com.reandroid.arsc.io.BlockReader; - -import java.io.IOException; - -public class V2SignedData extends LengthPrefixedBlock { - private final V2Signer signer; - private final BottomBlock unknown; - public V2SignedData() { - super(2, false); - this.signer = new V2Signer(); - this.unknown = new BottomBlock(); - addChild(this.signer); - addChild(this.unknown); - } - public void onReadBytes(BlockReader reader) throws IOException { - super.onReadBytes(reader); - } - -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/v2/V2SignedDataList.java b/src/ARSCLib/com/reandroid/archive2/block/v2/V2SignedDataList.java deleted file mode 100644 index 5767ea39..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/v2/V2SignedDataList.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block.v2; - -import com.reandroid.archive2.block.LengthPrefixedList; - -public class V2SignedDataList extends LengthPrefixedList { - public V2SignedDataList() { - super(false); - } - - @Override - public V2SignedData newInstance() { - return new V2SignedData(); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/v2/V2Signer.java b/src/ARSCLib/com/reandroid/archive2/block/v2/V2Signer.java deleted file mode 100644 index cc99578b..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/v2/V2Signer.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block.v2; - -import com.reandroid.archive2.block.BottomBlock; -import com.reandroid.archive2.block.CertificateBlock; -import com.reandroid.archive2.block.CertificateBlockList; -import com.reandroid.archive2.block.LengthPrefixedBlock; - -import java.util.List; - -public class V2Signer extends LengthPrefixedBlock { - private final V2Signature v2Signature; - private final CertificateBlockList certificateBlockList; - private final BottomBlock unknown; - public V2Signer() { - super(3, false); - this.v2Signature = new V2Signature(); - this.certificateBlockList = new CertificateBlockList(); - this.unknown = new BottomBlock(); - addChild(this.v2Signature); - addChild(this.certificateBlockList); - addChild(this.unknown); - } - public List getCertificateBlockList(){ - return certificateBlockList.getElements(); - } - public void addCertificateBlock(CertificateBlock certificateBlock){ - certificateBlockList.add(certificateBlock); - } - public void removeCertificateBlock(CertificateBlock certificateBlock){ - certificateBlockList.remove(certificateBlock); - } - @Override - public String toString(){ - return super.toString()+", sig="+v2Signature+", certs="+certificateBlockList; - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/v3/SchemeV3.java b/src/ARSCLib/com/reandroid/archive2/block/v3/SchemeV3.java deleted file mode 100644 index 5b9c9d8e..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/v3/SchemeV3.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block.v3; - -import com.reandroid.archive2.block.SignatureId; -import com.reandroid.archive2.block.UnknownScheme; - -// TODO: implement structure -public class SchemeV3 extends UnknownScheme { - public SchemeV3() { - super(SignatureId.V3); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/block/v3/SchemeV31.java b/src/ARSCLib/com/reandroid/archive2/block/v3/SchemeV31.java deleted file mode 100644 index 40433481..00000000 --- a/src/ARSCLib/com/reandroid/archive2/block/v3/SchemeV31.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.block.v3; - -import com.reandroid.archive2.block.SignatureId; -import com.reandroid.archive2.block.UnknownScheme; - -// TODO: implement structure -public class SchemeV31 extends UnknownScheme { - public SchemeV31() { - super(SignatureId.V31); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/io/ArchiveEntrySource.java b/src/ARSCLib/com/reandroid/archive2/io/ArchiveEntrySource.java deleted file mode 100644 index cf4ece94..00000000 --- a/src/ARSCLib/com/reandroid/archive2/io/ArchiveEntrySource.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.io; - -import com.reandroid.archive.InputSource; -import com.reandroid.archive2.ArchiveEntry; -import com.reandroid.archive2.block.LocalFileHeader; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.util.zip.Inflater; -import java.util.zip.InflaterInputStream; -import java.util.zip.ZipEntry; - -public class ArchiveEntrySource extends InputSource { - private final ZipInput zipInput; - private final ArchiveEntry archiveEntry; - public ArchiveEntrySource(ZipInput zipInput, ArchiveEntry archiveEntry){ - super(archiveEntry.getName()); - this.zipInput = zipInput; - this.archiveEntry = archiveEntry; - setMethod(archiveEntry.getMethod()); - } - - @Override - public byte[] getBytes(int length) throws IOException { - if(getMethod() != ZipEntry.STORED){ - return super.getBytes(length); - } - FileChannel fileChannel = getFileChannel(); - byte[] bytes = new byte[length]; - ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); - fileChannel.read(byteBuffer); - return bytes; - } - - public FileChannel getFileChannel() throws IOException { - FileChannel fileChannel = getZipSource().getFileChannel(); - fileChannel.position(getFileOffset()); - return fileChannel; - } - public ZipInput getZipSource(){ - return zipInput; - } - public ArchiveEntry getArchiveEntry() { - return archiveEntry; - } - public long getFileOffset(){ - return getArchiveEntry().getFileOffset(); - } - @Override - public long getLength() throws IOException{ - return getArchiveEntry().getDataSize(); - } - @Override - public long getCrc() throws IOException{ - return getArchiveEntry().getCrc(); - } - @Override - public InputStream openStream() throws IOException { - ArchiveEntry archiveEntry = getArchiveEntry(); - LocalFileHeader lfh = archiveEntry.getLocalFileHeader(); - InputStream inputStream = getZipSource().getInputStream( - archiveEntry.getFileOffset(), archiveEntry.getDataSize()); - if(lfh.getSize() == lfh.getCompressedSize()){ - return inputStream; - } - return new InflaterInputStream(inputStream, - new Inflater(true), 512); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/io/ArchiveUtil.java b/src/ARSCLib/com/reandroid/archive2/io/ArchiveUtil.java deleted file mode 100644 index 35f3477e..00000000 --- a/src/ARSCLib/com/reandroid/archive2/io/ArchiveUtil.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.io; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -public class ArchiveUtil { - - public static void writeAll(InputStream inputStream, OutputStream outputStream) throws IOException{ - int bufferLength = 1024 * 1000; - byte[] buffer = new byte[bufferLength]; - int read; - while ((read = inputStream.read(buffer, 0, bufferLength))>0){ - outputStream.write(buffer, 0, read); - } - } - public static void skip(InputStream inputStream, long amount) throws IOException { - if(amount==0){ - return; - } - int bufferLength = 1024*1024*100; - if(bufferLength>amount){ - bufferLength = (int) amount; - } - byte[] buffer = new byte[bufferLength]; - int read; - long remain = amount; - while (remain > 0 && (read = inputStream.read(buffer, 0, bufferLength))>0){ - remain = remain - read; - if(remain extends InputStream { - private final T inputStream; - private final CRC32 crc; - private long size; - private long mCheckSum; - private boolean mFinished; - public CountingInputStream(T inputStream, boolean disableCrc){ - this.inputStream = inputStream; - CRC32 crc32; - if(disableCrc){ - crc32 = null; - }else { - crc32 = new CRC32(); - } - this.crc = crc32; - } - public CountingInputStream(T inputStream){ - this(inputStream, false); - } - public T getInputStream() { - return inputStream; - } - public long getSize() { - return size; - } - public long getCrc() { - return mCheckSum; - } - @Override - public int read(byte[] bytes, int offset, int length) throws IOException{ - if(mFinished){ - return -1; - } - length = inputStream.read(bytes, offset, length); - if(length < 0){ - onFinished(); - return length; - } - this.size += length; - if(this.crc != null){ - this.crc.update(bytes, offset, length); - } - return length; - } - @Override - public int read(byte[] bytes) throws IOException{ - return this.read(bytes, 0, bytes.length); - } - @Override - public int read() throws IOException { - throw new IOException("Why one byte ?"); - } - @Override - public long skip(long amount) throws IOException { - if(mFinished){ - return 0; - } - if(amount <= 0){ - return amount; - } - InputStream inputStream = this.inputStream; - if(inputStream instanceof CountingInputStream){ - return inputStream.skip(amount); - } - long remaining = amount; - int len = 1024 * 1000; - if(remaining < len){ - len = (int) remaining; - } - final byte[] buffer = new byte[len]; - int read; - while (true){ - read = inputStream.read(buffer, 0, len); - if(read < 0){ - onFinished(); - break; - } - remaining = remaining - read; - if(remaining <= 0){ - break; - } - if(remaining < len){ - len = (int) remaining; - } - } - return amount - remaining; - } - @Override - public void close() throws IOException{ - if(!mFinished){ - onFinished(); - } - inputStream.close(); - } - private void onFinished(){ - this.mFinished = true; - if(this.crc!=null){ - this.mCheckSum = this.crc.getValue(); - } - } - @Override - public String toString(){ - if(!mFinished || crc==null){ - return "[" + size + "]: " + inputStream.getClass().getSimpleName(); - } - return "[size=" + size +", crc=" + HexUtil.toHex8(mCheckSum) + "]: " + inputStream.getClass().getSimpleName(); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/io/CountingOutputStream.java b/src/ARSCLib/com/reandroid/archive2/io/CountingOutputStream.java deleted file mode 100644 index 0ae2a2b7..00000000 --- a/src/ARSCLib/com/reandroid/archive2/io/CountingOutputStream.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.io; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.zip.CRC32; - -public class CountingOutputStream extends OutputStream { - private final T outputStream; - private CRC32 crc; - private long size; - public CountingOutputStream(T outputStream, boolean disableCrc){ - this.outputStream = outputStream; - CRC32 crc32; - if(disableCrc){ - crc32 = null; - }else { - crc32 = new CRC32(); - } - this.crc = crc32; - } - public CountingOutputStream(T outputStream){ - this(outputStream, false); - } - - public void disableCrc(boolean disableCrc) { - if(!disableCrc){ - if(crc == null){ - this.crc = new CRC32(); - } - }else{ - this.crc = null; - } - } - - public void reset(){ - this.crc = new CRC32(); - this.size = 0L; - } - public T getOutputStream() { - return outputStream; - } - public long getSize() { - return size; - } - public long getCrc() { - if(crc != null){ - return crc.getValue(); - } - return 0; - } - @Override - public void write(byte[] bytes, int offset, int length) throws IOException{ - if(length == 0){ - return; - } - outputStream.write(bytes, offset, length); - this.size += length; - if(this.crc != null){ - this.crc.update(bytes, offset, length); - } - } - @Override - public void write(byte[] bytes) throws IOException{ - this.write(bytes, 0, bytes.length); - } - @Override - public void write(int i) throws IOException { - this.write(new byte[]{(byte) i}, 0, 1); - } - @Override - public void close() throws IOException{ - outputStream.close(); - } - @Override - public void flush() throws IOException { - outputStream.flush(); - } - @Override - public String toString(){ - return "[" + size + "]: " + outputStream.getClass().getSimpleName(); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/io/FileChannelOutputStream.java b/src/ARSCLib/com/reandroid/archive2/io/FileChannelOutputStream.java deleted file mode 100644 index 81411e24..00000000 --- a/src/ARSCLib/com/reandroid/archive2/io/FileChannelOutputStream.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.io; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; - -public class FileChannelOutputStream extends OutputStream { - private final FileChannel fileChannel; - public FileChannelOutputStream(FileChannel fileChannel){ - this.fileChannel = fileChannel; - } - @Override - public void write(byte[] bytes) throws IOException { - write(bytes, 0, bytes.length); - } - @Override - public void write(byte[] bytes, int offset, int length) throws IOException { - long position = fileChannel.position(); - length = fileChannel.write(ByteBuffer.wrap(bytes, offset, length)); - fileChannel.position(position + length); - } - @Override - public void write(int i) throws IOException { - byte b = (byte) (i & 0xff); - write(new byte[]{b}); - } - @Override - public void close(){ - - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/io/RandomStream.java b/src/ARSCLib/com/reandroid/archive2/io/RandomStream.java deleted file mode 100644 index 62a8e47d..00000000 --- a/src/ARSCLib/com/reandroid/archive2/io/RandomStream.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.io; - -import java.io.IOException; -import java.nio.channels.Channel; -import java.nio.channels.FileChannel; - -public interface RandomStream extends Channel { - long position() throws IOException; - void position(long pos) throws IOException; - @Override - void close() throws IOException; - @Override - boolean isOpen(); - FileChannel getFileChannel() throws IOException; -} diff --git a/src/ARSCLib/com/reandroid/archive2/io/ReadOnlyStream.java b/src/ARSCLib/com/reandroid/archive2/io/ReadOnlyStream.java deleted file mode 100644 index 6b895472..00000000 --- a/src/ARSCLib/com/reandroid/archive2/io/ReadOnlyStream.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.io; - -import java.io.IOException; -import java.io.InputStream; - -public interface ReadOnlyStream extends RandomStream{ - long getLength() throws IOException; - InputStream getInputStream(long offset, long length) throws IOException; -} diff --git a/src/ARSCLib/com/reandroid/archive2/io/SlicedInputStream.java b/src/ARSCLib/com/reandroid/archive2/io/SlicedInputStream.java deleted file mode 100644 index c01d9af1..00000000 --- a/src/ARSCLib/com/reandroid/archive2/io/SlicedInputStream.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.io; - -import java.io.IOException; -import java.io.InputStream; - -public class SlicedInputStream extends InputStream{ - private final InputStream inputStream; - private final long mOffset; - private final long mLength; - private long mCount; - private boolean mFinished; - private boolean mStarted; - public SlicedInputStream(InputStream inputStream, long offset, long length){ - this.inputStream = inputStream; - this.mOffset = offset; - this.mLength = length; - } - @Override - public int read(byte[] bytes, int off, int len) throws IOException{ - if(mFinished){ - return -1; - } - checkStarted(); - long remain = mLength - mCount; - if(remain <= 0){ - onFinished(); - return -1; - } - boolean finishNext = false; - if(len > remain){ - len = (int) remain; - finishNext = true; - } - int read = inputStream.read(bytes, off, len); - mCount += read; - if(finishNext){ - onFinished(); - } - return read; - } - @Override - public int read(byte[] bytes) throws IOException{ - return this.read(bytes, 0, bytes.length); - } - @Override - public int read() throws IOException { - if(mFinished){ - return -1; - } - checkStarted(); - long remain = mLength - mCount; - if(remain <= 0){ - onFinished(); - return -1; - } - int result = inputStream.read(); - mCount = mCount + 1; - if(remain == 1){ - onFinished(); - } - return result; - } - @Override - public long skip(long n) throws IOException{ - checkStarted(); - long amount = inputStream.skip(n); - if(amount>0){ - mCount += amount; - } - return amount; - } - @Override - public void close() throws IOException { - onFinished(); - } - private void onFinished() throws IOException { - mFinished = true; - inputStream.close(); - } - private void checkStarted() throws IOException { - if(mStarted){ - return; - } - mStarted = true; - inputStream.skip(mOffset); - mCount = 0; - } - @Override - public String toString(){ - return "["+mOffset+","+mLength+"] "+mCount; - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/io/WriteOnlyStream.java b/src/ARSCLib/com/reandroid/archive2/io/WriteOnlyStream.java deleted file mode 100644 index f4f78f63..00000000 --- a/src/ARSCLib/com/reandroid/archive2/io/WriteOnlyStream.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.io; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -public interface WriteOnlyStream extends RandomStream{ - void write(ReadOnlyStream readStream, long length) throws IOException; - void write(InputStream inputStream) throws IOException; - OutputStream getOutputStream() throws IOException; -} diff --git a/src/ARSCLib/com/reandroid/archive2/io/ZipFileInput.java b/src/ARSCLib/com/reandroid/archive2/io/ZipFileInput.java deleted file mode 100644 index 4f9b3006..00000000 --- a/src/ARSCLib/com/reandroid/archive2/io/ZipFileInput.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.io; - -import com.reandroid.common.FileChannelInputStream; - -import java.io.*; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.file.StandardOpenOption; - -public class ZipFileInput extends ZipInput { - private final File file; - private FileChannel fileChannel; - private InputStream mCurrentInputStream; - public ZipFileInput(File file){ - this.file = file; - } - - public File getFile(){ - return file; - } - - @Override - public long position() throws IOException { - FileChannel fileChannel = this.fileChannel; - if(fileChannel != null){ - return fileChannel.position(); - } - return 0; - } - @Override - public void position(long pos) throws IOException { - getFileChannel().position(pos); - } - @Override - public long getLength(){ - return this.file.length(); - } - @Override - public InputStream getInputStream(long offset, long length) throws IOException { - closeCurrentInputStream(); - FileChannel fileChannel = getFileChannel(); - fileChannel.position(offset); - mCurrentInputStream = new FileChannelInputStream(fileChannel, length); - return mCurrentInputStream; - } - - @Override - public byte[] getFooter(int minLength) throws IOException { - long position = getLength(); - if(minLength>position){ - minLength = (int) position; - } - position = position - minLength; - FileChannel fileChannel = getFileChannel(); - fileChannel.position(position); - ByteBuffer buffer = ByteBuffer.allocate(minLength); - fileChannel.read(buffer); - return buffer.array(); - } - @Override - public FileChannel getFileChannel() throws IOException { - FileChannel fileChannel = this.fileChannel; - if(fileChannel != null){ - return fileChannel; - } - synchronized (this){ - fileChannel = FileChannel.open(this.file.toPath(), StandardOpenOption.READ); - this.fileChannel = fileChannel; - return fileChannel; - } - } - @Override - public void close() throws IOException { - closeCurrentInputStream(); - closeChannel(); - } - @Override - public boolean isOpen(){ - FileChannel fileChannel = this.fileChannel; - if(fileChannel == null){ - return false; - } - synchronized (this){ - return fileChannel.isOpen(); - } - } - private void closeChannel() throws IOException { - FileChannel fileChannel = this.fileChannel; - if(fileChannel == null){ - return; - } - synchronized (this){ - fileChannel.close(); - this.fileChannel = null; - } - } - private void closeCurrentInputStream() throws IOException { - InputStream current = this.mCurrentInputStream; - if(current == null){ - return; - } - current.close(); - mCurrentInputStream = null; - } - @Override - public String toString(){ - return "File: " + this.file; - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/io/ZipFileOutput.java b/src/ARSCLib/com/reandroid/archive2/io/ZipFileOutput.java deleted file mode 100644 index 56407955..00000000 --- a/src/ARSCLib/com/reandroid/archive2/io/ZipFileOutput.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.io; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.file.StandardOpenOption; - -public class ZipFileOutput extends ZipOutput{ - private final File file; - private FileChannel fileChannel; - private FileChannelOutputStream outputStream; - public ZipFileOutput(File file) throws IOException { - initFile(file); - this.file = file; - } - public File getFile() { - return file; - } - public void write(FileChannel input, long length) throws IOException{ - FileChannel fileChannel = getFileChannel(); - long pos = fileChannel.position(); - length = fileChannel.transferFrom(input, pos, length); - fileChannel.position(pos + length); - } - - @Override - public long position() throws IOException { - return getFileChannel().position(); - } - @Override - public void position(long pos) throws IOException { - getFileChannel().position(pos); - } - @Override - public void close() throws IOException { - FileChannel fileChannel = this.fileChannel; - if(fileChannel != null){ - fileChannel.close(); - } - } - @Override - public boolean isOpen() { - FileChannel fileChannel = this.fileChannel; - if(fileChannel != null){ - return fileChannel.isOpen(); - } - return false; - } - @Override - public FileChannel getFileChannel() throws IOException { - FileChannel fileChannel = this.fileChannel; - if(fileChannel != null){ - return fileChannel; - } - synchronized (this){ - fileChannel = FileChannel.open(this.file.toPath(), StandardOpenOption.WRITE); - this.fileChannel = fileChannel; - return fileChannel; - } - } - @Override - public void write(ReadOnlyStream readStream, long length) throws IOException { - FileChannel input = readStream.getFileChannel(); - if(input != null){ - write(input, length); - return; - } - write(readStream.getInputStream(readStream.position(), length)); - } - @Override - public void write(InputStream inputStream) throws IOException { - FileChannel fileChannel = getFileChannel(); - long pos = fileChannel.position(); - int bufferLength = 1024 * 1000 * 100; - byte[] buffer = new byte[bufferLength]; - long result = 0; - int read; - while ((read = inputStream.read(buffer, 0, bufferLength)) > 0){ - ByteBuffer byteBuffer = ByteBuffer.wrap(buffer, 0, read); - fileChannel.write(byteBuffer); - result += read; - } - inputStream.close(); - fileChannel.position(pos + result); - } - @Override - public FileChannelOutputStream getOutputStream() throws IOException { - FileChannelOutputStream outputStream = this.outputStream; - if(outputStream == null){ - outputStream = new FileChannelOutputStream(getFileChannel()); - this.outputStream = outputStream; - } - return outputStream; - } - - - private static void initFile(File file) throws IOException{ - if(file.isDirectory()){ - throw new IOException("Not file: " + file); - } - File dir = file.getParentFile(); - if(dir != null && !dir.exists()){ - dir.mkdirs(); - } - if(file.exists()){ - file.delete(); - } - file.createNewFile(); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/io/ZipInput.java b/src/ARSCLib/com/reandroid/archive2/io/ZipInput.java deleted file mode 100644 index 080501d4..00000000 --- a/src/ARSCLib/com/reandroid/archive2/io/ZipInput.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.io; - -import java.io.IOException; - -public abstract class ZipInput implements ReadOnlyStream { - public abstract byte[] getFooter(int minLength) throws IOException; -} diff --git a/src/ARSCLib/com/reandroid/archive2/io/ZipOutput.java b/src/ARSCLib/com/reandroid/archive2/io/ZipOutput.java deleted file mode 100644 index b925a9ba..00000000 --- a/src/ARSCLib/com/reandroid/archive2/io/ZipOutput.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.io; - -public abstract class ZipOutput implements WriteOnlyStream{ - -} diff --git a/src/ARSCLib/com/reandroid/archive2/model/CentralFileDirectory.java b/src/ARSCLib/com/reandroid/archive2/model/CentralFileDirectory.java deleted file mode 100644 index e309ba4d..00000000 --- a/src/ARSCLib/com/reandroid/archive2/model/CentralFileDirectory.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.model; - -import com.reandroid.archive2.block.CentralEntryHeader; -import com.reandroid.archive2.block.EndRecord; -import com.reandroid.archive2.block.LocalFileHeader; -import com.reandroid.archive2.block.SignatureFooter; -import com.reandroid.archive2.io.ZipInput; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -public class CentralFileDirectory { - private final List headerList; - private EndRecord endRecord; - private SignatureFooter signatureFooter; - public CentralFileDirectory(){ - this.headerList = new ArrayList<>(); - } - public CentralEntryHeader get(LocalFileHeader lfh){ - String name = lfh.getFileName(); - CentralEntryHeader ceh = get(lfh.getIndex()); - if(ceh!=null && Objects.equals(ceh.getFileName() , name)){ - return ceh; - } - return get(name); - } - public CentralEntryHeader get(String name){ - if(name == null){ - name = ""; - } - for(CentralEntryHeader ceh:getHeaderList()){ - if(name.equals(ceh.getFileName())){ - return ceh; - } - } - return null; - } - public CentralEntryHeader get(int i){ - if(i<0 || i>=headerList.size()){ - return null; - } - return headerList.get(i); - } - public int count(){ - return headerList.size(); - } - public List getHeaderList() { - return headerList; - } - - public SignatureFooter getSignatureFooter() { - return signatureFooter; - } - public EndRecord getEndRecord() { - return endRecord; - } - public void visit(ZipInput zipInput) throws IOException { - byte[] footer = zipInput.getFooter(SignatureFooter.MIN_SIZE + EndRecord.MAX_LENGTH); - EndRecord endRecord = findEndRecord(footer); - int length = (int) endRecord.getLengthOfCentralDirectory(); - int endLength = endRecord.countBytes(); - if(footer.length < (length + endLength)){ - footer = zipInput.getFooter(SignatureFooter.MIN_SIZE + length + endLength); - } - int offset = footer.length - length - endLength; - this.endRecord = endRecord; - loadCentralFileHeaders(footer, offset, length); - this.signatureFooter = tryFindSignatureFooter(footer, endRecord); - } - private void loadCentralFileHeaders(byte[] footer, int offset, int length) throws IOException { - ByteArrayInputStream inputStream = new ByteArrayInputStream(footer, offset, length); - loadCentralFileHeaders(inputStream); - } - private void loadCentralFileHeaders(InputStream inputStream) throws IOException { - List headerList = this.headerList; - CentralEntryHeader ceh = new CentralEntryHeader(); - ceh.readBytes(inputStream); - while (ceh.isValidSignature()){ - headerList.add(ceh); - ceh = new CentralEntryHeader(); - ceh.readBytes(inputStream); - } - inputStream.close(); - } - private EndRecord findEndRecord(byte[] footer) throws IOException{ - int length = footer.length; - int minLength = EndRecord.MIN_LENGTH; - int start = length - minLength; - for(int offset=start; offset>=0; offset--){ - EndRecord endRecord = new EndRecord(); - endRecord.putBytes(footer, offset, 0, minLength); - if(endRecord.isValidSignature()){ - return endRecord; - } - } - throw new IOException("Failed to find end record"); - } - private SignatureFooter tryFindSignatureFooter(byte[] footer, EndRecord endRecord) throws IOException { - int lenCd = (int) endRecord.getLengthOfCentralDirectory(); - int endLength = endRecord.countBytes(); - int length = SignatureFooter.MIN_SIZE; - int offset = footer.length - endLength - lenCd - length; - if(offset < 0){ - return null; - } - ByteArrayInputStream inputStream = new ByteArrayInputStream(footer, offset, length); - SignatureFooter signatureFooter = new SignatureFooter(); - signatureFooter.readBytes(inputStream); - if(signatureFooter.isValid()){ - return signatureFooter; - } - return null; - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/model/LocalFileDirectory.java b/src/ARSCLib/com/reandroid/archive2/model/LocalFileDirectory.java deleted file mode 100644 index b359603a..00000000 --- a/src/ARSCLib/com/reandroid/archive2/model/LocalFileDirectory.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.model; - -import com.reandroid.archive2.block.*; -import com.reandroid.archive2.block.ApkSignatureBlock; -import com.reandroid.archive2.io.ZipInput; -import com.reandroid.arsc.io.BlockReader; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - -public class LocalFileDirectory { - private final CentralFileDirectory centralFileDirectory; - private final List headerList; - private ApkSignatureBlock apkSignatureBlock; - public LocalFileDirectory(CentralFileDirectory centralFileDirectory){ - this.centralFileDirectory = centralFileDirectory; - this.headerList = new ArrayList<>(); - } - public LocalFileDirectory(){ - this(new CentralFileDirectory()); - } - public void visit(ZipInput zipInput) throws IOException { - getCentralFileDirectory().visit(zipInput); - visitLocalFile(zipInput); - visitApkSigBlock(zipInput); - } - private void visitLocalFile(ZipInput zipInput) throws IOException { - List headerList = this.getHeaderList(); - long offset; - int index = 0; - CentralFileDirectory centralFileDirectory = getCentralFileDirectory(); - long length = zipInput.getLength(); - InputStream inputStream = zipInput.getInputStream(0, length); - for(CentralEntryHeader ceh : centralFileDirectory.getHeaderList()){ - offset = ceh.getLocalRelativeOffset(); - inputStream.reset(); - offset = inputStream.skip(offset); - LocalFileHeader lfh = LocalFileHeader.read(inputStream); - if(lfh == null){ - throw new IOException("Error reading LFH at " - + offset + ", for CEH = " + ceh.getFileName()); - } - offset = offset + lfh.countBytes(); - lfh.setFileOffset(offset); - ceh.setFileOffset(offset); - lfh.mergeZeroValues(ceh); - inputStream.skip(lfh.getDataSize()); - DataDescriptor dataDescriptor = null; - if(lfh.hasDataDescriptor()){ - dataDescriptor = new DataDescriptor(); - int read = dataDescriptor.readBytes(inputStream); - if(read != dataDescriptor.countBytes()){ - dataDescriptor = null; - } - } - lfh.setDataDescriptor(dataDescriptor); - lfh.setIndex(index); - headerList.add(lfh); - index++; - } - } - private void visitApkSigBlock(ZipInput zipInput) throws IOException{ - CentralFileDirectory cfd = getCentralFileDirectory(); - SignatureFooter footer = cfd.getSignatureFooter(); - if(footer == null || !footer.isValid()){ - return; - } - EndRecord endRecord = cfd.getEndRecord(); - long length = footer.getSignatureSize() + 8; - long offset = endRecord.getOffsetOfCentralDirectory() - length; - ApkSignatureBlock apkSignatureBlock = new ApkSignatureBlock(footer); - apkSignatureBlock.readBytes(new BlockReader(zipInput.getInputStream(offset, length))); - this.apkSignatureBlock = apkSignatureBlock; - } - public ApkSignatureBlock getApkSigBlock() { - return apkSignatureBlock; - } - public CentralFileDirectory getCentralFileDirectory() { - return centralFileDirectory; - } - public List getHeaderList() { - return headerList; - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/writer/ApkWriter.java b/src/ARSCLib/com/reandroid/archive2/writer/ApkWriter.java deleted file mode 100644 index 79adfd3d..00000000 --- a/src/ARSCLib/com/reandroid/archive2/writer/ApkWriter.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.writer; - -import com.reandroid.apk.APKLogger; -import com.reandroid.apk.RenamedInputSource; -import com.reandroid.archive.InputSource; -import com.reandroid.archive.WriteProgress; -import com.reandroid.archive2.ZipSignature; -import com.reandroid.archive2.block.ApkSignatureBlock; -import com.reandroid.archive2.block.EndRecord; -import com.reandroid.archive2.io.ArchiveEntrySource; -import com.reandroid.archive2.io.ZipFileOutput; -import com.reandroid.arsc.chunk.TableBlock; - -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -public class ApkWriter extends ZipFileOutput { - private final Object mLock = new Object(); - private final Collection sourceList; - private ZipAligner zipAligner; - private ApkSignatureBlock apkSignatureBlock; - private APKLogger apkLogger; - private WriteProgress writeProgress; - - public ApkWriter(File file, Collection sourceList) throws IOException { - super(file); - this.sourceList = sourceList; - this.zipAligner = ZipAligner.apkAligner(); - } - public void write()throws IOException { - synchronized (mLock){ - List outputList = buildOutputEntry(); - logMessage("Buffering compress changed files ..."); - BufferFileInput buffer = writeBuffer(outputList); - buffer.unlock(); - align(outputList); - writeApk(outputList); - buffer.close(); - - writeSignatureBlock(); - - writeCEH(outputList); - this.close(); - logMessage("Written to: " + getFile().getName()); - } - } - public void setApkSignatureBlock(ApkSignatureBlock apkSignatureBlock) { - this.apkSignatureBlock = apkSignatureBlock; - } - public ZipAligner getZipAligner() { - return zipAligner; - } - public void setZipAligner(ZipAligner zipAligner) { - this.zipAligner = zipAligner; - } - - private void writeCEH(List outputList) throws IOException{ - logMessage("Writing CEH ..."); - EndRecord endRecord = new EndRecord(); - endRecord.setSignature(ZipSignature.END_RECORD); - long offset = position(); - endRecord.setOffsetOfCentralDirectory((int) offset); - endRecord.setNumberOfDirectories(outputList.size()); - endRecord.setTotalNumberOfDirectories(outputList.size()); - for(OutputSource outputSource:outputList){ - outputSource.writeCEH(this); - } - long len = position() - offset; - endRecord.setLengthOfCentralDirectory(len); - endRecord.writeBytes(getOutputStream()); - } - private void writeApk(List outputList) throws IOException{ - logMessage("Writing files: " + outputList.size()); - for(OutputSource outputSource:outputList){ - outputSource.writeApk( this); - } - } - private void writeSignatureBlock() throws IOException { - ApkSignatureBlock signatureBlock = this.apkSignatureBlock; - if(signatureBlock == null){ - return; - } - logMessage("Writing signature block ..."); - long offset = position(); - int alignment = 4096; - int filesPadding = (int) ((alignment - (offset % alignment)) % alignment); - OutputStream outputStream = getOutputStream(); - if(filesPadding > 0){ - outputStream.write(new byte[filesPadding]); - } - logMessage("files padding = " + filesPadding); - signatureBlock.updatePadding(); - signatureBlock.writeBytes(outputStream); - } - private BufferFileInput writeBuffer(List outputList) throws IOException { - File bufferFile = getBufferFile(); - BufferFileOutput output = new BufferFileOutput(bufferFile); - BufferFileInput input = new BufferFileInput(bufferFile); - OutputSource tableSource = null; - for(OutputSource outputSource:outputList){ - InputSource inputSource = outputSource.getInputSource(); - if(tableSource == null && TableBlock.FILE_NAME.equals(inputSource.getAlias())){ - tableSource = outputSource; - continue; - } - onCompressFileProgress(inputSource.getAlias(), - inputSource.getMethod(), - output.position()); - outputSource.makeBuffer(input, output); - } - if(tableSource != null){ - tableSource.makeBuffer(input, output); - } - output.close(); - return input; - } - private void align(List outputList){ - ZipAligner aligner = getZipAligner(); - if(aligner!=null){ - aligner.reset(); - logMessage("Zip align ..."); - } - for(OutputSource outputSource:outputList){ - outputSource.align(aligner); - } - } - private File getBufferFile(){ - File file = getFile(); - File dir = file.getParentFile(); - String name = file.getAbsolutePath(); - name = "tmp" + name.hashCode(); - File bufFile; - if(dir != null){ - bufFile = new File(dir, name); - }else { - bufFile = new File(name); - } - bufFile.deleteOnExit(); - return bufFile; - } - private List buildOutputEntry(){ - Collection sourceList = this.sourceList; - List results = new ArrayList<>(sourceList.size()); - for(InputSource inputSource:sourceList){ - results.add(toOutputSource(inputSource)); - } - return results; - } - private OutputSource toOutputSource(InputSource inputSource){ - if(inputSource instanceof ArchiveEntrySource){ - return new ArchiveOutputSource(inputSource); - } - if(inputSource instanceof RenamedInputSource){ - InputSource renamed = ((RenamedInputSource) inputSource).getInputSource(); - if(renamed instanceof ArchiveEntrySource){ - return new RenamedArchiveSource((RenamedInputSource) inputSource); - } - } - return new OutputSource(inputSource); - } - - public void setWriteProgress(WriteProgress writeProgress){ - this.writeProgress = writeProgress; - } - private void onCompressFileProgress(String path, int mode, long writtenBytes) { - if(writeProgress!=null){ - writeProgress.onCompressFile(path, mode, writtenBytes); - } - } - - APKLogger getApkLogger(){ - return apkLogger; - } - public void setAPKLogger(APKLogger logger) { - this.apkLogger = logger; - } - private void logMessage(String msg) { - if(apkLogger!=null){ - apkLogger.logMessage(msg); - } - } - private void logError(String msg, Throwable tr) { - if(apkLogger!=null){ - apkLogger.logError(msg, tr); - } - } - private void logVerbose(String msg) { - if(apkLogger!=null){ - apkLogger.logVerbose(msg); - } - } - -} diff --git a/src/ARSCLib/com/reandroid/archive2/writer/ArchiveOutputSource.java b/src/ARSCLib/com/reandroid/archive2/writer/ArchiveOutputSource.java deleted file mode 100644 index b6edaf22..00000000 --- a/src/ARSCLib/com/reandroid/archive2/writer/ArchiveOutputSource.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.writer; - -import com.reandroid.archive.InputSource; -import com.reandroid.archive2.block.LocalFileHeader; -import com.reandroid.archive2.io.ArchiveEntrySource; -import com.reandroid.archive2.io.ZipFileInput; -import com.reandroid.archive2.io.ZipInput; - - -public class ArchiveOutputSource extends OutputSource{ - public ArchiveOutputSource(InputSource inputSource){ - super(inputSource); - } - - ArchiveEntrySource getArchiveSource(){ - return (ArchiveEntrySource) super.getInputSource(); - } - @Override - EntryBuffer makeFromEntry(){ - ArchiveEntrySource entrySource = getArchiveSource(); - ZipInput zip = entrySource.getZipSource(); - if(!(zip instanceof ZipFileInput)){ - return null; - } - LocalFileHeader lfh = entrySource.getArchiveEntry().getLocalFileHeader(); - if(lfh.getMethod() != getInputSource().getMethod()){ - return null; - } - return new EntryBuffer((ZipFileInput) zip, - lfh.getFileOffset(), - lfh.getDataSize()); - } - @Override - public LocalFileHeader createLocalFileHeader(){ - ArchiveEntrySource source = getArchiveSource(); - return source.getArchiveEntry().getLocalFileHeader(); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/writer/BufferFileInput.java b/src/ARSCLib/com/reandroid/archive2/writer/BufferFileInput.java deleted file mode 100644 index 61ca375f..00000000 --- a/src/ARSCLib/com/reandroid/archive2/writer/BufferFileInput.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.writer; - -import com.reandroid.archive2.io.ZipFileInput; - -import java.io.File; -import java.io.IOException; -import java.nio.channels.FileChannel; - -public class BufferFileInput extends ZipFileInput { - private boolean unlocked; - public BufferFileInput(File file){ - super(file); - } - - public void unlock(){ - this.unlocked = true; - } - - @Override - public FileChannel getFileChannel() throws IOException { - if(unlocked){ - return super.getFileChannel(); - } - throw new IOException("File locked!"); - } - @Override - public void close() throws IOException { - super.close(); - if(unlocked){ - File file = super.getFile(); - if(file.isFile()){ - file.delete(); - } - unlocked = false; - } - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/writer/BufferFileOutput.java b/src/ARSCLib/com/reandroid/archive2/writer/BufferFileOutput.java deleted file mode 100644 index 8eae2b4b..00000000 --- a/src/ARSCLib/com/reandroid/archive2/writer/BufferFileOutput.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.writer; - -import com.reandroid.archive2.io.ZipFileOutput; - -import java.io.File; -import java.io.IOException; - -public class BufferFileOutput extends ZipFileOutput { - public BufferFileOutput(File file) throws IOException { - super(file); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/writer/EntryBuffer.java b/src/ARSCLib/com/reandroid/archive2/writer/EntryBuffer.java deleted file mode 100644 index 59b6670b..00000000 --- a/src/ARSCLib/com/reandroid/archive2/writer/EntryBuffer.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.writer; - -import com.reandroid.archive2.io.ZipFileInput; - -public class EntryBuffer { - private final ZipFileInput zipFileInput; - private final long offset; - private final long length; - public EntryBuffer(ZipFileInput zipFileInput, long offset, long length){ - this.zipFileInput = zipFileInput; - this.offset = offset; - this.length = length; - } - - public ZipFileInput getZipFileInput() { - return zipFileInput; - } - public long getOffset() { - return offset; - } - public long getLength() { - return length; - } - -} diff --git a/src/ARSCLib/com/reandroid/archive2/writer/OutputSource.java b/src/ARSCLib/com/reandroid/archive2/writer/OutputSource.java deleted file mode 100644 index f2b3efae..00000000 --- a/src/ARSCLib/com/reandroid/archive2/writer/OutputSource.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.writer; - -import com.reandroid.archive.InputSource; -import com.reandroid.archive2.ZipSignature; -import com.reandroid.archive2.block.CentralEntryHeader; -import com.reandroid.archive2.block.DataDescriptor; -import com.reandroid.archive2.block.LocalFileHeader; -import com.reandroid.archive2.io.CountingOutputStream; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.channels.FileChannel; -import java.util.zip.Deflater; -import java.util.zip.DeflaterOutputStream; -import java.util.zip.ZipEntry; - -class OutputSource { - private final InputSource inputSource; - private LocalFileHeader lfh; - private EntryBuffer entryBuffer; - - OutputSource(InputSource inputSource){ - this.inputSource = inputSource; - } - void align(ZipAligner aligner){ - LocalFileHeader lfh = getLocalFileHeader(); - if(aligner == null){ - lfh.setExtra(null); - }else { - aligner.align(getInputSource(), lfh); - } - } - void makeBuffer(BufferFileInput input, BufferFileOutput output) throws IOException { - EntryBuffer entryBuffer = this.entryBuffer; - if(entryBuffer != null){ - return; - } - entryBuffer = makeFromEntry(); - if(entryBuffer != null){ - this.entryBuffer = entryBuffer; - return; - } - this.entryBuffer = writeBuffer(input, output); - } - private EntryBuffer writeBuffer(BufferFileInput input, BufferFileOutput output) throws IOException { - long offset = output.position(); - writeBufferFile(output); - long length = output.position() - offset; - return new EntryBuffer(input, offset, length); - } - EntryBuffer makeFromEntry(){ - return null; - } - - void writeApk(ApkWriter apkWriter) throws IOException{ - EntryBuffer entryBuffer = this.entryBuffer; - FileChannel input = entryBuffer.getZipFileInput().getFileChannel(); - input.position(entryBuffer.getOffset()); - LocalFileHeader lfh = getLocalFileHeader(); - writeLFH(lfh, apkWriter); - writeData(input, entryBuffer.getLength(), apkWriter); - writeDD(lfh.getDataDescriptor(), apkWriter); - } - void writeCEH(ApkWriter apkWriter) throws IOException{ - LocalFileHeader lfh = getLocalFileHeader(); - CentralEntryHeader ceh = CentralEntryHeader.fromLocalFileHeader(lfh); - ceh.writeBytes(apkWriter.getOutputStream()); - } - private void writeLFH(LocalFileHeader lfh, ApkWriter apkWriter) throws IOException{ - lfh.writeBytes(apkWriter.getOutputStream()); - } - private void writeData(FileChannel input, long length, ApkWriter apkWriter) throws IOException{ - long offset = apkWriter.position(); - LocalFileHeader lfh = getLocalFileHeader(); - lfh.setFileOffset(offset); - apkWriter.write(input, length); - } - void writeDD(DataDescriptor dataDescriptor, ApkWriter apkWriter) throws IOException{ - if(dataDescriptor == null){ - return; - } - dataDescriptor.writeBytes(apkWriter.getOutputStream()); - } - private void writeBufferFile(BufferFileOutput output) throws IOException { - LocalFileHeader lfh = getLocalFileHeader(); - - InputSource inputSource = getInputSource(); - OutputStream rawStream = output.getOutputStream(); - - CountingOutputStream rawCounter = new CountingOutputStream<>(rawStream); - CountingOutputStream deflateCounter = null; - - if(inputSource.getMethod() != ZipEntry.STORED){ - DeflaterOutputStream deflaterInputStream = - new DeflaterOutputStream(rawCounter, new Deflater(Deflater.BEST_SPEED, true), true); - deflateCounter = new CountingOutputStream<>(deflaterInputStream, false); - } - if(deflateCounter != null){ - rawCounter.disableCrc(true); - inputSource.write(deflateCounter); - deflateCounter.close(); - rawCounter.close(); - }else { - inputSource.write(rawCounter); - } - - lfh.setCompressedSize(rawCounter.getSize()); - - if(deflateCounter != null){ - lfh.setMethod(ZipEntry.DEFLATED); - lfh.setCrc(deflateCounter.getCrc()); - lfh.setSize(deflateCounter.getSize()); - }else { - lfh.setSize(rawCounter.getSize()); - lfh.setMethod(ZipEntry.STORED); - lfh.setCrc(rawCounter.getCrc()); - } - - inputSource.disposeInputSource(); - } - - InputSource getInputSource() { - return inputSource; - } - LocalFileHeader getLocalFileHeader(){ - if(lfh == null){ - lfh = createLocalFileHeader(); - lfh.setFileName(getInputSource().getAlias()); - clearAlignment(lfh); - } - return lfh; - } - LocalFileHeader createLocalFileHeader(){ - InputSource inputSource = getInputSource(); - LocalFileHeader lfh = new LocalFileHeader(); - lfh.setSignature(ZipSignature.LOCAL_FILE); - lfh.getGeneralPurposeFlag().initDefault(); - lfh.setFileName(inputSource.getAlias()); - lfh.setMethod(inputSource.getMethod()); - return lfh; - } - private void clearAlignment(LocalFileHeader lfh){ - lfh.getGeneralPurposeFlag().setHasDataDescriptor(false); - lfh.setDataDescriptor(null); - lfh.setExtra(null); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/writer/RenamedArchiveSource.java b/src/ARSCLib/com/reandroid/archive2/writer/RenamedArchiveSource.java deleted file mode 100644 index 1db6b0fc..00000000 --- a/src/ARSCLib/com/reandroid/archive2/writer/RenamedArchiveSource.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.writer; - -import com.reandroid.apk.RenamedInputSource; -import com.reandroid.archive2.io.ArchiveEntrySource; - -public class RenamedArchiveSource extends ArchiveOutputSource{ - public RenamedArchiveSource(RenamedInputSource inputSource) { - super(inputSource); - } - @Override - ArchiveEntrySource getArchiveSource(){ - return (ArchiveEntrySource) - ((RenamedInputSource)super.getInputSource()).getInputSource(); - } -} diff --git a/src/ARSCLib/com/reandroid/archive2/writer/ZipAligner.java b/src/ARSCLib/com/reandroid/archive2/writer/ZipAligner.java deleted file mode 100644 index 65fa12a1..00000000 --- a/src/ARSCLib/com/reandroid/archive2/writer/ZipAligner.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.archive2.writer; - -import com.reandroid.archive.InputSource; -import com.reandroid.archive2.block.DataDescriptor; -import com.reandroid.archive2.block.LocalFileHeader; - -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.zip.ZipEntry; - -public class ZipAligner { - private final Map alignmentMap; - private int defaultAlignment; - private boolean enableDataDescriptor; - private long mCurrentOffset; - - public ZipAligner(){ - alignmentMap = new HashMap<>(); - } - - public void setFileAlignment(Pattern patternFileName, int alignment){ - if(patternFileName == null){ - return; - } - alignmentMap.remove(patternFileName); - if(alignment > 1){ - alignmentMap.put(patternFileName, alignment); - } - } - public void clearFileAlignment(){ - alignmentMap.clear(); - } - public void setDefaultAlignment(int defaultAlignment) { - if(defaultAlignment <= 0){ - defaultAlignment = 1; - } - this.defaultAlignment = defaultAlignment; - } - public void setEnableDataDescriptor(boolean enableDataDescriptor) { - this.enableDataDescriptor = enableDataDescriptor; - } - - void reset(){ - mCurrentOffset = 0; - } - void align(InputSource inputSource, LocalFileHeader lfh){ - lfh.setExtra(null); - int padding; - if(inputSource.getMethod() != ZipEntry.STORED){ - padding = 0; - createDataDescriptor(lfh); - }else { - int alignment = getAlignment(inputSource.getAlias()); - long dataOffset = mCurrentOffset + lfh.countBytes(); - padding = (int) ((alignment - (dataOffset % alignment)) % alignment); - } - lfh.setExtra(new byte[padding]); - mCurrentOffset += lfh.getDataSize() + lfh.countBytes(); - DataDescriptor dataDescriptor = lfh.getDataDescriptor(); - if(dataDescriptor!=null){ - mCurrentOffset += dataDescriptor.countBytes(); - } - } - private void createDataDescriptor(LocalFileHeader lfh){ - DataDescriptor dataDescriptor; - if(enableDataDescriptor){ - dataDescriptor = DataDescriptor.fromLocalFile(lfh); - }else { - dataDescriptor = null; - } - lfh.setDataDescriptor(dataDescriptor); - } - private int getAlignment(String name){ - for(Map.Entry entry:alignmentMap.entrySet()){ - Matcher matcher = entry.getKey().matcher(name); - if(matcher.matches()){ - return entry.getValue(); - } - } - return defaultAlignment; - } - - public static ZipAligner apkAligner(){ - ZipAligner zipAligner = new ZipAligner(); - zipAligner.setDefaultAlignment(ALIGNMENT_4); - Pattern patternNativeLib = Pattern.compile("^lib/.+\\.so$"); - zipAligner.setFileAlignment(patternNativeLib, ALIGNMENT_PAGE); - zipAligner.setEnableDataDescriptor(true); - return zipAligner; - } - - private static final int ALIGNMENT_4 = 4; - private static final int ALIGNMENT_PAGE = 4096; -} diff --git a/src/ARSCLib/com/reandroid/arsc/ApkFile.java b/src/ARSCLib/com/reandroid/arsc/ApkFile.java deleted file mode 100644 index afb664d9..00000000 --- a/src/ARSCLib/com/reandroid/arsc/ApkFile.java +++ /dev/null @@ -1,38 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc; - -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.chunk.xml.AndroidManifestBlock; -import com.reandroid.arsc.chunk.xml.ResXmlDocument; -import com.reandroid.arsc.decoder.Decoder; - -import java.io.IOException; - -public interface ApkFile { - AndroidManifestBlock getAndroidManifestBlock(); - TableBlock getTableBlock(); - ResXmlDocument loadResXmlDocument(String path) throws IOException; - Decoder getDecoder(); - void setDecoder(Decoder decoder); - - enum ApkType { - BASE, - SPLIT, - CORE, - UNKNOWN - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/BuildInfo.java b/src/ARSCLib/com/reandroid/arsc/BuildInfo.java deleted file mode 100755 index 1b1aa7b9..00000000 --- a/src/ARSCLib/com/reandroid/arsc/BuildInfo.java +++ /dev/null @@ -1,58 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc; - -import java.io.InputStream; -import java.util.Properties; - -public class BuildInfo { - private static Properties sProperties; - - public static String getName(){ - Properties properties=getProperties(); - return properties.getProperty("lib.name", "ARSCLib"); - } - public static String getVersion(){ - Properties properties=getProperties(); - return properties.getProperty("lib.version", ""); - } - public static String getRepo(){ - Properties properties=getProperties(); - return properties.getProperty("lib.repo", "https://github.com/REAndroid"); - } - public static String getDescription(){ - Properties properties=getProperties(); - return properties.getProperty("lib.description", "Failed to load properties"); - } - - private static Properties getProperties(){ - if(sProperties==null){ - sProperties=loadProperties(); - } - return sProperties; - } - private static Properties loadProperties(){ - InputStream inputStream=BuildInfo.class.getResourceAsStream("/arsclib.properties"); - Properties properties=new Properties(); - try{ - properties.load(inputStream); - }catch (Exception ignored){ - } - return properties; - } - - public static final String NAME_arsc_lib_version="arsc_lib_version"; -} diff --git a/src/ARSCLib/com/reandroid/arsc/array/CompoundItemArray.java b/src/ARSCLib/com/reandroid/arsc/array/CompoundItemArray.java deleted file mode 100644 index 30983370..00000000 --- a/src/ARSCLib/com/reandroid/arsc/array/CompoundItemArray.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.array; - -import com.reandroid.arsc.base.BlockArray; -import com.reandroid.arsc.value.AttributeType; -import com.reandroid.arsc.value.AttributeDataFormat; -import com.reandroid.arsc.value.ResValueMap; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONArray; - -public abstract class CompoundItemArray extends BlockArray implements JSONConvert { - public CompoundItemArray(){ - super(); - } - public AttributeDataFormat[] getFormats(){ - ResValueMap formatsMap = getByType(AttributeType.FORMATS); - if(formatsMap != null){ - return AttributeDataFormat.decodeValueTypes(formatsMap.getData()); - } - return null; - } - public boolean containsType(AttributeType attributeType){ - for(T valueMap : getChildes()){ - if(attributeType == valueMap.getAttributeType()){ - return true; - } - } - return false; - } - public T getByType(AttributeType attributeType){ - if(attributeType == null){ - return null; - } - for(T valueMap : getChildes()){ - if(attributeType == valueMap.getAttributeType()){ - return valueMap; - } - } - return null; - } - public T getByName(int name){ - for(T resValueMap : getChildes()){ - if(resValueMap != null && name == resValueMap.getName()){ - return resValueMap; - } - } - return null; - } - @Override - protected void onRefreshed() { - } - public void onRemoved(){ - for(T resValueMap : getChildes()){ - resValueMap.onRemoved(); - } - } - @Override - public void clearChildes(){ - this.onRemoved(); - super.clearChildes(); - } - @Override - public JSONArray toJson() { - JSONArray jsonArray=new JSONArray(); - if(isNull()){ - return jsonArray; - } - T[] childes = getChildes(); - for(int i = 0; i < childes.length; i++){ - jsonArray.put(i, childes[i].toJson()); - } - return jsonArray; - } - @Override - public void fromJson(JSONArray json){ - clearChildes(); - if(json==null){ - return; - } - int count=json.length(); - ensureSize(count); - for(int i=0;i mapArray){ - if(mapArray == null || mapArray == this){ - return; - } - clearChildes(); - int count = mapArray.childesCount(); - ensureSize(count); - for(int i=0;i implements JSONConvert { - public EntryArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart){ - super(offsets, itemCount, itemStart); - } - public void linkTableStringsInternal(TableStringPool tableStringPool){ - Iterator itr = iterator(true); - while (itr.hasNext()){ - Entry entry = itr.next(); - entry.linkTableStringsInternal(tableStringPool); - } - } - public void linkSpecStringsInternal(SpecStringPool specStringPool){ - Iterator itr = iterator(true); - while (itr.hasNext()){ - Entry entry = itr.next(); - entry.linkSpecStringsInternal(specStringPool); - } - } - public int getHighestEntryId(){ - if(isSparse()){ - return ((SparseOffsetsArray) getOffsetArray()).getHighestId(); - } - return childesCount(); - } - public int getEntryId(int index){ - OffsetArray offsetArray = getOffsetArray(); - if(offsetArray instanceof SparseOffsetsArray){ - return ((SparseOffsetsArray) offsetArray).getIdx(index); - } - return index; - } - public int getEntryIndex(int entryId){ - OffsetArray offsetArray = getOffsetArray(); - if(offsetArray instanceof SparseOffsetsArray){ - return ((SparseOffsetsArray) offsetArray).indexOf(entryId); - } - return entryId; - } - public boolean isSparse(){ - return super.getOffsetArray() instanceof SparseOffsetsArray; - } - public void destroy(){ - for(Entry entry:listItems()){ - if(entry!=null){ - entry.setNull(true); - } - } - clearChildes(); - } - public Boolean hasComplexEntry(){ - Iterator itr = iterator(true); - while (itr.hasNext()){ - Entry entry = itr.next(); - if(entry.isComplex()){ - return true; - } - ResValue resValue = entry.getResValue(); - ValueType valueType = resValue.getValueType(); - if(valueType == null || valueType == ValueType.REFERENCE - || valueType == ValueType.NULL){ - continue; - } - return false; - } - return null; - } - public boolean isEmpty(){ - return !iterator(true).hasNext(); - } - - public Entry getOrCreate(short entryId){ - int id = 0xffff & entryId; - Entry entry = getEntry(id); - if(entry != null){ - return entry; - } - boolean sparse = isSparse(); - int count; - if(sparse){ - count = childesCount() + 1; - }else { - count = id + 1; - } - ensureSize(count); - if(!sparse){ - refreshCount(); - return super.get(id); - } - SparseOffsetsArray offsetsArray = (SparseOffsetsArray) getOffsetArray(); - offsetsArray.ensureArraySize(count); - int index = count - 1; - offsetsArray.setIdx(index, id); - refreshCount(); - return super.get(index); - } - public Entry get(short entryId){ - return getEntry(entryId); - } - public Entry getEntry(short entryId){ - return getEntry(0xffff & entryId); - } - public Entry getEntry(int entryId){ - int index = getEntryIndex(entryId); - return super.get(index); - } - /** - * It is allowed to have duplicate entry name therefore it is not recommend to use this. - */ - public Entry getEntry(String entryName){ - if(entryName == null){ - return null; - } - Iterator itr = iterator(true); - while (itr.hasNext()){ - Entry entry = itr.next(); - if(entryName.equals(entry.getName())){ - return entry; - } - } - return null; - } - @Override - public Entry newInstance() { - return new Entry(); - } - @Override - public Entry[] newInstance(int len) { - return new Entry[len]; - } - - /** - * To be removed, use getEntry(String entryName) - */ - @Deprecated - public Entry searchByEntryName(String entryName){ - return getEntry(entryName); - } - @Override - public JSONArray toJson() { - JSONArray jsonArray=new JSONArray(); - int index=0; - String name_id = Entry.NAME_id; - for(Entry entry : listItems(true)){ - JSONObject childObject = entry.toJson(); - if(childObject==null){ - continue; - } - childObject.put(name_id, entry.getId()); - jsonArray.put(index, childObject); - index++; - } - return jsonArray; - } - @Override - public void fromJson(JSONArray json) { - clearChildes(); - if(isSparse()){ - fromJsonSparse(json); - }else { - fromJsonNonSparse(json); - } - refreshCountAndStart(); - } - private void fromJsonNonSparse(JSONArray json){ - int length=json.length(); - ensureSize(length); - String name_id = Entry.NAME_id; - for(int i=0;i itr = entryArray.iterator(true); - while (itr.hasNext()){ - Entry comingBlock = itr.next(); - Entry existingBlock = getOrCreate((short) comingBlock.getId()); - existingBlock.merge(comingBlock); - } - } - private void mergeNonSparse(EntryArray entryArray){ - ensureSize(entryArray.childesCount()); - Iterator itr = entryArray.iterator(true); - while (itr.hasNext()){ - Entry comingBlock = itr.next(); - Entry existingBlock = super.get(comingBlock.getIndex()); - existingBlock.merge(comingBlock); - } - } - @Override - public String toString(){ - return getClass().getSimpleName()+": size="+childesCount(); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/array/LibraryInfoArray.java b/src/ARSCLib/com/reandroid/arsc/array/LibraryInfoArray.java deleted file mode 100755 index 79e1ae58..00000000 --- a/src/ARSCLib/com/reandroid/arsc/array/LibraryInfoArray.java +++ /dev/null @@ -1,107 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.array; - -import com.reandroid.arsc.base.BlockArray; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.item.IntegerItem; -import com.reandroid.arsc.value.LibraryInfo; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONArray; -import com.reandroid.json.JSONObject; - -import java.io.IOException; - -public class LibraryInfoArray extends BlockArray implements JSONConvert { - private final IntegerItem mInfoCount; - public LibraryInfoArray(IntegerItem infoCount){ - this.mInfoCount=infoCount; - } - public LibraryInfo getOrCreate(int pkgId){ - LibraryInfo info=getById(pkgId); - if(info!=null){ - return info; - } - int index=childesCount(); - ensureSize(index+1); - info=get(index); - info.setPackageId(pkgId); - return info; - } - public LibraryInfo getById(int pkgId){ - for(LibraryInfo info:listItems()){ - if(pkgId==info.getPackageId()){ - return info; - } - } - return null; - } - @Override - public LibraryInfo newInstance() { - return new LibraryInfo(); - } - @Override - public LibraryInfo[] newInstance(int len) { - return new LibraryInfo[len]; - } - @Override - protected void onRefreshed() { - mInfoCount.set(childesCount()); - } - - @Override - public void onReadBytes(BlockReader reader) throws IOException { - setChildesCount(mInfoCount.get()); - super.onReadBytes(reader); - } - @Override - public JSONArray toJson() { - JSONArray jsonArray=new JSONArray(); - int i=0; - for(LibraryInfo libraryInfo:listItems()){ - JSONObject jsonObject= libraryInfo.toJson(); - if(jsonObject==null){ - continue; - } - jsonArray.put(i, jsonObject); - i++; - } - return jsonArray; - } - @Override - public void fromJson(JSONArray json) { - clearChildes(); - if(json==null){ - return; - } - int length= json.length(); - ensureSize(length); - for (int i=0;i extends BlockArray implements BlockLoad { - private final OffsetArray mOffsets; - private final IntegerItem mItemStart; - private final IntegerItem mItemCount; - private final ByteArray mEnd4Block; - private byte mEnd4Type; - public OffsetBlockArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart){ - super(); - this.mOffsets=offsets; - this.mItemCount=itemCount; - this.mItemStart=itemStart; - this.mEnd4Block=new ByteArray(); - mItemCount.setBlockLoad(this); - } - OffsetArray getOffsetArray(){ - return mOffsets; - } - void setEndBytes(byte b){ - this.mEnd4Type=b; - this.mEnd4Block.fill(b); - } - @Override - public void clearChildes(){ - super.clearChildes(); - mOffsets.clear(); - mItemStart.set(0); - mItemCount.set(0); - mEnd4Block.clear(); - } - @Override - public int countBytes(){ - int result=super.countBytes(); - int endCount=mEnd4Block.countBytes(); - return result+endCount; - } - @Override - public void onCountUpTo(BlockCounter counter){ - super.onCountUpTo(counter); - if(counter.FOUND){ - return; - } - mEnd4Block.onCountUpTo(counter); - } - @Override - public byte[] getBytes(){ - byte[] results=super.getBytes(); - if(results==null){ - return null; - } - byte[] endBytes=mEnd4Block.getBytes(); - results=addBytes(results, endBytes); - return results; - } - @Override - public int onWriteBytes(OutputStream stream) throws IOException { - int result=super.onWriteBytes(stream); - if(result==0){ - return 0; - } - result+=mEnd4Block.writeBytes(stream); - return result; - } - @Override - protected void onRefreshed() { - int count=childesCount(); - OffsetArray offsetArray = this.mOffsets; - offsetArray.setSize(count); - T[] childes=getChildes(); - int sum=0; - if(childes!=null){ - int max=childes.length; - for(int i=0;imaxPos){ - maxPos=pos; - } - } - reader.seek(maxPos); - refreshEnd4Block(reader, mEnd4Block); - } - @Override - public void onBlockLoaded(BlockReader reader, Block sender) throws IOException { - if(sender==mItemCount){ - int count=mItemCount.get(); - setChildesCount(count); - mOffsets.setSize(count); - } - } - - @Override - public String toString(){ - StringBuilder builder=new StringBuilder(); - builder.append(getClass().getSimpleName()); - builder.append(": count = "); - int s= childesCount(); - builder.append(s); - int count=mItemCount.get(); - if(s!=count){ - builder.append(", countValue="); - builder.append(count); - } - builder.append(", start="); - builder.append(mItemStart.get()); - return builder.toString(); - } - -} diff --git a/src/ARSCLib/com/reandroid/arsc/array/PackageArray.java b/src/ARSCLib/com/reandroid/arsc/array/PackageArray.java deleted file mode 100755 index 5fa3aca8..00000000 --- a/src/ARSCLib/com/reandroid/arsc/array/PackageArray.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.array; - -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.base.BlockArray; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.io.BlockLoad; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.item.IntegerItem; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONArray; -import com.reandroid.json.JSONObject; - -import java.io.IOException; -import java.util.Comparator; -import java.util.Iterator; - -public class PackageArray extends BlockArray - implements BlockLoad, JSONConvert, Comparator { - private final IntegerItem mPackageCount; - public PackageArray(IntegerItem packageCount){ - this.mPackageCount=packageCount; - mPackageCount.setBlockLoad(this); - } - public void destroy(){ - Iterator itr = iterator(true); - while (itr.hasNext()){ - PackageBlock packageBlock=itr.next(); - packageBlock.destroy(); - } - clearChildes(); - } - public PackageBlock pickOne(){ - return pickOne(getChildes(), 0); - } - public PackageBlock pickOne(int packageId){ - return pickOne(getChildes(), packageId); - } - private PackageBlock pickOne(PackageBlock[] items, int packageId){ - if(items==null||items.length==0){ - return null; - } - if(items.length==1){ - return items[0]; - } - PackageBlock largest=null; - for(PackageBlock packageBlock:items){ - if(packageBlock == null){ - continue; - } - if(packageId!=0 && packageId!=packageBlock.getId()){ - continue; - } - if(largest==null){ - largest=packageBlock; - }else if(packageBlock.getEntriesGroupMap().size() > - largest.getEntriesGroupMap().size()){ - largest=packageBlock; - } - } - return largest; - } - public void sort(){ - for(PackageBlock packageBlock:listItems()){ - packageBlock.sortTypes(); - } - sort(this); - } - public PackageBlock getOrCreate(byte pkgId){ - return getOrCreate(0xff & pkgId); - } - public PackageBlock getOrCreate(int pkgId){ - PackageBlock packageBlock = getPackageBlockById(pkgId); - if(packageBlock != null){ - return packageBlock; - } - packageBlock = createNext(); - packageBlock.setId(pkgId); - packageBlock.setName("PACKAGE NAME"); - return packageBlock; - } - public PackageBlock getPackageBlockById(byte pkgId){ - return getPackageBlockById(0xff & pkgId); - } - public PackageBlock getPackageBlockById(int pkgId){ - Iterator itr=iterator(true); - while (itr.hasNext()){ - PackageBlock packageBlock=itr.next(); - if(packageBlock.getId()==pkgId){ - return packageBlock; - } - } - return null; - } - @Override - public PackageBlock newInstance() { - return new PackageBlock(); - } - - @Override - public PackageBlock[] newInstance(int len) { - return new PackageBlock[len]; - } - - @Override - protected void onRefreshed() { - refreshPackageCount(); - } - private void refreshPackageCount(){ - mPackageCount.set(childesCount()); - } - - @Override - public void onBlockLoaded(BlockReader reader, Block sender) throws IOException { - if(sender != mPackageCount){ - return; - } - setChildesCount(mPackageCount.get()); - } - @Override - public JSONArray toJson() { - JSONArray jsonArray=new JSONArray(); - int i=0; - for(PackageBlock packageBlock:listItems()){ - JSONObject jsonObject= packageBlock.toJson(); - if(jsonObject==null){ - continue; - } - jsonArray.put(i, jsonObject); - i++; - } - return jsonArray; - } - @Override - public void fromJson(JSONArray json) { - int length= json.length(); - clearChildes(); - ensureSize(length); - for (int i=0;i { - public ResValueMapArray(){ - super(); - } - @Override - public ResValueMap newInstance() { - return new ResValueMap(); - } - - @Override - public ResValueMap[] newInstance(int len) { - return new ResValueMap[len]; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/array/ResXmlAttributeArray.java b/src/ARSCLib/com/reandroid/arsc/array/ResXmlAttributeArray.java deleted file mode 100755 index a1820115..00000000 --- a/src/ARSCLib/com/reandroid/arsc/array/ResXmlAttributeArray.java +++ /dev/null @@ -1,142 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.array; - -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.base.BlockArray; -import com.reandroid.arsc.header.HeaderBlock; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.chunk.xml.ResXmlAttribute; -import com.reandroid.arsc.item.ShortItem; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONArray; -import com.reandroid.json.JSONObject; - -import java.io.IOException; -import java.util.Comparator; - -public class ResXmlAttributeArray extends BlockArray - implements Comparator, JSONConvert { - private final HeaderBlock mHeaderBlock; - private final ShortItem mAttributeStart; - private final ShortItem mAttributeCount; - private final ShortItem mAttributesUnitSize; - public ResXmlAttributeArray(HeaderBlock headerBlock, - ShortItem attributeStart, - ShortItem attributeCount, - ShortItem attributesUnitSize){ - this.mHeaderBlock=headerBlock; - this.mAttributeStart=attributeStart; - this.mAttributeCount=attributeCount; - this.mAttributesUnitSize=attributesUnitSize; - } - public void setAttributesUnitSize(int size){ - ResXmlAttribute[] attributes=getChildes(); - for(int i=0;i { - private final HeaderBlock mHeaderBlock; - private final Map mResIdMap; - private boolean mUpdated; - public ResXmlIDArray(HeaderBlock headerBlock){ - super(); - this.mHeaderBlock=headerBlock; - this.mResIdMap=new HashMap<>(); - } - public void addResourceId(int index, int resId){ - if(index<0){ - return; - } - ensureSize(index+1); - ResXmlID xmlID=get(index); - if(xmlID!=null){ - xmlID.set(resId); - } - } - public ResXmlID getOrCreate(int resId){ - updateIdMap(); - ResXmlID xmlID=mResIdMap.get(resId); - if(xmlID!=null){ - return xmlID; - } - xmlID=new ResXmlID(resId); - add(xmlID); - mUpdated=true; - mResIdMap.put(resId, xmlID); - return xmlID; - } - public ResXmlID getByResId(int resId){ - updateIdMap(); - return mResIdMap.get(resId); - } - public void refreshIdMap(){ - mUpdated = false; - updateIdMap(); - } - private void updateIdMap(){ - if(mUpdated){ - return; - } - mUpdated=true; - mResIdMap.clear(); - ResXmlID[] allChildes=getChildes(); - if(allChildes==null||allChildes.length==0){ - return; - } - int max=allChildes.length; - for(int i=0;i { - public ResXmlStringArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { - super(offsets, itemCount, itemStart, is_utf8); - } - @Override - List listUnusedStringsToRemove(){ - List results=new ArrayList<>(); - ResXmlIDMap idMap = getResXmlIDMap(); - int lastIndex = -1; - if(idMap!=null){ - lastIndex = idMap.countId(); - } - for(ResXmlString item:listItems()){ - if(item == null - || item.hasReference() - || item.getIndex() result){ - result = id; - } - } - if(result == NO_ENTRY){ - result = 0; - } - return result; - } - public int indexOf(int idx){ - int size = super.size(); - for(int i=0; i>> 16) & 0xffff; - return value * 4; - } - @Override - public void setOffset(int index, int offset){ - int value; - if(offset == NO_ENTRY){ - value = 0; - }else { - int idx = getAt(index); - idx = idx & 0xffff; - offset = offset & 0xffff; - offset = offset / 4; - offset = offset << 16; - value = offset | idx; - } - super.put(index, value); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/array/SpecBlockArray.java b/src/ARSCLib/com/reandroid/arsc/array/SpecBlockArray.java deleted file mode 100755 index 22f918ba..00000000 --- a/src/ARSCLib/com/reandroid/arsc/array/SpecBlockArray.java +++ /dev/null @@ -1,39 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.array; - -import com.reandroid.arsc.base.BlockArray; -import com.reandroid.arsc.chunk.SpecBlock; - -public class SpecBlockArray extends BlockArray { - public SpecBlockArray(){ - super(); - } - @Override - public SpecBlock newInstance() { - return new SpecBlock(); - } - - @Override - public SpecBlock[] newInstance(int len) { - return new SpecBlock[len]; - } - - @Override - protected void onRefreshed() { - - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/array/SpecStringArray.java b/src/ARSCLib/com/reandroid/arsc/array/SpecStringArray.java deleted file mode 100755 index 82e2c1b9..00000000 --- a/src/ARSCLib/com/reandroid/arsc/array/SpecStringArray.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.array; - -import com.reandroid.arsc.item.IntegerItem; -import com.reandroid.arsc.item.SpecString; - -public class SpecStringArray extends StringArray { - public SpecStringArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { - super(offsets, itemCount, itemStart, is_utf8); - } - @Override - public SpecString newInstance() { - return new SpecString(isUtf8()); - } - @Override - public SpecString[] newInstance(int len) { - return new SpecString[len]; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/array/SpecTypePairArray.java b/src/ARSCLib/com/reandroid/arsc/array/SpecTypePairArray.java deleted file mode 100755 index 903061f1..00000000 --- a/src/ARSCLib/com/reandroid/arsc/array/SpecTypePairArray.java +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.array; - -import com.reandroid.arsc.base.BlockArray; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.SpecBlock; -import com.reandroid.arsc.chunk.TypeBlock; -import com.reandroid.arsc.container.SpecTypePair; -import com.reandroid.arsc.group.EntryGroup; -import com.reandroid.arsc.group.StringGroup; -import com.reandroid.arsc.item.TypeString; -import com.reandroid.arsc.pool.TypeStringPool; -import com.reandroid.arsc.value.Entry; -import com.reandroid.arsc.value.ResConfig; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONArray; -import com.reandroid.json.JSONObject; - -import java.util.*; - -public class SpecTypePairArray extends BlockArray - implements JSONConvert, Comparator { - public SpecTypePairArray(){ - super(); - } - - public void sort(){ - for(SpecTypePair specTypePair:listItems()){ - specTypePair.sortTypes(); - } - sort(this); - } - public void removeEmptyPairs(){ - List allPairs=new ArrayList<>(listItems()); - boolean foundEmpty=false; - for(SpecTypePair typePair:allPairs){ - typePair.removeEmptyTypeBlocks(); - if(typePair.isEmpty()){ - super.remove(typePair, false); - foundEmpty=true; - } - } - if(foundEmpty){ - trimNullBlocks(); - } - } - public boolean isEmpty(){ - Iterator iterator=iterator(true); - while (iterator.hasNext()){ - SpecTypePair pair=iterator.next(); - if(!pair.isEmpty()){ - return false; - } - } - return true; - } - public Entry getOrCreateEntry(byte typeId, short entryId, String qualifiers){ - TypeBlock typeBlock=getOrCreateTypeBlock(typeId, qualifiers); - return typeBlock.getOrCreateEntry(entryId); - } - public Entry getEntry(byte typeId, short entryId, String qualifiers){ - TypeBlock typeBlock=getTypeBlock(typeId, qualifiers); - if(typeBlock==null){ - return null; - } - return typeBlock.getEntry(entryId); - } - public TypeBlock getOrCreateTypeBlock(byte typeId, String qualifiers){ - SpecTypePair pair=getOrCreate(typeId); - return pair.getOrCreateTypeBlock(qualifiers); - } - public TypeBlock getTypeBlock(byte typeId, String qualifiers){ - SpecTypePair pair= getSpecTypePair(typeId); - if(pair==null){ - return null; - } - return pair.getTypeBlock(qualifiers); - } - public TypeBlock getOrCreate(byte typeId, ResConfig resConfig){ - SpecTypePair pair=getOrCreate(typeId); - return pair.getTypeBlockArray().getOrCreate(resConfig); - } - public SpecTypePair getOrCreate(byte typeId){ - SpecTypePair pair = getSpecTypePair(typeId); - if(pair!=null){ - return pair; - } - pair = createNext(); - pair.setTypeId(typeId); - return pair; - } - public SpecTypePair getOrCreate(String typeName){ - SpecTypePair specTypePair = getSpecTypePair(typeName); - if(specTypePair != null){ - return specTypePair; - } - TypeString typeString = getOrCreateTypeString(typeName); - byte id = (byte) typeString.getId(); - specTypePair = createNext(); - specTypePair.setTypeId(id); - return specTypePair; - } - public TypeBlock getOrCreateTypeBlock(String typeName, ResConfig resConfig){ - return getOrCreate(typeName).getOrCreateTypeBlock(resConfig); - } - public TypeBlock getOrCreateTypeBlock(String typeName, String qualifiers){ - return getOrCreate(typeName).getOrCreateTypeBlock(qualifiers); - } - public SpecTypePair getSpecTypePair(int typeId){ - return getSpecTypePair((byte) typeId); - } - public SpecTypePair getSpecTypePair(byte typeId){ - SpecTypePair[] items = getChildes(); - if(items == null){ - return null; - } - int length = items.length; - for(int i = 0; i < length; i++){ - SpecTypePair specTypePair = items[i]; - if(specTypePair != null && specTypePair.getTypeId() == typeId){ - return specTypePair; - } - } - return null; - } - public SpecTypePair getSpecTypePair(String typeName){ - if(typeName == null){ - return null; - } - Iterator itr = iterator(true); - while (itr.hasNext()){ - SpecTypePair specTypePair = itr.next(); - if(specTypePair.isEqualTypeName(typeName)){ - return specTypePair; - } - } - return null; - } - public Entry getAnyEntry(byte typeId, short entryId){ - if(typeId == 0){ - return null; - } - SpecTypePair specTypePair = getSpecTypePair(typeId); - if(specTypePair != null){ - return specTypePair.getAnyEntry(entryId); - } - return null; - } - public Entry getAnyEntry(String typeName, String entryName){ - SpecTypePair specTypePair = getSpecTypePair(typeName); - if(specTypePair != null){ - return specTypePair.getAnyEntry(entryName); - } - return null; - } - public Entry getEntry(String qualifiers, String typeName, String entryName){ - ResConfig resConfig = new ResConfig(); - resConfig.parseQualifiers(qualifiers); - return getEntry(resConfig, typeName, entryName); - } - public Entry getEntry(ResConfig resConfig, String typeName, String entryName){ - SpecTypePair specTypePair = getSpecTypePair(typeName); - if(specTypePair != null){ - return specTypePair.getEntry(resConfig, entryName); - } - return null; - } - public EntryGroup getEntryGroup(String typeName, String entryName){ - SpecTypePair specTypePair = getSpecTypePair(typeName); - if(specTypePair != null){ - return specTypePair.getEntryGroup(entryName); - } - return null; - } - @Override - public SpecTypePair newInstance() { - return new SpecTypePair(); - } - @Override - public SpecTypePair[] newInstance(int len) { - return new SpecTypePair[len]; - } - @Override - protected void onRefreshed() { - - } - @Override - protected void onPreRefreshRefresh(){ - validateEntryCounts(); - } - - private void validateEntryCounts(){ - Map entryCountMap=mapHighestEntryCount(); - for(Map.Entry entry:entryCountMap.entrySet()){ - byte id=entry.getKey(); - int count=entry.getValue(); - SpecTypePair pair= getSpecTypePair(id); - pair.getSpecBlock().setEntryCount(count); - pair.getTypeBlockArray().setEntryCount(count); - } - } - private Map mapHighestEntryCount(){ - Map results=new HashMap<>(); - SpecTypePair[] childes=getChildes(); - for (SpecTypePair pair:childes){ - int count=pair.getHighestEntryCount(); - byte id=pair.getTypeId(); - Integer exist=results.get(id); - if(exist==null || count>exist){ - results.put(id, count); - } - } - return results; - } - public int getSmallestTypeId(){ - SpecTypePair[] childes=getChildes(); - if(childes==null){ - return 0; - } - int result=0; - boolean firstFound=false; - for (int i=0;iresult){ - result=id; - } - } - return result; - } - private TypeString getOrCreateTypeString(String typeName){ - TypeStringPool typeStringPool = getTypeStringPool(); - if(typeStringPool == null){ - return null; - } - StringGroup group = typeStringPool.get(typeName); - if(group != null){ - return group.get(0); - } - int id = typeStringPool.getLastId() + 1; - return typeStringPool.getOrCreate(id, typeName); - } - private TypeStringPool getTypeStringPool(){ - PackageBlock packageBlock = getPackageBlock(); - if(packageBlock != null){ - return packageBlock.getTypeStringPool(); - } - return null; - } - private PackageBlock getPackageBlock(){ - return getParentInstance(PackageBlock.class); - } - @Override - public JSONArray toJson() { - return toJson(false); - } - @Override - public void fromJson(JSONArray json) { - if(json==null){ - return; - } - int length = json.length(); - for (int i=0;i - implements BlockLoad, JSONConvert { - private final IntegerItem count; - public StagedAliasEntryArray(IntegerItem count){ - super(); - this.count=count; - this.count.setBlockLoad(this); - } - public boolean contains(StagedAliasEntry aliasEntry){ - StagedAliasEntry[] childes=getChildes(); - if(childes==null){ - return false; - } - for(int i=0;i extends OffsetBlockArray implements JSONConvert { - private boolean mUtf8; - - public StringArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { - super(offsets, itemCount, itemStart); - this.mUtf8=is_utf8; - setEndBytes((byte)0x00); - } - public List toStringList(){ - return new AbstractList() { - @Override - public String get(int i) { - T item=StringArray.this.get(i); - if(item==null){ - return null; - } - return item.getHtml(); - } - @Override - public int size() { - return childesCount(); - } - }; - } - public List removeUnusedStrings(){ - List unusedList = listUnusedStringsToRemove(); - remove(unusedList); - for(T item:unusedList){ - item.onRemoved(); - } - return unusedList; - } - List listUnusedStringsToRemove(){ - return listUnusedStrings(); - } - public List listUnusedStrings(){ - List results=new ArrayList<>(); - for(T item:listItems()){ - if(!item.hasReference()){ - results.add(item); - } - } - return results; - } - public void setUtf8(boolean is_utf8){ - if(mUtf8==is_utf8){ - return; - } - mUtf8=is_utf8; - T[] childes=getChildes(); - if(childes!=null){ - int max=childes.length; - for(int i=0;i implements JSONConvert { - public StyleArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart) { - super(offsets, itemCount, itemStart); - setEndBytes(END_BYTE); - } - @Override - public void clearChildes(){ - for(StyleItem styleItem:listItems()){ - styleItem.onRemoved(); - } - super.clearChildes(); - } - @Override - void refreshEnd4Block(BlockReader reader, ByteArray end4Block) throws IOException { - end4Block.clear(); - if(reader.available()<4){ - return; - } - IntegerItem integerItem=new IntegerItem(); - while (reader.available()>=4){ - int pos=reader.getPosition(); - integerItem.readBytes(reader); - if(integerItem.get()!=0xFFFFFFFF){ - reader.seek(pos); - break; - } - end4Block.add(integerItem.getBytes()); - } - } - @Override - void refreshEnd4Block(ByteArray end4Block) { - super.refreshEnd4Block(end4Block); - if(childesCount()==0){ - return; - } - end4Block.ensureArraySize(8); - end4Block.fill(END_BYTE); - } - @Override - protected void refreshChildes(){ - // Not required - } - @Override - public StyleItem newInstance() { - return new StyleItem(); - } - @Override - public StyleItem[] newInstance(int len) { - return new StyleItem[len]; - } - - @Override - public JSONArray toJson() { - if(childesCount()==0){ - return null; - } - return null; - } - @Override - public void fromJson(JSONArray json) { - - } - public void merge(StyleArray styleArray){ - if(styleArray==null||styleArray==this){ - return; - } - if(childesCount()!=0){ - return; - } - int count=styleArray.childesCount(); - ensureSize(count); - for(int i=0;i { - public TableStringArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { - super(offsets, itemCount, itemStart, is_utf8); - } - @Override - public TableString newInstance() { - return new TableString(isUtf8()); - } - @Override - public TableString[] newInstance(int len) { - return new TableString[len]; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/array/TypeBlockArray.java b/src/ARSCLib/com/reandroid/arsc/array/TypeBlockArray.java deleted file mode 100755 index 3d991c8e..00000000 --- a/src/ARSCLib/com/reandroid/arsc/array/TypeBlockArray.java +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.array; - -import com.reandroid.arsc.chunk.ChunkType; -import com.reandroid.arsc.base.BlockArray; -import com.reandroid.arsc.chunk.SpecBlock; -import com.reandroid.arsc.chunk.TypeBlock; -import com.reandroid.arsc.container.SpecTypePair; -import com.reandroid.arsc.header.HeaderBlock; -import com.reandroid.arsc.header.TypeHeader; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.item.TypeString; -import com.reandroid.arsc.value.Entry; -import com.reandroid.arsc.value.ResConfig; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONArray; -import com.reandroid.json.JSONObject; - -import java.io.IOException; -import java.util.*; -import java.util.function.Predicate; - -public class TypeBlockArray extends BlockArray - implements JSONConvert, Comparator { - private byte mTypeId; - private Boolean mHasComplexEntry; - - public TypeBlockArray(){ - super(); - } - - public Boolean hasComplexEntry(){ - if(mHasComplexEntry != null){ - return mHasComplexEntry; - } - for(TypeBlock typeBlock : listItems(true)){ - Boolean hasComplex = typeBlock.getEntryArray().hasComplexEntry(); - if(hasComplex != null){ - mHasComplexEntry = hasComplex; - } - } - return mHasComplexEntry; - } - public void destroy(){ - for(TypeBlock typeBlock:listItems()){ - if(typeBlock!=null){ - typeBlock.destroy(); - } - } - clearChildes(); - } - public void sort(){ - sort(this); - } - public boolean removeNullEntries(int startId){ - boolean result = true; - for(TypeBlock typeBlock:listItems()){ - boolean removed = typeBlock.removeNullEntries(startId); - result = result && removed; - } - return result; - } - public void removeEmptyBlocks(){ - List allTypes=new ArrayList<>(listItems()); - boolean foundEmpty=false; - for(TypeBlock typeBlock:allTypes){ - if(typeBlock.isEmpty()){ - super.remove(typeBlock, false); - foundEmpty=true; - } - } - if(foundEmpty){ - trimNullBlocks(); - } - } - public Entry getOrCreateEntry(short entryId, String qualifiers){ - TypeBlock typeBlock=getOrCreate(qualifiers); - return typeBlock.getOrCreateEntry(entryId); - } - public boolean isEmpty(){ - for(TypeBlock typeBlock:listItems()){ - if(typeBlock!=null && !typeBlock.isEmpty()){ - return false; - } - } - return true; - } - public Entry getEntry(short entryId, String qualifiers){ - TypeBlock typeBlock=getTypeBlock(qualifiers); - if(typeBlock==null){ - return null; - } - return typeBlock.getEntry(entryId); - } - public Entry getEntry(ResConfig resConfig, String entryName){ - TypeBlock typeBlock = getTypeBlock(resConfig); - if(typeBlock != null){ - return typeBlock.getEntry(entryName); - } - return null; - } - public TypeBlock getOrCreate(ResConfig resConfig){ - return getOrCreate(resConfig, false); - } - public TypeBlock getOrCreate(ResConfig resConfig, boolean sparse){ - TypeBlock typeBlock = getTypeBlock(resConfig, sparse); - if(typeBlock != null){ - return typeBlock; - } - byte id = getTypeId(); - typeBlock = createNext(sparse); - typeBlock.setTypeId(id); - ResConfig config = typeBlock.getResConfig(); - config.copyFrom(resConfig); - return typeBlock; - } - public TypeBlock getOrCreate(String qualifiers){ - TypeBlock typeBlock=getTypeBlock(qualifiers); - if(typeBlock!=null){ - return typeBlock; - } - typeBlock=createNext(); - ResConfig config=typeBlock.getResConfig(); - config.parseQualifiers(qualifiers); - return typeBlock; - } - public TypeBlock getTypeBlock(String qualifiers){ - TypeBlock[] items=getChildes(); - if(items==null){ - return null; - } - int max=items.length; - for(int i=0;i listResConfig(){ - return new AbstractList() { - @Override - public ResConfig get(int i) { - TypeBlock typeBlock=TypeBlockArray.this.get(i); - if(typeBlock!=null){ - return typeBlock.getResConfig(); - } - return null; - } - - @Override - public int size() { - return TypeBlockArray.this.childesCount(); - } - }; - } - public Iterator iteratorNonEmpty(){ - return super.iterator(NON_EMPTY_TESTER); - } - public boolean hasDuplicateResConfig(boolean ignoreEmpty){ - Set uniqueHashSet = new HashSet<>(); - Iterator itr; - if(ignoreEmpty){ - itr = iteratorNonEmpty(); - }else { - itr = iterator(true); - } - while (itr.hasNext()){ - Integer hash = itr.next() - .getResConfig().hashCode(); - if(uniqueHashSet.contains(hash)){ - return true; - } - uniqueHashSet.add(hash); - } - return false; - } - private SpecBlock getSpecBlock(){ - SpecTypePair parent = getParent(SpecTypePair.class); - if(parent != null){ - return parent.getSpecBlock(); - } - return null; - } - @Override - protected boolean remove(TypeBlock block, boolean trim){ - if(block==null){ - return false; - } - block.cleanEntries(); - return super.remove(block, trim); - } - @Override - public TypeBlock newInstance() { - byte id = getTypeId(); - TypeBlock typeBlock = new TypeBlock(false); - typeBlock.setTypeId(id); - return typeBlock; - } - @Override - public TypeBlock[] newInstance(int len) { - return new TypeBlock[len]; - } - public TypeBlock createNext(boolean sparse){ - byte id = getTypeId(); - TypeBlock typeBlock = new TypeBlock(sparse); - typeBlock.setTypeId(id); - add(typeBlock); - return typeBlock; - } - @Override - protected void onRefreshed() { - - } - @Override - public void onReadBytes(BlockReader reader) throws IOException { - boolean readOk=true; - while (readOk){ - readOk=readTypeBlockArray(reader); - } - } - private boolean readTypeBlockArray(BlockReader reader) throws IOException{ - HeaderBlock headerBlock=reader.readHeaderBlock(); - if(headerBlock==null){ - return false; - } - ChunkType chunkType=headerBlock.getChunkType(); - if(chunkType!=ChunkType.TYPE){ - return false; - } - TypeHeader typeHeader = reader.readTypeHeader(); - int id = getTypeId(); - if(id!=0 && typeHeader.getId().unsignedInt() != id){ - return false; - } - int pos=reader.getPosition(); - TypeBlock typeBlock=createNext(); - typeBlock.readBytes(reader); - return reader.getPosition()>pos; - } - public int getHighestEntryCount(){ - int result=0; - for(TypeBlock typeBlock:getChildes()){ - int high = typeBlock.getEntryArray().getHighestEntryId(); - if(high > result){ - result = high; - } - } - return result; - } - public void setEntryCount(int count){ - for(TypeBlock typeBlock:getChildes()){ - if(!typeBlock.isSparse()){ - typeBlock.setEntryCount(count); - } - } - } - public TypeString getTypeString(){ - for(TypeBlock typeBlock:getChildes()){ - TypeString typeString=typeBlock.getTypeString(); - if(typeString!=null){ - return typeString; - } - } - return null; - } - @Override - public JSONArray toJson() { - JSONArray jsonArray=new JSONArray(); - int i=0; - for(TypeBlock typeBlock:listItems()){ - JSONObject jsonObject= typeBlock.toJson(); - if(jsonObject==null){ - continue; - } - jsonArray.put(i, jsonObject); - i++; - } - return jsonArray; - } - @Override - public void fromJson(JSONArray json) { - if(json == null){ - return; - } - int length = json.length(); - for(int i = 0; i < length; i++){ - JSONObject jsonObject = json.getJSONObject(i); - TypeBlock typeBlock = createNext( - jsonObject.optBoolean(TypeBlock.NAME_is_sparse, false)); - typeBlock.fromJson(jsonObject); - } - } - public void merge(TypeBlockArray typeBlockArray){ - if(typeBlockArray == null || typeBlockArray == this){ - return; - } - for(TypeBlock typeBlock:typeBlockArray.listItems()){ - TypeBlock exist = getOrCreate( - typeBlock.getResConfig(), typeBlock.isSparse()); - exist.merge(typeBlock); - } - } - /** - * TOBEREMOVED - * - * It's mistake to have this method - * - */ - @Deprecated - public Entry searchByEntryName(String entryName){ - if(entryName==null){ - return null; - } - TypeBlock[] childes = getChildes(); - if(childes==null || childes.length==0){ - return null; - } - return childes[0].getEntry(entryName); - } - @Override - public int compare(TypeBlock typeBlock1, TypeBlock typeBlock2) { - return typeBlock1.compareTo(typeBlock2); - } - - private static final Predicate NON_EMPTY_TESTER = new Predicate() { - @Override - public boolean test(TypeBlock typeBlock) { - if(typeBlock == null || typeBlock.isNull()){ - return false; - } - return !typeBlock.isEmpty(); - } - }; -} diff --git a/src/ARSCLib/com/reandroid/arsc/array/TypeStringArray.java b/src/ARSCLib/com/reandroid/arsc/array/TypeStringArray.java deleted file mode 100755 index 1c6de643..00000000 --- a/src/ARSCLib/com/reandroid/arsc/array/TypeStringArray.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.array; - -import com.reandroid.arsc.item.IntegerItem; -import com.reandroid.arsc.item.TypeString; - -public class TypeStringArray extends StringArray { - private int lastCreateIndex; - public TypeStringArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { - super(offsets, itemCount, itemStart, is_utf8); - } - @Override - public TypeString newInstance() { - TypeString typeString=new TypeString(isUtf8()); - //create default name - this.lastCreateIndex++; - typeString.set("type-"+lastCreateIndex); - return typeString; - } - @Override - public TypeString[] newInstance(int len) { - return new TypeString[len]; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/base/Block.java b/src/ARSCLib/com/reandroid/arsc/base/Block.java deleted file mode 100755 index d66e8b41..00000000 --- a/src/ARSCLib/com/reandroid/arsc/base/Block.java +++ /dev/null @@ -1,134 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.base; - -import com.reandroid.arsc.io.BlockLoad; -import com.reandroid.arsc.io.BlockReader; - -import java.io.IOException; -import java.io.OutputStream; - -public abstract class Block { - private int mIndex=-1; - private Block mParent; - private boolean mNull; - private BlockLoad mBlockLoad; - public abstract byte[] getBytes(); - public abstract int countBytes(); - public final int countUpTo(Block block){ - BlockCounter counter=new BlockCounter(block); - onCountUpTo(counter); - return counter.COUNT; - } - public abstract void onCountUpTo(BlockCounter counter); - public final void readBytes(BlockReader reader) throws IOException{ - onReadBytes(reader); - notifyBlockLoad(reader); - } - public final void setBlockLoad(BlockLoad blockLoad){ - mBlockLoad=blockLoad; - } - public void notifyBlockLoad() throws IOException { - notifyBlockLoad(null); - } - private void notifyBlockLoad(BlockReader reader) throws IOException{ - BlockLoad blockLoad=mBlockLoad; - if(blockLoad!=null){ - blockLoad.onBlockLoaded(reader, this); - } - } - protected void onReadBytes(BlockReader reader) throws IOException{ - } - public final int writeBytes(OutputStream stream) throws IOException{ - if(isNull()){ - return 0; - } - return onWriteBytes(stream); - } - protected abstract int onWriteBytes(OutputStream stream) throws IOException; - public boolean isNull(){ - return mNull; - } - public void setNull(boolean is_null){ - mNull=is_null; - } - public final int getIndex(){ - return mIndex; - } - public final void setIndex(int index){ - int old=mIndex; - if(index==old){ - return; - } - mIndex=index; - if(old!=-1 && index!=-1){ - onIndexChanged(old, index); - } - } - public void onIndexChanged(int oldIndex, int newIndex){ - - } - public final void setParent(Block parent){ - if(parent==this){ - return; - } - mParent=parent; - } - public final Block getParent(){ - return mParent; - } - public final T getParent(Class parentClass){ - Block parent = getParent(); - while (parent!=null){ - if(parent.getClass() == parentClass){ - return (T) parent; - } - parent = parent.getParent(); - } - return null; - } - public final T getParentInstance(Class parentClass){ - Block parent = getParent(); - while (parent!=null){ - if(parentClass.isInstance(parent)){ - return (T) parent; - } - parent = parent.getParent(); - } - return null; - } - - - protected static byte[] addBytes(byte[] bts1, byte[] bts2){ - boolean empty1=(bts1==null || bts1.length==0); - boolean empty2=(bts2==null || bts2.length==0); - if(empty1 && empty2){ - return null; - } - if(empty1){ - return bts2; - } - if(empty2){ - return bts1; - } - int len=bts1.length+bts2.length; - byte[] result=new byte[len]; - int start=bts1.length; - System.arraycopy(bts1, 0, result, 0, start); - System.arraycopy(bts2, 0, result, start, bts2.length); - return result; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/base/BlockArray.java b/src/ARSCLib/com/reandroid/arsc/base/BlockArray.java deleted file mode 100755 index b050be70..00000000 --- a/src/ARSCLib/com/reandroid/arsc/base/BlockArray.java +++ /dev/null @@ -1,502 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.base; - -import java.util.*; -import java.util.function.Predicate; - - -public abstract class BlockArray extends BlockContainer implements BlockArrayCreator { - private T[] elementData; - public BlockArray(){ - elementData= newInstance(0); - } - - public void removeAllNull(int start){ - removeAll(start, true); - } - public void removeAll(int start){ - removeAll(start, false); - } - private void removeAll(int start, boolean check_null){ - List removeList = subList(start); - if(removeList.size()==0 || (check_null && !isAllNull(removeList))){ - return; - } - T[] itemArray = this.elementData; - for(T item:removeList){ - if(item==null){ - continue; - } - if(!item.isNull()){ - item.setNull(true); - } - int index = item.getIndex(); - if(index>=0 && itemArray[index]==item){ - item.setIndex(-1); - item.setParent(null); - itemArray[index] = null; - } - } - setChildesCount(start); - } - public List subList(int start){ - return subList(start, -1); - } - public List subList(int start, int count){ - T[] items = this.elementData; - if(items==null){ - return new ArrayList<>(); - } - int length = items.length; - if(start>=length){ - return new ArrayList<>(); - } - if(start < 0){ - start=0; - } - int end = count; - if(end < 0){ - end = items.length; - }else { - end = start + count; - if(end > length){ - end=length; - } - } - List results = new ArrayList<>(end - start); - for(int i=start; i listItems(){ - return listItems(false); - } - public Collection listItems(boolean skipNullBlocks){ - return new AbstractCollection() { - @Override - public Iterator iterator(){ - return BlockArray.this.iterator(skipNullBlocks); - } - @Override - public boolean contains(Object o){ - return BlockArray.this.contains(o); - } - @Override - public int size() { - return BlockArray.this.childesCount(); - } - }; - } - @Override - public T[] getChildes(){ - return elementData; - } - public void ensureSize(int size){ - if(size<= childesCount()){ - return; - } - setChildesCount(size); - } - public void setChildesCount(int count){ - if(count<0){ - count=0; - } - if(count==0){ - clearChildes(); - return; - } - int diff = count - childesCount(); - if(diff==0){ - return; - } - changeSize(diff); - } - public void clearChildes(){ - T[] allChildes=elementData; - if(allChildes==null || allChildes.length==0){ - return; - } - int max=allChildes.length; - for(int i=0;i0){ - System.arraycopy(old, 0, update, 0, oldLen); - } - boolean foundNull=false; - for(int i=0;i comparator){ - T[] data=this.elementData; - if(comparator==null || data==null || data.length<2){ - return; - } - Arrays.sort(data, 0, data.length, comparator); - for(int i=0;i= index; i--){ - T exist = childes[i]; - childes[i] = null; - int newIndex = i + 1; - childes[newIndex] = exist; - exist.setIndex(newIndex); - } - childes[index] = item; - item.setParent(this); - item.setIndex(index); - } - public void setItem(int index, T item){ - ensureSize(index+1); - elementData[index]=item; - item.setIndex(index); - item.setParent(this); - } - public void add(T block){ - if(block==null){ - return; - } - T[] old=elementData; - int index=old.length; - elementData= newInstance(index+1); - if(index>0){ - System.arraycopy(old, 0, elementData, 0, index); - } - elementData[index]=block; - block.setIndex(index); - block.setParent(this); - } - public final int countNonNull(){ - return countNonNull(true); - } - public final int childesCount(){ - return elementData.length; - } - public final T createNext(){ - T block=newInstance(); - add(block); - return block; - } - public final T get(int i){ - if(i >= childesCount() || i<0){ - return null; - } - return elementData[i]; - } - public int indexOf(Object block){ - T[] items=elementData; - if(items==null){ - return -1; - } - int len=items.length; - for(int i=0;i iterator() { - return iterator(false); - } - public Iterator iterator(boolean skipNullBlock) { - return new BlockIterator(skipNullBlock); - } - public Iterator iterator(Predicate tester) { - return new PredicateIterator(tester); - } - public boolean contains(Object block){ - T[] items=elementData; - if(block==null || items==null){ - return false; - } - int len=items.length; - for(int i=0;i blockList){ - T[] items=elementData; - if(items==null || items.length==0){ - return; - } - int len=items.length; - for(T block:blockList){ - if(block==null){ - continue; - } - int i=block.getIndex(); - if(i<0 || i>=len){ - continue; - } - if(items[i]!=block){ - continue; - } - items[i]=null; - } - trimNullBlocks(); - } - public boolean remove(T block){ - return remove(block, true); - } - protected boolean remove(T block, boolean trim){ - T[] items=elementData; - if(block==null||items==null){ - return false; - } - boolean found=false; - int len=items.length; - for(int i=0;isize){ - end=size; - }else { - end=index; - } - if(end>0){ - System.arraycopy(old, 0, update, 0, end); - } - for(int i=end;i extends BlockCreator{ - T[] newInstance(int len); -} diff --git a/src/ARSCLib/com/reandroid/arsc/base/BlockContainer.java b/src/ARSCLib/com/reandroid/arsc/base/BlockContainer.java deleted file mode 100755 index 4e52ec67..00000000 --- a/src/ARSCLib/com/reandroid/arsc/base/BlockContainer.java +++ /dev/null @@ -1,156 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.base; - -import com.reandroid.arsc.container.BlockList; -import com.reandroid.arsc.io.BlockReader; - -import java.io.IOException; -import java.io.OutputStream; - -public abstract class BlockContainer extends Block{ - public BlockContainer(){ - super(); - } - - protected void onPreRefreshRefresh(){ - - } - protected abstract void onRefreshed(); - public final void refresh(){ - if(isNull()){ - return; - } - onPreRefreshRefresh(); - refreshChildes(); - onRefreshed(); - } - protected void refreshChildes(){ - T[] childes=getChildes(); - if(childes!=null){ - int max=childes.length; - for(int i=0;i container=(BlockContainer)item; - container.refresh(); - }else if(item instanceof BlockList){ - BlockList blockList=(BlockList)item; - blockList.refresh(); - } - } - } - } - @Override - public void onCountUpTo(BlockCounter counter){ - if(counter.FOUND){ - return; - } - if(counter.END==this){ - counter.FOUND=true; - return; - } - T[] childes=getChildes(); - if(childes==null){ - return; - } - int max=childes.length; - for(int i=0;i { - T newInstance(); -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/Chunk.java b/src/ARSCLib/com/reandroid/arsc/chunk/Chunk.java deleted file mode 100755 index c31124ed..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/Chunk.java +++ /dev/null @@ -1,78 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk; - -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.container.ExpandableBlockContainer; -import com.reandroid.arsc.container.SingleBlockContainer; -import com.reandroid.arsc.header.HeaderBlock; -import com.reandroid.arsc.io.BlockReader; - -import java.io.IOException; - -public abstract class Chunk extends ExpandableBlockContainer { - private final T mHeaderBlock; - protected final SingleBlockContainer firstPlaceHolder; - protected Chunk(T headerBlock, int initialChildesCount) { - super(initialChildesCount+2); - this.mHeaderBlock = headerBlock; - this.firstPlaceHolder = new SingleBlockContainer<>(); - addChild(headerBlock); - addChild(firstPlaceHolder); - } - public SingleBlockContainer getFirstPlaceHolder() { - return firstPlaceHolder; - } - void setHeaderLoaded(HeaderBlock.HeaderLoaded headerLoaded){ - getHeaderBlock().setHeaderLoaded(headerLoaded); - } - public final T getHeaderBlock(){ - return mHeaderBlock; - } - @Override - protected final void onRefreshed() { - getHeaderBlock().refreshHeader(); - onChunkRefreshed(); - } - protected abstract void onChunkRefreshed(); - public void onChunkLoaded(){ - - } - @Override - public void onReadBytes(BlockReader reader) throws IOException { - HeaderBlock headerBlock=reader.readHeaderBlock(); - checkInvalidChunk(headerBlock); - BlockReader chunkReader = reader.create(headerBlock.getChunkSize()); - super.onReadBytes(chunkReader); - reader.offset(headerBlock.getChunkSize()); - chunkReader.close(); - onChunkLoaded(); - } - void checkInvalidChunk(HeaderBlock headerBlock) throws IOException { - ChunkType chunkType = headerBlock.getChunkType(); - if(chunkType==null || chunkType==ChunkType.NULL){ - throw new IOException("Invalid chunk: "+headerBlock); - } - } - @Override - public String toString(){ - StringBuilder builder=new StringBuilder(); - builder.append(getClass().getSimpleName()); - builder.append(": "); - builder.append(getHeaderBlock()); - return builder.toString(); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/ChunkType.java b/src/ARSCLib/com/reandroid/arsc/chunk/ChunkType.java deleted file mode 100755 index 70a58a6d..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/ChunkType.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk; - -import com.reandroid.arsc.util.HexUtil; - -public enum ChunkType { - NULL((short)0x0000), - - STRING((short)0x0001), - TABLE((short)0x0002), - XML((short)0x0003), - - XML_START_NAMESPACE((short)0x0100), - XML_END_NAMESPACE((short)0x0101), - XML_START_ELEMENT((short)0x0102), - XML_END_ELEMENT((short)0x0103), - XML_CDATA((short)0x0104), - XML_LAST_CHUNK((short)0x017f), - XML_RESOURCE_MAP((short)0x0180), - - PACKAGE((short)0x0200), - TYPE((short)0x0201), - SPEC((short)0x0202), - LIBRARY((short)0x0203), - OVERLAYABLE((short)0x0204), - OVERLAYABLE_POLICY((short)0x0205), - STAGED_ALIAS((short)0x0206); - - public final short ID; - ChunkType(short id) { - this.ID = id; - } - - @Override - public String toString(){ - return name() + "(" + HexUtil.toHex4(ID) + ")"; - } - - public static ChunkType get(short id){ - ChunkType[] all=values(); - for(ChunkType t:all){ - if(t.ID ==id){ - return t; - } - } - return null; - } - - public static ChunkType getTable(short id){ - for(ChunkType t:table_chunk_types){ - if(t.ID ==id){ - return t; - } - } - return null; - } - public static ChunkType getXml(short id){ - for(ChunkType t:xml_chunk_types){ - if(t.ID ==id){ - return t; - } - } - return null; - } - - private static final ChunkType[] table_chunk_types=new ChunkType[]{ - PACKAGE, - TYPE, - SPEC, - LIBRARY - }; - private static final ChunkType[] xml_chunk_types=new ChunkType[]{ - XML_START_NAMESPACE, - XML_END_NAMESPACE, - XML_START_ELEMENT, - XML_END_ELEMENT, - XML_CDATA, - XML_LAST_CHUNK, - XML_RESOURCE_MAP - }; -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/LibraryBlock.java b/src/ARSCLib/com/reandroid/arsc/chunk/LibraryBlock.java deleted file mode 100755 index aeca72d9..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/LibraryBlock.java +++ /dev/null @@ -1,76 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk; - -import com.reandroid.arsc.array.LibraryInfoArray; -import com.reandroid.arsc.header.LibraryHeader; -import com.reandroid.arsc.value.LibraryInfo; - -import java.util.Collection; - - public class LibraryBlock extends Chunk { - private final LibraryInfoArray mLibraryInfoArray; - public LibraryBlock() { - super(new LibraryHeader(),1); - LibraryHeader header = getHeaderBlock(); - this.mLibraryInfoArray = new LibraryInfoArray(header.getCount()); - - addChild(mLibraryInfoArray); - } - public LibraryInfoArray getLibraryInfoArray(){ - return mLibraryInfoArray; - } - public void addLibraryInfo(LibraryBlock libraryBlock){ - if(libraryBlock==null){ - return; - } - for(LibraryInfo info:libraryBlock.getLibraryInfoArray().listItems()){ - addLibraryInfo(info); - } - } - public void addLibraryInfo(LibraryInfo info){ - if(info==null){ - return; - } - getLibraryInfoArray().add(info); - getHeaderBlock().getCount().set(mLibraryInfoArray.childesCount()); - } - public Collection listLibraryInfo(){ - return getLibraryInfoArray().listItems(); - } - @Override - public boolean isNull(){ - return mLibraryInfoArray.childesCount()==0; - } - public int getLibraryCount(){ - return mLibraryInfoArray.childesCount(); - } - public void setLibraryCount(int count){ - getHeaderBlock().getCount().set(count); - mLibraryInfoArray.setChildesCount(count); - } - @Override - protected void onChunkRefreshed() { - getHeaderBlock().getCount().set(mLibraryInfoArray.childesCount()); - } - - public void merge(LibraryBlock libraryBlock){ - if(libraryBlock==null||libraryBlock==this){ - return; - } - getLibraryInfoArray().merge(libraryBlock.getLibraryInfoArray()); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/MainChunk.java b/src/ARSCLib/com/reandroid/arsc/chunk/MainChunk.java deleted file mode 100644 index 0782fb90..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/MainChunk.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.reandroid.arsc.chunk; - -import com.reandroid.arsc.ApkFile; -import com.reandroid.arsc.pool.StringPool; - -public interface MainChunk { - StringPool getStringPool(); - ApkFile getApkFile(); - void setApkFile(ApkFile apkFile); - TableBlock getTableBlock(); -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/Overlayable.java b/src/ARSCLib/com/reandroid/arsc/chunk/Overlayable.java deleted file mode 100644 index ae8bbbcf..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/Overlayable.java +++ /dev/null @@ -1,169 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ - package com.reandroid.arsc.chunk; - - import com.reandroid.arsc.container.BlockList; - import com.reandroid.arsc.header.HeaderBlock; - import com.reandroid.arsc.header.OverlayableHeader; - import com.reandroid.arsc.io.BlockReader; - import com.reandroid.arsc.item.ByteArray; - import com.reandroid.json.JSONArray; - import com.reandroid.json.JSONConvert; - import com.reandroid.json.JSONObject; - - import java.io.IOException; - import java.util.List; - - /** - * Replica of struct "ResTable_overlayable_header" as on AOSP androidfw/ResourceTypes.h - * We didn't test this class with resource table, if someone found a resource/apk please - * create issue on https://github.com/REAndroid/ARSCLib - * */ - public class Overlayable extends Chunk implements JSONConvert { - private final BlockList policyList; - private final ByteArray extraBytes; - - public Overlayable() { - super(new OverlayableHeader(), 2); - this.policyList = new BlockList<>(); - this.extraBytes = new ByteArray(); - addChild(this.policyList); - addChild(this.extraBytes); - } - - public OverlayablePolicy get(int flags){ - for(OverlayablePolicy policy:listOverlayablePolicies()){ - if(flags==policy.getFlags()){ - return policy; - } - } - return null; - } - public void addOverlayablePolicy(OverlayablePolicy overlayablePolicy){ - this.policyList.add(overlayablePolicy); - } - public List listOverlayablePolicies() { - return policyList.getChildes(); - } - public ByteArray getExtraBytes() { - return extraBytes; - } - - public String getName(){ - return getHeaderBlock().getName().get(); - } - public void setName(String str){ - getHeaderBlock().getName().set(str); - } - public String getActor(){ - return getHeaderBlock().getActor().get(); - } - public void setActor(String str){ - getHeaderBlock().getActor().set(str); - } - - @Override - protected void onChunkRefreshed() { - } - - @Override - public void onReadBytes(BlockReader reader) throws IOException { - HeaderBlock headerBlock = reader.readHeaderBlock(); - checkInvalidChunk(headerBlock); - - int size = headerBlock.getChunkSize(); - BlockReader chunkReader = reader.create(size); - headerBlock = getHeaderBlock(); - headerBlock.readBytes(chunkReader); - - readOverlayablePlolicies(chunkReader); - readExtraBytes(chunkReader); - - reader.offset(size); - chunkReader.close(); - onChunkLoaded(); - } - private void readOverlayablePlolicies(BlockReader reader) throws IOException { - HeaderBlock headerBlock = reader.readHeaderBlock(); - BlockList policyList = this.policyList; - while (headerBlock!=null && headerBlock.getChunkType()==ChunkType.OVERLAYABLE_POLICY){ - OverlayablePolicy policy = new OverlayablePolicy(); - policyList.add(policy); - policy.readBytes(reader); - headerBlock = reader.readHeaderBlock(); - } - } - private void readExtraBytes(BlockReader reader) throws IOException { - int remaining = reader.available(); - this.extraBytes.setSize(remaining); - this.extraBytes.readBytes(reader); - } - - @Override - public JSONObject toJson() { - JSONObject jsonObject = new JSONObject(); - jsonObject.put(NAME_name, getName()); - jsonObject.put(NAME_actor, getActor()); - JSONArray jsonArray = new JSONArray(); - for(OverlayablePolicy policy:listOverlayablePolicies()){ - jsonArray.put(policy.toJson()); - } - jsonObject.put(NAME_policies, jsonArray); - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - setName(json.optString(NAME_name)); - setActor(json.optString(NAME_actor)); - JSONArray jsonArray = json.getJSONArray(NAME_policies); - int length = jsonArray.length(); - BlockList policyList = this.policyList; - for(int i=0;i implements BlockLoad, - JSONConvert { - private final IntegerArray tableRefArray; - public OverlayablePolicy(){ - super(new OverlayablePolicyHeader(), 1); - this.tableRefArray = new IntegerArray(); - - addChild(this.tableRefArray); - - getHeaderBlock().getEntryCount().setBlockLoad(this); - } - @Override - public boolean isNull() { - return getTableReferenceCount()==0; - } - public int getTableReferenceCount(){ - return getTableRefArray().size(); - } - - public Collection listTableReferences(){ - return getTableRefArray().toList(); - } - public IntegerArray getTableRefArray() { - return tableRefArray; - } - public int getFlags() { - return getHeaderBlock().getFlags().get(); - } - public void setFlags(int flags){ - getHeaderBlock().getFlags().set(flags); - } - public void setFlags(PolicyFlag[] policyFlags){ - setFlags(PolicyFlag.sum(policyFlags)); - } - public void addFlag(PolicyFlag policyFlag){ - int i = policyFlag==null? 0 : policyFlag.getFlagValue(); - setFlags(getFlags() | i); - } - public PolicyFlag[] getPolicyFlags(){ - return PolicyFlag.valuesOf(getFlags()); - } - @Override - protected void onChunkRefreshed() { - getHeaderBlock().getEntryCount().set(getTableRefArray().size()); - } - @Override - public void onBlockLoaded(BlockReader reader, Block sender) throws IOException { - IntegerItem entryCount = getHeaderBlock().getEntryCount(); - if(sender==entryCount){ - this.tableRefArray.setSize(entryCount.get()); - } - } - - @Override - public JSONObject toJson() { - JSONObject jsonObject = new JSONObject(); - jsonObject.put(NAME_flags, getFlags()); - JSONArray jsonArray = new JSONArray(); - for(Integer reference:listTableReferences()){ - jsonArray.put(reference); - } - jsonObject.put(NAME_references, jsonArray); - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - setFlags(json.getInt(NAME_flags)); - JSONArray jsonArray = json.getJSONArray(NAME_references); - IntegerArray integerArray = getTableRefArray(); - int length = jsonArray.length(); - integerArray.setSize(length); - for(int i=0;i - implements ParentChunk, - JSONConvert, - Comparable { - - private final TypeStringPool mTypeStringPool; - private final SpecStringPool mSpecStringPool; - - private final PackageBody mBody; - - private final Map mEntriesGroup; - private boolean entryGroupMapLocked; - - public PackageBlock() { - super(new PackageHeader(), 3); - PackageHeader header = getHeaderBlock(); - - this.mTypeStringPool=new TypeStringPool(false, header.getTypeIdOffsetItem()); - this.mSpecStringPool=new SpecStringPool(true); - - this.mBody = new PackageBody(); - - this.mEntriesGroup = new HashMap<>(); - this.entryGroupMapLocked = true; - - addChild(mTypeStringPool); - addChild(mSpecStringPool); - addChild(mBody); - } - public void linkTableStringsInternal(TableStringPool tableStringPool){ - for(SpecTypePair specTypePair : listSpecTypePairs()){ - specTypePair.linkTableStringsInternal(tableStringPool); - } - } - public void linkSpecStringsInternal(SpecStringPool specStringPool){ - for(SpecTypePair specTypePair : listSpecTypePairs()){ - specTypePair.linkSpecStringsInternal(specStringPool); - } - } - public void destroy(){ - getEntriesGroupMap().clear(); - getPackageBody().destroy(); - getTypeStringPool().destroy(); - getSpecStringPool().destroy(); - setId(0); - setName(""); - } - public Entry getEntry(String qualifiers, String type, String name){ - return getSpecTypePairArray().getEntry(qualifiers, type, name); - } - public Entry getEntry(ResConfig resConfig, String type, String name){ - return getSpecTypePairArray().getEntry(resConfig, type, name); - } - public Entry getOrCreate(String qualifiers, String type, String name){ - return getOrCreate(ResConfig.parse(qualifiers), type, name); - } - public Entry getOrCreate(ResConfig resConfig, String typeName, String name){ - SpecTypePair specTypePair = getOrCreateSpecTypePair(typeName); - TypeBlock typeBlock = specTypePair.getOrCreateTypeBlock(resConfig); - return typeBlock.getOrCreateEntry(name); - } - public TypeBlock getOrCreateTypeBlock(String qualifiers, String typeName){ - SpecTypePair specTypePair = getOrCreateSpecTypePair(typeName); - return specTypePair.getOrCreateTypeBlock(qualifiers); - } - public TypeBlock getOrCreateTypeBlock(ResConfig resConfig, String typeName){ - SpecTypePair specTypePair = getOrCreateSpecTypePair(typeName); - return specTypePair.getOrCreateTypeBlock(resConfig); - } - public SpecTypePair getOrCreateSpecTypePair(String typeName){ - return getSpecTypePairArray().getOrCreate(typeName); - } - public int getTypeIdOffset(){ - return getHeaderBlock().getTypeIdOffset(); - } - public BlockList getUnknownChunkList(){ - return mBody.getUnknownChunkList(); - } - - public StagedAliasEntry searchByStagedResId(int stagedResId){ - for(StagedAlias stagedAlias:getStagedAliasList().getChildes()){ - StagedAliasEntry entry=stagedAlias.getStagedAliasEntryArray() - .searchByStagedResId(stagedResId); - if(entry!=null){ - return entry; - } - } - return null; - } - public List listStagedAlias(){ - return getStagedAliasList().getChildes(); - } - public StagedAliasList getStagedAliasList(){ - return mBody.getStagedAliasList(); - } - public OverlayableList getOverlayableList(){ - return mBody.getOverlayableList(); - } - public BlockList getOverlayablePolicyList(){ - return mBody.getOverlayablePolicyList(); - } - public void sortTypes(){ - getSpecTypePairArray().sort(); - } - - public void removeEmpty(){ - getSpecTypePairArray().removeEmptyPairs(); - } - public boolean isEmpty(){ - return getSpecTypePairArray().isEmpty(); - } - public int getId(){ - return getHeaderBlock().getPackageId().get(); - } - public void setId(byte id){ - setId(0xff & id); - } - public void setId(int id){ - getHeaderBlock().getPackageId().set(id); - } - public String getName(){ - return getHeaderBlock().getPackageName().get(); - } - public void setName(String name){ - getHeaderBlock().getPackageName().set(name); - } - public TableBlock getTableBlock(){ - Block parent=getParent(); - while(parent!=null){ - if(parent instanceof TableBlock){ - return (TableBlock)parent; - } - parent=parent.getParent(); - } - return null; - } - public TypeStringPool getTypeStringPool(){ - return mTypeStringPool; - } - @Override - public SpecStringPool getSpecStringPool(){ - return mSpecStringPool; - } - @Override - public TableBlock getMainChunk(){ - return getTableBlock(); - } - @Override - public PackageBlock getPackageBlock(){ - return this; - } - public PackageBody getPackageBody() { - return mBody; - } - public SpecTypePairArray getSpecTypePairArray(){ - return mBody.getSpecTypePairArray(); - } - public Collection listLibraryInfo(){ - return getLibraryBlock().listLibraryInfo(); - } - - public void addLibrary(LibraryBlock libraryBlock){ - if(libraryBlock==null){ - return; - } - for(LibraryInfo info:libraryBlock.getLibraryInfoArray().listItems()){ - addLibraryInfo(info); - } - } - public void addLibraryInfo(LibraryInfo info){ - getLibraryBlock().addLibraryInfo(info); - } - public LibraryBlock getLibraryBlock(){ - return mBody.getLibraryBlock(); - } - public Set listResourceIds(){ - return getEntriesGroupMap().keySet(); - } - public Entry getOrCreateEntry(byte typeId, short entryId, String qualifiers){ - return getSpecTypePairArray().getOrCreateEntry(typeId, entryId, qualifiers); - } - - public Entry getAnyEntry(int resourceId){ - int packageId = (resourceId >> 24) & 0xff; - if(packageId != getId()){ - return null; - } - byte typeId = (byte) ((resourceId >> 16) & 0xff); - short entryId = (short) (resourceId & 0xffff); - return getSpecTypePairArray().getAnyEntry(typeId, entryId); - } - public Entry getEntry(byte typeId, short entryId, String qualifiers){ - return getSpecTypePairArray().getEntry(typeId, entryId, qualifiers); - } - public TypeBlock getOrCreateTypeBlock(byte typeId, String qualifiers){ - return getSpecTypePairArray().getOrCreateTypeBlock(typeId, qualifiers); - } - public TypeBlock getTypeBlock(byte typeId, String qualifiers){ - return getSpecTypePairArray().getTypeBlock(typeId, qualifiers); - } - - private void unlockEntryGroup() { - synchronized (this){ - if(!this.entryGroupMapLocked){ - return; - } - entryGroupMapLocked = false; - Map map = this.mEntriesGroup; - map.clear(); - createEntryGroupMap(map); - } - } - private void createEntryGroupMap(Map map){ - map.clear(); - for(SpecTypePair specTypePair : listSpecTypePairs()){ - map.putAll(specTypePair.createEntryGroups(true)); - } - } - public Map getEntriesGroupMap(){ - unlockEntryGroup(); - return mEntriesGroup; - } - public Collection listEntryGroup(){ - return getEntriesGroupMap().values(); - } - - /** - * Searches entries by resource id from local map, then if not find - * search by alias resource id - * */ - public EntryGroup getEntryGroup(int resourceId){ - if(resourceId==0){ - return null; - } - EntryGroup entryGroup=getEntriesGroupMap().get(resourceId); - if(entryGroup!=null){ - return entryGroup; - } - StagedAliasEntry stagedAliasEntry = searchByStagedResId(resourceId); - if(stagedAliasEntry!=null){ - return getEntriesGroupMap() - .get(stagedAliasEntry.getFinalizedResId()); - } - return null; - } - public void updateEntry(Entry entry){ - if(this.entryGroupMapLocked){ - return; - } - if(entry == null || entry.isNull()){ - return; - } - int resourceId = entry.getResourceId(); - Map map = getEntriesGroupMap(); - EntryGroup group = map.get(resourceId); - if(group == null){ - group = new EntryGroup(resourceId); - map.put(resourceId, group); - } - group.add(entry); - } - public void removeEntryGroup(Entry entry){ - if(entry == null){ - return; - } - int resourceId = entry.getResourceId(); - Map map = getEntriesGroupMap(); - EntryGroup group = map.get(resourceId); - if(group == null){ - return; - } - group.remove(entry); - if(group.size() == 0){ - map.remove(resourceId); - } - } - public List listEntries(byte typeId, int entryId){ - List results=new ArrayList<>(); - for(SpecTypePair pair:listSpecTypePair(typeId)){ - results.addAll(pair.listEntries(entryId)); - } - return results; - } - public List listSpecTypePair(byte typeId){ - List results = new ArrayList<>(); - for(SpecTypePair specTypePair : listSpecTypePairs()){ - if(typeId == specTypePair.getTypeId()){ - results.add(specTypePair); - } - } - return results; - } - public SpecTypePair getSpecTypePair(String typeName){ - return getSpecTypePairArray().getSpecTypePair(typeName); - } - public SpecTypePair getSpecTypePair(int typeId){ - return getSpecTypePairArray().getSpecTypePair((byte) typeId); - } - public EntryGroup getEntryGroup(String typeName, String entryName){ - return getSpecTypePairArray().getEntryGroup(typeName, entryName); - } - public Collection listSpecTypePairs(){ - return getSpecTypePairArray().listItems(); - } - /** - * Use listSpecTypePairs() - * */ - @Deprecated - public Collection listAllSpecTypePair(){ - return listSpecTypePairs(); - } - - private void refreshTypeStringPoolOffset(){ - int pos=countUpTo(mTypeStringPool); - getHeaderBlock().getTypeStringPoolOffset().set(pos); - } - private void refreshTypeStringPoolCount(){ - getHeaderBlock().getTypeStringPoolCount().set(mTypeStringPool.countStrings()); - } - private void refreshSpecStringPoolOffset(){ - int pos=countUpTo(mSpecStringPool); - getHeaderBlock().getSpecStringPoolOffset().set(pos); - } - private void refreshSpecStringCount(){ - getHeaderBlock().getSpecStringPoolCount().set(mSpecStringPool.countStrings()); - } - private void refreshTypeIdOffset(){ - // TODO: find solution - //int largest=getSpecTypePairArray().getHighestTypeId(); - //int count=getTypeStringPool().countStrings(); - //getHeaderBlock().getTypeIdOffset().set(count-largest); - getHeaderBlock().getTypeIdOffsetItem().set(0); - } - public void onEntryAdded(Entry entry){ - updateEntry(entry); - } - @Override - public void onChunkLoaded() { - } - - @Override - protected void onChunkRefreshed() { - refreshTypeStringPoolOffset(); - refreshTypeStringPoolCount(); - refreshSpecStringPoolOffset(); - refreshSpecStringCount(); - refreshTypeIdOffset(); - } - - @Override - public JSONObject toJson() { - return toJson(true); - } - public JSONObject toJson(boolean addTypes) { - JSONObject jsonObject=new JSONObject(); - - jsonObject.put(BuildInfo.NAME_arsc_lib_version, BuildInfo.getVersion()); - - jsonObject.put(NAME_package_id, getId()); - jsonObject.put(NAME_package_name, getName()); - jsonObject.put(NAME_specs, getSpecTypePairArray().toJson(!addTypes)); - LibraryInfoArray libraryInfoArray = getLibraryBlock().getLibraryInfoArray(); - if(libraryInfoArray.childesCount()>0){ - jsonObject.put(NAME_libraries,libraryInfoArray.toJson()); - } - StagedAlias stagedAlias = - StagedAlias.mergeAll(getStagedAliasList().getChildes()); - if(stagedAlias!=null){ - jsonObject.put(NAME_staged_aliases, - stagedAlias.getStagedAliasEntryArray().toJson()); - } - JSONArray jsonArray = getOverlayableList().toJson(); - if(jsonArray!=null){ - jsonObject.put(NAME_overlaybles, jsonArray); - } - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - setId(json.getInt(NAME_package_id)); - setName(json.getString(NAME_package_name)); - getSpecTypePairArray().fromJson(json.optJSONArray(NAME_specs)); - LibraryInfoArray libraryInfoArray = getLibraryBlock().getLibraryInfoArray(); - libraryInfoArray.fromJson(json.optJSONArray(NAME_libraries)); - if(json.has(NAME_staged_aliases)){ - StagedAlias stagedAlias=new StagedAlias(); - stagedAlias.getStagedAliasEntryArray() - .fromJson(json.getJSONArray(NAME_staged_aliases)); - getStagedAliasList().add(stagedAlias); - } - if(json.has(NAME_overlaybles)){ - getOverlayableList().fromJson(json.getJSONArray(NAME_overlaybles)); - } - } - public void merge(PackageBlock packageBlock){ - if(packageBlock==null||packageBlock==this){ - return; - } - if(getId()!=packageBlock.getId()){ - throw new IllegalArgumentException("Can not merge different id packages: " - +getId()+"!="+packageBlock.getId()); - } - setName(packageBlock.getName()); - getLibraryBlock().merge(packageBlock.getLibraryBlock()); - mergeSpecStringPool(packageBlock); - getSpecTypePairArray().merge(packageBlock.getSpecTypePairArray()); - getOverlayableList().merge(packageBlock.getOverlayableList()); - getStagedAliasList().merge(packageBlock.getStagedAliasList()); - } - private void mergeSpecStringPool(PackageBlock coming){ - this.getSpecStringPool().addStrings( - coming.getSpecStringPool().toStringList()); - } - - @Override - public int compareTo(PackageBlock pkg) { - return Integer.compare(getId(), pkg.getId()); - } - @Override - public String toString(){ - StringBuilder builder=new StringBuilder(); - builder.append(super.toString()); - builder.append(", id="); - builder.append(HexUtil.toHex2((byte) getId())); - builder.append(", name="); - builder.append(getName()); - int libCount=getLibraryBlock().getLibraryCount(); - if(libCount>0){ - builder.append(", libraries="); - builder.append(libCount); - } - return builder.toString(); - } - - public static final String NAME_package_id = "package_id"; - public static final String NAME_package_name = "package_name"; - public static final String JSON_FILE_NAME = "package.json"; - private static final String NAME_specs = "specs"; - public static final String NAME_libraries = "libraries"; - public static final String NAME_staged_aliases = "staged_aliases"; - public static final String NAME_overlaybles = "overlaybles"; -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/ParentChunk.java b/src/ARSCLib/com/reandroid/arsc/chunk/ParentChunk.java deleted file mode 100644 index 325810a1..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/ParentChunk.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk; - -import com.reandroid.arsc.pool.StringPool; - -public interface ParentChunk { - StringPool getSpecStringPool(); - MainChunk getMainChunk(); - PackageBlock getPackageBlock(); -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/SpecBlock.java b/src/ARSCLib/com/reandroid/arsc/chunk/SpecBlock.java deleted file mode 100755 index 65873ead..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/SpecBlock.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk; - -import com.reandroid.arsc.array.TypeBlockArray; -import com.reandroid.arsc.container.SpecTypePair; -import com.reandroid.arsc.header.SpecHeader; -import com.reandroid.arsc.item.*; -import com.reandroid.arsc.util.HexUtil; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONObject; - -import java.util.List; - -public class SpecBlock extends Chunk implements JSONConvert { - private final SpecFlagsArray specFlagsArray; - public SpecBlock() { - super(new SpecHeader(), 1); - SpecHeader header = getHeaderBlock(); - this.specFlagsArray = new SpecFlagsArray(header.getEntryCount()); - addChild(specFlagsArray); - } - public void destroy(){ - setParent(null); - getSpecFlagsArray().clear(); - } - public SpecFlag getSpecFlag(int id){ - return getSpecFlagsArray().getFlag(id); - } - public SpecFlagsArray getSpecFlagsArray(){ - return specFlagsArray; - } - public List listSpecFlags(){ - return specFlagsArray.toList(); - } - public byte getTypeId(){ - return getHeaderBlock().getId().get(); - } - public int getId(){ - return getHeaderBlock().getId().unsignedInt(); - } - public void setId(int id){ - setTypeId((byte) (0xff & id)); - } - public void setTypeId(byte id){ - getHeaderBlock().getId().set(id); - getTypeBlockArray().setTypeId(id); - } - public TypeBlockArray getTypeBlockArray(){ - SpecTypePair specTypePair=getSpecTypePair(); - if(specTypePair!=null){ - return specTypePair.getTypeBlockArray(); - } - return null; - } - SpecTypePair getSpecTypePair(){ - return getParent(SpecTypePair.class); - } - public int getEntryCount() { - return specFlagsArray.size(); - } - public void setEntryCount(int count){ - specFlagsArray.setSize(count); - specFlagsArray.refresh(); - } - @Override - protected void onChunkRefreshed() { - specFlagsArray.refresh(); - } - - public void merge(SpecBlock specBlock){ - if(specBlock == null || specBlock==this){ - return; - } - this.getSpecFlagsArray().merge(specBlock.getSpecFlagsArray()); - } - @Override - public String toString(){ - StringBuilder builder=new StringBuilder(); - builder.append(super.toString()); - TypeBlockArray typeBlockArray=getTypeBlockArray(); - if(typeBlockArray!=null){ - builder.append(", typesCount="); - builder.append(typeBlockArray.childesCount()); - } - return builder.toString(); - } - - @Override - public JSONObject toJson() { - JSONObject jsonObject=new JSONObject(); - jsonObject.put(TypeBlock.NAME_id, getId()); - jsonObject.put(NAME_spec_flags, getSpecFlagsArray().toJson()); - return jsonObject; - } - - @Override - public void fromJson(JSONObject json) { - setId(json.getInt(TypeBlock.NAME_id)); - getSpecFlagsArray().fromJson(json.optJSONArray(NAME_spec_flags)); - } - - public enum Flag{ - SPEC_PUBLIC((byte) 0x40), - SPEC_STAGED_API((byte) 0x20); - - private final byte flag; - Flag(byte flag) { - this.flag = flag; - } - public byte getFlag() { - return flag; - } - public static boolean isPublic(byte flag){ - return (SPEC_PUBLIC.flag & flag) == SPEC_PUBLIC.flag; - } - public static boolean isStagedApi(byte flag){ - return (SPEC_STAGED_API.flag & flag) == SPEC_STAGED_API.flag; - } - public static String toString(byte flagValue){ - StringBuilder builder = new StringBuilder(); - boolean appendOnce = false; - int sum = 0; - int flagValueInt = flagValue & 0xff; - for(Flag flag:values()){ - int flagInt = flag.flag & 0xff; - if((flagInt & flagValueInt) != flagInt){ - continue; - } - if(appendOnce){ - builder.append('|'); - } - builder.append(flag); - appendOnce = true; - sum = sum | flagInt; - } - if(sum != flagValueInt){ - if(appendOnce){ - builder.append('|'); - } - builder.append(HexUtil.toHex2((byte) flagValueInt)); - } - return builder.toString(); - } - } - - public static final String NAME_spec = "spec"; - public static final String NAME_spec_flags = "spec_flags"; - public static final String NAME_flag = "flag"; -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/StagedAlias.java b/src/ARSCLib/com/reandroid/arsc/chunk/StagedAlias.java deleted file mode 100644 index ed1421f6..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/StagedAlias.java +++ /dev/null @@ -1,83 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ - package com.reandroid.arsc.chunk; - - import com.reandroid.arsc.array.StagedAliasEntryArray; - import com.reandroid.arsc.header.StagedAliasHeader; - import com.reandroid.arsc.value.StagedAliasEntry; - - import java.util.Collection; - - public class StagedAlias extends Chunk { - private final StagedAliasEntryArray stagedAliasEntryArray; - public StagedAlias() { - super(new StagedAliasHeader(), 1); - StagedAliasHeader header = getHeaderBlock(); - - stagedAliasEntryArray = new StagedAliasEntryArray(header.getCount()); - addChild(stagedAliasEntryArray); - } - public void merge(StagedAlias stagedAlias){ - if(stagedAlias==null||stagedAlias==this){ - return; - } - StagedAliasEntryArray exist = getStagedAliasEntryArray(); - for(StagedAliasEntry entry:stagedAlias.listStagedAliasEntry()){ - if(!exist.contains(entry)){ - exist.add(entry); - } - } - } - public StagedAliasEntryArray getStagedAliasEntryArray() { - return stagedAliasEntryArray; - } - public Collection listStagedAliasEntry(){ - return getStagedAliasEntryArray().listItems(); - } - public int getStagedAliasEntryCount(){ - return getStagedAliasEntryArray().childesCount(); - } - @Override - public boolean isNull(){ - return getStagedAliasEntryCount()==0; - } - @Override - protected void onChunkRefreshed() { - getHeaderBlock().getCount().set(getStagedAliasEntryCount()); - } - @Override - public String toString(){ - return getClass().getSimpleName()+ - ": count="+getStagedAliasEntryCount(); - } - public static StagedAlias mergeAll(Collection stagedAliasList){ - if(stagedAliasList.size()==0){ - return null; - } - StagedAlias result=new StagedAlias(); - for(StagedAlias stagedAlias:stagedAliasList){ - if(stagedAlias.isNull()){ - continue; - } - result.merge(stagedAlias); - } - if(!result.isNull()){ - result.refresh(); - return result; - } - return null; - } - } diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/TableBlock.java b/src/ARSCLib/com/reandroid/arsc/chunk/TableBlock.java deleted file mode 100755 index e56de1c6..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/TableBlock.java +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk; - -import com.reandroid.arsc.ApkFile; -import com.reandroid.arsc.BuildInfo; -import com.reandroid.arsc.array.PackageArray; -import com.reandroid.arsc.group.EntryGroup; -import com.reandroid.arsc.header.HeaderBlock; -import com.reandroid.arsc.header.InfoHeader; -import com.reandroid.arsc.header.TableHeader; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.pool.TableStringPool; -import com.reandroid.arsc.value.*; -import com.reandroid.common.EntryStore; -import com.reandroid.common.ReferenceResolver; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONArray; -import com.reandroid.json.JSONObject; - -import java.io.*; -import java.util.*; -import java.util.function.Predicate; - -public class TableBlock extends Chunk - implements MainChunk, JSONConvert, EntryStore { - private final TableStringPool mTableStringPool; - private final PackageArray mPackageArray; - private final List mFrameWorks; - private ApkFile mApkFile; - private ReferenceResolver referenceResolver; - - public TableBlock() { - super(new TableHeader(), 2); - TableHeader header = getHeaderBlock(); - this.mTableStringPool = new TableStringPool(true); - this.mPackageArray = new PackageArray(header.getPackageCount()); - this.mFrameWorks = new ArrayList<>(); - addChild(mTableStringPool); - addChild(mPackageArray); - } - - public void linkTableStringsInternal(TableStringPool tableStringPool){ - for(PackageBlock packageBlock : listPackages()){ - packageBlock.linkTableStringsInternal(tableStringPool); - } - } - public List resolveReference(int referenceId){ - return resolveReference(referenceId, null); - } - public List resolveReferenceWithConfig(int referenceId, ResConfig resConfig){ - ReferenceResolver resolver = this.referenceResolver; - if(resolver == null){ - resolver = new ReferenceResolver(this); - this.referenceResolver = resolver; - } - return resolver.resolveWithConfig(referenceId, resConfig); - } - public List resolveReference(int referenceId, Predicate filter){ - ReferenceResolver resolver = this.referenceResolver; - if(resolver == null){ - resolver = new ReferenceResolver(this); - this.referenceResolver = resolver; - } - return resolver.resolveAll(referenceId, filter); - } - public void destroy(){ - getPackageArray().destroy(); - getStringPool().destroy(); - clearFrameworks(); - refresh(); - } - public int countPackages(){ - return getPackageArray().childesCount(); - } - - public PackageBlock pickOne(){ - return getPackageArray().pickOne(); - } - public PackageBlock pickOne(int packageId){ - return getPackageArray().pickOne(packageId); - } - public void sortPackages(){ - getPackageArray().sort(); - } - public Collection listPackages(){ - return getPackageArray().listItems(); - } - @Override - public TableStringPool getStringPool() { - return mTableStringPool; - } - @Override - public ApkFile getApkFile(){ - return mApkFile; - } - @Override - public void setApkFile(ApkFile apkFile){ - this.mApkFile = apkFile; - } - @Override - public TableBlock getTableBlock() { - return this; - } - - public TableStringPool getTableStringPool(){ - return mTableStringPool; - } - public PackageBlock getPackageBlockById(int pkgId){ - return getPackageArray().getPackageBlockById(pkgId); - } - public PackageArray getPackageArray(){ - return mPackageArray; - } - - private void refreshPackageCount(){ - int count = getPackageArray().childesCount(); - getHeaderBlock().getPackageCount().set(count); - } - @Override - protected void onChunkRefreshed() { - refreshPackageCount(); - } - @Override - public void onReadBytes(BlockReader reader) throws IOException { - TableHeader tableHeader = getHeaderBlock(); - tableHeader.readBytes(reader); - if(tableHeader.getChunkType()!=ChunkType.TABLE){ - throw new IOException("Not resource table: "+tableHeader); - } - boolean stringPoolLoaded=false; - InfoHeader infoHeader = reader.readHeaderBlock(); - PackageArray packageArray=mPackageArray; - packageArray.clearChildes(); - while(infoHeader!=null && reader.isAvailable()){ - ChunkType chunkType=infoHeader.getChunkType(); - if(chunkType==ChunkType.STRING){ - if(!stringPoolLoaded){ - mTableStringPool.readBytes(reader); - stringPoolLoaded=true; - } - }else if(chunkType==ChunkType.PACKAGE){ - PackageBlock packageBlock=packageArray.createNext(); - packageBlock.readBytes(reader); - }else { - UnknownChunk unknownChunk=new UnknownChunk(); - unknownChunk.readBytes(reader); - addChild(unknownChunk); - } - infoHeader=reader.readHeaderBlock(); - } - reader.close(); - } - - public void readBytes(File file) throws IOException{ - BlockReader reader=new BlockReader(file); - super.readBytes(reader); - } - public void readBytes(InputStream inputStream) throws IOException{ - BlockReader reader=new BlockReader(inputStream); - super.readBytes(reader); - } - public final int writeBytes(File file) throws IOException{ - if(isNull()){ - throw new IOException("Can NOT save null block"); - } - File dir=file.getParentFile(); - if(dir!=null && !dir.exists()){ - dir.mkdirs(); - } - OutputStream outputStream=new FileOutputStream(file); - int length = super.writeBytes(outputStream); - outputStream.close(); - return length; - } - - public Entry getAnyEntry(int resourceId){ - if(resourceId == 0 || ((resourceId >> 16) & 0xff) == 0){ - return null; - } - Entry result = null; - for(PackageBlock packageBlock : listPackages()){ - Entry entry = packageBlock.getAnyEntry(resourceId); - if(entry == null){ - continue; - } - if(!entry.isNull()){ - return entry; - } - if(result == null){ - result = entry; - } - } - if(result != null){ - return result; - } - for(TableBlock tableBlock : getFrameWorks()){ - Entry entry = tableBlock.getAnyEntry(resourceId); - if(entry == null){ - continue; - } - if(!entry.isNull()){ - return entry; - } - if(result == null){ - result = entry; - } - } - return result; - } - public EntryGroup search(int resourceId){ - if(resourceId==0){ - return null; - } - EntryGroup entryGroup = searchLocal(resourceId); - if(entryGroup!=null){ - return entryGroup; - } - for(TableBlock tableBlock:getFrameWorks()){ - entryGroup = tableBlock.search(resourceId); - if(entryGroup!=null){ - return entryGroup; - } - } - return null; - } - private EntryGroup searchLocal(int resourceId){ - if(resourceId==0){ - return null; - } - int aliasId = searchResourceIdAlias(resourceId); - for(PackageBlock packageBlock:listPackages()){ - EntryGroup entryGroup = packageBlock.getEntryGroup(resourceId); - if(entryGroup!=null){ - return entryGroup; - } - entryGroup = packageBlock.getEntryGroup(aliasId); - if(entryGroup!=null){ - return entryGroup; - } - } - return null; - } - @Override - public Collection getEntryGroups(int resourceId) { - List results = new ArrayList<>(); - EntryGroup entryGroup = searchLocal(resourceId); - if(entryGroup!=null){ - results.add(entryGroup); - } - for(TableBlock framework:getFrameWorks()){ - results.addAll(framework.getEntryGroups(resourceId)); - } - return results; - } - @Override - public EntryGroup getEntryGroup(int resourceId) { - return search(resourceId); - } - @Override - public Collection getPackageBlocks(int packageId) { - List results=new ArrayList<>(); - PackageBlock packageBlock = getPackageBlockById(packageId); - if(packageBlock!=null){ - results.add(packageBlock); - } - for(TableBlock tableBlock:getFrameWorks()){ - results.addAll(tableBlock.getPackageBlocks(packageId)); - } - return results; - } - public int searchResourceIdAlias(int resourceId){ - for(PackageBlock packageBlock:listPackages()){ - StagedAliasEntry stagedAliasEntry = - packageBlock.searchByStagedResId(resourceId); - if(stagedAliasEntry!=null){ - return stagedAliasEntry.getFinalizedResId(); - } - } - return 0; - } - public List getFrameWorks(){ - return mFrameWorks; - } - public boolean isAndroid(){ - PackageBlock packageBlock = pickOne(); - if(packageBlock == null){ - return false; - } - return "android".equals(packageBlock.getName()) - && packageBlock.getId() == 0x01; - } - public boolean hasFramework(){ - return getFrameWorks().size() != 0; - } - public void addFramework(TableBlock tableBlock){ - if(tableBlock==null||tableBlock==this){ - return; - } - for(TableBlock frm:tableBlock.getFrameWorks()){ - if(frm==this || frm==tableBlock || tableBlock.equals(frm)){ - return; - } - } - mFrameWorks.add(tableBlock); - } - public void removeFramework(TableBlock tableBlock){ - mFrameWorks.remove(tableBlock); - } - public void clearFrameworks(){ - mFrameWorks.clear(); - } - @Override - public JSONObject toJson() { - JSONObject jsonObject=new JSONObject(); - - jsonObject.put(BuildInfo.NAME_arsc_lib_version, BuildInfo.getVersion()); - - jsonObject.put(NAME_packages, getPackageArray().toJson()); - JSONArray jsonArray = getStringPool().toJson(); - if(jsonArray!=null){ - jsonObject.put(NAME_styled_strings, jsonArray); - } - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - getPackageArray().fromJson(json.getJSONArray(NAME_packages)); - refresh(); - } - public void merge(TableBlock tableBlock){ - if(tableBlock==null||tableBlock==this){ - return; - } - if(countPackages()==0 && getStringPool().countStrings()==0){ - getStringPool().merge(tableBlock.getStringPool()); - } - getPackageArray().merge(tableBlock.getPackageArray()); - refresh(); - } - @Override - public String toString(){ - StringBuilder builder=new StringBuilder(); - builder.append(super.toString()); - builder.append(", packages="); - int pkgCount=mPackageArray.childesCount(); - builder.append(pkgCount); - return builder.toString(); - } - - @Deprecated - public static TableBlock loadWithAndroidFramework(InputStream inputStream) throws IOException{ - return load(inputStream); - } - public static TableBlock load(File file) throws IOException{ - return load(new FileInputStream(file)); - } - public static TableBlock load(InputStream inputStream) throws IOException{ - TableBlock tableBlock=new TableBlock(); - tableBlock.readBytes(inputStream); - return tableBlock; - } - - public static boolean isResTableBlock(File file){ - if(file==null){ - return false; - } - boolean result=false; - try { - InputStream inputStream=new FileInputStream(file); - result=isResTableBlock(inputStream); - inputStream.close(); - } catch (IOException ignored) { - } - return result; - } - public static boolean isResTableBlock(InputStream inputStream){ - try { - HeaderBlock headerBlock= BlockReader.readHeaderBlock(inputStream); - return isResTableBlock(headerBlock); - } catch (IOException ignored) { - return false; - } - } - public static boolean isResTableBlock(BlockReader blockReader){ - if(blockReader==null){ - return false; - } - try { - HeaderBlock headerBlock = blockReader.readHeaderBlock(); - return isResTableBlock(headerBlock); - } catch (IOException ignored) { - return false; - } - } - public static boolean isResTableBlock(HeaderBlock headerBlock){ - if(headerBlock==null){ - return false; - } - ChunkType chunkType=headerBlock.getChunkType(); - return chunkType==ChunkType.TABLE; - } - public static final String FILE_NAME="resources.arsc"; - - private static final String NAME_packages="packages"; - public static final String NAME_styled_strings="styled_strings"; -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/TypeBlock.java b/src/ARSCLib/com/reandroid/arsc/chunk/TypeBlock.java deleted file mode 100755 index 74bb3a60..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/TypeBlock.java +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk; - -import com.reandroid.arsc.array.EntryArray; -import com.reandroid.arsc.array.OffsetArray; -import com.reandroid.arsc.array.SparseOffsetsArray; -import com.reandroid.arsc.container.SpecTypePair; -import com.reandroid.arsc.header.TypeHeader; -import com.reandroid.arsc.item.*; -import com.reandroid.arsc.pool.SpecStringPool; -import com.reandroid.arsc.pool.TableStringPool; -import com.reandroid.arsc.pool.TypeStringPool; -import com.reandroid.arsc.value.Entry; -import com.reandroid.arsc.value.ResConfig; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONObject; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -public class TypeBlock extends Chunk - implements JSONConvert, Comparable { - - private final EntryArray mEntryArray; - private TypeString mTypeString; - public TypeBlock(boolean sparse) { - super(new TypeHeader(sparse), 2); - TypeHeader header = getHeaderBlock(); - - OffsetArray entryOffsets; - if(sparse){ - entryOffsets = new SparseOffsetsArray(); - }else { - entryOffsets = new OffsetArray(); - } - this.mEntryArray = new EntryArray(entryOffsets, - header.getCount(), header.getEntriesStart()); - - addChild(entryOffsets); - addChild(mEntryArray); - } - public void linkTableStringsInternal(TableStringPool tableStringPool){ - EntryArray entryArray = getEntryArray(); - entryArray.linkTableStringsInternal(tableStringPool); - } - public void linkSpecStringsInternal(SpecStringPool specStringPool){ - EntryArray entryArray = getEntryArray(); - entryArray.linkSpecStringsInternal(specStringPool); - } - public boolean isSparse(){ - return getHeaderBlock().isSparse(); - } - public void destroy(){ - getEntryArray().destroy(); - setId(0); - setParent(null); - } - public boolean removeNullEntries(int startId){ - startId = 0x0000ffff & startId; - EntryArray entryArray = getEntryArray(); - entryArray.removeAllNull(startId); - return entryArray.childesCount() == startId; - } - public PackageBlock getPackageBlock(){ - SpecTypePair specTypePair = getParent(SpecTypePair.class); - if(specTypePair!=null){ - return specTypePair.getPackageBlock(); - } - return null; - } - public String getTypeName(){ - TypeString typeString=getTypeString(); - if(typeString==null){ - return null; - } - return typeString.get(); - } - public TypeString getTypeString(){ - if(mTypeString!=null){ - if(mTypeString.getId()==getTypeId()){ - return mTypeString; - } - mTypeString=null; - } - PackageBlock packageBlock=getPackageBlock(); - if(packageBlock==null){ - return null; - } - TypeStringPool typeStringPool=packageBlock.getTypeStringPool(); - mTypeString=typeStringPool.getById(getId()); - return mTypeString; - } - public byte getTypeId(){ - return getHeaderBlock().getId().get(); - } - public int getId(){ - return getHeaderBlock().getId().unsignedInt(); - } - public void setId(int id){ - setTypeId((byte) (0xff & id)); - } - public void setTypeId(byte id){ - getHeaderBlock().getId().set(id); - } - public void setTypeName(String name){ - TypeStringPool typeStringPool=getTypeStringPool(); - int id= getId(); - TypeString typeString=typeStringPool.getById(id); - if(typeString==null){ - typeString=typeStringPool.getOrCreate(id, name); - } - typeString.set(name); - } - private TypeStringPool getTypeStringPool(){ - PackageBlock packageBlock=getPackageBlock(); - if(packageBlock!=null){ - return packageBlock.getTypeStringPool(); - } - return null; - } - public void setEntryCount(int count){ - IntegerItem entryCount = getHeaderBlock().getCount(); - if(count == entryCount.get()){ - return; - } - entryCount.set(count); - onSetEntryCount(count); - } - public boolean isEmpty(){ - return getEntryArray().isEmpty(); - } - public boolean isDefault(){ - return getResConfig().isDefault(); - } - public String getQualifiers(){ - return getResConfig().getQualifiers(); - } - public void setQualifiers(String qualifiers){ - getResConfig().parseQualifiers(qualifiers); - } - public int countNonNullEntries(){ - return getEntryArray().countNonNull(); - } - public SpecTypePair getParentSpecTypePair(){ - return getParent(SpecTypePair.class); - } - public void cleanEntries(){ - PackageBlock packageBlock=getPackageBlock(); - List allEntries=listEntries(true); - for(Entry entry :allEntries){ - if(packageBlock!=null){ - packageBlock.removeEntryGroup(entry); - } - entry.setNull(true); - } - } - public void removeEntry(Entry entry){ - PackageBlock packageBlock=getPackageBlock(); - if(packageBlock!=null){ - packageBlock.removeEntryGroup(entry); - } - entry.setNull(true); - } - public Entry getOrCreateEntry(String name){ - Entry entry = getEntryArray().getEntry(name); - if(entry != null){ - return entry; - } - SpecTypePair specTypePair = getParentSpecTypePair(); - Entry exist = specTypePair.getAnyEntry(name); - int id; - if(exist!=null){ - id = exist.getId(); - }else { - id = specTypePair.getHighestEntryCount(); - } - SpecString specString = getPackageBlock() - .getSpecStringPool().getOrCreate(name); - entry = getOrCreateEntry((short) id); - if(entry.isNull()){ - Boolean hasComplex = hasComplexEntry(); - if(hasComplex != null){ - entry.ensureComplex(hasComplex); - } - } - entry.setSpecReference(specString.getIndex()); - return entry; - } - public Entry getOrCreateEntry(short entryId){ - return getEntryArray().getOrCreate(entryId); - } - public Entry getEntry(short entryId){ - return getEntryArray().getEntry(entryId); - } - /** - * It is allowed to have duplicate entry name therefore it is not recommend to use this. - */ - public Entry getEntry(String entryName){ - return getEntryArray().getEntry(entryName); - } - public Boolean hasComplexEntry(){ - SpecTypePair specTypePair = getParentSpecTypePair(); - if(specTypePair != null){ - return specTypePair.hasComplexEntry(); - } - return null; - } - public ResConfig getResConfig(){ - return getHeaderBlock().getConfig(); - } - public EntryArray getEntryArray(){ - return mEntryArray; - } - public List listEntries(){ - return listEntries(false); - } - public List listEntries(boolean skipNullBlock){ - List results=new ArrayList<>(); - Iterator itr = getEntryArray().iterator(skipNullBlock); - while (itr.hasNext()){ - Entry block=itr.next(); - results.add(block); - } - return results; - } - public Entry getEntry(int entryId){ - return getEntryArray().get(entryId); - } - - private void onSetEntryCount(int count) { - getEntryArray().setChildesCount(count); - } - @Override - protected void onChunkRefreshed() { - getEntryArray().refreshCountAndStart(); - } - @Override - protected void onPreRefreshRefresh(){ - getHeaderBlock().getConfig().refresh(); - super.onPreRefreshRefresh(); - } - /* - * method Block.addBytes is inefficient for large size byte array - * so let's override here because this block is the largest - */ - @Override - public byte[] getBytes(){ - ByteArrayOutputStream os=new ByteArrayOutputStream(); - try { - writeBytes(os); - os.close(); - } catch (IOException ignored) { - } - return os.toByteArray(); - } - @Override - public JSONObject toJson() { - JSONObject jsonObject = new JSONObject(); - if(isSparse()){ - jsonObject.put(NAME_is_sparse, true); - } - jsonObject.put(NAME_id, getId()); - jsonObject.put(NAME_name, getTypeName()); - jsonObject.put(NAME_config, getResConfig().toJson()); - jsonObject.put(NAME_entries, getEntryArray().toJson()); - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - setId(json.getInt(NAME_id)); - String name = json.optString(NAME_name); - if(name!=null){ - setTypeName(name); - } - getEntryArray() - .fromJson(json.getJSONArray(NAME_entries)); - getResConfig() - .fromJson(json.getJSONObject(NAME_config)); - } - public void merge(TypeBlock typeBlock){ - if(typeBlock==null||typeBlock==this){ - return; - } - if(getTypeId() != typeBlock.getTypeId()){ - throw new IllegalArgumentException("Can not merge different id types: " - +getTypeId()+"!="+typeBlock.getTypeId()); - } - setTypeName(typeBlock.getTypeName()); - getEntryArray().merge(typeBlock.getEntryArray()); - } - @Override - public int compareTo(TypeBlock typeBlock) { - int id1 = getId(); - int id2 = typeBlock.getId(); - if(id1 != id2){ - return Integer.compare(id1, id2); - } - String q1 = (isSparse() ? "1" : "0") - + getResConfig().getQualifiers(); - String q2 = (typeBlock.isSparse() ? "1" : "0") - + typeBlock.getResConfig().getQualifiers(); - return q1.compareTo(q2); - } - public boolean isEqualTypeName(String typeName){ - return isEqualTypeName(getTypeName(), typeName); - } - - /** - * To be removed, use getEntry(String entryName) - */ - @Deprecated - public Entry searchByEntryName(String entryName){ - return getEntryArray().getEntry(entryName); - } - @Override - public String toString(){ - StringBuilder builder=new StringBuilder(); - builder.append(getTypeName()); - builder.append('{'); - builder.append(getHeaderBlock()); - builder.append('}'); - return builder.toString(); - } - - public static boolean isEqualTypeName(String name1, String name2){ - if(name1 == null){ - return name2 == null; - } - if(name2 == null){ - return false; - } - if(name1.equals(name2)){ - return true; - } - return trimTypeName(name1).equals(trimTypeName(name2)); - } - private static String trimTypeName(String typeName){ - while (typeName.length() > 0 && isWildTypeNamePrefix(typeName.charAt(0))){ - typeName = typeName.substring(1); - } - return typeName; - } - private static boolean isWildTypeNamePrefix(char ch){ - switch (ch){ - case '^': - case '*': - case '+': - return true; - default: - return false; - } - } - - public static final String NAME_name = "name"; - public static final String NAME_config = "config"; - public static final String NAME_id = "id"; - public static final String NAME_entries = "entries"; - public static final String NAME_is_sparse = "is_sparse"; -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/UnknownChunk.java b/src/ARSCLib/com/reandroid/arsc/chunk/UnknownChunk.java deleted file mode 100644 index aaa4b2e2..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/UnknownChunk.java +++ /dev/null @@ -1,98 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk; - - import com.reandroid.arsc.header.HeaderBlock; - import com.reandroid.arsc.item.ByteArray; - - import java.io.*; - - /** - * This class can load any valid chunk, aimed to - * handle any future android changes - * */ -public class UnknownChunk extends Chunk implements HeaderBlock.HeaderLoaded { - private final ByteArray body; - public UnknownChunk() { - super(new HeaderBlock(INITIAL_CHUNK_TYPE), 1); - this.body = new ByteArray(); - addChild(body); - setHeaderLoaded(this); - } - public ByteArray getBody(){ - return body; - } - @Override - public void onChunkTypeLoaded(short type) { - } - @Override - public void onHeaderSizeLoaded(int headerSize) { - } - @Override - public void onChunkSizeLoaded(int headerSize, int chunkSize) { - getBody().setSize(chunkSize - headerSize); - } - - @Override - void checkInvalidChunk(HeaderBlock headerBlock) throws IOException { - } - @Override - protected void onChunkRefreshed() { - } - @Override - public byte[] getBytes(){ - ByteArrayOutputStream os=new ByteArrayOutputStream(); - try { - writeBytes(os); - os.close(); - } catch (IOException ignored) { - } - return os.toByteArray(); - } - public int readBytes(File file) throws IOException{ - FileInputStream inputStream=new FileInputStream(file); - int result=readBytes(inputStream); - inputStream.close(); - return result; - } - public int readBytes(InputStream inputStream) throws IOException{ - int result; - result=getHeaderBlock().readBytes(inputStream); - result+=getBody().readBytes(inputStream); - super.notifyBlockLoad(); - return result; - } - public final int writeBytes(File file) throws IOException{ - File dir=file.getParentFile(); - if(dir!=null && !dir.exists()){ - if(dir.mkdirs()){ - throw new IOException("Can not create directory: "+dir); - } - } - OutputStream outputStream=new FileOutputStream(file); - int length = super.writeBytes(outputStream); - outputStream.close(); - return length; - } - @Override - public String toString(){ - return getHeaderBlock() - +" {Body="+getBody().size()+"}"; - } - - private static final short INITIAL_CHUNK_TYPE = 0x0000; - - } diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/xml/AndroidManifestBlock.java b/src/ARSCLib/com/reandroid/arsc/chunk/xml/AndroidManifestBlock.java deleted file mode 100644 index c84a95eb..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/xml/AndroidManifestBlock.java +++ /dev/null @@ -1,503 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk.xml; - -import com.reandroid.arsc.ApkFile; -import com.reandroid.arsc.value.ValueType; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - -public class AndroidManifestBlock extends ResXmlDocument { - private int mGuessedPackageId; - public AndroidManifestBlock(){ - super(); - super.getStringPool().setUtf8(false); - } - public ApkFile.ApkType guessApkType(){ - if(isSplit()){ - return ApkFile.ApkType.SPLIT; - } - Boolean core = isCoreApp(); - if(core!=null && core){ - return ApkFile.ApkType.CORE; - } - if(getMainActivity()!=null){ - return ApkFile.ApkType.BASE; - } - return null; - } - public Boolean isCoreApp(){ - ResXmlElement manifest = getManifestElement(); - if(manifest == null){ - return null; - } - ResXmlAttribute attribute = manifest.searchAttributeByName(NAME_coreApp); - if(attribute == null){ - return null; - } - if(attribute.getValueType() != ValueType.INT_BOOLEAN){ - return null; - } - return attribute.getValueAsBoolean(); - } - public boolean isSplit(){ - ResXmlElement manifest = getManifestElement(); - if(manifest == null){ - return false; - } - return manifest.searchAttributeByName(NAME_split)!=null; - } - public String getSplit(){ - ResXmlElement manifest = getManifestElement(); - if(manifest == null){ - return null; - } - ResXmlAttribute attribute = manifest.searchAttributeByName(NAME_split); - if(attribute!=null){ - return attribute.getValueAsString(); - } - return null; - } - public void setSplit(String split, boolean forceCreate){ - ResXmlElement manifest = getManifestElement(); - if(manifest == null){ - return; - } - ResXmlAttribute attribute; - if(forceCreate){ - attribute = manifest.getOrCreateAttribute(NAME_split, 0); - }else { - attribute = manifest.searchAttributeByName(NAME_split); - if(attribute==null){ - return; - } - } - attribute.setValueAsString(split); - } - // TODO: find a better way - public int guessCurrentPackageId(){ - if(mGuessedPackageId == 0){ - mGuessedPackageId = ((getIconResourceId()>>24) & 0xff); - } - return mGuessedPackageId; - } - public int getIconResourceId(){ - ResXmlElement applicationElement = getApplicationElement(); - if(applicationElement==null){ - return 0; - } - ResXmlAttribute iconAttribute=applicationElement.searchAttributeByResourceId(ID_icon); - if(iconAttribute==null || iconAttribute.getValueType() != ValueType.REFERENCE){ - return 0; - } - return iconAttribute.getData(); - } - public void setIconResourceId(int resourceId){ - ResXmlElement applicationElement = getApplicationElement(); - if(applicationElement==null){ - return; - } - ResXmlAttribute iconAttribute = - applicationElement.getOrCreateAndroidAttribute(NAME_icon, ID_icon); - iconAttribute.setValueType(ValueType.REFERENCE); - iconAttribute.setData(resourceId); - } - public boolean isDebuggable(){ - ResXmlElement application=getApplicationElement(); - if(application==null){ - return false; - } - ResXmlAttribute attribute = application - .searchAttributeByResourceId(ID_debuggable); - if(attribute==null){ - return false; - } - return attribute.getValueAsBoolean(); - } - public void setDebuggable(boolean debuggable){ - ResXmlElement application=getApplicationElement(); - if(application==null){ - return; - } - ResXmlAttribute attribute = application - .searchAttributeByResourceId(ID_debuggable); - if(debuggable){ - if(attribute==null){ - attribute=application.createAndroidAttribute(NAME_debuggable, ID_debuggable); - } - attribute.setValueAsBoolean(true); - }else if(attribute!=null) { - application.removeAttribute(attribute); - } - } - public ResXmlElement getMainActivity(){ - for(ResXmlElement activity:listActivities()){ - for(ResXmlElement intentFilter:activity.listElements(TAG_intent_filter)){ - for(ResXmlElement action:intentFilter.listElements(TAG_action)){ - ResXmlAttribute attribute = action.searchAttributeByResourceId(ID_name); - if(attribute==null){ - continue; - } - if(VALUE_android_intent_action_MAIN.equals(attribute.getValueAsString())){ - return activity; - } - } - } - } - return null; - } - public ResXmlElement getActivityByName(String name){ - for(ResXmlElement activity:listActivities()){ - ResXmlAttribute attribute = activity.searchAttributeByResourceId(AndroidManifestBlock.ID_name); - if(name != null && attribute != null && name.equals(attribute.getValueAsString())) - return activity; - } - return null; - } - public List listActivities(){ - return listActivities(true); - } - public List listActivities(boolean includeActivityAlias){ - ResXmlElement application=getApplicationElement(); - if(application==null){ - return new ArrayList<>(); - } - List results = application.listElements(TAG_activity); - if(includeActivityAlias){ - results.addAll(application.listElements(TAG_activity_alias)); - } - return results; - } - public List listApplicationElementsByTag(String tag){ - ResXmlElement application=getApplicationElement(); - if(application==null){ - return new ArrayList<>(); - } - return application.listElements(tag); - } - public List getUsesPermissions(){ - List results=new ArrayList<>(); - ResXmlElement manifestElement=getManifestElement(); - if(manifestElement==null){ - return results; - } - List permissionList = manifestElement.listElements(TAG_uses_permission); - for(ResXmlElement permission:permissionList){ - ResXmlAttribute nameAttr = permission.searchAttributeByResourceId(ID_name); - if(nameAttr==null||nameAttr.getValueType()!=ValueType.STRING){ - continue; - } - String val=nameAttr.getValueAsString(); - if(val!=null){ - results.add(val); - } - } - return results; - } - public ResXmlElement getUsesPermission(String permissionName){ - ResXmlElement manifestElement=getManifestElement(); - if(manifestElement==null){ - return null; - } - List permissionList = manifestElement.listElements(TAG_uses_permission); - for(ResXmlElement permission:permissionList){ - ResXmlAttribute nameAttr = permission.searchAttributeByResourceId(ID_name); - if(nameAttr==null || nameAttr.getValueType()!=ValueType.STRING){ - continue; - } - String val=nameAttr.getValueAsString(); - if(val==null){ - continue; - } - if(val.equals(permissionName)){ - return permission; - } - } - return null; - } - public ResXmlElement addUsesPermission(String permissionName){ - ResXmlElement manifestElement=getManifestElement(); - if(manifestElement==null){ - return null; - } - ResXmlElement exist = getUsesPermission(permissionName); - if(exist!=null){ - return exist; - } - ResXmlElement result = manifestElement.createChildElement(TAG_uses_permission); - ResXmlAttribute attr = result.getOrCreateAndroidAttribute(NAME_name, ID_name); - attr.setValueAsString(permissionName); - int i = manifestElement.lastIndexOf(TAG_uses_permission); - i++; - manifestElement.changeIndex(result, i); - return result; - } - public String getPackageName(){ - ResXmlElement manifest=getManifestElement(); - if(manifest==null){ - return null; - } - ResXmlAttribute attribute = manifest.searchAttributeByName(NAME_PACKAGE); - if(attribute==null || attribute.getValueType()!=ValueType.STRING){ - return null; - } - return attribute.getValueAsString(); - } - public boolean setPackageName(String packageName){ - ResXmlElement manifestElement=getManifestElement(); - if(manifestElement==null){ - return false; - } - ResXmlAttribute attribute= manifestElement.searchAttributeByName(NAME_PACKAGE); - if(attribute==null){ - return false; - } - attribute.setValueAsString(packageName); - return true; - } - public Integer getPlatformBuildVersionCode(){ - ResXmlElement manifest = getManifestElement(); - if(manifest==null){ - return null; - } - ResXmlAttribute attribute = manifest.searchAttributeByName(NAME_platformBuildVersionCode); - if(attribute==null || attribute.getValueType()!=ValueType.INT_DEC){ - return null; - } - return attribute.getData(); - } - public Integer getTargetSdkVersion(){ - ResXmlElement manifest = getManifestElement(); - if(manifest==null){ - return null; - } - ResXmlElement usesSdk = manifest.getElementByTagName(TAG_uses_sdk); - if(usesSdk==null){ - return null; - } - ResXmlAttribute attribute = usesSdk.searchAttributeByResourceId(ID_targetSdkVersion); - if(attribute==null || attribute.getValueType()!=ValueType.INT_DEC){ - return null; - } - return attribute.getData(); - } - public Integer getCompileSdkVersion(){ - return getManifestAttributeInt(ID_compileSdkVersion); - } - public void setCompileSdkVersion(int val){ - setManifestAttributeInt(NAME_compileSdkVersion, ID_compileSdkVersion, val); - } - public String getCompileSdkVersionCodename(){ - return getManifestAttributeString(ID_compileSdkVersionCodename); - } - public boolean setCompileSdkVersionCodename(String val){ - ResXmlElement manifest=getManifestElement(); - if(manifest==null){ - return false; - } - ResXmlAttribute attribute = manifest.searchAttributeByResourceId(ID_compileSdkVersionCodename); - if(attribute==null){ - return false; - } - attribute.setValueAsString(val); - return true; - } - public Integer getVersionCode(){ - return getManifestAttributeInt(ID_versionCode); - } - public void setVersionCode(int val){ - setManifestAttributeInt(NAME_versionCode, ID_versionCode, val); - } - public String getVersionName(){ - return getManifestAttributeString(ID_versionName); - } - public boolean setVersionName(String packageName){ - return setManifestAttributeString(NAME_versionName, ID_versionName, packageName); - } - private String getManifestAttributeString(int resourceId){ - ResXmlElement manifest=getManifestElement(); - if(manifest==null){ - return null; - } - ResXmlAttribute attribute = manifest.searchAttributeByResourceId(resourceId); - if(attribute==null || attribute.getValueType()!=ValueType.STRING){ - return null; - } - return attribute.getValueAsString(); - } - private boolean setManifestAttributeString(String attributeName, int resourceId, String value){ - ResXmlElement manifestElement=getOrCreateManifestElement(); - ResXmlAttribute attribute = manifestElement - .getOrCreateAndroidAttribute(attributeName, resourceId); - attribute.setValueAsString(value); - return true; - } - private void setManifestAttributeInt(String attributeName, int resourceId, int value){ - ResXmlElement manifestElement=getOrCreateManifestElement(); - ResXmlAttribute attribute = manifestElement - .getOrCreateAndroidAttribute(attributeName, resourceId); - attribute.setTypeAndData(ValueType.INT_DEC, value); - } - private Integer getManifestAttributeInt(int resourceId){ - ResXmlElement manifestElement=getManifestElement(); - if(manifestElement==null){ - return null; - } - ResXmlAttribute attribute= manifestElement.searchAttributeByResourceId(resourceId); - if(attribute==null || attribute.getValueType()!=ValueType.INT_DEC){ - return null; - } - return attribute.getData(); - } - public ResXmlElement getApplicationElement(){ - ResXmlElement manifestElement=getManifestElement(); - if(manifestElement==null){ - return null; - } - return manifestElement.getElementByTagName(TAG_application); - } - public ResXmlElement getManifestElement(){ - ResXmlElement manifestElement=getResXmlElement(); - if(manifestElement==null){ - return null; - } - if(!TAG_manifest.equals(manifestElement.getTag())){ - return null; - } - return manifestElement; - } - private ResXmlElement getOrCreateManifestElement(){ - ResXmlElement manifestElement=getResXmlElement(); - if(manifestElement==null){ - manifestElement=createRootElement(TAG_manifest); - } - if(!TAG_manifest.equals(manifestElement.getTag())){ - manifestElement.setTag(TAG_manifest); - } - return manifestElement; - } - @Override - public String toString(){ - StringBuilder builder=new StringBuilder(); - builder.append(getClass().getSimpleName()); - builder.append("{"); - builder.append(NAME_PACKAGE).append("=").append(getPackageName()); - builder.append(", ").append(NAME_versionCode).append("=").append(getVersionCode()); - builder.append(", ").append(NAME_versionName).append("=").append(getVersionName()); - builder.append(", ").append(NAME_compileSdkVersion).append("=").append(getCompileSdkVersion()); - builder.append(", ").append(NAME_compileSdkVersionCodename).append("=").append(getCompileSdkVersionCodename()); - - List allPermissions= getUsesPermissions(); - builder.append(", PERMISSIONS["); - boolean appendOnce=false; - for(String permissions:allPermissions){ - if(appendOnce){ - builder.append(", "); - } - builder.append(permissions); - appendOnce=true; - } - builder.append("]"); - builder.append("}"); - return builder.toString(); - } - public static boolean isAndroidManifestBlock(ResXmlDocument xmlBlock){ - if(xmlBlock==null){ - return false; - } - ResXmlElement root = xmlBlock.getResXmlElement(); - if(root==null){ - return false; - } - return TAG_manifest.equals(root.getTag()); - } - public static AndroidManifestBlock load(File file) throws IOException { - return load(new FileInputStream(file)); - } - public static AndroidManifestBlock load(InputStream inputStream) throws IOException { - AndroidManifestBlock manifestBlock=new AndroidManifestBlock(); - manifestBlock.readBytes(inputStream); - return manifestBlock; - } - public static final String TAG_action = "action"; - public static final String TAG_activity = "activity"; - public static final String TAG_activity_alias = "activity-alias"; - public static final String TAG_application = "application"; - public static final String TAG_category = "category"; - public static final String TAG_data = "data"; - public static final String TAG_intent_filter = "intent-filter"; - public static final String TAG_manifest = "manifest"; - public static final String TAG_meta_data = "meta-data"; - public static final String TAG_package = "package"; - public static final String TAG_permission = "permission"; - public static final String TAG_provider = "provider"; - public static final String TAG_receiver = "receiver"; - public static final String TAG_service = "service"; - public static final String TAG_uses_feature = "uses-feature"; - public static final String TAG_uses_library = "uses-library"; - public static final String TAG_uses_permission = "uses-permission"; - public static final String TAG_uses_sdk = "uses-sdk"; - - public static final String NAME_compileSdkVersion = "compileSdkVersion"; - public static final String NAME_compileSdkVersionCodename = "compileSdkVersionCodename"; - public static final String NAME_installLocation="installLocation"; - public static final String NAME_PACKAGE = "package"; - public static final String NAME_split = "split"; - public static final String NAME_coreApp = "coreApp"; - public static final String NAME_platformBuildVersionCode = "platformBuildVersionCode"; - public static final String NAME_platformBuildVersionName = "platformBuildVersionName"; - public static final String NAME_versionCode = "versionCode"; - public static final String NAME_versionName = "versionName"; - public static final String NAME_name = "name"; - public static final String NAME_extractNativeLibs = "extractNativeLibs"; - public static final String NAME_isSplitRequired = "isSplitRequired"; - public static final String NAME_value = "value"; - public static final String NAME_resource = "resource"; - public static final String NAME_debuggable = "debuggable"; - public static final String NAME_icon = "icon"; - public static final String NAME_label = "label"; - public static final String NAME_theme = "theme"; - public static final String NAME_id = "id"; - - public static final int ID_name = 0x01010003; - public static final int ID_compileSdkVersion = 0x01010572; - public static final int ID_targetSdkVersion = 0x01010270; - public static final int ID_compileSdkVersionCodename = 0x01010573; - public static final int ID_authorities = 0x01010018; - public static final int ID_host = 0x01010028; - public static final int ID_configChanges = 0x0101001f; - public static final int ID_screenOrientation = 0x0101001e; - public static final int ID_extractNativeLibs = 0x010104ea; - public static final int ID_isSplitRequired = 0x01010591; - public static final int ID_value = 0x01010024; - public static final int ID_resource = 0x01010025; - public static final int ID_versionCode = 0x0101021b; - public static final int ID_versionName = 0x0101021c; - public static final int ID_debuggable = 0x0101000f; - public static final int ID_icon = 0x01010002; - public static final int ID_label = 0x01010001; - public static final int ID_theme = 0x01010000; - public static final int ID_id = 0x010100d0; - - public static final String VALUE_android_intent_action_MAIN = "android.intent.action.MAIN"; - - public static final String FILE_NAME="AndroidManifest.xml"; -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/xml/BaseXmlChunk.java b/src/ARSCLib/com/reandroid/arsc/chunk/xml/BaseXmlChunk.java deleted file mode 100755 index f91b3629..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/xml/BaseXmlChunk.java +++ /dev/null @@ -1,205 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ - package com.reandroid.arsc.chunk.xml; - - import com.reandroid.arsc.chunk.ChunkType; - import com.reandroid.arsc.base.Block; - import com.reandroid.arsc.chunk.Chunk; - import com.reandroid.arsc.header.XmlNodeHeader; - import com.reandroid.arsc.item.IntegerItem; - import com.reandroid.arsc.item.ResXmlString; - import com.reandroid.arsc.pool.ResXmlStringPool; - - import java.util.HashSet; - import java.util.Set; - - class BaseXmlChunk extends Chunk { - private final IntegerItem mNamespaceReference; - private final IntegerItem mStringReference; - - BaseXmlChunk(ChunkType chunkType, int initialChildesCount) { - super(new XmlNodeHeader(chunkType), initialChildesCount+2); - - this.mNamespaceReference=new IntegerItem(-1); - this.mStringReference=new IntegerItem(-1); - - addChild(mNamespaceReference); - addChild(mStringReference); - } - void onRemoved(){ - ResXmlStringPool stringPool = getStringPool(); - if(stringPool==null){ - return; - } - stringPool.removeReference(getHeaderBlock().getCommentReference()); - stringPool.removeReference(mNamespaceReference); - stringPool.removeReference(mStringReference); - } - void linkStringReferences(){ - linkStringReference(getHeaderBlock().getCommentReference()); - linkStringReference(mNamespaceReference); - linkStringReference(mStringReference); - } - private void linkStringReference(IntegerItem item){ - ResXmlString xmlString = getResXmlString(item.get()); - if(xmlString!=null){ - xmlString.addReferenceIfAbsent(item); - } - } - void unLinkStringReference(IntegerItem item){ - ResXmlString xmlString = getResXmlString(item.get()); - if(xmlString!=null){ - xmlString.removeReference(item); - } - } - public void setLineNumber(int val){ - getHeaderBlock().getLineNumber().set(val); - } - public int getLineNumber(){ - return getHeaderBlock().getLineNumber().get(); - } - public void setCommentReference(int val){ - if(val == getCommentReference()){ - return; - } - IntegerItem comment=getHeaderBlock().getCommentReference(); - unLinkStringReference(comment); - getHeaderBlock().getCommentReference().set(val); - linkStringReference(comment); - } - public int getCommentReference(){ - return getHeaderBlock().getCommentReference().get(); - } - public void setNamespaceReference(int val){ - if(val == getNamespaceReference()){ - return; - } - unLinkStringReference(mNamespaceReference); - mNamespaceReference.set(val); - linkStringReference(mNamespaceReference); - } - public int getNamespaceReference(){ - return mNamespaceReference.get(); - } - public void setStringReference(int val){ - if(val == getStringReference()){ - return; - } - unLinkStringReference(mStringReference); - mStringReference.set(val); - linkStringReference(mStringReference); - } - public int getStringReference(){ - return mStringReference.get(); - } - public ResXmlString setString(String str){ - ResXmlStringPool pool = getStringPool(); - if(pool==null){ - return null; - } - ResXmlString xmlString = pool.getOrCreate(str); - setStringReference(xmlString.getIndex()); - return xmlString; - } - public ResXmlStringPool getStringPool(){ - Block parent=getParent(); - while (parent!=null){ - if(parent instanceof ResXmlDocument){ - return ((ResXmlDocument)parent).getStringPool(); - } - if(parent instanceof ResXmlElement){ - return ((ResXmlElement)parent).getStringPool(); - } - parent=parent.getParent(); - } - return null; - } - public ResXmlString getResXmlString(int ref){ - if(ref<0){ - return null; - } - ResXmlStringPool stringPool=getStringPool(); - if(stringPool!=null){ - return stringPool.get(ref); - } - return null; - } - ResXmlString getOrCreateResXmlString(String str){ - ResXmlStringPool stringPool=getStringPool(); - if(stringPool!=null){ - return stringPool.getOrCreate(str); - } - return null; - } - String getString(int ref){ - ResXmlString xmlString=getResXmlString(ref); - if(xmlString!=null){ - return xmlString.get(); - } - return null; - } - ResXmlString getOrCreateString(String str){ - ResXmlStringPool stringPool=getStringPool(); - if(stringPool==null){ - return null; - } - return stringPool.getOrCreate(str); - } - - public String getName(){ - return getString(getStringReference()); - } - public String getUri(){ - return getString(getNamespaceReference()); - } - public String getComment(){ - return getString(getCommentReference()); - } - public void setComment(String comment){ - if(comment==null||comment.length()==0){ - setCommentReference(-1); - }else { - String old=getComment(); - if(comment.equals(old)){ - return; - } - ResXmlString xmlString = getOrCreateResXmlString(comment); - setCommentReference(xmlString.getIndex()); - } - } - public ResXmlElement getParentResXmlElement(){ - return getParent(ResXmlElement.class); - } - @Override - protected void onChunkRefreshed() { - - } - @Override - public String toString(){ - ChunkType chunkType=getHeaderBlock().getChunkType(); - if(chunkType==null){ - return super.toString(); - } - StringBuilder builder=new StringBuilder(); - builder.append(chunkType.toString()); - builder.append(": line="); - builder.append(getLineNumber()); - builder.append(" {"); - builder.append(getName()); - builder.append("}"); - return builder.toString(); - } - } diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ParserEvent.java b/src/ARSCLib/com/reandroid/arsc/chunk/xml/ParserEvent.java deleted file mode 100644 index 11d46cc8..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ParserEvent.java +++ /dev/null @@ -1,59 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk.xml; - -import org.xmlpull.v1.XmlPullParser; - -public class ParserEvent { - private final int event; - private final ResXmlNode xmlNode; - private final String comment; - private final boolean endComment; - public ParserEvent(int event, ResXmlNode xmlNode, String comment, boolean endComment){ - this.event = event; - this.xmlNode = xmlNode; - this.comment = comment; - this.endComment = endComment; - } - public ParserEvent(int event, ResXmlNode xmlNode){ - this(event, xmlNode, null, false); - } - public int getEvent() { - return event; - } - public ResXmlNode getXmlNode() { - return xmlNode; - } - public String getComment() { - return comment; - } - public boolean isEndComment() { - return endComment; - } - - public static final int START_DOCUMENT = XmlPullParser.START_DOCUMENT; - public static final int END_DOCUMENT = XmlPullParser.END_DOCUMENT; - public static final int START_TAG = XmlPullParser.START_TAG; - public static final int END_TAG = XmlPullParser.END_TAG; - public static final int TEXT = XmlPullParser.TEXT; - public static final int CDSECT = XmlPullParser.CDSECT; - public static final int ENTITY_REF = XmlPullParser.ENTITY_REF; - public static final int IGNORABLE_WHITESPACE = XmlPullParser.IGNORABLE_WHITESPACE; - public static final int PROCESSING_INSTRUCTION = XmlPullParser.PROCESSING_INSTRUCTION; - public static final int COMMENT = XmlPullParser.COMMENT; - public static final int DOCDECL = XmlPullParser.DOCDECL; - -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ParserEventList.java b/src/ARSCLib/com/reandroid/arsc/chunk/xml/ParserEventList.java deleted file mode 100644 index f3832045..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ParserEventList.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk.xml; - - -import com.reandroid.arsc.decoder.ValueDecoder; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -public class ParserEventList implements Iterator { - private final List eventList; - private int index; - private ParserEvent mCurrent; - private int type = -1; - public ParserEventList(){ - this.eventList = new ArrayList<>(); - } - public void clear(){ - this.eventList.clear(); - reset(); - } - public int getType(){ - return type; - } - public String getText(){ - if(type == ParserEvent.COMMENT){ - return mCurrent.getComment(); - } - if(type == ParserEvent.START_TAG || type == ParserEvent.END_TAG){ - return getElement().getTag(); - } - if(type == ParserEvent.TEXT){ - String text = ((ResXmlTextNode)getXmlNode()).getText(); - if(text == null){ - text = ""; - } - return ValueDecoder.escapeSpecialCharacter(text); - } - return null; - } - public int getLineNumber(){ - if(type!=ParserEvent.COMMENT - && type!=ParserEvent.START_TAG - && type!=ParserEvent.END_TAG){ - return 0; - } - ResXmlNode xmlNode = getXmlNode(); - if(mCurrent.isEndComment() || type==ParserEvent.END_TAG){ - return ((ResXmlElement)xmlNode).getEndLineNumber(); - } - if(type==ParserEvent.TEXT){ - return ((ResXmlTextNode)xmlNode).getLineNumber(); - } - return ((ResXmlElement)xmlNode).getStartLineNumber(); - } - public ResXmlNode getXmlNode(){ - return mCurrent.getXmlNode(); - } - public ResXmlElement getElement(){ - return (ResXmlElement) mCurrent.getXmlNode(); - } - @Override - public ParserEvent next(){ - if(!hasNext()){ - return null; - } - ParserEvent event = get(index); - index++; - mCurrent = event; - type = event.getEvent(); - return event; - } - @Override - public boolean hasNext(){ - return index < size(); - } - public int size(){ - return eventList.size(); - } - public int getIndex() { - return index; - } - public void reset(){ - index = 0; - mCurrent = null; - type = -1; - } - void add(ParserEvent parserEvent){ - if(parserEvent==null){ - return; - } - eventList.add(parserEvent); - } - private ParserEvent get(int i){ - return eventList.get(i); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResIdBuilder.java b/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResIdBuilder.java deleted file mode 100644 index 43fe3377..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResIdBuilder.java +++ /dev/null @@ -1,78 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk.xml; - -import com.reandroid.arsc.array.ResXmlIDArray; -import com.reandroid.arsc.array.StringArray; -import com.reandroid.arsc.item.ResXmlID; -import com.reandroid.arsc.item.ResXmlString; -import com.reandroid.arsc.pool.ResXmlStringPool; - -import java.util.*; - -public class ResIdBuilder implements Comparator { - private final Map mIdNameMap; - public ResIdBuilder(){ - this.mIdNameMap=new HashMap<>(); - } - public void buildTo(ResXmlIDMap resXmlIDMap){ - ResXmlStringPool stringPool = resXmlIDMap.getXmlStringPool(); - StringArray xmlStringsArray = stringPool.getStringsArray(); - ResXmlIDArray xmlIDArray = resXmlIDMap.getResXmlIDArray(); - List idList=getSortedIds(); - int size = idList.size(); - xmlStringsArray.ensureSize(size); - xmlIDArray.ensureSize(size); - for(int i=0;i getSortedIds(){ - List results=new ArrayList<>(mIdNameMap.keySet()); - results.sort(this); - return results; - } - @Override - public int compare(Integer i1, Integer i2) { - return i1.compareTo(i2); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlAttribute.java b/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlAttribute.java deleted file mode 100755 index 7ebd6447..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlAttribute.java +++ /dev/null @@ -1,510 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk.xml; - -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.group.EntryGroup; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.item.*; -import com.reandroid.arsc.pool.ResXmlStringPool; -import com.reandroid.arsc.pool.StringPool; -import com.reandroid.arsc.util.HexUtil; -import com.reandroid.arsc.value.AttributeValue; -import com.reandroid.arsc.value.Entry; -import com.reandroid.arsc.value.ValueItem; -import com.reandroid.arsc.value.ValueType; -import com.reandroid.common.EntryStore; -import com.reandroid.json.JSONObject; -import com.reandroid.xml.XMLAttribute; -import com.reandroid.xml.XMLException; - -import java.io.IOException; -import java.util.Objects; - -public class ResXmlAttribute extends ValueItem implements AttributeValue, Comparable{ - private ReferenceItem mNSReference; - private ReferenceItem mNameReference; - private ReferenceItem mNameIdReference; - private ReferenceItem mValueStringReference; - public ResXmlAttribute(int attributeUnitSize) { - super(attributeUnitSize, OFFSET_SIZE); - byte[] bts = getBytesInternal(); - putInteger(bts, OFFSET_NS, -1); - putInteger(bts, OFFSET_NAME, -1); - putInteger(bts, OFFSET_STRING, -1); - } - public ResXmlAttribute() { - this(20); - } - - public String getUri(){ - return getString(getNamespaceReference()); - } - public String getFullName(){ - String name=getName(); - if(name==null){ - return null; - } - String prefix=getNamePrefix(); - if(prefix==null){ - return name; - } - return prefix+":"+name; - } - public String getName(){ - return getString(getNameReference()); - } - public String getNamePrefix(){ - ResXmlElement xmlElement=getParentResXmlElement(); - if(xmlElement==null){ - return null; - } - ResXmlStartNamespace startNamespace=xmlElement.getStartNamespaceByUriRef(getNamespaceReference()); - if(startNamespace==null){ - return null; - } - return startNamespace.getPrefix(); - } - // WARN! Careful this is not real value - public String getValueString(){ - return getString(getValueStringReference()); - } - @Override - public int getNameResourceID(){ - ResXmlID xmlID = getResXmlID(); - if(xmlID != null){ - return xmlID.get(); - } - return 0; - } - @Override - public void setNameResourceID(int resourceId){ - ResXmlIDMap xmlIDMap=getResXmlIDMap(); - if(xmlIDMap==null){ - return; - } - ResXmlID xmlID = xmlIDMap.getOrCreate(resourceId); - setNameReference(xmlID.getIndex()); - } - @Override - public Entry resolveName(){ - return resolve(getNameResourceID()); - } - - public void setName(String name, int resourceId){ - if(Objects.equals(name, getName()) && resourceId==getNameResourceID()){ - return; - } - unlink(mNameReference); - unLinkNameId(getResXmlID()); - ResXmlString xmlString = getOrCreateAttributeName(name, resourceId); - if(xmlString==null){ - return; - } - setNameReference(xmlString.getIndex()); - mNameReference = link(OFFSET_NAME); - linkNameId(); - } - private void linkStartNameSpace(){ - ResXmlElement xmlElement=getParentResXmlElement(); - if(xmlElement==null){ - return; - } - ResXmlStartNamespace startNamespace=xmlElement.getStartNamespaceByUriRef(getNamespaceReference()); - if(startNamespace==null){ - return; - } - startNamespace.addAttributeReference(this); - } - private void unLinkStartNameSpace(){ - ResXmlElement xmlElement = getParentResXmlElement(); - if(xmlElement == null){ - return; - } - ResXmlStartNamespace startNamespace = - xmlElement.getStartNamespaceByUriRef(getNamespaceReference()); - if(startNamespace == null){ - return; - } - startNamespace.removeAttributeReference(this); - } - private ResXmlString getOrCreateAttributeName(String name, int resourceId){ - ResXmlStringPool stringPool = getStringPool(); - if(stringPool==null){ - return null; - } - return stringPool.getOrCreateAttribute(resourceId, name); - } - public ResXmlElement getParentResXmlElement(){ - return getParent(ResXmlElement.class); - } - public int getAttributesUnitSize(){ - return OFFSET_SIZE + super.getSize(); - } - public void setAttributesUnitSize(int size){ - int eight = size - OFFSET_SIZE; - super.setSize(eight); - } - private String getString(int ref){ - if(ref<0){ - return null; - } - StringPool stringPool = getStringPool(); - if(stringPool == null){ - return null; - } - StringItem stringItem = stringPool.get(ref); - if(stringItem == null){ - return null; - } - return stringItem.getHtml(); - } - private ResXmlID getResXmlID(){ - ResXmlIDMap xmlIDMap = getResXmlIDMap(); - if(xmlIDMap == null){ - return null; - } - return xmlIDMap.getResXmlIDArray().get(getNameReference()); - } - private ResXmlIDMap getResXmlIDMap(){ - ResXmlElement xmlElement=getParentResXmlElement(); - if(xmlElement!=null){ - return xmlElement.getResXmlIDMap(); - } - return null; - } - - int getNamespaceReference(){ - return getInteger(getBytesInternal(), OFFSET_NS); - } - public void setNamespace(String uri, String prefix){ - if(uri == null || prefix == null){ - setNamespaceReference(-1); - return; - } - ResXmlElement parentElement = getParentResXmlElement(); - if(parentElement == null){ - return; - } - ResXmlStartNamespace ns = parentElement.getOrCreateNamespace(uri, prefix); - setNamespaceReference(ns.getUriReference()); - } - public void setNamespaceReference(int ref){ - if(ref == getNamespaceReference()){ - return; - } - unlink(mNSReference); - putInteger(getBytesInternal(), OFFSET_NS, ref); - mNSReference = link(OFFSET_NS); - linkStartNameSpace(); - } - int getNameReference(){ - return getInteger(getBytesInternal(), OFFSET_NAME); - } - void setNameReference(int ref){ - if(ref == getNameReference()){ - return; - } - unLinkNameId(getResXmlID()); - unlink(mNameReference); - putInteger(getBytesInternal(), OFFSET_NAME, ref); - mNameReference = link(OFFSET_NAME); - linkNameId(); - } - int getValueStringReference(){ - return getInteger(getBytesInternal(), OFFSET_STRING); - } - void setValueStringReference(int ref){ - if(ref == getValueStringReference() && mValueStringReference!=null){ - return; - } - StringPool stringPool = getStringPool(); - if(stringPool == null){ - return; - } - StringItem stringItem = stringPool.get(ref); - unlink(mValueStringReference); - if(stringItem!=null){ - ref = stringItem.getIndex(); - } - putInteger(getBytesInternal(), OFFSET_STRING, ref); - ReferenceItem referenceItem = null; - if(stringItem!=null){ - referenceItem = new ReferenceBlock<>(this, OFFSET_STRING); - stringItem.addReference(referenceItem); - } - mValueStringReference = referenceItem; - } - - @Override - public void onReadBytes(BlockReader reader) throws IOException { - super.onReadBytes(reader); - super.onDataLoaded(); - linkAll(); - linkStartNameSpace(); - } - @Override - public void onRemoved(){ - super.onRemoved(); - unLinkStartNameSpace(); - unlinkAll(); - } - @Override - protected void onUnlinkDataString(ReferenceItem referenceItem){ - unlink(referenceItem); - } - @Override - protected void onDataChanged(){ - if(getValueType()==ValueType.STRING){ - setValueStringReference(getData()); - }else { - setValueStringReference(-1); - } - } - @Override - public ResXmlDocument getParentChunk() { - ResXmlElement element = getParentResXmlElement(); - if(element!=null){ - return element.getParentDocument(); - } - return null; - } - - private void linkNameId(){ - ResXmlID xmlID = getResXmlID(); - if(xmlID==null){ - return; - } - unLinkNameId(xmlID); - ReferenceItem referenceItem = new ReferenceBlock<>(this, OFFSET_NAME); - xmlID.addReference(referenceItem); - mNameIdReference = referenceItem; - } - private void unLinkNameId(ResXmlID xmlID){ - ReferenceItem referenceItem = mNameIdReference; - if(referenceItem==null || xmlID == null){ - return; - } - xmlID.removeReference(referenceItem); - mNameIdReference = null; - if(xmlID.hasReference()){ - return; - } - ResXmlIDMap xmlIDMap = getResXmlIDMap(); - if(xmlIDMap == null){ - return; - } - xmlIDMap.removeSafely(xmlID); - } - private void linkAll(){ - unlink(mNSReference); - mNSReference = link(OFFSET_NS); - unlink(mNameReference); - mNameReference = link(OFFSET_NAME); - unlink(mValueStringReference); - mValueStringReference = link(OFFSET_STRING); - - linkNameId(); - } - private void unlinkAll(){ - unlink(mNSReference); - unlink(mNameReference); - unlink(mValueStringReference); - mNSReference = null; - mNameReference = null; - mValueStringReference = null; - - unLinkNameId(getResXmlID()); - } - private ReferenceItem link(int offset){ - if(offset<0){ - return null; - } - StringPool stringPool = getStringPool(); - if(stringPool == null){ - return null; - } - int ref = getInteger(getBytesInternal(), offset); - StringItem stringItem = stringPool.get(ref); - if(stringItem == null){ - return null; - } - ReferenceItem referenceItem = new ReferenceBlock<>(this, offset); - stringItem.addReference(referenceItem); - return referenceItem; - } - private void unlink(ReferenceItem reference){ - if(reference == null){ - return; - } - ResXmlStringPool stringPool = getStringPool(); - if(stringPool==null){ - return; - } - stringPool.removeReference(reference); - } - @Override - public ResXmlStringPool getStringPool(){ - StringPool stringPool = super.getStringPool(); - if(stringPool instanceof ResXmlStringPool){ - return (ResXmlStringPool) stringPool; - } - return null; - } - @Override - public int compareTo(ResXmlAttribute other) { - int id1=getNameResourceID(); - int id2=other.getNameResourceID(); - if(id1==0 && id2!=0){ - return 1; - } - if(id2==0 && id1!=0){ - return -1; - } - if(id1!=0){ - return Integer.compare(id1, id2); - } - String name1=getName(); - if(name1==null){ - name1=""; - } - String name2=other.getName(); - if(name2==null){ - name2=""; - } - return name1.compareTo(name2); - } - @Override - public JSONObject toJson() { - JSONObject jsonObject= new JSONObject(); - jsonObject.put(NAME_name, getName()); - jsonObject.put(NAME_id, getNameResourceID()); - jsonObject.put(NAME_namespace_uri, getUri()); - ValueType valueType=getValueType(); - jsonObject.put(NAME_value_type, valueType.name()); - if(valueType==ValueType.STRING){ - jsonObject.put(NAME_data, getValueAsString()); - }else if(valueType==ValueType.INT_BOOLEAN){ - jsonObject.put(NAME_data, getValueAsBoolean()); - }else { - jsonObject.put(NAME_data, getData()); - } - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - String name = json.optString(NAME_name, ""); - int id = json.optInt(NAME_id, 0); - setName(name, id); - String uri= json.optString(NAME_namespace_uri, null); - if(uri!=null){ - ResXmlStartNamespace ns = getParentResXmlElement().getStartNamespaceByUri(uri); - if(ns==null){ - ns = getParentResXmlElement().getRootResXmlElement() - .getOrCreateNamespace(uri, ""); - } - setNamespaceReference(ns.getUriReference()); - } - ValueType valueType=ValueType.fromName(json.getString(NAME_value_type)); - if(valueType==ValueType.STRING){ - setValueAsString(json.optString(NAME_data, "")); - }else if(valueType==ValueType.INT_BOOLEAN){ - setValueAsBoolean(json.getBoolean(NAME_data)); - }else { - setValueType(valueType); - setData(json.getInt(NAME_data)); - } - } - public XMLAttribute decodeToXml(EntryStore entryStore, int currentPackageId) throws XMLException { - int resourceId=getNameResourceID(); - String name; - if(resourceId==0){ - name=getName(); - }else { - EntryGroup group = entryStore.getEntryGroup(resourceId); - if(group==null){ - //Lets ignore such error until XML encoder implemented - //throw new XMLException("Failed to decode attribute name: " - //HexUtil.toHex8("@0x", resourceId)); - name = HexUtil.toHex8("@0x", resourceId); - }else { - name = group.getSpecName(); - } - } - String prefix = getNamePrefix(); - if(prefix!=null){ - name=prefix+":"+name; - } - ValueType valueType = getValueType(); - int raw = getData(); - String value = ValueDecoder.decode(entryStore, currentPackageId, (AttributeValue) this); - XMLAttribute attribute = new XMLAttribute(name, value); - attribute.setNameId(resourceId); - if(valueType==ValueType.REFERENCE||valueType==ValueType.ATTRIBUTE){ - attribute.setValueId(raw); - } - return attribute; - } - @Override - public String toString(){ - String fullName = getFullName(); - if(fullName!=null ){ - int id=getNameResourceID(); - if(id!=0){ - fullName=fullName+"(@"+ HexUtil.toHex8(id)+")"; - } - String valStr; - ValueType valueType=getValueType(); - if(valueType==ValueType.STRING){ - valStr=getValueAsString(); - }else if (valueType==ValueType.INT_BOOLEAN){ - valStr = String.valueOf(getValueAsBoolean()); - }else if (valueType==ValueType.INT_DEC){ - valStr = String.valueOf(getData()); - }else { - valStr = "["+valueType+"] " + HexUtil.toHex8(getData()); - } - if(valStr!=null){ - return fullName+"=\""+valStr+"\""; - } - return fullName+"["+valueType+"]=\""+ getData()+"\""; - } - StringBuilder builder= new StringBuilder(); - builder.append(getClass().getSimpleName()); - builder.append(": "); - builder.append(getIndex()); - builder.append("{NamespaceReference=").append(getNamespaceReference()); - builder.append(", NameReference=").append(getNameReference()); - builder.append(", ValueStringReference=").append(getValueStringReference()); - builder.append(", ValueSize=").append(getSize()); - builder.append(", ValueTypeByte=").append(getType() & 0xff); - builder.append(", Data=").append(getData()); - builder.append("}"); - return builder.toString(); - } - - - - public static final String NAME_id = "id"; - public static final String NAME_name = "name"; - public static final String NAME_namespace_uri = "namespace_uri"; - - private static final int OFFSET_NS = 0; - private static final int OFFSET_NAME = 4; - private static final int OFFSET_STRING = 8; - - private static final int OFFSET_SIZE = 12; -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlDocument.java b/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlDocument.java deleted file mode 100755 index 1a5c280e..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlDocument.java +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk.xml; - -import com.reandroid.arsc.ApkFile; -import com.reandroid.arsc.chunk.*; -import com.reandroid.arsc.container.SingleBlockContainer; -import com.reandroid.arsc.header.HeaderBlock; -import com.reandroid.arsc.header.InfoHeader; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.pool.ResXmlStringPool; -import com.reandroid.arsc.pool.StringPool; -import com.reandroid.arsc.value.ValueType; -import com.reandroid.common.EntryStore; -import com.reandroid.common.FileChannelInputStream; -import com.reandroid.json.JSONArray; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONObject; -import com.reandroid.xml.XMLDocument; -import com.reandroid.xml.XMLElement; -import com.reandroid.xml.XMLException; - -import java.io.*; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -public class ResXmlDocument extends Chunk - implements MainChunk, ParentChunk, JSONConvert { - private final ResXmlStringPool mResXmlStringPool; - private final ResXmlIDMap mResXmlIDMap; - private ResXmlElement mResXmlElement; - private final SingleBlockContainer mResXmlElementContainer; - private ApkFile mApkFile; - private PackageBlock mPackageBlock; - public ResXmlDocument() { - super(new HeaderBlock(ChunkType.XML),3); - this.mResXmlStringPool=new ResXmlStringPool(true); - this.mResXmlIDMap=new ResXmlIDMap(); - this.mResXmlElement=new ResXmlElement(); - this.mResXmlElementContainer=new SingleBlockContainer<>(); - this.mResXmlElementContainer.setItem(mResXmlElement); - addChild(mResXmlStringPool); - addChild(mResXmlIDMap); - addChild(mResXmlElementContainer); - } - public void destroy(){ - ResXmlElement root = getResXmlElement(); - if(root!=null){ - root.clearChildes(); - setResXmlElement(null); - } - getResXmlIDMap().destroy(); - getStringPool().destroy(); - refresh(); - } - public void setAttributesUnitSize(int size, boolean setToAll){ - ResXmlElement root = getResXmlElement(); - if(root!=null){ - root.setAttributesUnitSize(size, setToAll); - } - } - public ResXmlElement createRootElement(String tag){ - int lineNo=1; - ResXmlElement resXmlElement=new ResXmlElement(); - resXmlElement.newStartElement(lineNo); - - setResXmlElement(resXmlElement); - - if(tag!=null){ - resXmlElement.setTag(tag); - } - return resXmlElement; - } - void linkStringReferences(){ - ResXmlElement element=getResXmlElement(); - if(element!=null){ - element.linkStringReferences(); - } - } - /* - * method Block.addBytes is inefficient for large size byte array - * so let's override here because this block is the largest - */ - @Override - public byte[] getBytes(){ - ByteArrayOutputStream os=new ByteArrayOutputStream(); - try { - writeBytes(os); - os.close(); - } catch (IOException ignored) { - } - return os.toByteArray(); - } - @Override - public void onReadBytes(BlockReader reader) throws IOException { - HeaderBlock headerBlock=reader.readHeaderBlock(); - if(headerBlock==null){ - return; - } - BlockReader chunkReader=reader.create(headerBlock.getChunkSize()); - headerBlock=getHeaderBlock(); - headerBlock.readBytes(chunkReader); - // android/aapt2 accepts 0x0000 (NULL) chunk type as XML, it could - // be android's bug and might be fixed in the future until then lets fix it ourselves - headerBlock.setType(ChunkType.XML); - while (chunkReader.isAvailable()){ - boolean readOk=readNext(chunkReader); - if(!readOk){ - break; - } - } - reader.offset(headerBlock.getChunkSize()); - chunkReader.close(); - onChunkLoaded(); - } - @Override - public void onChunkLoaded(){ - super.onChunkLoaded(); - linkStringReferences(); - } - private boolean readNext(BlockReader reader) throws IOException { - if(!reader.isAvailable()){ - return false; - } - int position=reader.getPosition(); - HeaderBlock headerBlock=reader.readHeaderBlock(); - if(headerBlock==null){ - return false; - } - ChunkType chunkType=headerBlock.getChunkType(); - if(chunkType==ChunkType.STRING){ - mResXmlStringPool.readBytes(reader); - }else if(chunkType==ChunkType.XML_RESOURCE_MAP){ - mResXmlIDMap.readBytes(reader); - }else if(isElementChunk(chunkType)){ - mResXmlElementContainer.readBytes(reader); - return reader.isAvailable(); - }else { - throw new IOException("Unexpected chunk "+headerBlock); - } - return reader.isAvailable() && position!=reader.getPosition(); - } - private boolean isElementChunk(ChunkType chunkType){ - if(chunkType==ChunkType.XML_START_ELEMENT){ - return true; - } - if(chunkType==ChunkType.XML_END_ELEMENT){ - return true; - } - if(chunkType==ChunkType.XML_START_NAMESPACE){ - return true; - } - if(chunkType==ChunkType.XML_END_NAMESPACE){ - return true; - } - if(chunkType==ChunkType.XML_CDATA){ - return true; - } - if(chunkType==ChunkType.XML_LAST_CHUNK){ - return true; - } - return false; - } - @Override - public ResXmlStringPool getStringPool(){ - return mResXmlStringPool; - } - @Override - public ApkFile getApkFile(){ - return mApkFile; - } - @Override - public void setApkFile(ApkFile apkFile){ - this.mApkFile = apkFile; - } - @Override - public PackageBlock getPackageBlock(){ - ApkFile apkFile = this.mApkFile; - PackageBlock packageBlock = this.mPackageBlock; - if(apkFile == null || packageBlock != null){ - return packageBlock; - } - TableBlock tableBlock = apkFile.getTableBlock(); - if(tableBlock != null){ - return tableBlock.pickOne(); - } - return null; - } - public void setPackageBlock(PackageBlock packageBlock) { - this.mPackageBlock = packageBlock; - } - @Override - public TableBlock getTableBlock(){ - PackageBlock packageBlock = getPackageBlock(); - if(packageBlock != null){ - TableBlock tableBlock = packageBlock.getTableBlock(); - if(tableBlock != null){ - return tableBlock; - } - } - ApkFile apkFile = getApkFile(); - if(apkFile != null){ - return apkFile.getTableBlock(); - } - return null; - } - @Override - public StringPool getSpecStringPool() { - return null; - } - @Override - public MainChunk getMainChunk(){ - return this; - } - public ResXmlIDMap getResXmlIDMap(){ - return mResXmlIDMap; - } - public ResXmlElement getResXmlElement(){ - return mResXmlElement; - } - public void setResXmlElement(ResXmlElement resXmlElement){ - this.mResXmlElement=resXmlElement; - this.mResXmlElementContainer.setItem(resXmlElement); - } - @Override - protected void onChunkRefreshed() { - - } - public void readBytes(File file) throws IOException{ - BlockReader reader=new BlockReader(file); - super.readBytes(reader); - } - public void readBytes(InputStream inputStream) throws IOException{ - BlockReader reader=new BlockReader(inputStream); - super.readBytes(reader); - } - public final int writeBytes(File file) throws IOException{ - if(isNull()){ - throw new IOException("Can NOT save null block"); - } - File dir=file.getParentFile(); - if(dir!=null && !dir.exists()){ - dir.mkdirs(); - } - OutputStream outputStream=new FileOutputStream(file); - int length = super.writeBytes(outputStream); - outputStream.close(); - return length; - } - @Override - public JSONObject toJson() { - JSONObject jsonObject=new JSONObject(); - jsonObject.put(ResXmlDocument.NAME_element, getResXmlElement().toJson()); - JSONArray pool = getStringPool().toJson(); - if(pool!=null){ - jsonObject.put(ResXmlDocument.NAME_styled_strings, pool); - } - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - onFromJson(json); - ResXmlElement xmlElement=getResXmlElement(); - xmlElement.fromJson(json.optJSONObject(ResXmlDocument.NAME_element)); - refresh(); - } - public XMLDocument decodeToXml() throws XMLException { - ApkFile apkFile = getApkFile(); - if(apkFile == null){ - throw new XMLException("Null parent apk file"); - } - int currentPackageId = 0; - AndroidManifestBlock manifestBlock; - if(this instanceof AndroidManifestBlock){ - manifestBlock = ((AndroidManifestBlock)this); - }else { - manifestBlock = apkFile.getAndroidManifestBlock(); - } - if(manifestBlock!=null){ - currentPackageId = manifestBlock.guessCurrentPackageId(); - } - TableBlock tableBlock = apkFile.getTableBlock(); - return decodeToXml(tableBlock, currentPackageId); - } - public XMLDocument decodeToXml(EntryStore entryStore, int currentPackageId) throws XMLException { - XMLDocument xmlDocument = new XMLDocument(); - XMLElement xmlElement = getResXmlElement() - .decodeToXml(entryStore, currentPackageId); - xmlDocument.setDocumentElement(xmlElement); - return xmlDocument; - } - private void onFromJson(JSONObject json){ - List attributeList=recursiveAttributes(json.optJSONObject(ResXmlDocument.NAME_element)); - buildResourceIds(attributeList); - Set allStrings=recursiveStrings(json.optJSONObject(ResXmlDocument.NAME_element)); - ResXmlStringPool stringPool = getStringPool(); - stringPool.addStrings(allStrings); - stringPool.refresh(); - } - private void buildResourceIds(List attributeList){ - ResIdBuilder builder=new ResIdBuilder(); - for(JSONObject attribute:attributeList){ - int id=attribute.getInt(ResXmlAttribute.NAME_id); - if(id==0){ - continue; - } - String name=attribute.getString(ResXmlAttribute.NAME_name); - builder.add(id, name); - } - builder.buildTo(getResXmlIDMap()); - } - private List recursiveAttributes(JSONObject elementJson){ - List results = new ArrayList<>(); - if(elementJson==null){ - return results; - } - JSONArray attributes = elementJson.optJSONArray(ResXmlElement.NAME_attributes); - if(attributes != null){ - int length = attributes.length(); - for(int i=0; i recursiveStrings(JSONObject elementJson){ - Set results = new HashSet<>(); - if(elementJson==null){ - return results; - } - results.add(elementJson.optString(ResXmlElement.NAME_namespace_uri)); - results.add(elementJson.optString(ResXmlElement.NAME_name)); - JSONArray namespaces=elementJson.optJSONArray(ResXmlElement.NAME_namespaces); - if(namespaces != null){ - int length = namespaces.length(); - for(int i=0; i, - Comparator { - private final BlockList mStartNamespaceList; - private final SingleBlockContainer mStartElementContainer; - private final BlockList mBody; - private final SingleBlockContainer mEndElementContainer; - private final BlockList mEndNamespaceList; - private int mLevel; - public ResXmlElement() { - super(5); - this.mStartNamespaceList = new BlockList<>(); - this.mStartElementContainer= new SingleBlockContainer<>(); - this.mBody = new BlockList<>(); - this.mEndElementContainer = new SingleBlockContainer<>(); - this.mEndNamespaceList = new BlockList<>(); - addChild(0, mStartNamespaceList); - addChild(1, mStartElementContainer); - addChild(2, mBody); - addChild(3, mEndElementContainer); - addChild(4, mEndNamespaceList); - } - public void changeIndex(ResXmlElement element, int index){ - int i = 0; - for(ResXmlNode xmlNode:mBody.getChildes()){ - if(i == index){ - element.setIndex(i); - i++; - } - if(xmlNode==element){ - continue; - } - xmlNode.setIndex(i); - i++; - } - mBody.sort(this); - } - public int lastIndexOf(String tagName){ - List elementList = listElements(tagName); - int i = elementList.size(); - if(i==0){ - return -1; - } - i--; - return elementList.get(i).getIndex(); - } - public int indexOf(String tagName){ - ResXmlElement element = getElementByTagName(tagName); - if(element!=null){ - return element.getIndex(); - } - return -1; - } - public int indexOf(ResXmlElement element){ - int index = 0; - for(ResXmlNode xmlNode:mBody.getChildes()){ - if(xmlNode==element){ - return index; - } - index++; - } - return -1; - } - public void setAttributesUnitSize(int size, boolean setToAll){ - ResXmlStartElement startElement = getStartElement(); - startElement.setAttributesUnitSize(size); - if(setToAll){ - for(ResXmlElement child:listElements()){ - child.setAttributesUnitSize(size, setToAll); - } - } - } - public String getStartComment(){ - ResXmlStartElement start = getStartElement(); - if(start!=null){ - return start.getComment(); - } - return null; - } - String getEndComment(){ - ResXmlEndElement end = getEndElement(); - if(end!=null){ - return end.getComment(); - } - return null; - } - public int getStartLineNumber(){ - ResXmlStartElement start = getStartElement(); - if(start!=null){ - return start.getLineNumber(); - } - return 0; - } - public int getEndLineNumber(){ - ResXmlEndElement end = getEndElement(); - if(end!=null){ - return end.getLineNumber(); - } - return 0; - } - public void setComment(String comment){ - getStartElement().setComment(comment); - } - public void calculatePositions(){ - ResXmlStartElement start = getStartElement(); - if(start!=null){ - start.calculatePositions(); - } - } - public ResXmlAttribute newAttribute(){ - return getStartElement().newAttribute(); - } - @Override - void onRemoved(){ - for(ResXmlStartNamespace startNamespace:getStartNamespaceList()){ - startNamespace.onRemoved(); - } - ResXmlStartElement start = getStartElement(); - if(start != null){ - start.onRemoved(); - } - for(ResXmlNode xmlNode : listXmlNodes()){ - xmlNode.onRemoved(); - } - } - @Override - void linkStringReferences(){ - for(ResXmlStartNamespace startNamespace:getStartNamespaceList()){ - startNamespace.linkStringReferences(); - } - ResXmlStartElement start = getStartElement(); - if(start != null){ - start.linkStringReferences(); - } - for(ResXmlNode xmlNode : getXmlNodes()){ - xmlNode.linkStringReferences(); - } - } - public ResXmlElement createChildElement(){ - return createChildElement(null); - } - public ResXmlElement createChildElement(String tag){ - int lineNo=getStartElement().getLineNumber()+1; - ResXmlElement resXmlElement=new ResXmlElement(); - resXmlElement.newStartElement(lineNo); - - addElement(resXmlElement); - - if(tag!=null){ - resXmlElement.setTag(tag); - } - return resXmlElement; - } - public ResXmlAttribute getOrCreateAndroidAttribute(String name, int resourceId){ - return getOrCreateAttribute(NS_ANDROID_URI, NS_ANDROID_PREFIX, name, resourceId); - } - public ResXmlAttribute getOrCreateAttribute(String uri, String prefix, String name, int resourceId){ - ResXmlAttribute attribute=searchAttribute(name, resourceId); - if(attribute==null){ - attribute = createAttribute(name, resourceId); - if(uri!=null){ - ResXmlElement root = getRootResXmlElement(); - ResXmlStartNamespace ns = root.getOrCreateNamespace(uri, prefix); - attribute.setNamespaceReference(ns.getUriReference()); - } - } - return attribute; - } - public ResXmlAttribute getOrCreateAttribute(String name, int resourceId){ - ResXmlAttribute attribute=searchAttribute(name, resourceId); - if(attribute==null){ - attribute=createAttribute(name, resourceId); - } - return attribute; - } - public ResXmlAttribute createAndroidAttribute(String name, int resourceId){ - ResXmlAttribute attribute=createAttribute(name, resourceId); - ResXmlStartNamespace ns = getOrCreateNamespace(NS_ANDROID_URI, NS_ANDROID_PREFIX); - attribute.setNamespaceReference(ns.getUriReference()); - return attribute; - } - public ResXmlAttribute createAttribute(String name, int resourceId){ - ResXmlAttribute attribute=new ResXmlAttribute(); - addAttribute(attribute); - attribute.setName(name, resourceId); - return attribute; - } - public void addAttribute(ResXmlAttribute attribute){ - getStartElement().getResXmlAttributeArray().add(attribute); - } - public ResXmlElement getElementByTagName(String name){ - if(name==null){ - return null; - } - for(ResXmlElement child:listElements()){ - if(name.equals(child.getTag())||name.equals(child.getTagName())){ - return child; - } - } - return null; - } - private ResXmlAttribute searchAttribute(String name, int resourceId){ - if(resourceId==0){ - return searchAttributeByName(name); - } - return searchAttributeByResourceId(resourceId); - } - // Searches attribute with resource id = 0 - public ResXmlAttribute searchAttributeByName(String name){ - ResXmlStartElement startElement=getStartElement(); - if(startElement!=null){ - return startElement.searchAttributeByName(name); - } - return null; - } - public ResXmlAttribute searchAttributeByResourceId(int resourceId){ - ResXmlStartElement startElement=getStartElement(); - if(startElement!=null){ - return startElement.searchAttributeByResourceId(resourceId); - } - return null; - } - public void setTag(String tag){ - ResXmlStringPool pool = getStringPool(); - if(pool==null){ - return; - } - ensureStartEndElement(); - ResXmlStartElement start=getStartElement(); - String prefix=null; - String name=tag; - int i=tag.lastIndexOf(':'); - if(i>=0){ - prefix=tag.substring(0,i); - i++; - name=tag.substring(i); - } - start.setName(name); - ResXmlStartNamespace ns = getStartNamespaceByPrefix(prefix); - if(ns!=null){ - start.setNamespaceReference(ns.getUriReference()); - } - } - public String getTagName(){ - ResXmlStartElement startElement=getStartElement(); - if(startElement!=null){ - return startElement.getTagName(); - } - return null; - } - public String getTag(){ - ResXmlStartElement startElement=getStartElement(); - if(startElement!=null){ - return startElement.getName(); - } - return null; - } - public String getTagUri(){ - ResXmlStartElement startElement=getStartElement(); - if(startElement!=null){ - return startElement.getUri(); - } - return null; - } - public String getTagPrefix(){ - ResXmlStartElement startElement=getStartElement(); - if(startElement!=null){ - return startElement.getPrefix(); - } - return null; - } - public int getAttributeCount() { - ResXmlStartElement startElement=getStartElement(); - if(startElement!=null){ - return startElement.getResXmlAttributeArray().childesCount(); - } - return 0; - } - public ResXmlAttribute getAttributeAt(int index){ - ResXmlStartElement startElement=getStartElement(); - if(startElement!=null){ - return startElement.getResXmlAttributeArray().get(index); - } - return null; - } - public Collection listAttributes(){ - ResXmlStartElement startElement=getStartElement(); - if(startElement!=null){ - return startElement.listResXmlAttributes(); - } - return new ArrayList<>(); - } - public ResXmlStringPool getStringPool(){ - Block parent=getParent(); - while (parent!=null){ - if(parent instanceof ResXmlDocument){ - return ((ResXmlDocument)parent).getStringPool(); - } - if(parent instanceof ResXmlElement){ - return ((ResXmlElement)parent).getStringPool(); - } - parent=parent.getParent(); - } - return null; - } - public ResXmlIDMap getResXmlIDMap(){ - ResXmlDocument resXmlDocument = getParentDocument(); - if(resXmlDocument!=null){ - return resXmlDocument.getResXmlIDMap(); - } - return null; - } - public ResXmlDocument getParentDocument(){ - return getParentInstance(ResXmlDocument.class); - } - - @Override - public int getDepth(){ - ResXmlElement parent = getParentResXmlElement(); - if(parent != null){ - return parent.getDepth() + 1; - } - return 0; - } - @Override - void addEvents(ParserEventList parserEventList){ - String comment = getStartComment(); - if(comment!=null){ - parserEventList.add( - new ParserEvent(ParserEvent.COMMENT, this, comment, false)); - } - parserEventList.add(new ParserEvent(ParserEvent.START_TAG, this)); - for(ResXmlNode xmlNode:getXmlNodes()){ - xmlNode.addEvents(parserEventList); - } - comment = getEndComment(); - if(comment!=null){ - parserEventList.add( - new ParserEvent(ParserEvent.COMMENT, this, comment, true)); - } - parserEventList.add(new ParserEvent(ParserEvent.END_TAG, this)); - } - public int getLevel(){ - return mLevel; - } - private void setLevel(int level){ - mLevel = level; - } - public void addElement(ResXmlElement element){ - mBody.add(element); - } - public boolean removeAttribute(ResXmlAttribute resXmlAttribute){ - if(resXmlAttribute != null){ - resXmlAttribute.onRemoved(); - } - return getStartElement().getResXmlAttributeArray().remove(resXmlAttribute); - } - public boolean removeElement(ResXmlElement element){ - if(element !=null && element.getParent()!=null){ - element.onRemoved(); - } - return mBody.remove(element); - } - public boolean removeNode(ResXmlNode node){ - if(node instanceof ResXmlElement){ - return removeElement((ResXmlElement) node); - } - return mBody.remove(node); - } - public int countElements(){ - int result = 0; - for(ResXmlNode xmlNode: getXmlNodes()){ - if(xmlNode instanceof ResXmlElement){ - result++; - } - } - return result; - } - public void clearChildes(){ - List copyOfNodeList=new ArrayList<>(mBody.getChildes()); - for(ResXmlNode xmlNode:copyOfNodeList){ - if(xmlNode==null){ - continue; - } - xmlNode.onRemoved(); - mBody.remove(xmlNode); - } - } - public ResXmlNode getResXmlNode(int position){ - return mBody.get(position); - } - public int countResXmlNodes(){ - return mBody.size(); - } - public boolean hasText(){ - for(ResXmlNode xmlNode : getXmlNodes()){ - if(xmlNode instanceof ResXmlTextNode){ - return true; - } - } - return false; - } - public boolean hasElement(){ - for(ResXmlNode xmlNode : getXmlNodes()){ - if(xmlNode instanceof ResXmlElement){ - return true; - } - } - return false; - } - public List listXmlNodes(){ - return new ArrayList<>(getXmlNodes()); - } - private List getXmlNodes(){ - return mBody.getChildes(); - } - public List listXmlText(){ - List results=new ArrayList<>(); - for(ResXmlNode xmlNode: getXmlNodes()){ - if(xmlNode instanceof ResXmlTextNode){ - results.add(((ResXmlTextNode) xmlNode).getResXmlText()); - } - } - return results; - } - public List listXmlTextNodes(){ - List results=new ArrayList<>(); - for(ResXmlNode xmlNode: getXmlNodes()){ - if(xmlNode instanceof ResXmlTextNode){ - results.add((ResXmlTextNode) xmlNode); - } - } - return results; - } - public List listElements(){ - List results=new ArrayList<>(); - for(ResXmlNode xmlNode: getXmlNodes()){ - if(xmlNode instanceof ResXmlElement){ - results.add((ResXmlElement) xmlNode); - } - } - return results; - } - public List listElements(String name){ - List results=new ArrayList<>(); - if(name==null){ - return results; - } - for(ResXmlElement element:listElements()){ - if(name.equals(element.getTag())||name.equals(element.getTagName())){ - results.add(element); - } - } - return results; - } - public ResXmlElement getRootResXmlElement(){ - ResXmlElement parent = getParentResXmlElement(); - if(parent != null){ - return parent.getRootResXmlElement(); - } - return this; - } - public ResXmlElement getParentResXmlElement(){ - return getParentInstance(ResXmlElement.class); - } - public ResXmlStartNamespace getStartNamespaceByUriRef(int uriRef){ - if(uriRef<0){ - return null; - } - for(ResXmlStartNamespace ns:mStartNamespaceList.getChildes()){ - if(uriRef==ns.getUriReference()){ - return ns; - } - } - ResXmlElement xmlElement=getParentResXmlElement(); - if(xmlElement!=null){ - return xmlElement.getStartNamespaceByUriRef(uriRef); - } - return null; - } - public ResXmlStartNamespace getNamespace(String uri, String prefix){ - if(uri == null || prefix == null){ - return null; - } - for(ResXmlStartNamespace ns : mStartNamespaceList.getChildes()){ - if(uri.equals(ns.getUri()) && prefix.equals(ns.getPrefix())){ - return ns; - } - } - ResXmlElement xmlElement = getParentResXmlElement(); - if(xmlElement != null){ - return xmlElement.getNamespace(uri, prefix); - } - return null; - } - public ResXmlStartNamespace getOrCreateNamespace(String uri, String prefix){ - ResXmlStartNamespace exist = getNamespace(uri, prefix); - if(exist != null){ - return exist; - } - return getRootResXmlElement().createNamespace(uri, prefix); - } - public ResXmlStartNamespace createNamespace(String uri, String prefix){ - ResXmlStartNamespace startNamespace = new ResXmlStartNamespace(); - ResXmlEndNamespace endNamespace = new ResXmlEndNamespace(); - startNamespace.setEnd(endNamespace); - - addStartNamespace(startNamespace); - addEndNamespace(endNamespace); - ResXmlStringPool stringPool = getStringPool(); - ResXmlString xmlString = stringPool.createNew(uri); - startNamespace.setUriReference(xmlString.getIndex()); - startNamespace.setPrefix(prefix); - - return startNamespace; - } - public ResXmlStartNamespace getStartNamespaceByUri(String uri){ - if(uri==null){ - return null; - } - for(ResXmlStartNamespace ns:mStartNamespaceList.getChildes()){ - if(uri.equals(ns.getUri())){ - return ns; - } - } - ResXmlElement xmlElement=getParentResXmlElement(); - if(xmlElement!=null){ - return xmlElement.getStartNamespaceByUri(uri); - } - return null; - } - public ResXmlStartNamespace getStartNamespaceByPrefix(String prefix){ - if(prefix==null){ - return null; - } - for(ResXmlStartNamespace ns:mStartNamespaceList.getChildes()){ - if(prefix.equals(ns.getPrefix())){ - return ns; - } - } - ResXmlElement xmlElement=getParentResXmlElement(); - if(xmlElement!=null){ - return xmlElement.getStartNamespaceByPrefix(prefix); - } - return null; - } - public List getStartNamespaceList(){ - return mStartNamespaceList.getChildes(); - } - public int getNamespaceCount(){ - return mStartNamespaceList.size(); - } - public ResXmlStartNamespace getNamespace(int index){ - return mStartNamespaceList.get(index); - } - public void addStartNamespace(ResXmlStartNamespace item){ - mStartNamespaceList.add(item); - } - private List getEndNamespaceList(){ - return mEndNamespaceList.getChildes(); - } - public void addEndNamespace(ResXmlEndNamespace item){ - mEndNamespaceList.add(item); - } - void removeNamespace(ResXmlStartNamespace startNamespace){ - if(startNamespace == null){ - return; - } - startNamespace.onRemoved(); - mStartNamespaceList.remove(startNamespace); - mEndNamespaceList.remove(startNamespace.getEnd()); - } - - ResXmlStartElement newStartElement(int lineNo){ - ResXmlStartElement startElement=new ResXmlStartElement(); - setStartElement(startElement); - - ResXmlEndElement endElement=new ResXmlEndElement(); - startElement.setResXmlEndElement(endElement); - - setEndElement(endElement); - endElement.setResXmlStartElement(startElement); - - startElement.setLineNumber(lineNo); - endElement.setLineNumber(lineNo); - - return startElement; - } - - public ResXmlStartElement getStartElement(){ - return mStartElementContainer.getItem(); - } - private void setStartElement(ResXmlStartElement item){ - mStartElementContainer.setItem(item); - } - - private ResXmlEndElement getEndElement(){ - return mEndElementContainer.getItem(); - } - private void setEndElement(ResXmlEndElement item){ - mEndElementContainer.setItem(item); - } - - public void addResXmlTextNode(ResXmlTextNode xmlTextNode){ - mBody.add(xmlTextNode); - } - public void addResXmlText(ResXmlText xmlText){ - if(xmlText!=null){ - addResXmlTextNode(new ResXmlTextNode(xmlText)); - } - } - public void addResXmlText(String text){ - if(text==null){ - return; - } - ResXmlTextNode xmlTextNode=new ResXmlTextNode(); - addResXmlTextNode(xmlTextNode); - xmlTextNode.setText(text); - } - - private boolean isBalanced(){ - return isElementBalanced() && isNamespaceBalanced(); - } - private boolean isNamespaceBalanced(){ - return (mStartNamespaceList.size()==mEndNamespaceList.size()); - } - private boolean isElementBalanced(){ - return (hasStartElement() && hasEndElement()); - } - private boolean hasStartElement(){ - return mStartElementContainer.hasItem(); - } - private boolean hasEndElement(){ - return mEndElementContainer.hasItem(); - } - - private void linkStartEnd(){ - linkStartEndElement(); - linkStartEndNameSpaces(); - } - private void linkStartEndElement(){ - ResXmlStartElement start=getStartElement(); - ResXmlEndElement end=getEndElement(); - if(start==null || end==null){ - return; - } - start.setResXmlEndElement(end); - end.setResXmlStartElement(start); - } - private void ensureStartEndElement(){ - ResXmlStartElement start=getStartElement(); - ResXmlEndElement end=getEndElement(); - if(start!=null && end!=null){ - return; - } - if(start==null){ - start=new ResXmlStartElement(); - setStartElement(start); - } - if(end==null){ - end=new ResXmlEndElement(); - setEndElement(end); - } - linkStartEndElement(); - } - private void linkStartEndNameSpaces(){ - if(!isNamespaceBalanced()){ - return; - } - int max=mStartNamespaceList.size(); - for(int i=0;i0 && getLevel()==0){ - onFinishedUnexpected(reader); - return; - } - onFinishedSuccess(reader, headerBlock); - } - private void onFinishedSuccess(BlockReader reader, HeaderBlock headerBlock) throws IOException{ - - } - private void onFinishedUnexpected(BlockReader reader) throws IOException{ - StringBuilder builder=new StringBuilder(); - builder.append("Unexpected finish reading: reader=").append(reader.toString()); - HeaderBlock header = reader.readHeaderBlock(); - if(header!=null){ - builder.append(", next header="); - builder.append(header.toString()); - } - throw new IOException(builder.toString()); - } - private void onStartElement(BlockReader reader) throws IOException{ - if(hasStartElement()){ - ResXmlElement childElement=new ResXmlElement(); - addElement(childElement); - childElement.setLevel(getLevel()+1); - childElement.readBytes(reader); - }else{ - ResXmlStartElement startElement=new ResXmlStartElement(); - setStartElement(startElement); - startElement.readBytes(reader); - } - } - private void onEndElement(BlockReader reader) throws IOException{ - if(hasEndElement()){ - multipleEndElement(reader); - return; - } - ResXmlEndElement endElement=new ResXmlEndElement(); - setEndElement(endElement); - endElement.readBytes(reader); - } - private void onStartNamespace(BlockReader reader) throws IOException{ - ResXmlStartNamespace startNamespace=new ResXmlStartNamespace(); - addStartNamespace(startNamespace); - startNamespace.readBytes(reader); - } - private void onEndNamespace(BlockReader reader) throws IOException{ - ResXmlEndNamespace endNamespace=new ResXmlEndNamespace(); - addEndNamespace(endNamespace); - endNamespace.readBytes(reader); - } - private void onXmlText(BlockReader reader) throws IOException{ - ResXmlText xmlText=new ResXmlText(); - addResXmlText(xmlText); - xmlText.readBytes(reader); - } - - private void unknownChunk(BlockReader reader, HeaderBlock headerBlock) throws IOException{ - throw new IOException("Unknown chunk: "+headerBlock.toString()); - } - private void multipleEndElement(BlockReader reader) throws IOException{ - throw new IOException("Multiple end element: "+reader.toString()); - } - private void unexpectedChunk(BlockReader reader, HeaderBlock headerBlock) throws IOException{ - throw new IOException("Unexpected chunk: "+headerBlock.toString()); - } - private void unBalancedFinish(BlockReader reader) throws IOException{ - if(!isNamespaceBalanced()){ - throw new IOException("Unbalanced namespace: start=" - +mStartNamespaceList.size()+", end="+mEndNamespaceList.size()); - } - - if(!isElementBalanced()){ - // Should not happen unless corrupted file, auto corrected above - StringBuilder builder=new StringBuilder(); - builder.append("Unbalanced element: start="); - ResXmlStartElement startElement=getStartElement(); - if(startElement!=null){ - builder.append(startElement); - }else { - builder.append("null"); - } - builder.append(", end="); - ResXmlEndElement endElement=getEndElement(); - if(endElement!=null){ - builder.append(endElement); - }else { - builder.append("null"); - } - throw new IOException(builder.toString()); - } - } - @Override - public JSONObject toJson() { - JSONObject jsonObject=new JSONObject(); - jsonObject.put(NAME_node_type, NAME_element); - ResXmlStartElement start = getStartElement(); - jsonObject.put(NAME_line, start.getLineNumber()); - int i=0; - JSONArray nsList=new JSONArray(); - for(ResXmlStartNamespace namespace:getStartNamespaceList()){ - JSONObject ns=new JSONObject(); - ns.put(NAME_namespace_uri, namespace.getUri()); - ns.put(NAME_namespace_prefix, namespace.getPrefix()); - nsList.put(i, ns); - i++; - } - if(i>0){ - jsonObject.put(NAME_namespaces, nsList); - } - jsonObject.put(NAME_name, start.getName()); - String comment=start.getComment(); - if(comment!=null){ - jsonObject.put(NAME_comment, comment); - } - String uri=start.getUri(); - if(uri!=null){ - jsonObject.put(NAME_namespace_uri, uri); - } - JSONArray attrArray=start.getResXmlAttributeArray().toJson(); - jsonObject.put(NAME_attributes, attrArray); - i=0; - JSONArray childes=new JSONArray(); - for(ResXmlNode xmlNode: getXmlNodes()){ - childes.put(i, xmlNode.toJson()); - i++; - } - if(i>0){ - jsonObject.put(NAME_childes, childes); - } - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - ResXmlStartElement start = getStartElement(); - int lineNo=json.optInt(NAME_line, 1); - if(start==null){ - start = newStartElement(lineNo); - }else { - start.setLineNumber(lineNo); - } - JSONArray nsArray = json.optJSONArray(NAME_namespaces); - if(nsArray!=null){ - int length=nsArray.length(); - for(int i=0;i"); - for(ResXmlText xmlText : listXmlText()){ - builder.append(xmlText.getText()); - } - builder.append(""); - }else { - builder.append("/>"); - } - return builder.toString(); - } - return "NULL"; - } - static ResXmlElement newResXmlElement(String tag){ - ResXmlElement resXmlElement=new ResXmlElement(); - ResXmlStartElement startElement=new ResXmlStartElement(); - resXmlElement.setStartElement(startElement); - ResXmlEndElement endElement=new ResXmlEndElement(); - resXmlElement.setEndElement(endElement); - resXmlElement.setTag(tag); - return resXmlElement; - } - - public static final String NS_ANDROID_URI = "http://schemas.android.com/apk/res/android"; - public static final String NS_ANDROID_PREFIX = "android"; - - static final String NAME_element = "element"; - static final String NAME_name = "name"; - static final String NAME_comment = "comment"; - static final String NAME_text = "text"; - static final String NAME_namespaces = "namespaces"; - static final String NAME_namespace_uri = "namespace_uri"; - static final String NAME_namespace_prefix = "namespace_prefix"; - private static final String NAME_line = "line"; - static final String NAME_attributes = "attributes"; - static final String NAME_childes = "childes"; -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlEndElement.java b/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlEndElement.java deleted file mode 100755 index ea32e125..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlEndElement.java +++ /dev/null @@ -1,32 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ - package com.reandroid.arsc.chunk.xml; - - import com.reandroid.arsc.chunk.ChunkType; - - public class ResXmlEndElement extends BaseXmlChunk { - private ResXmlStartElement mResXmlStartElement; - public ResXmlEndElement(){ - super(ChunkType.XML_END_ELEMENT, 0); - } - - public void setResXmlStartElement(ResXmlStartElement element){ - mResXmlStartElement=element; - } - public ResXmlStartElement getResXmlStartElement(){ - return mResXmlStartElement; - } - } diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlEndNamespace.java b/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlEndNamespace.java deleted file mode 100755 index 22edb1b6..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlEndNamespace.java +++ /dev/null @@ -1,30 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ - package com.reandroid.arsc.chunk.xml; - - import com.reandroid.arsc.chunk.ChunkType; - - public class ResXmlEndNamespace extends ResXmlNamespace{ - public ResXmlEndNamespace() { - super(ChunkType.XML_END_NAMESPACE); - } - public ResXmlStartNamespace getStart(){ - return (ResXmlStartNamespace) getPair(); - } - public void setStart(ResXmlStartNamespace namespace){ - setPair(namespace); - } - } diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlIDMap.java b/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlIDMap.java deleted file mode 100755 index c1f78c66..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlIDMap.java +++ /dev/null @@ -1,94 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ - package com.reandroid.arsc.chunk.xml; - - import com.reandroid.arsc.chunk.ChunkType; - import com.reandroid.arsc.array.ResXmlIDArray; - import com.reandroid.arsc.chunk.Chunk; - import com.reandroid.arsc.header.HeaderBlock; - import com.reandroid.arsc.item.ResXmlID; - import com.reandroid.arsc.item.ResXmlString; - import com.reandroid.arsc.pool.ResXmlStringPool; - - import java.util.Collection; - - public class ResXmlIDMap extends Chunk { - private final ResXmlIDArray mResXmlIDArray; - public ResXmlIDMap() { - super(new HeaderBlock(ChunkType.XML_RESOURCE_MAP), 1); - this.mResXmlIDArray=new ResXmlIDArray(getHeaderBlock()); - addChild(mResXmlIDArray); - } - void removeSafely(ResXmlID resXmlID){ - if(resXmlID==null - || resXmlID.getParent()==null - || resXmlID.getIndex()<0 - || resXmlID.hasReference()){ - return; - } - ResXmlString xmlString = resXmlID.getResXmlString(); - if(xmlString == null - || xmlString.getParent()==null - || xmlString.getIndex()<0 - || xmlString.hasReference()){ - return; - } - ResXmlStringPool stringPool = getXmlStringPool(); - if(stringPool == null){ - return; - } - resXmlID.set(0); - ResXmlIDArray idArray = getResXmlIDArray(); - idArray.remove(resXmlID); - stringPool.removeString(xmlString); - } - public int countId(){ - return getResXmlIDArray().childesCount(); - } - public void destroy(){ - getResXmlIDArray().clearChildes(); - } - public ResXmlIDArray getResXmlIDArray(){ - return mResXmlIDArray; - } - - public Collection listResXmlID(){ - return getResXmlIDArray().listItems(); - } - public void addResourceId(int index, int resId){ - getResXmlIDArray().addResourceId(index, resId); - } - public ResXmlID getResXmlID(int ref){ - return getResXmlIDArray().get(ref); - } - public ResXmlID getOrCreate(int resId){ - return getResXmlIDArray().getOrCreate(resId); - } - public ResXmlID getByResId(int resId){ - return getResXmlIDArray().getByResId(resId); - } - @Override - protected void onChunkRefreshed() { - - } - ResXmlStringPool getXmlStringPool(){ - ResXmlDocument resXmlDocument = getParentInstance(ResXmlDocument.class); - if(resXmlDocument!=null){ - return resXmlDocument.getStringPool(); - } - return null; - } - } diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlNamespace.java b/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlNamespace.java deleted file mode 100644 index 123af290..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlNamespace.java +++ /dev/null @@ -1,87 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk.xml; - -import com.reandroid.arsc.chunk.ChunkType; -import com.reandroid.arsc.item.ResXmlString; - -abstract class ResXmlNamespace extends BaseXmlChunk{ - private ResXmlNamespace mPair; - ResXmlNamespace(ChunkType chunkType) { - super(chunkType, 0); - } - @Override - public String getUri(){ - return getString(getUriReference()); - } - public void setUri(String uri){ - ResXmlString xmlString = getOrCreateString(uri); - if(xmlString==null){ - throw new IllegalArgumentException("Null ResXmlString, add to parent element first"); - } - setUriReference(xmlString.getIndex()); - } - public String getPrefix(){ - return getString(getPrefixReference()); - } - public void setPrefix(String prefix){ - ResXmlString xmlString = getOrCreateString(prefix); - if(xmlString==null){ - throw new IllegalArgumentException("Null ResXmlString, add to parent element first"); - } - setPrefixReference(xmlString.getIndex()); - } - public int getUriReference(){ - return getStringReference(); - } - public void setUriReference(int ref){ - setStringReference(ref); - ResXmlNamespace pair=getPair(); - if(pair!=null && pair.getUriReference()!=ref){ - pair.setUriReference(ref); - } - } - public int getPrefixReference(){ - return getNamespaceReference(); - } - public void setPrefixReference(int ref){ - setNamespaceReference(ref); - ResXmlNamespace pair=getPair(); - if(pair!=null && pair.getPrefixReference()!=ref){ - pair.setPrefixReference(ref); - } - } - ResXmlNamespace getPair(){ - return mPair; - } - void setPair(ResXmlNamespace pair){ - if(pair==this){ - return; - } - this.mPair=pair; - if(pair !=null && pair.getPair()!=this){ - pair.setPair(this); - } - } - @Override - public String toString(){ - String uri=getUri(); - if(uri==null){ - return super.toString(); - } - return "xmlns:"+getPrefix()+"=\""+getUri()+"\""; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlNode.java b/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlNode.java deleted file mode 100644 index 344fbea0..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlNode.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk.xml; - -import com.reandroid.arsc.container.FixedBlockContainer; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONObject; - -public abstract class ResXmlNode extends FixedBlockContainer implements JSONConvert { - ResXmlNode(int childesCount) { - super(childesCount); - } - abstract void onRemoved(); - abstract void linkStringReferences(); - public abstract int getDepth(); - abstract void addEvents(ParserEventList parserEventList); - - public static final String NAME_node_type = "node_type"; -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlPullParser.java b/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlPullParser.java deleted file mode 100644 index 91dadb12..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlPullParser.java +++ /dev/null @@ -1,731 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk.xml; - -import android.content.res.XmlResourceParser; -import com.reandroid.arsc.ApkFile; -import com.reandroid.arsc.decoder.Decoder; -import com.reandroid.arsc.value.ValueType; -import org.xmlpull.v1.XmlPullParserException; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; - -public class ResXmlPullParser implements XmlResourceParser { - private Decoder mDecoder; - private final ParserEventList mEventList = new ParserEventList(); - private ResXmlDocument mDocument; - private boolean mDocumentCreatedHere; - private DocumentLoadedListener documentLoadedListener; - private boolean processNamespaces; - private boolean reportNamespaceAttrs; - private boolean mIsTagStared; - - public ResXmlPullParser(Decoder decoder){ - this.mDecoder = decoder; - this.processNamespaces = false; - this.reportNamespaceAttrs = false; - } - public ResXmlPullParser(){ - this(null); - } - public synchronized ResXmlPullParser getParser(){ - if(isBusy()){ - return new ResXmlPullParser(getDecoder()); - } - closeDocument(); - return this; - } - public synchronized boolean isBusy() { - return !mEventList.hasNext(); - } - public synchronized void setResXmlDocument(ResXmlDocument xmlDocument){ - closeDocument(); - this.mDocument = xmlDocument; - initDefaultFeatures(); - initializeDecoder(xmlDocument); - xmlDocument.addEvents(mEventList); - } - public ResXmlDocument getResXmlDocument() { - return mDocument; - } - - public void setDecoder(Decoder decoder) { - this.mDecoder = decoder; - } - public Decoder getDecoder(){ - return mDecoder; - } - private void initializeDecoder(ResXmlDocument xmlDocument){ - Decoder decoder = this.mDecoder; - if(decoder!=null){ - if(decoder.getApkFile()==null){ - decoder.setApkFile(xmlDocument.getApkFile()); - } - return; - } - ApkFile apkFile = xmlDocument.getApkFile(); - if(apkFile!=null){ - decoder = apkFile.getDecoder(); - if(decoder!=null){ - this.mDecoder = decoder; - return; - } - } - mDecoder = Decoder.create(xmlDocument); - } - - public void closeDocument(){ - mEventList.clear(); - mIsTagStared = false; - destroyDocument(); - } - private void destroyDocument(){ - if(!mDocumentCreatedHere){ - return; - } - mDocumentCreatedHere = false; - if(this.mDocument == null){ - return; - } - this.mDocument.destroy(); - this.mDocument = null; - } - - @Override - public void close(){ - closeDocument(); - } - @Override - public int getAttributeCount() { - ResXmlElement element = getCurrentElement(); - if(element == null){ - return 0; - } - int count = element.getAttributeCount(); - if(isCountNamespacesAsAttribute()){ - count += element.getNamespaceCount(); - } - return count; - } - @Override - public String getAttributeName(int index) { - if(isCountNamespacesAsAttribute()){ - int nsCount = getNamespaceCountInternal(); - if(index < nsCount){ - return getNamespaceAttributeName(index); - } - } - return decodeAttributeName(getResXmlAttributeAt(index)); - } - @Override - public String getAttributeValue(int index) { - if(isCountNamespacesAsAttribute()){ - int nsCount = getNamespaceCountInternal(); - if(index < nsCount){ - return getNamespaceAttributeValue(index); - } - } - return decodeAttributeValue(getResXmlAttributeAt(index)); - } - @Override - public String getAttributeValue(String namespace, String name) { - return decodeAttributeValue(getAttribute(namespace, name)); - } - @Override - public String getPositionDescription() { - return null; - } - @Override - public int getAttributeNameResource(int index) { - ResXmlAttribute attribute = getResXmlAttributeAt(index); - if(attribute!=null){ - return attribute.getNameResourceID(); - } - return 0; - } - @Override - public int getAttributeListValue(String namespace, String attribute, String[] options, int defaultValue) { - ResXmlAttribute xmlAttribute = getAttribute(namespace, attribute); - if(xmlAttribute == null){ - return defaultValue; - } - List list = Arrays.asList(options); - int index = list.indexOf(decodeAttributeValue(xmlAttribute)); - if(index==-1){ - return defaultValue; - } - return index; - } - @Override - public boolean getAttributeBooleanValue(String namespace, String attribute, boolean defaultValue) { - ResXmlAttribute xmlAttribute = getAttribute(namespace, attribute); - if(xmlAttribute == null || xmlAttribute.getValueType() != ValueType.INT_BOOLEAN){ - return defaultValue; - } - return xmlAttribute.getValueAsBoolean(); - } - @Override - public int getAttributeResourceValue(String namespace, String attribute, int defaultValue) { - ResXmlAttribute xmlAttribute = getAttribute(namespace, attribute); - if(xmlAttribute == null){ - return defaultValue; - } - ValueType valueType=xmlAttribute.getValueType(); - if(valueType==ValueType.ATTRIBUTE - ||valueType==ValueType.REFERENCE - ||valueType==ValueType.DYNAMIC_ATTRIBUTE - ||valueType==ValueType.DYNAMIC_REFERENCE){ - return xmlAttribute.getData(); - } - return defaultValue; - } - @Override - public int getAttributeIntValue(String namespace, String attribute, int defaultValue) { - ResXmlAttribute xmlAttribute = getAttribute(namespace, attribute); - if(xmlAttribute == null){ - return defaultValue; - } - ValueType valueType=xmlAttribute.getValueType(); - if(valueType==ValueType.INT_DEC - ||valueType==ValueType.INT_HEX){ - return xmlAttribute.getData(); - } - return defaultValue; - } - @Override - public int getAttributeUnsignedIntValue(String namespace, String attribute, int defaultValue) { - ResXmlAttribute xmlAttribute = getAttribute(namespace, attribute); - if(xmlAttribute == null){ - return defaultValue; - } - ValueType valueType=xmlAttribute.getValueType(); - if(valueType==ValueType.INT_DEC){ - return xmlAttribute.getData(); - } - return defaultValue; - } - @Override - public float getAttributeFloatValue(String namespace, String attribute, float defaultValue) { - ResXmlAttribute xmlAttribute = getAttribute(namespace, attribute); - if(xmlAttribute == null){ - return defaultValue; - } - ValueType valueType=xmlAttribute.getValueType(); - if(valueType==ValueType.FLOAT){ - return Float.intBitsToFloat(xmlAttribute.getData()); - } - return defaultValue; - } - - @Override - public int getAttributeListValue(int index, String[] options, int defaultValue) { - ResXmlAttribute xmlAttribute = getResXmlAttributeAt(index); - if(xmlAttribute == null){ - return defaultValue; - } - List list = Arrays.asList(options); - int i = list.indexOf(decodeAttributeValue(xmlAttribute)); - if(i==-1){ - return defaultValue; - } - return index; - } - @Override - public boolean getAttributeBooleanValue(int index, boolean defaultValue) { - ResXmlAttribute xmlAttribute = getResXmlAttributeAt(index); - if(xmlAttribute == null || xmlAttribute.getValueType() != ValueType.INT_BOOLEAN){ - return defaultValue; - } - return xmlAttribute.getValueAsBoolean(); - } - @Override - public int getAttributeResourceValue(int index, int defaultValue) { - ResXmlAttribute xmlAttribute = getResXmlAttributeAt(index); - if(xmlAttribute == null){ - return defaultValue; - } - ValueType valueType=xmlAttribute.getValueType(); - if(valueType==ValueType.ATTRIBUTE - ||valueType==ValueType.REFERENCE - ||valueType==ValueType.DYNAMIC_ATTRIBUTE - ||valueType==ValueType.DYNAMIC_REFERENCE){ - return xmlAttribute.getData(); - } - return defaultValue; - } - @Override - public int getAttributeIntValue(int index, int defaultValue) { - ResXmlAttribute xmlAttribute = getResXmlAttributeAt(index); - if(xmlAttribute == null){ - return defaultValue; - } - return xmlAttribute.getData(); - } - @Override - public int getAttributeUnsignedIntValue(int index, int defaultValue) { - ResXmlAttribute xmlAttribute = getResXmlAttributeAt(index); - if(xmlAttribute == null){ - return defaultValue; - } - return xmlAttribute.getData(); - } - @Override - public float getAttributeFloatValue(int index, float defaultValue) { - ResXmlAttribute xmlAttribute = getResXmlAttributeAt(index); - if(xmlAttribute == null){ - return defaultValue; - } - ValueType valueType=xmlAttribute.getValueType(); - if(valueType==ValueType.FLOAT){ - return Float.intBitsToFloat(xmlAttribute.getData()); - } - return defaultValue; - } - - @Override - public String getIdAttribute() { - ResXmlStartElement startElement = getResXmlStartElement(); - if(startElement!=null){ - ResXmlAttribute attribute = startElement.getIdAttribute(); - if(attribute!=null){ - return attribute.getName(); - } - } - return null; - } - @Override - public String getClassAttribute() { - ResXmlStartElement startElement = getResXmlStartElement(); - if(startElement!=null){ - ResXmlAttribute attribute = startElement.getClassAttribute(); - if(attribute!=null){ - return attribute.getName(); - } - } - return null; - } - @Override - public int getIdAttributeResourceValue(int defaultValue) { - ResXmlStartElement startElement = getResXmlStartElement(); - if(startElement!=null){ - ResXmlAttribute attribute = startElement.getIdAttribute(); - if(attribute!=null){ - return attribute.getNameResourceID(); - } - } - return 0; - } - @Override - public int getStyleAttribute() { - ResXmlStartElement startElement = getResXmlStartElement(); - if(startElement!=null){ - ResXmlAttribute attribute = startElement.getStyleAttribute(); - if(attribute!=null){ - return attribute.getNameResourceID(); - } - } - return 0; - } - - @Override - public void setFeature(String name, boolean state) throws XmlPullParserException { - boolean changed; - if(FEATURE_PROCESS_NAMESPACES.equals(name)) { - changed = processNamespaces != state; - processNamespaces = state; - }else if(FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) { - changed = reportNamespaceAttrs != state; - reportNamespaceAttrs = state; - }else { - throw new XmlPullParserException("Unsupported feature: " + name); - } - if(changed && mIsTagStared){ - throw new XmlPullParserException("Feature changed during parsing: " - + name + ", state=" + state); - } - } - - @Override - public boolean getFeature(String name) { - if(FEATURE_PROCESS_NAMESPACES.equals(name)) { - return processNamespaces; - }else if(FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) { - return reportNamespaceAttrs; - } - return false; - } - @Override - public void setProperty(String name, Object value) throws XmlPullParserException { - } - @Override - public Object getProperty(String name) { - return null; - } - @Override - public void setInput(Reader in) throws XmlPullParserException { - InputStream inputStream = getFromLock(in); - if(inputStream == null){ - throw new XmlPullParserException("Can't parse binary xml from reader"); - } - setInput(inputStream, null); - } - @Override - public void setInput(InputStream inputStream, String inputEncoding) throws XmlPullParserException { - loadResXmlDocument(inputStream); - } - @Override - public String getInputEncoding() { - // Not applicable but let not return null - return "UTF-8"; - } - @Override - public void defineEntityReplacementText(String entityName, String replacementText) throws XmlPullParserException { - } - @Override - public int getNamespaceCount(int depth) throws XmlPullParserException { - if(isCountNamespacesAsAttribute()){ - return 0; - } - ResXmlElement element = getCurrentElement(); - while(element!=null && element.getDepth()>depth){ - element=element.getParentResXmlElement(); - } - if(element!=null){ - return element.getNamespaceCount(); - } - return 0; - } - @Override - public String getNamespacePrefix(int pos) throws XmlPullParserException { - ResXmlElement element = getCurrentElement(); - if(element!=null){ - return element.getNamespace(pos).getPrefix(); - } - return null; - } - @Override - public String getNamespaceUri(int pos) throws XmlPullParserException { - ResXmlElement element = getCurrentElement(); - if(element!=null){ - return element.getNamespace(pos).getUri(); - } - return null; - } - @Override - public String getNamespace(String prefix) { - ResXmlElement element = getCurrentElement(); - if(element!=null){ - ResXmlStartNamespace startNamespace = element.getStartNamespaceByPrefix(prefix); - if(startNamespace!=null){ - return startNamespace.getUri(); - } - } - return null; - } - @Override - public int getDepth() { - int event = mEventList.getType(); - if(event == START_TAG || event == END_TAG || event == TEXT){ - return mEventList.getXmlNode().getDepth(); - } - return 0; - } - @Override - public int getLineNumber() { - return mEventList.getLineNumber(); - } - @Override - public int getColumnNumber() { - return 0; - } - @Override - public boolean isWhitespace() throws XmlPullParserException { - String text = getText(); - if(text == null){ - return true; - } - text = text.trim(); - return text.length() == 0; - } - @Override - public String getText() { - return mEventList.getText(); - } - @Override - public char[] getTextCharacters(int[] holderForStartAndLength) { - String text = getText(); - if (text == null) { - holderForStartAndLength[0] = -1; - holderForStartAndLength[1] = -1; - return null; - } - char[] result = text.toCharArray(); - holderForStartAndLength[0] = 0; - holderForStartAndLength[1] = result.length; - return result; - } - @Override - public String getNamespace() { - ResXmlElement element = getCurrentElement(); - if(element!=null){ - return element.getTagUri(); - } - return null; - } - @Override - public String getName() { - ResXmlElement element = getCurrentElement(); - if(element!=null){ - return element.getTag(); - } - return null; - } - @Override - public String getPrefix() { - ResXmlElement element = getCurrentElement(); - if(element!=null){ - return element.getTagPrefix(); - } - return null; - } - @Override - public boolean isEmptyElementTag() throws XmlPullParserException { - ResXmlElement element = getCurrentElement(); - if(element!=null){ - return element.countResXmlNodes() == 0 && element.getAttributeCount()==0; - } - return true; - } - @Override - public String getAttributeNamespace(int index) { - if(processNamespaces){ - return null; - } - ResXmlAttribute attribute = getResXmlAttributeAt(index); - if(attribute != null){ - return attribute.getUri(); - } - return null; - } - @Override - public String getAttributePrefix(int index) { - if(processNamespaces){ - return null; - } - ResXmlAttribute attribute = getResXmlAttributeAt(index); - if(attribute != null){ - return attribute.getNamePrefix(); - } - return null; - } - @Override - public String getAttributeType(int index) { - return "CDATA"; - } - @Override - public boolean isAttributeDefault(int index) { - return false; - } - private String decodeAttributeName(ResXmlAttribute attribute){ - if(attribute == null){ - return null; - } - String name; - int resourceId = attribute.getNameResourceID(); - if(resourceId == 0 || mDecoder==null){ - name = attribute.getName(); - }else { - name = mDecoder.decodeResourceName(attribute.getNameResourceID(), true); - if(processNamespaces){ - name = attribute.getNamePrefix() + ":" + name; - } - } - return name; - } - private String decodeAttributeValue(ResXmlAttribute attribute){ - if(attribute==null){ - return null; - } - return mDecoder.decodeAttributeValue(attribute); - } - public ResXmlAttribute getResXmlAttributeAt(int index){ - index = getRealAttributeIndex(index); - ResXmlElement element = getCurrentElement(); - if(element == null){ - return null; - } - return element.getAttributeAt(index); - } - public ResXmlAttribute getAttribute(String namespace, String name) { - ResXmlElement element = getCurrentElement(); - if(element == null){ - return null; - } - for(ResXmlAttribute attribute:element.listAttributes()){ - if(Objects.equals(namespace, attribute.getUri()) - && Objects.equals(name, attribute.getName())){ - return attribute; - } - } - return null; - } - private ResXmlStartElement getResXmlStartElement(){ - ResXmlElement element = getCurrentElement(); - if(element!=null){ - return element.getStartElement(); - } - return null; - } - public ResXmlElement getCurrentElement() { - int type = mEventList.getType(); - if(type==START_TAG||type==END_TAG){ - return mEventList.getElement(); - } - return null; - } - private int getRealAttributeIndex(int index){ - if(isCountNamespacesAsAttribute()){ - index = index - getNamespaceCountInternal(); - } - return index; - } - private int getNamespaceCountInternal(){ - ResXmlElement element = getCurrentElement(); - if(element != null){ - return element.getNamespaceCount(); - } - return 0; - } - private boolean isCountNamespacesAsAttribute(){ - return processNamespaces & reportNamespaceAttrs; - } - private String getNamespaceAttributeName(int index){ - ResXmlStartNamespace namespace = getCurrentElement() - .getNamespace(index); - String prefix = namespace.getPrefix(); - if(processNamespaces){ - prefix = "xmlns:" + prefix; - } - return prefix; - } - private String getNamespaceAttributeValue(int index){ - ResXmlStartNamespace namespace = getCurrentElement() - .getNamespace(index); - return namespace.getUri(); - } - @Override - public int getEventType() throws XmlPullParserException { - return mEventList.getType(); - } - @Override - public int next() throws XmlPullParserException, IOException { - mEventList.next(); - int type = mEventList.getType(); - if(type == START_TAG){ - mIsTagStared = true; - } - return type; - } - @Override - public int nextToken() throws XmlPullParserException, IOException { - return next(); - } - @Override - public void require(int type, String namespace, String name) throws XmlPullParserException, IOException { - if (type != this.getEventType() - || (namespace != null && !namespace.equals(getNamespace())) - || (name != null && !name.equals(getName()))) { - throw new XmlPullParserException( - "expected: " + TYPES[type] + " {" + namespace + "}" + name, this, null); - } - } - @Override - public String nextText() throws XmlPullParserException, IOException { - int event = getEventType(); - if (event != START_TAG) { - throw new XmlPullParserException("precondition: START_TAG", this, null); - } - while (event!=TEXT && event!=END_TAG && event!=END_DOCUMENT){ - event=next(); - } - if(event==TEXT){ - return getText(); - } - return ""; - } - @Override - public int nextTag() throws XmlPullParserException, IOException { - int event = getEventType(); - if (event != START_TAG) { - throw new XmlPullParserException("precondition: START_TAG", this, null); - } - event = next(); - while (event!=START_TAG && event!=END_DOCUMENT){ - event=next(); - } - return event; - } - - private static InputStream getFromLock(Reader reader){ - try{ - Field field = Reader.class.getDeclaredField("lock"); - field.setAccessible(true); - Object obj = field.get(reader); - if(obj instanceof InputStream){ - return (InputStream) obj; - } - }catch (Throwable ignored){ - } - return null; - } - - public void setDocumentLoadedListener(DocumentLoadedListener documentLoadedListener) { - this.documentLoadedListener = documentLoadedListener; - } - - private void loadResXmlDocument(InputStream inputStream) throws XmlPullParserException { - synchronized (this){ - ResXmlDocument xmlDocument = new ResXmlDocument(); - try { - xmlDocument.readBytes(inputStream); - } catch (IOException exception) { - XmlPullParserException pullParserException = new XmlPullParserException(exception.getMessage()); - pullParserException.initCause(exception); - throw pullParserException; - } - DocumentLoadedListener listener = this.documentLoadedListener; - if(listener != null){ - xmlDocument = listener.onDocumentLoaded(xmlDocument); - } - setResXmlDocument(xmlDocument); - this.mDocumentCreatedHere = true; - } - } - private void initDefaultFeatures(){ - processNamespaces = true; - reportNamespaceAttrs = true; - } - - public static interface DocumentLoadedListener{ - public ResXmlDocument onDocumentLoaded(ResXmlDocument resXmlDocument); - } - -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlStartElement.java b/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlStartElement.java deleted file mode 100755 index 730f748a..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlStartElement.java +++ /dev/null @@ -1,298 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ - package com.reandroid.arsc.chunk.xml; - - import com.reandroid.arsc.chunk.ChunkType; - import com.reandroid.arsc.array.ResXmlAttributeArray; - import com.reandroid.arsc.item.ResXmlString; - import com.reandroid.arsc.item.ShortItem; - - import java.util.Collection; - import java.util.Set; - - public class ResXmlStartElement extends BaseXmlChunk { - private final ShortItem mAttributeStart; - private final ShortItem mAttributeUnitSize; - private final ShortItem mAttributeCount; - private final ShortItem mIdAttributePosition; - private final ShortItem mClassAttributePosition; - private final ShortItem mStyleAttributePosition; - private final ResXmlAttributeArray mAttributeArray; - private ResXmlEndElement mResXmlEndElement; - public ResXmlStartElement() { - super(ChunkType.XML_START_ELEMENT, 7); - mAttributeStart = new ShortItem(ATTRIBUTES_DEFAULT_START); - mAttributeUnitSize = new ShortItem(ATTRIBUTES_UNIT_SIZE); - mAttributeCount = new ShortItem(); - mIdAttributePosition = new ShortItem(); - mClassAttributePosition = new ShortItem(); - mStyleAttributePosition = new ShortItem(); - mAttributeArray = new ResXmlAttributeArray(getHeaderBlock(), - mAttributeStart, - mAttributeCount, - mAttributeUnitSize); - addChild(mAttributeStart); - addChild(mAttributeUnitSize); - addChild(mAttributeCount); - addChild(mIdAttributePosition); - addChild(mClassAttributePosition); - addChild(mStyleAttributePosition); - addChild(mAttributeArray); - } - public ResXmlAttribute getIdAttribute(){ - return getResXmlAttributeArray().get(mIdAttributePosition.unsignedInt()-1); - } - public ResXmlAttribute getClassAttribute(){ - return getResXmlAttributeArray().get(mClassAttributePosition.unsignedInt()-1); - } - public ResXmlAttribute getStyleAttribute(){ - return getResXmlAttributeArray().get(mStyleAttributePosition.unsignedInt()-1); - } - void setAttributesUnitSize(int size){ - mAttributeArray.setAttributesUnitSize(size); - } - public ResXmlAttribute newAttribute(){ - ResXmlAttributeArray attributeArray = getResXmlAttributeArray(); - return attributeArray.createNext(); - } - @Override - void linkStringReferences(){ - super.linkStringReferences(); - ResXmlEndElement end = getResXmlEndElement(); - if(end!=null){ - end.linkStringReferences(); - } - } - @Override - void onRemoved(){ - super.onRemoved(); - ResXmlEndElement end = getResXmlEndElement(); - if(end!=null){ - end.onRemoved(); - } - for(ResXmlAttribute attr:listResXmlAttributes()){ - attr.onRemoved(); - } - } - @Override - protected void onPreRefreshRefresh(){ - sortAttributes(); - } - private void sortAttributes(){ - ResXmlAttributeArray array = getResXmlAttributeArray(); - - ResXmlAttribute idAttribute=array.get(mIdAttributePosition.get()-1); - ResXmlAttribute classAttribute=array.get(mClassAttributePosition.get()-1); - ResXmlAttribute styleAttribute=array.get(mStyleAttributePosition.get()-1); - - array.sortAttributes(); - if(idAttribute!=null){ - mIdAttributePosition.set((short) (idAttribute.getIndex()+1)); - } - if(classAttribute!=null){ - mClassAttributePosition.set((short) (classAttribute.getIndex()+1)); - // In case obfuscation - if(!ATTRIBUTE_NAME_CLASS.equals(classAttribute.getName())){ - classAttribute.setName(ATTRIBUTE_NAME_CLASS, 0); - } - } - if(styleAttribute!=null){ - mStyleAttributePosition.set((short) (styleAttribute.getIndex()+1)); - // In case obfuscation - if(!ATTRIBUTE_NAME_STYLE.equals(styleAttribute.getName())){ - styleAttribute.setName(ATTRIBUTE_NAME_STYLE, 0); - } - } - } - void calculatePositions(){ - ResXmlAttribute idAttribute=getAttribute(ATTRIBUTE_RESOURCE_ID_id); - ResXmlAttribute classAttribute=getNoIdAttribute(ATTRIBUTE_NAME_CLASS); - ResXmlAttribute styleAttribute=getNoIdAttribute(ATTRIBUTE_NAME_STYLE); - - if(idAttribute!=null){ - mIdAttributePosition.set((short) (idAttribute.getIndex()+1)); - } - if(classAttribute!=null){ - mClassAttributePosition.set((short) (classAttribute.getIndex()+1)); - } - if(styleAttribute!=null){ - mStyleAttributePosition.set((short) (styleAttribute.getIndex()+1)); - } - } - public ResXmlAttribute getAttribute(int resourceId){ - for(ResXmlAttribute attribute:listResXmlAttributes()){ - if(resourceId==attribute.getNameResourceID()){ - return attribute; - } - } - return null; - } - private ResXmlAttribute getNoIdAttribute(String name){ - for(ResXmlAttribute attribute:listResXmlAttributes()){ - if(attribute.getNameResourceID()!=0){ - continue; - } - if(name.equals(attribute.getName())){ - return attribute; - } - } - return null; - } - public ResXmlAttribute getAttribute(String uri, String name){ - if(name==null){ - return null; - } - for(ResXmlAttribute attribute:listResXmlAttributes()){ - if(name.equals(attribute.getName())||name.equals(attribute.getFullName())){ - if(uri!=null){ - if(uri.equals(attribute.getUri())){ - return attribute; - } - continue; - } - return attribute; - } - } - return null; - } - // Searches attribute with resource id = 0 - public ResXmlAttribute searchAttributeByName(String name){ - if(name==null){ - return null; - } - for(ResXmlAttribute attribute:listResXmlAttributes()){ - if(name.equals(attribute.getName()) || name.equals(attribute.getFullName())){ - return attribute; - } - } - return null; - } - public ResXmlAttribute searchAttributeByResourceId(int resourceId){ - if(resourceId==0){ - return null; - } - for(ResXmlAttribute attribute:listResXmlAttributes()){ - if(resourceId==attribute.getNameResourceID()){ - return attribute; - } - } - return null; - } - public String getTagName(){ - String prefix=getPrefix(); - String name=getName(); - if(prefix==null){ - return name; - } - return prefix+":"+name; - } - public void setName(String name){ - setString(name); - ResXmlEndElement endElement = getResXmlEndElement(); - if(endElement!=null){ - endElement.setString(name); - } - } - public Collection listResXmlAttributes(){ - return getResXmlAttributeArray().listItems(); - } - public ResXmlAttributeArray getResXmlAttributeArray(){ - return mAttributeArray; - } - - public String getUri(){ - int uriRef=getNamespaceReference(); - if(uriRef<0){ - return null; - } - ResXmlElement parentElement=getParentResXmlElement(); - ResXmlStartNamespace startNamespace=parentElement.getStartNamespaceByUriRef(uriRef); - if(startNamespace!=null){ - return startNamespace.getUri(); - } - return null; - } - public String getPrefix(){ - int uriRef=getNamespaceReference(); - if(uriRef<0){ - return null; - } - ResXmlElement parentElement=getParentResXmlElement(); - ResXmlStartNamespace startNamespace=parentElement.getStartNamespaceByUriRef(uriRef); - if(startNamespace!=null){ - return startNamespace.getPrefix(); - } - return null; - } - public void setResXmlEndElement(ResXmlEndElement element){ - mResXmlEndElement=element; - } - public ResXmlEndElement getResXmlEndElement(){ - return mResXmlEndElement; - } - - @Override - protected void onChunkRefreshed() { - refreshAttributeStart(); - refreshAttributeCount(); - } - private void refreshAttributeStart(){ - int start=countUpTo(mAttributeArray); - start=start-getHeaderBlock().getHeaderSize(); - mAttributeStart.set((short)start); - } - private void refreshAttributeCount(){ - int count=mAttributeArray.childesCount(); - mAttributeCount.set((short)count); - } - - @Override - public String toString(){ - String txt=getTagName(); - if(txt==null){ - return super.toString(); - } - StringBuilder builder=new StringBuilder(); - builder.append(txt); - ResXmlAttribute[] allAttr=mAttributeArray.getChildes(); - if(allAttr!=null){ - for(int i=0;i10){ - break; - } - builder.append(" "); - builder.append(allAttr[i].toString()); - } - } - return builder.toString(); - } - - private static final short ATTRIBUTES_UNIT_SIZE=20; - private static final short ATTRIBUTES_DEFAULT_START=20; - /* - * Find another way to mark an attribute is class, device actually relies on - * value of mClassAttributePosition */ - private static final String ATTRIBUTE_NAME_CLASS="class"; - /* - * Find another way to mark an attribute is style, device actually relies on - * value of mStyleAttributePosition */ - private static final String ATTRIBUTE_NAME_STYLE="style"; - /* - * Resource id value of attribute 'android:id' - * instead of relying on hardcoded value, we should find another way to - * mark an attribute is 'id' */ - private static final int ATTRIBUTE_RESOURCE_ID_id =0x010100d0; - } diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlStartNamespace.java b/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlStartNamespace.java deleted file mode 100755 index 35705379..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlStartNamespace.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk.xml; - -import com.reandroid.arsc.chunk.ChunkType; -import com.reandroid.xml.SchemaAttr; -import com.reandroid.xml.XMLAttribute; - -import java.util.HashSet; -import java.util.Set; - -public class ResXmlStartNamespace extends ResXmlNamespace { - private final Set mReferencedAttributes; - - public ResXmlStartNamespace() { - super(ChunkType.XML_START_NAMESPACE); - this.mReferencedAttributes = new HashSet<>(); - } - public ResXmlEndNamespace getEnd(){ - return (ResXmlEndNamespace) getPair(); - } - public void setEnd(ResXmlEndNamespace namespace){ - setPair(namespace); - } - @Override - void linkStringReferences(){ - super.linkStringReferences(); - ResXmlEndNamespace end = getEnd(); - if(end!=null){ - end.linkStringReferences(); - } - } - @Override - void onRemoved(){ - ResXmlEndNamespace end = getEnd(); - if(end!=null){ - end.onRemoved(); - } - mReferencedAttributes.clear(); - } - public boolean hasReferencedAttributes(){ - return mReferencedAttributes.size()>0; - } - public void clearReferencedAttributes(){ - mReferencedAttributes.clear(); - } - public Set getReferencedAttributes(){ - return mReferencedAttributes; - } - void addAttributeReference(ResXmlAttribute attribute){ - if(attribute!=null){ - mReferencedAttributes.add(attribute); - } - } - void removeAttributeReference(ResXmlAttribute attribute){ - if(attribute!=null){ - mReferencedAttributes.remove(attribute); - } - } - public XMLAttribute decodeToXml(){ - String uri=getUri(); - String prefix=getPrefix(); - if(isEmpty(uri) || isEmpty(prefix)){ - return null; - } - SchemaAttr schemaAttr=new SchemaAttr(prefix, uri); - schemaAttr.setLineNumber(getLineNumber()); - return schemaAttr; - } - private boolean isEmpty(String txt){ - if(txt==null){ - return true; - } - txt=txt.trim(); - return txt.length()==0; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlText.java b/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlText.java deleted file mode 100755 index 7780561f..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlText.java +++ /dev/null @@ -1,61 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk.xml; - -import com.reandroid.arsc.chunk.ChunkType; -import com.reandroid.arsc.item.IntegerItem; -import com.reandroid.arsc.item.ResXmlString; -import com.reandroid.arsc.pool.ResXmlStringPool; - -public class ResXmlText extends BaseXmlChunk { - private final IntegerItem mReserved; - public ResXmlText() { - super(ChunkType.XML_CDATA, 1); - this.mReserved=new IntegerItem(); - addChild(mReserved); - setStringReference(0); - } - public String getText(){ - ResXmlString xmlString=getResXmlString(getTextReference()); - if(xmlString!=null){ - return xmlString.getHtml(); - } - return null; - } - public int getTextReference(){ - return getNamespaceReference(); - } - public void setTextReference(int ref){ - setNamespaceReference(ref); - } - public void setText(String text){ - ResXmlStringPool stringPool=getStringPool(); - if(stringPool==null){ - return; - } - ResXmlString resXmlString = stringPool.getOrCreate(text); - int ref=resXmlString.getIndex(); - setTextReference(ref); - } - @Override - public String toString(){ - String txt=getText(); - if(txt!=null){ - return txt; - } - return super.toString(); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlTextNode.java b/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlTextNode.java deleted file mode 100644 index d50918b3..00000000 --- a/src/ARSCLib/com/reandroid/arsc/chunk/xml/ResXmlTextNode.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.chunk.xml; - -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.json.JSONObject; -import com.reandroid.xml.XMLText; - -public class ResXmlTextNode extends ResXmlNode { - private final ResXmlText resXmlText; - public ResXmlTextNode(ResXmlText resXmlText) { - super(1); - this.resXmlText = resXmlText; - addChild(0, resXmlText); - } - public ResXmlTextNode() { - this(new ResXmlText()); - } - public ResXmlText getResXmlText() { - return resXmlText; - } - public int getLineNumber(){ - return getResXmlText().getLineNumber(); - } - public String getComment() { - return getResXmlText().getComment(); - } - @Override - public int getDepth(){ - ResXmlElement parent = getParentResXmlElement(); - if(parent!=null){ - return parent.getDepth() + 1; - } - return 0; - } - @Override - void addEvents(ParserEventList parserEventList){ - String comment = getComment(); - if(comment!=null){ - parserEventList.add( - new ParserEvent(ParserEvent.COMMENT, this, comment, false)); - } - parserEventList.add(new ParserEvent(ParserEvent.TEXT, this)); - } - public ResXmlElement getParentResXmlElement(){ - return getResXmlText().getParentResXmlElement(); - } - - public void setLineNumber(int lineNumber){ - getResXmlText().setLineNumber(lineNumber); - } - public String getText(){ - return getResXmlText().getText(); - } - public void setText(String text){ - getResXmlText().setText(text); - } - public int getTextReference(){ - return getResXmlText().getTextReference(); - } - public void setTextReference(int ref){ - getResXmlText().setTextReference(ref); - } - @Override - void onRemoved(){ - getResXmlText().onRemoved(); - } - @Override - void linkStringReferences(){ - getResXmlText().linkStringReferences(); - } - @Override - public String toString(){ - String txt=getText(); - if(txt!=null){ - return txt; - } - return super.toString(); - } - @Override - public JSONObject toJson() { - JSONObject jsonObject=new JSONObject(); - jsonObject.put(NAME_node_type, NAME_text); - jsonObject.put(NAME_text, getText()); - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - setText(json.optString(NAME_text, null)); - } - public XMLText decodeToXml() { - XMLText xmlText=new XMLText(ValueDecoder.escapeSpecialCharacter(getText())); - xmlText.setLineNumber(getLineNumber()); - return xmlText; - } - - public static final String NAME_text="text"; -} diff --git a/src/ARSCLib/com/reandroid/arsc/container/BlockList.java b/src/ARSCLib/com/reandroid/arsc/container/BlockList.java deleted file mode 100755 index daef4bf0..00000000 --- a/src/ARSCLib/com/reandroid/arsc/container/BlockList.java +++ /dev/null @@ -1,137 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.container; - -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.base.BlockContainer; -import com.reandroid.arsc.base.BlockCounter; -import com.reandroid.arsc.io.BlockReader; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; - -public class BlockList extends Block { - private final List mItems; - public BlockList(){ - super(); - mItems=new ArrayList<>(); - } - public void clearChildes(){ - ArrayList childList = new ArrayList<>(getChildes()); - for(T child:childList){ - remove(child); - } - } - public void sort(Comparator comparator){ - mItems.sort(comparator); - } - public boolean remove(T item){ - if(item!=null){ - item.setParent(null); - item.setIndex(-1); - } - return mItems.remove(item); - } - public void add(T item){ - if(item==null){ - return; - } - item.setIndex(mItems.size()); - item.setParent(this); - mItems.add(item); - } - public T get(int i){ - if(i>=mItems.size() || i<0){ - return null; - } - return mItems.get(i); - } - public int size(){ - return mItems.size(); - } - public List getChildes(){ - return mItems; - } - public final void refresh(){ - if(isNull()){ - return; - } - refreshChildes(); - } - private void refreshChildes(){ - for(T item:getChildes()){ - if(item instanceof BlockContainer){ - BlockContainer container=(BlockContainer)item; - container.refresh(); - }else if(item instanceof BlockList){ - BlockList blockList=(BlockList)item; - blockList.refresh(); - } - } - } - @Override - public byte[] getBytes() { - byte[] results=null; - for(T item:mItems){ - if(item!=null){ - results=addBytes(results, item.getBytes()); - } - } - return results; - } - @Override - public int countBytes() { - int result=0; - for(T item:mItems){ - result+=item.countBytes(); - } - return result; - } - - @Override - public void onCountUpTo(BlockCounter counter) { - if(counter.FOUND){ - return; - } - if(counter.END==this){ - counter.FOUND=true; - return; - } - for(T item:mItems){ - if(counter.FOUND){ - break; - } - item.onCountUpTo(counter); - } - } - @Override - protected int onWriteBytes(OutputStream stream) throws IOException { - int result=0; - for(T item:mItems){ - result+=item.writeBytes(stream); - } - return result; - } - @Override - public void onReadBytes(BlockReader reader) throws IOException{ - for(T item:mItems){ - item.readBytes(reader); - } - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/container/ExpandableBlockContainer.java b/src/ARSCLib/com/reandroid/arsc/container/ExpandableBlockContainer.java deleted file mode 100755 index 8b3d7189..00000000 --- a/src/ARSCLib/com/reandroid/arsc/container/ExpandableBlockContainer.java +++ /dev/null @@ -1,62 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.container; - -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.base.BlockContainer; - -public class ExpandableBlockContainer extends BlockContainer { - private Block[] mChildes; - private int mCursor; - public ExpandableBlockContainer(int initialSize){ - super(); - this.mChildes=new Block[initialSize]; - } - public final void addChild(Block block){ - if(block==null){ - return; - } - int index=mCursor; - ensureCount(index+1); - mChildes[index]=block; - block.setIndex(index); - block.setParent(this); - mCursor++; - } - private void ensureCount(int count){ - if(count<= childesCount()){ - return; - } - Block[] old=mChildes; - mChildes=new Block[count]; - for(int i=0;i { - private final Block[] mChildes; - public FixedBlockContainer(int childesCount){ - super(); - mChildes=new Block[childesCount]; - } - public void addChild(int index, Block block){ - mChildes[index]=block; - block.setIndex(index); - block.setParent(this); - } - @Override - protected void onRefreshed(){ - } - @Override - public int childesCount() { - return mChildes.length; - } - @Override - public Block[] getChildes() { - return mChildes; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/container/PackageBody.java b/src/ARSCLib/com/reandroid/arsc/container/PackageBody.java deleted file mode 100755 index 04b02115..00000000 --- a/src/ARSCLib/com/reandroid/arsc/container/PackageBody.java +++ /dev/null @@ -1,147 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.container; - -import com.reandroid.arsc.chunk.*; -import com.reandroid.arsc.array.SpecTypePairArray; -import com.reandroid.arsc.header.HeaderBlock; -import com.reandroid.arsc.header.SpecHeader; -import com.reandroid.arsc.header.TypeHeader; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.list.OverlayableList; -import com.reandroid.arsc.list.StagedAliasList; - -import java.io.IOException; - -public class PackageBody extends FixedBlockContainer { - - private final SpecTypePairArray mSpecTypePairArray; - private final LibraryBlock mLibraryBlock; - private final StagedAliasList mStagedAliasList; - private final OverlayableList mOverlayableList; - private final BlockList mOverlayablePolicyList; - private final BlockList mUnknownChunkList; - public PackageBody(){ - super(6); - this.mSpecTypePairArray = new SpecTypePairArray(); - this.mLibraryBlock = new LibraryBlock(); - this.mStagedAliasList = new StagedAliasList(); - this.mOverlayableList = new OverlayableList(); - this.mOverlayablePolicyList = new BlockList<>(); - this.mUnknownChunkList = new BlockList<>(); - - addChild(0, mSpecTypePairArray); - addChild(1, mLibraryBlock); - addChild(2, mStagedAliasList); - addChild(3, mOverlayableList); - addChild(4, mOverlayablePolicyList); - addChild(5, mUnknownChunkList); - } - public void destroy(){ - getSpecTypePairArray().clearChildes(); - getLibraryBlock().getLibraryInfoArray().clearChildes(); - getStagedAliasList().clearChildes(); - getOverlayableList().clearChildes(); - getOverlayablePolicyList().clearChildes(); - getUnknownChunkList().clearChildes(); - } - public OverlayableList getOverlayableList() { - return mOverlayableList; - } - public BlockList getOverlayablePolicyList() { - return mOverlayablePolicyList; - } - public StagedAliasList getStagedAliasList() { - return mStagedAliasList; - } - public LibraryBlock getLibraryBlock(){ - return mLibraryBlock; - } - public SpecTypePairArray getSpecTypePairArray() { - return mSpecTypePairArray; - } - public BlockList getUnknownChunkList(){ - return mUnknownChunkList; - } - - @Override - public void onReadBytes(BlockReader reader) throws IOException{ - boolean readOk=true; - while (readOk){ - readOk=readNextBlock(reader); - } - } - private boolean readNextBlock(BlockReader reader) throws IOException { - HeaderBlock headerBlock = reader.readHeaderBlock(); - if(headerBlock==null){ - return false; - } - int pos=reader.getPosition(); - ChunkType chunkType=headerBlock.getChunkType(); - if(chunkType==ChunkType.SPEC){ - readSpecBlock(reader); - }else if(chunkType==ChunkType.TYPE){ - readTypeBlock(reader); - }else if(chunkType==ChunkType.LIBRARY){ - readLibraryBlock(reader); - }else if(chunkType==ChunkType.OVERLAYABLE){ - readOverlayable(reader); - }else if(chunkType==ChunkType.OVERLAYABLE_POLICY){ - readOverlayablePolicy(reader); - }else if(chunkType==ChunkType.STAGED_ALIAS){ - readStagedAlias(reader); - }else { - readUnknownChunk(reader); - } - return pos!=reader.getPosition(); - } - private void readSpecBlock(BlockReader reader) throws IOException{ - SpecHeader specHeader = reader.readSpecHeader(); - SpecTypePair specTypePair = mSpecTypePairArray.getOrCreate(specHeader.getId().get()); - specTypePair.getSpecBlock().readBytes(reader); - } - private void readTypeBlock(BlockReader reader) throws IOException{ - TypeHeader typeHeader = reader.readTypeHeader(); - SpecTypePair specTypePair = mSpecTypePairArray.getOrCreate(typeHeader.getId().get()); - TypeBlock typeBlock = specTypePair.getTypeBlockArray().createNext(typeHeader.isSparse()); - typeBlock.readBytes(reader); - } - private void readLibraryBlock(BlockReader reader) throws IOException{ - LibraryBlock libraryBlock=new LibraryBlock(); - libraryBlock.readBytes(reader); - mLibraryBlock.addLibraryInfo(libraryBlock); - } - private void readStagedAlias(BlockReader reader) throws IOException{ - StagedAlias stagedAlias = new StagedAlias(); - stagedAlias.readBytes(reader); - mStagedAliasList.add(stagedAlias); - } - private void readOverlayable(BlockReader reader) throws IOException{ - Overlayable overlayable = new Overlayable(); - overlayable.readBytes(reader); - mOverlayableList.add(overlayable); - } - private void readOverlayablePolicy(BlockReader reader) throws IOException{ - OverlayablePolicy overlayablePolicy = new OverlayablePolicy(); - overlayablePolicy.readBytes(reader); - mOverlayablePolicyList.add(overlayablePolicy); - } - private void readUnknownChunk(BlockReader reader) throws IOException{ - UnknownChunk unknownChunk = new UnknownChunk(); - unknownChunk.readBytes(reader); - mUnknownChunkList.add(unknownChunk); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/container/ResValueContainer.java b/src/ARSCLib/com/reandroid/arsc/container/ResValueContainer.java deleted file mode 100755 index a9b4a97b..00000000 --- a/src/ARSCLib/com/reandroid/arsc/container/ResValueContainer.java +++ /dev/null @@ -1,57 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.container; - -import com.reandroid.arsc.base.BlockContainer; -import com.reandroid.arsc.value.ValueItem; - -public class ResValueContainer extends BlockContainer { - private final ValueItem[] mChildes; - public ResValueContainer(){ - super(); - mChildes=new ValueItem[1]; - } - @Override - protected void onRefreshed(){ - } - @Override - public int childesCount() { - return mChildes.length; - } - @Override - public ValueItem[] getChildes() { - return mChildes; - } - public void setResValue(ValueItem resValue){ - ValueItem old=getResValue(); - if(old!=null){ - old.setIndex(-1); - old.setParent(null); - } - mChildes[0]=resValue; - if(resValue==null){ - return; - } - resValue.setIndex(0); - resValue.setParent(this); - } - public ValueItem getResValue(){ - if(mChildes.length==0){ - return null; - } - return mChildes[0]; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/container/SingleBlockContainer.java b/src/ARSCLib/com/reandroid/arsc/container/SingleBlockContainer.java deleted file mode 100755 index 1135e84a..00000000 --- a/src/ARSCLib/com/reandroid/arsc/container/SingleBlockContainer.java +++ /dev/null @@ -1,122 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.container; - -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.base.BlockContainer; -import com.reandroid.arsc.base.BlockCounter; -import com.reandroid.arsc.io.BlockReader; - -import java.io.IOException; -import java.io.OutputStream; - -public class SingleBlockContainer extends BlockContainer { - private T mItem; - public SingleBlockContainer(){ - super(); - } - @Override - protected void refreshChildes(){ - if(mItem!=null){ - if(mItem instanceof BlockContainer){ - ((BlockContainer)mItem).refresh(); - } - } - } - @Override - protected void onRefreshed() { - - } - public T getItem() { - return mItem; - } - public void setItem(T item) { - if(item==null){ - if(mItem!=null){ - mItem.setIndex(-1); - mItem.setParent(null); - } - mItem=null; - return; - } - this.mItem = item; - item.setIndex(getIndex()); - item.setParent(this); - } - public boolean hasItem(){ - return this.mItem!=null; - } - @Override - public byte[] getBytes() { - if(mItem!=null){ - return mItem.getBytes(); - } - return null; - } - @Override - public int countBytes() { - if(mItem!=null){ - return mItem.countBytes(); - } - return 0; - } - - @Override - public void onCountUpTo(BlockCounter counter) { - if(counter.FOUND){ - return; - } - if(counter.END==this){ - counter.FOUND=true; - return; - } - if(mItem!=null){ - mItem.onCountUpTo(counter); - } - } - - @Override - public void onReadBytes(BlockReader reader) throws IOException{ - if(mItem!=null){ - mItem.readBytes(reader); - } - } - @Override - public int onWriteBytes(OutputStream stream) throws IOException { - if(mItem!=null){ - return mItem.writeBytes(stream); - } - return 0; - } - - @Override - public int childesCount() { - return hasItem()?0:1; - } - - @Override - public T[] getChildes() { - return null; - } - - @Override - public String toString(){ - if(mItem!=null){ - return mItem.toString(); - } - return getClass().getSimpleName()+": EMPTY"; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/container/SpecTypePair.java b/src/ARSCLib/com/reandroid/arsc/container/SpecTypePair.java deleted file mode 100755 index 69f9cbe3..00000000 --- a/src/ARSCLib/com/reandroid/arsc/container/SpecTypePair.java +++ /dev/null @@ -1,383 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.container; - -import com.reandroid.arsc.array.EntryArray; -import com.reandroid.arsc.chunk.*; -import com.reandroid.arsc.array.TypeBlockArray; -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.base.BlockContainer; -import com.reandroid.arsc.group.EntryGroup; -import com.reandroid.arsc.header.HeaderBlock; -import com.reandroid.arsc.header.TypeHeader; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.item.TypeString; -import com.reandroid.arsc.pool.SpecStringPool; -import com.reandroid.arsc.pool.TableStringPool; -import com.reandroid.arsc.util.HexUtil; -import com.reandroid.arsc.value.Entry; -import com.reandroid.arsc.value.ResConfig; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONObject; - -import java.io.IOException; -import java.util.*; - -public class SpecTypePair extends BlockContainer - implements JSONConvert, Comparable{ - private final Block[] mChildes; - private final SpecBlock mSpecBlock; - private final TypeBlockArray mTypeBlockArray; - - public SpecTypePair(SpecBlock specBlock, TypeBlockArray typeBlockArray){ - this.mSpecBlock = specBlock; - this.mTypeBlockArray = typeBlockArray; - - this.mChildes = new Block[]{specBlock, typeBlockArray}; - - specBlock.setIndex(0); - typeBlockArray.setIndex(1); - - specBlock.setParent(this); - typeBlockArray.setParent(this); - } - public SpecTypePair(){ - this(new SpecBlock(), new TypeBlockArray()); - } - - public Boolean hasComplexEntry(){ - return getTypeBlockArray().hasComplexEntry(); - } - public void linkTableStringsInternal(TableStringPool tableStringPool){ - for(TypeBlock typeBlock:listTypeBlocks()){ - typeBlock.linkTableStringsInternal(tableStringPool); - } - } - public void linkSpecStringsInternal(SpecStringPool specStringPool){ - for(TypeBlock typeBlock:listTypeBlocks()){ - typeBlock.linkSpecStringsInternal(specStringPool); - } - } - public Map createEntryGroups(){ - return createEntryGroups(false); - } - public Map createEntryGroups(boolean skipNullEntries){ - Map map = new LinkedHashMap<>(); - for(TypeBlock typeBlock : listTypeBlocks()){ - EntryArray entryArray = typeBlock.getEntryArray(); - for(Entry entry : entryArray.listItems(skipNullEntries)){ - if(entry == null){ - continue; - } - int id = entry.getResourceId(); - EntryGroup entryGroup = map.get(id); - if(entryGroup == null){ - entryGroup = new EntryGroup(id); - map.put(id, entryGroup); - } - entryGroup.add(entry); - } - } - return map; - } - public EntryGroup createEntryGroup(int id){ - id = 0xffff & id; - EntryGroup entryGroup = null; - for(TypeBlock typeBlock:listTypeBlocks()){ - Entry entry = typeBlock.getEntry(id); - if(entry == null){ - continue; - } - if(entryGroup == null){ - entryGroup = new EntryGroup(entry.getResourceId()); - } - entryGroup.add(entry); - } - return entryGroup; - } - public EntryGroup getEntryGroup(String entryName){ - EntryGroup entryGroup = null; - for(TypeBlock typeBlock:listTypeBlocks()){ - Entry entry = typeBlock.getEntry(entryName); - if(entry == null){ - continue; - } - if(entryGroup == null){ - entryGroup = new EntryGroup(entry.getResourceId()); - } - entryGroup.add(entry); - } - return entryGroup; - } - public void destroy(){ - getSpecBlock().destroy(); - getTypeBlockArray().destroy(); - } - public Entry getAnyEntry(short entryId){ - Entry result = null; - TypeBlock[] types = getTypeBlockArray().getChildes(); - for(int i = 0; i < types.length; i++){ - TypeBlock typeBlock = types[i]; - if(typeBlock == null){ - continue; - } - Entry entry = typeBlock.getEntry(entryId); - if(entry == null){ - continue; - } - if(!entry.isNull()){ - return entry; - } - if(result == null){ - result = entry; - } - } - return result; - } - public Entry getAnyEntry(String name){ - TypeBlock[] types = getTypeBlockArray().getChildes(); - for(int i = 0; i < types.length; i++){ - TypeBlock typeBlock = types[i]; - if(typeBlock == null){ - continue; - } - Entry entry = typeBlock.getEntry(name); - if(entry != null){ - return entry; - } - } - return null; - } - public Entry getEntry(ResConfig resConfig, String entryName){ - return getTypeBlockArray().getEntry(resConfig, entryName); - } - public void sortTypes(){ - getTypeBlockArray().sort(); - } - public boolean removeNullEntries(int startId){ - startId = 0x0000ffff & startId; - boolean removed = getTypeBlockArray().removeNullEntries(startId); - if(!removed){ - return false; - } - getSpecBlock().setEntryCount(startId); - return true; - } - public void removeEmptyTypeBlocks(){ - getTypeBlockArray().removeEmptyBlocks(); - } - public boolean isEmpty(){ - return getTypeBlockArray().isEmpty(); - } - public int countTypeBlocks(){ - return getTypeBlockArray().childesCount(); - } - public Entry getOrCreateEntry(short entryId, String qualifiers){ - return getTypeBlockArray().getOrCreateEntry(entryId, qualifiers); - } - public Entry getEntry(short entryId, String qualifiers){ - return getTypeBlockArray().getEntry(entryId, qualifiers); - } - public TypeBlock getOrCreateTypeBlock(String qualifiers){ - return getTypeBlockArray().getOrCreate(qualifiers); - } - public TypeBlock getOrCreateTypeBlock(ResConfig resConfig){ - return getTypeBlockArray().getOrCreate(resConfig); - } - public TypeBlock getTypeBlock(String qualifiers){ - return getTypeBlockArray().getTypeBlock(qualifiers); - } - public TypeBlock getTypeBlock(ResConfig resConfig){ - return getTypeBlockArray().getTypeBlock(resConfig); - } - public List listResConfig(){ - return mTypeBlockArray.listResConfig(); - } - - public Iterator iteratorNonEmpty(){ - return mTypeBlockArray.iteratorNonEmpty(); - } - public boolean hasDuplicateResConfig(boolean ignoreEmpty){ - return mTypeBlockArray.hasDuplicateResConfig(ignoreEmpty); - } - - public byte getTypeId(){ - return mSpecBlock.getTypeId(); - } - public int getId(){ - return mSpecBlock.getId(); - } - public void setTypeId(byte id){ - mSpecBlock.setTypeId(id); - mTypeBlockArray.setTypeId(id); - } - public String getTypeName(){ - TypeString typeString = getTypeString(); - if(typeString!=null){ - return typeString.get(); - } - return null; - } - public boolean isEqualTypeName(String typeName){ - return TypeBlock.isEqualTypeName(getTypeName(), typeName); - } - /** - * TOBEREMOVED - * - * It is allowed to have duplicate entry name therefore it is not recommend to use this. - * Lets depreciate to warn developer - */ - @Deprecated - public Entry searchByEntryName(String entryName){ - return getTypeBlockArray().searchByEntryName(entryName); - } - public SpecBlock getSpecBlock(){ - return mSpecBlock; - } - public TypeBlockArray getTypeBlockArray(){ - return mTypeBlockArray; - } - public PackageBlock getPackageBlock(){ - return getParent(PackageBlock.class); - } - public List listEntries(int entryId){ - List results=new ArrayList<>(); - Iterator itr = mTypeBlockArray.iterator(true); - while (itr.hasNext()){ - TypeBlock typeBlock=itr.next(); - Entry entry = typeBlock.getEntry(entryId); - if(entry ==null|| entry.isNull()){ - continue; - } - results.add(entry); - } - return results; - } - public List listEntries(String entryName){ - List results = new ArrayList<>(); - Iterator itr = mTypeBlockArray.iterator(true); - while (itr.hasNext()){ - TypeBlock typeBlock = itr.next(); - Entry entry = typeBlock.getEntry(entryName); - if(entry != null){ - results.add(entry); - } - } - return results; - } - public Collection listTypeBlocks(){ - return getTypeBlockArray().listItems(); - } - - @Override - protected void onRefreshed() { - - } - @Override - public int childesCount() { - return mChildes.length; - } - @Override - public Block[] getChildes() { - return mChildes; - } - - @Override - public void onReadBytes(BlockReader reader) throws IOException { - HeaderBlock headerBlock=reader.readHeaderBlock(); - if(headerBlock==null){ - return; - } - ChunkType chunkType=headerBlock.getChunkType(); - if(chunkType == ChunkType.TYPE){ - readTypeBlock(reader); - return; - } - if(chunkType!=ChunkType.SPEC){ - readUnexpectedNonSpecBlock(reader, headerBlock); - } - mSpecBlock.readBytes(reader); - } - private void readTypeBlock(BlockReader reader) throws IOException { - TypeHeader typeHeader = reader.readTypeHeader(); - TypeBlock typeBlock = mTypeBlockArray.createNext(typeHeader.isSparse()); - typeBlock.readBytes(reader); - } - private void readUnexpectedNonSpecBlock(BlockReader reader, HeaderBlock headerBlock) throws IOException{ - throw new IOException("Unexpected block: "+headerBlock.toString()+", Should be: "+ChunkType.SPEC); - } - public int getHighestEntryCount(){ - return getTypeBlockArray().getHighestEntryCount(); - } - public TypeString getTypeString(){ - PackageBlock packageBlock = getPackageBlock(); - if(packageBlock!=null){ - return packageBlock.getTypeStringPool().getById(getId()); - } - return null; - } - - @Override - public JSONObject toJson() { - return toJson(false); - } - @Override - public void fromJson(JSONObject json) { - getSpecBlock().fromJson(json.getJSONObject(SpecBlock.NAME_spec)); - getTypeBlockArray().fromJson(json.optJSONArray(NAME_types)); - } - public JSONObject toJson(boolean specOnly) { - JSONObject jsonObject=new JSONObject(); - jsonObject.put(SpecBlock.NAME_spec, getSpecBlock().toJson()); - if(!specOnly){ - jsonObject.put(NAME_types, getTypeBlockArray().toJson()); - } - return jsonObject; - } - public void merge(SpecTypePair typePair){ - if(typePair==null||typePair==this){ - return; - } - if(getTypeId() != typePair.getTypeId()){ - throw new IllegalArgumentException("Can not merge different id types: " - +getTypeId()+"!="+typePair.getTypeId()); - } - getSpecBlock().merge(typePair.getSpecBlock()); - getTypeBlockArray().merge(typePair.getTypeBlockArray()); - } - @Override - public int compareTo(SpecTypePair specTypePair) { - return Integer.compare(getId(), specTypePair.getId()); - } - @Override - public String toString(){ - StringBuilder builder=new StringBuilder(); - builder.append(HexUtil.toHex2(getTypeId())); - builder.append(" ("); - TypeString ts = getTypeString(); - if(ts!=null){ - builder.append(ts.get()); - }else { - builder.append("null"); - } - builder.append(") config count="); - builder.append(getTypeBlockArray().childesCount()); - return builder.toString(); - } - - public static final String NAME_types = "types"; - public static final String NAME_sparse_types = "sparse_types"; -} diff --git a/src/ARSCLib/com/reandroid/arsc/decoder/ColorUtil.java b/src/ARSCLib/com/reandroid/arsc/decoder/ColorUtil.java deleted file mode 100644 index df734916..00000000 --- a/src/ARSCLib/com/reandroid/arsc/decoder/ColorUtil.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.decoder; - -import com.reandroid.arsc.value.ValueType; - -public class ColorUtil { - - public static String decode(ValueType valueType, int data){ - if(valueType == null){ - return null; - } - StringBuilder builder = new StringBuilder(); - builder.append('#'); - switch (valueType){ - case INT_COLOR_RGB4: - builder.append(byteToHex(data >> 16)); - builder.append(byteToHex(data >> 8)); - builder.append(byteToHex(data)); - break; - case INT_COLOR_ARGB4: - builder.append(byteToHex(data >> 24)); - builder.append(byteToHex(data >> 16)); - builder.append(byteToHex(data >> 8)); - builder.append(byteToHex(data)); - break; - case INT_COLOR_RGB8: - builder.append(byteToHex(data >> 20)); - builder.append(byteToHex(data >> 16)); - builder.append(byteToHex(data >> 12)); - builder.append(byteToHex(data >> 8)); - builder.append(byteToHex(data >> 4)); - builder.append(byteToHex(data)); - break; - case INT_COLOR_ARGB8: - builder.append(byteToHex(data >> 28)); - builder.append(byteToHex(data >> 24)); - builder.append(byteToHex(data >> 20)); - builder.append(byteToHex(data >> 16)); - builder.append(byteToHex(data >> 12)); - builder.append(byteToHex(data >> 8)); - builder.append(byteToHex(data >> 4)); - builder.append(byteToHex(data)); - break; - default: - return null; - } - return builder.toString(); - } - public static ValueDecoder.EncodeResult encode(String hexColor){ - int[] values = hexToIntegers(hexColor); - if(values == null){ - return null; - } - ValueType valueType; - int color = 0; - - int len = values.length; - if (len == 4) { - valueType = ValueType.INT_COLOR_RGB4; - color |= 0xFF000000; - color |= (values[1] << 20); - color |= (values[1] << 16); - color |= (values[2] << 12); - color |= (values[2] << 8); - color |= (values[3] << 4); - color |= values[3]; - } else if (len == 5) { - valueType = ValueType.INT_COLOR_ARGB4; - color |= values[1] << 28; - color |= values[1] << 24; - color |= values[2] << 20; - color |= values[2] << 16; - color |= values[3] << 12; - color |= values[3] << 8; - color |= values[4] << 4; - color |= values[4]; - } else if (len == 7) { - valueType = ValueType.INT_COLOR_RGB8; - color |= 0xFF000000; - color |= values[1] << 20; - color |= values[2] << 16; - color |= values[3] << 12; - color |= values[4] << 8; - color |= values[5] << 4; - color |= values[6]; - } else if (len == 9) { - valueType = ValueType.INT_COLOR_ARGB8; - color |= values[1] << 28; - color |= values[2] << 24; - color |= values[3] << 20; - color |= values[4] << 16; - color |= values[5] << 12; - color |= values[6] << 8; - color |= values[7] << 4; - color |= values[8]; - }else { - return null; - } - return new ValueDecoder.EncodeResult(valueType, color); - } - private static char byteToHex(int i){ - i = i & 0xf; - if(i < 0xa){ - return (char) ('0' + i); - } - i = i - 0xa; - return (char) ('a' + i); - } - private static int[] hexToIntegers(String hexColor){ - if(hexColor == null){ - return null; - } - int length = hexColor.length(); - if(length < 4 || length > 9){ - return null; - } - hexColor = hexColor.toUpperCase(); - char[] chars = hexColor.toCharArray(); - if(chars[0] != '#'){ - return null; - } - length = chars.length; - int[] result = new int[length]; - for(int i = 1; i < length; i++){ - int ch = chars[i]; - int value; - if(ch >= '0' && ch <= '9'){ - value = ch - '0'; - }else if(ch >= 'A' && ch <= 'F'){ - value = 10 + (ch - 'A'); - }else { - return null; - } - result[i] = value; - } - return result; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/decoder/ComplexUtil.java b/src/ARSCLib/com/reandroid/arsc/decoder/ComplexUtil.java deleted file mode 100644 index e2648034..00000000 --- a/src/ARSCLib/com/reandroid/arsc/decoder/ComplexUtil.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.decoder; - -public class ComplexUtil { - - public static String decodeComplex(boolean fraction, int complex_value){ - int radixFlag = (complex_value >> COMPLEX_RADIX_SHIFT) & COMPLEX_RADIX_MASK; - Radix radix = Radix.forFlag(radixFlag); - - int mantissa = (complex_value & ( COMPLEX_MANTISSA_MASK <> COMPLEX_UNIT_SHIFT) & COMPLEX_UNIT_MASK; - Unit unit = Unit.fromFlag(fraction, unit_type); - return radix.formatFloat(fraction, value) + unit.getSymbol(); - } - public static int encodeComplex(float value, String unit){ - return encodeComplex(value, Unit.fromSymbol(unit)); - } - public static int encodeComplex(float value, Unit unit){ - boolean neg = value < 0; - if (neg) { - value = -value; - } - long bits = (long)(value*(1<<23) + 0.5f); - - Radix radix = Radix.getRadix(bits); - int mantissa = (int)((bits>>radix.getShift()) & COMPLEX_MANTISSA_MASK); - if (neg) { - mantissa = (-mantissa) & COMPLEX_MANTISSA_MASK; - } - int result = (radix.getFlag()<= 0.5f){ - i = i + 1; - } - value = ((float) i)/multiplier; - if(neg){ - value = -value; - } - if(scale){ - value = value * 100.0f; - } - return Float.toString(value); - } - public static Radix forFlag(int flag){ - if(flag == 0){ - return RADIX_23p0; - } - if(flag == 1){ - return RADIX_16p7; - } - if(flag == 2){ - return RADIX_8p15; - } - if(flag == 3){ - return RADIX_0p23; - } - throw new NumberFormatException("Unknown radix flag = "+flag); - } - public static Radix getRadix(long bits){ - if ((bits&0x7fffff) == 0) { - return RADIX_23p0; - } - if ((bits&0xffffffffff800000L) == 0) { - return RADIX_0p23; - } - if ((bits&0xffffffff80000000L) == 0) { - return RADIX_8p15; - } - if ((bits&0xffffff8000000000L) == 0) { - return RADIX_16p7; - } - throw new NumberFormatException("Radix bits out of range bits = "+bits); - } - public int getFlag() { - return flag; - } - public int getShift() { - return shift; - } - public float getMultiplier() { - return multiplier; - } - } - private static final int COMPLEX_RADIX_SHIFT = 4; - private static final int COMPLEX_RADIX_MASK = 0x3; - private static final int COMPLEX_MANTISSA_SHIFT = 8; - private static final int COMPLEX_MANTISSA_MASK = 0x00ffffff; - private static final float MANTISSA_MULT = (1.0f / (1 << 8)); - private static final int COMPLEX_UNIT_SHIFT = 0; - private static final int COMPLEX_UNIT_MASK = 0xf; -} diff --git a/src/ARSCLib/com/reandroid/arsc/decoder/Decoder.java b/src/ARSCLib/com/reandroid/arsc/decoder/Decoder.java deleted file mode 100644 index 5478e675..00000000 --- a/src/ARSCLib/com/reandroid/arsc/decoder/Decoder.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.decoder; - -import com.reandroid.apk.AndroidFrameworks; -import com.reandroid.apk.FrameworkApk; -import com.reandroid.arsc.ApkFile; -import com.reandroid.arsc.chunk.MainChunk; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.chunk.xml.AndroidManifestBlock; -import com.reandroid.arsc.chunk.xml.ResXmlDocument; -import com.reandroid.arsc.group.EntryGroup; -import com.reandroid.arsc.util.FrameworkTable; -import com.reandroid.arsc.util.HexUtil; -import com.reandroid.arsc.value.AttributeValue; -import com.reandroid.arsc.value.Value; -import com.reandroid.arsc.value.ValueType; -import com.reandroid.common.EntryStore; - -import java.io.IOException; - -public class Decoder { - private final EntryStore entryStore; - private int currentPackageId; - private ApkFile mApkFile; - public Decoder(EntryStore entryStore, int currentPackageId){ - this.entryStore = entryStore; - this.currentPackageId = currentPackageId; - } - public String decodeResourceName(int resourceId){ - return decodeResourceName(resourceId, true); - } - public String decodeResourceName(int resourceId, boolean defaultHex){ - if(resourceId == 0){ - return null; - } - EntryGroup entryGroup = getEntryStore().getEntryGroup(resourceId); - if(entryGroup!=null){ - return entryGroup.getSpecName(); - } - if(defaultHex){ - return hexResourceName(resourceId); - } - return null; - } - private String hexResourceName(int resourceId){ - return HexUtil.toHex8("@0x", resourceId); - } - public String decodeValue(Value value){ - if(value==null){ - return null; - } - ValueType valueType = value.getValueType(); - if(valueType == ValueType.STRING){ - return value.getValueAsString(); - } - return ValueDecoder.decode(getEntryStore(), getCurrentPackageId(), value); - } - public String decodeAttributeValue(AttributeValue attributeValue){ - return decodeAttributeValue(attributeValue, true); - } - public String decodeAttributeValue(AttributeValue attributeValue, boolean escapeStartChar){ - if(attributeValue == null){ - return null; - } - String result = ValueDecoder.decode(getEntryStore(), getCurrentPackageId(), attributeValue); - if(!escapeStartChar || result == null || result.length() == 0 - || attributeValue.getValueType() != ValueType.STRING){ - return result; - } - return ValueDecoder.escapeSpecialCharacter(result); - } - private EntryStore getEntryStore() { - return entryStore; - } - public int getCurrentPackageId() { - return currentPackageId; - } - public void setCurrentPackageId(int currentPackageId) { - this.currentPackageId = currentPackageId; - } - public ApkFile getApkFile(){ - return mApkFile; - } - public void setApkFile(ApkFile apkFile) { - this.mApkFile = apkFile; - } - public boolean isNullDecoder(){ - return false; - } - - public static Decoder create(ResXmlDocument resXmlDocument){ - MainChunk mainChunk = resXmlDocument.getMainChunk(); - if(mainChunk == null){ - return getNullEntryStoreDecoder(); - } - ApkFile apkFile = mainChunk.getApkFile(); - if(apkFile == null){ - return getNullEntryStoreDecoder(); - } - TableBlock tableBlock = apkFile.getTableBlock(); - if(tableBlock == null){ - return getNullEntryStoreDecoder(); - } - AndroidManifestBlock manifestBlock = apkFile.getAndroidManifestBlock(); - if(manifestBlock!=null){ - int currentPackageId = manifestBlock.guessCurrentPackageId(); - if(currentPackageId!=0){ - return create(tableBlock, currentPackageId); - } - } - return create(tableBlock); - } - public static Decoder create(TableBlock tableBlock){ - if(!tableBlock.hasFramework() && !tableBlock.isAndroid()){ - tableBlock.addFramework(getFramework()); - } - int currentPackageId; - PackageBlock packageBlock = tableBlock.pickOne(); - if(packageBlock!=null){ - currentPackageId = packageBlock.getId(); - }else { - // 0x7f most common - currentPackageId = 0x7f; - } - return create(tableBlock, currentPackageId); - } - public static Decoder create(TableBlock tableBlock, int currentPackageId){ - if(!tableBlock.hasFramework() && !tableBlock.isAndroid()){ - TableBlock framework = getFramework(); - if(framework!=null){ - PackageBlock packageBlock = framework.pickOne(); - if(packageBlock!=null && packageBlock.getId() != currentPackageId){ - tableBlock.addFramework(framework); - } - } - } - return new Decoder(tableBlock, currentPackageId); - } - private static TableBlock getFramework(){ - try { - FrameworkApk frameworkApk = AndroidFrameworks.getCurrent(); - if(frameworkApk == null){ - frameworkApk = AndroidFrameworks.getLatest(); - AndroidFrameworks.setCurrent(frameworkApk); - } - return frameworkApk.getTableBlock(); - } catch (IOException ignored) { - } - // Should not reach here but to be safe return dummy - return new FrameworkTable(); - } - - public static Decoder getNullEntryStoreDecoder(){ - if(NULL_ENTRY_STORE_DECODER!=null){ - return NULL_ENTRY_STORE_DECODER; - } - synchronized (Decoder.class){ - NullEntryDecoder decoder = new NullEntryDecoder(getFramework(), 0x7f); - NULL_ENTRY_STORE_DECODER = decoder; - return decoder; - } - } - static class NullEntryDecoder extends Decoder{ - public NullEntryDecoder(EntryStore entryStore, int currentPackageId) { - super(entryStore, currentPackageId); - } - @Override - public boolean isNullDecoder(){ - return true; - } - } - private static NullEntryDecoder NULL_ENTRY_STORE_DECODER; -} diff --git a/src/ARSCLib/com/reandroid/arsc/decoder/ThreeByteCharsetDecoder.java b/src/ARSCLib/com/reandroid/arsc/decoder/ThreeByteCharsetDecoder.java deleted file mode 100644 index 0f37c363..00000000 --- a/src/ARSCLib/com/reandroid/arsc/decoder/ThreeByteCharsetDecoder.java +++ /dev/null @@ -1,222 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.decoder; - -import java.nio.Buffer; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CoderResult; -import java.nio.charset.StandardCharsets; - -public class ThreeByteCharsetDecoder extends CharsetDecoder { - public static final ThreeByteCharsetDecoder INSTANCE = new ThreeByteCharsetDecoder(); - public ThreeByteCharsetDecoder() { - super(StandardCharsets.UTF_8, 1.0F, 1.0F); - } - @Override - protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) { - return src.hasArray() && dst.hasArray() ? this.decodeArrayLoop(src, dst) : this.decodeBufferLoop(src, dst); - } - private CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) { - byte[] srcBytes = src.array(); - int sourcePosition = src.arrayOffset() + src.position(); - int sourceLimit = src.arrayOffset() + src.limit(); - char[] dstChars = dst.array(); - int dstPosition = dst.arrayOffset() + dst.position(); - int dstLimit = dst.arrayOffset() + dst.limit(); - int min = sourceLimit - sourcePosition; - int start = min; - min = dstLimit - dstPosition; - if(min < start){ - start = min; - } - start = dstPosition + start; - - while ( dstPosition < start && srcBytes[sourcePosition] >= 0) { - dstChars[dstPosition++] = (char) srcBytes[sourcePosition++]; - } - - while (sourcePosition < sourceLimit) { - int b1 = srcBytes[sourcePosition]; - if (b1 < 0) { - if (b1 >> 5 == -2 && (b1 & 0x1E) != 0) { - if (sourceLimit - sourcePosition < 2 || dstPosition >= dstLimit) { - return xFlow(src, sourcePosition, sourceLimit, dst, dstPosition, 2); - } - int b2 = srcBytes[sourcePosition + 1]; - if (isNotContinuation(b2)) { - return malformedForLength(src, sourcePosition, dst, dstPosition); - } - dstChars[dstPosition++] = (char) (b1 << 6 ^ b2 ^ 0x0F80); - sourcePosition += 2; - } else { - if (b1 >> 4 != -2) { - return malformed(src, sourcePosition, dst, dstPosition, 1); - } - - int srcRemaining = sourceLimit - sourcePosition; - if (srcRemaining < 3 || dstPosition >= dstLimit) { - if (srcRemaining > 1 && isMalformed3_2(b1, srcBytes[sourcePosition + 1])) { - return malformedForLength(src, sourcePosition, dst, dstPosition); - } - - return xFlow(src, sourcePosition, sourceLimit, dst, dstPosition, 3); - } - - int b2 = srcBytes[sourcePosition + 1]; - int b3 = srcBytes[sourcePosition + 2]; - if (isMalformed3(b1, b2, b3)) { - return malformed(src, sourcePosition, dst, dstPosition, 3); - } - - dstChars[dstPosition++] = (char) (b1 << 12 ^ b2 << 6 ^ b3 ^ 0xFFFE1F80); - sourcePosition += 3; - } - } else { - if (dstPosition >= dstLimit) { - return xFlow(src, sourcePosition, sourceLimit, dst, dstPosition, 1); - } - - dstChars[dstPosition++] = (char) b1; - ++sourcePosition; - } - } - - return xFlow(src, sourcePosition, sourceLimit, dst, dstPosition, 0); - } - private CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) { - int mark = src.position(); - int limit = src.limit(); - - while (mark < limit) { - int b1 = src.get(); - if (b1 < 0) { - if (b1 >> 5 == -2 && (b1 & 0x1E) != 0) { - if (limit - mark < 2 || dst.remaining() < 1) { - return xFlow(src, mark, 2); - } - int b2 = src.get(); - if (isNotContinuation(b2)) { - return malformedForLength(src, mark); - } - dst.put((char) (b1 << 6 ^ b2 ^ 0x0F80)); - mark += 2; - } else { - if (b1 >> 4 != -2) { - return malformed(src, mark, 1); - } - - int srcRemaining = limit - mark; - if (srcRemaining < 3 || dst.remaining() < 1) { - if (srcRemaining > 1 && isMalformed3_2(b1, src.get())) { - return malformedForLength(src, mark); - } - - return xFlow(src, mark, 3); - } - - int b2 = src.get(); - int b3 = src.get(); - if (isMalformed3(b1, b2, b3)) { - return malformed(src, mark, 3); - } - - dst.put((char) (b1 << 12 ^ b2 << 6 ^ b3 ^ 0xFFFE1F80)); - mark += 3; - } - } else { - if (dst.remaining() < 1) { - return xFlow(src, mark, 1); - } - - dst.put((char) b1); - ++mark; - } - } - return xFlow(src, mark, 0); - } - - private static void updatePositions(Buffer src, int sourcePosition, Buffer dst, int dstPosition) { - src.position(sourcePosition - src.arrayOffset()); - dst.position(dstPosition - dst.arrayOffset()); - } - private static boolean isNotContinuation(int b) { - return (b & 0xC0) != 0x80; - } - private static boolean isMalformed3(int b1, int b2, int b3) { - return b1 == -32 && (b2 & 0xE0) == 0x80 || (b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80; - } - private static boolean isMalformed3_2(int b1, int b2) { - return b1 == -32 && (b2 & 0xE0) == 0x80 || (b2 & 0xC0) != 0x80; - } - private static CoderResult malformedN(ByteBuffer src, int nb) { - int b1; - int b2; - switch (nb) { - case 1: - case 2: - return CoderResult.malformedForLength(1); - case 3: - b1 = src.get(); - b2 = src.get(); - return CoderResult.malformedForLength((b1 != -32 || (b2 & 0xE0) != 0x80) && !isNotContinuation(b2) ? 2 : 1); - case 4: - b1 = src.get() & 0xFF; - b2 = src.get() & 0xFF; - if (b1 <= 244 - && (b1 != 0xF0 || b2 >= 144 && b2 <= 0xBF) - && (b1 != 244 || (b2 & 0xF0) == 0x80) - && !isNotContinuation(b2)) { - if (isNotContinuation(src.get())) { - return CoderResult.malformedForLength(2); - } - return CoderResult.malformedForLength(3); - } - return CoderResult.malformedForLength(1); - default: - return null; - } - } - private static CoderResult malformed(ByteBuffer src, int sourcePosition, CharBuffer dst, int dstPosition, int numBytes) { - src.position(sourcePosition - src.arrayOffset()); - CoderResult cr = malformedN(src, numBytes); - updatePositions(src, sourcePosition, dst, dstPosition); - return cr; - } - private static CoderResult malformed(ByteBuffer src, int mark, int nb) { - src.position(mark); - CoderResult cr = malformedN(src, nb); - src.position(mark); - return cr; - } - private static CoderResult malformedForLength(ByteBuffer src, int sourcePosition, CharBuffer dst, int dstPosition) { - updatePositions(src, sourcePosition, dst, dstPosition); - return CoderResult.malformedForLength(1); - } - private static CoderResult malformedForLength(ByteBuffer src, int mark) { - src.position(mark); - return CoderResult.malformedForLength(1); - } - private static CoderResult xFlow(Buffer src, int sourcePosition, int sourceLimit, Buffer dst, int dstPosition, int numBytes) { - updatePositions(src, sourcePosition, dst, dstPosition); - return numBytes != 0 && sourceLimit - sourcePosition >= numBytes ? CoderResult.OVERFLOW : CoderResult.UNDERFLOW; - } - private static CoderResult xFlow(Buffer src, int mark, int nb) { - src.position(mark); - return nb != 0 && src.remaining() >= nb ? CoderResult.OVERFLOW : CoderResult.UNDERFLOW; - } -} \ No newline at end of file diff --git a/src/ARSCLib/com/reandroid/arsc/decoder/ValueDecoder.java b/src/ARSCLib/com/reandroid/arsc/decoder/ValueDecoder.java deleted file mode 100755 index 151768ff..00000000 --- a/src/ARSCLib/com/reandroid/arsc/decoder/ValueDecoder.java +++ /dev/null @@ -1,922 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.decoder; - -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.group.EntryGroup; -import com.reandroid.arsc.item.TableString; -import com.reandroid.arsc.pool.TableStringPool; -import com.reandroid.arsc.util.HexUtil; -import com.reandroid.arsc.value.*; -import com.reandroid.arsc.value.attribute.AttributeBag; -import com.reandroid.common.EntryStore; - -import java.util.Collection; -import java.util.Iterator; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class ValueDecoder { - - public static String escapeSpecialCharacter(String text){ - if(text==null || text.length()==0){ - return text; - } - if(isSpecialCharacter(text.charAt(0))){ - return '\\' +text; - } - return text; - } - public static String unEscapeSpecialCharacter(String text){ - if(text==null || text.length()<2){ - return text; - } - if(text.charAt(0)!='\\' || !isSpecialCharacter(text.charAt(1))){ - return text; - } - return text.substring(1); - } - public static String quoteWhitespace(String text){ - if(!isWhiteSpace(text)){ - return text; - } - return "\"" + text + "\""; - } - public static String unQuoteWhitespace(String text){ - if(text == null || text.length() < 3){ - return text; - } - if(text.charAt(0) != '"' || text.charAt(text.length()-1) != '"'){ - return text; - } - String unQuoted = text.substring(1, text.length()-1); - if(!isWhiteSpace(unQuoted)){ - return text; - } - return unQuoted; - } - private static boolean isWhiteSpace(String text){ - if(text == null || text.length() == 0){ - return false; - } - char[] chars = text.toCharArray(); - for(int i = 0; i < chars.length; i++){ - if(!isWhiteSpace(chars[i])){ - return false; - } - } - return true; - } - private static boolean isWhiteSpace(char ch){ - switch (ch){ - case ' ': - case '\n': - case '\r': - case '\t': - return true; - default: - return false; - } - } - private static boolean isSpecialCharacter(char ch){ - switch (ch){ - case '@': - case '?': - case '#': - return true; - default: - return false; - } - } - public static EncodeResult encodeGuessAny(String txt){ - if(txt==null){ - return null; - } - EncodeResult result = encodeNullReference(txt); - if(result != null){ - return result; - } - result=encodeColor(txt); - if(result!=null){ - return result; - } - result=encodeDimensionOrFloat(txt); - if(result!=null){ - return result; - } - result=encodeHexOrInt(txt); - if(result!=null){ - return result; - } - return encodeBoolean(txt); - } - public static EncodeResult encodeBoolean(String txt){ - if(txt==null){ - return null; - } - txt=txt.trim().toLowerCase(); - if(txt.equals("true")){ - return new EncodeResult(ValueType.INT_BOOLEAN, 0xffffffff); - } - if(txt.equals("false")){ - return new EncodeResult(ValueType.INT_BOOLEAN, 0); - } - return null; - } - public static EncodeResult encodeNullReference(String txt){ - if(txt==null){ - return null; - } - if("@empty".equals(txt)){ - return new EncodeResult(ValueType.NULL, 1); - } - if("@null".equals(txt)){ - return new EncodeResult(ValueType.REFERENCE, 0); - } - if("?null".equals(txt)){ - return new EncodeResult(ValueType.ATTRIBUTE, 0); - } - return null; - } - public static EncodeResult encodeHexReference(String txt){ - if(txt==null){ - return null; - } - txt=txt.trim().toLowerCase(); - Matcher matcher = PATTERN_HEX_REFERENCE.matcher(txt); - if(!matcher.find()){ - return null; - } - String prefix = matcher.group(1); - int value = parseHex(matcher.group(2)); - ValueType valueType; - if("?".equals(prefix)){ - valueType = ValueType.ATTRIBUTE; - }else { - valueType = ValueType.REFERENCE; - } - return new EncodeResult(valueType, value); - } - public static boolean isInteger(String txt){ - if(txt==null){ - return false; - } - return PATTERN_INTEGER.matcher(txt).matches(); - } - public static boolean isHex(String txt){ - if(txt==null){ - return false; - } - return PATTERN_HEX.matcher(txt).matches(); - } - public static boolean isReference(String txt){ - if(txt==null){ - return false; - } - if(isNullReference(txt)){ - return true; - } - if(isHexReference(txt)){ - return true; - } - return PATTERN_REFERENCE.matcher(txt).matches(); - } - private static boolean isHexReference(String txt){ - return PATTERN_HEX_REFERENCE.matcher(txt).matches(); - } - private static boolean isNullReference(String txt){ - if("@null".equals(txt)||"?null".equals(txt)){ - return true; - } - if("@empty".equals(txt)){ - return true; - } - return false; - } - public static EncodeResult encodeColor(String value){ - return ColorUtil.encode(value); - } - public static EncodeResult encodeHexOrInt(String numString){ - if(numString==null){ - return null; - } - if(isHex(numString)){ - return new EncodeResult(ValueType.INT_HEX, parseHex(numString)); - } - if(isInteger(numString)){ - return new EncodeResult(ValueType.INT_DEC, parseInteger(numString)); - } - return null; - } - public static int parseHex(String hexString){ - boolean negative=false; - hexString=hexString.trim().toLowerCase(); - if(hexString.startsWith("-")){ - negative=true; - hexString=hexString.substring(1); - } - if(!hexString.startsWith("0x")){ - hexString="0x"+hexString; - } - long l=Long.decode(hexString); - if(negative){ - l=-l; - } - return (int) l; - } - public static int parseInteger(String intString){ - intString=intString.trim(); - boolean negative=false; - if(intString.startsWith("-")){ - negative=true; - intString=intString.substring(1); - } - long l=Long.parseLong(intString); - if(negative){ - l=-l; - } - return (int) l; - } - public static EncodeResult encodeDimensionOrFloat(String value){ - if(value==null){ - return null; - } - EncodeResult result = encodeFloat(value); - if(result == null){ - result = encodeDimensionOrFraction(value); - } - return result; - } - public static EncodeResult encodeFloat(String txt){ - Float value = parseFloat(txt); - if(value==null){ - return null; - } - return new EncodeResult(ValueType.FLOAT, - Float.floatToIntBits(value)); - } - public static Float parseFloat(String txt){ - if(txt==null || txt.indexOf('.')<0){ - return null; - } - try{ - return Float.parseFloat(txt); - }catch (NumberFormatException ignored){ - return null; - } - } - public static EncodeResult encodeDimensionOrFraction(String value){ - if(value==null){ - return null; - } - Matcher matcher = PATTERN_DIMEN.matcher(value); - if(!matcher.find()){ - return null; - } - String number = matcher.group(1); - String unit = matcher.group(4); - float fraction = Float.parseFloat(number); - return encodeDimensionOrFraction(fraction, unit); - } - private static EncodeResult encodeDimensionOrFraction(float value, String unitSymbol){ - ComplexUtil.Unit unit = ComplexUtil.Unit.fromSymbol(unitSymbol); - ValueType valueType; - if(unit == ComplexUtil.Unit.FRACTION || unit == ComplexUtil.Unit.FRACTION_PARENT){ - valueType = ValueType.FRACTION; - value = value / 100.0f; - }else { - valueType = ValueType.DIMENSION; - } - int result = ComplexUtil.encodeComplex(value, unit); - return new EncodeResult(valueType, result); - } - - public static String decodeAttributeName(EntryStore store, PackageBlock currentPackage, int resourceId){ - EntryGroup entryGroup=searchEntryGroup(store, currentPackage, resourceId); - if(entryGroup==null){ - return HexUtil.toHex8("@0x", resourceId); - } - Entry entry = entryGroup.pickOne(); - if(entry == null){ - return HexUtil.toHex8("@0x", resourceId); - } - String prefix=null; - if(currentPackage!=null){ - String name=currentPackage.getName(); - String other= entry.getPackageBlock().getName(); - if(!name.equals(other)){ - prefix=other+":"; - } - } - String name=entryGroup.getSpecName(); - if(prefix!=null){ - name=prefix+name; - } - return name; - } - public static String decodeAttribute(EntryStore store, int attrResId, int rawValue){ - AttributeBag attributeBag = getAttributeBag(store, attrResId); - if(attributeBag==null){ - return null; - } - return attributeBag.decodeAttributeValue(store, rawValue); - } - - public static String decodeEntryValue(EntryStore store, PackageBlock currentPackage, ValueType valueType, int data){ - if(store==null || currentPackage==null){ - return null; - } - if(valueType==ValueType.STRING){ - return decodeIntEntryString(currentPackage, data); - } - boolean is_reference=false; - boolean is_attribute=false; - if(valueType==ValueType.REFERENCE){ - if(data==0){ - return "@null"; - } - is_reference=true; - } - if(valueType==ValueType.ATTRIBUTE){ - if(data==0){ - return "?null"; - } - is_attribute=true; - } - if(is_reference || is_attribute){ - String ref=buildReferenceValue(store, valueType, currentPackage.getName(), data); - if(ref!=null){ - return ref; - } - char atOrQues=is_reference?'@':'?'; - ref=atOrQues+toHexResourceId(data); - return ref; - } - return decode(valueType, data); - } - public static String decodeIntEntry(EntryStore store, ResValue resValue){ - if(resValue ==null){ - return null; - } - Entry parentEntry = resValue.getEntry(); - if(parentEntry==null){ - return null; - } - ValueType valueType= resValue.getValueType(); - int data= resValue.getData(); - return decodeIntEntry(store, parentEntry, valueType, data); - } - public static String decodeIntEntry(EntryStore store, ResValueMap bagItem){ - if(bagItem==null){ - return null; - } - Entry parentEntry=bagItem.getEntry(); - if(parentEntry==null){ - return null; - } - ValueType valueType=bagItem.getValueType(); - int data=bagItem.getData(); - return decodeIntEntry(store, parentEntry, valueType, data); - } - public static String decodeIntEntry(EntryStore store, Entry parentEntry, ValueType valueType, int data){ - if(valueType == ValueType.NULL){ - return decodeNull(data); - } - if(valueType==ValueType.STRING){ - return decodeIntEntryString(parentEntry, data); - } - boolean is_reference=false; - boolean is_attribute=false; - if(valueType==ValueType.REFERENCE){ - if(data==0){ - return "@null"; - } - is_reference=true; - } - if(valueType==ValueType.ATTRIBUTE){ - if(data==0){ - return "?null"; - } - is_attribute=true; - } - if(is_reference || is_attribute){ - String ref=buildReferenceValue(store, parentEntry, valueType, data); - if(ref!=null){ - return ref; - } - char atOrQues=is_reference?'@':'?'; - ref=atOrQues+toHexResourceId(data); - return ref; - } - return decode(valueType, data); - } - public static String buildReferenceValue(EntryStore store, Entry entry){ - if(entry ==null){ - return null; - } - TableEntry tableEntry = entry.getTableEntry(); - if(tableEntry == null || (tableEntry instanceof CompoundEntry)){ - return null; - } - ResValue resValue = (ResValue) tableEntry.getValue(); - int resourceId = resValue.getData(); - ValueType valueType= resValue.getValueType(); - return buildReferenceValue(store, entry, valueType, resourceId); - } - public static String decode(EntryStore entryStore, int currentPackageId, Value value){ - - ValueType valueType = value.getValueType(); - if(valueType == ValueType.STRING){ - return value.getValueAsString(); - } - int data = value.getData(); - if(valueType==ValueType.REFERENCE || valueType==ValueType.ATTRIBUTE){ - String currentPackageName = getPackageName(entryStore, currentPackageId); - return buildReferenceValue(entryStore, - valueType, currentPackageName, - data); - } - return decode(valueType, data); - } - public static String decode(EntryStore entryStore, int currentPackageId, AttributeValue attributeValue){ - ValueType valueType = attributeValue.getValueType(); - if(valueType == ValueType.STRING){ - return attributeValue.getValueAsString(); - } - int data = attributeValue.getData(); - if(valueType==ValueType.REFERENCE || valueType==ValueType.ATTRIBUTE){ - String currentPackageName = getPackageName(entryStore, currentPackageId); - return buildReferenceValue(entryStore, - valueType, currentPackageName, - data); - } - if(valueType==ValueType.INT_DEC || valueType==ValueType.INT_HEX){ - String result = decodeAttribute(entryStore, - attributeValue.getNameResourceID(), - attributeValue.getData()); - if(result!=null){ - return result; - } - } - return decode(valueType, data); - } - @Deprecated - public static String decode(EntryStore entryStore, int currentPackageId, int nameResourceId, ValueType valueType, int rawVal){ - String currPackageName=getPackageName(entryStore, currentPackageId); - String result=buildReferenceValue(entryStore, valueType, currPackageName, rawVal); - if(result!=null){ - return result; - } - if(valueType==ValueType.STRING){ - // Should not happen the string could be in ResXmlBlock, but if you are lazy here it goes - return decodeString(entryStore, currentPackageId, rawVal); - } - if(valueType==ValueType.INT_DEC||valueType==ValueType.INT_HEX){ - result=decodeAttribute(entryStore, nameResourceId, rawVal); - if(result!=null){ - return result; - } - } - return decode(valueType, rawVal); - } - public static String decode(ValueType valueType, int data){ - if(valueType==null){ - return null; - } - String hexColor = ColorUtil.decode(valueType, data); - if(hexColor != null){ - return hexColor; - } - switch (valueType){ - case INT_BOOLEAN: - return decodeBoolean(data); - case DIMENSION: - case FLOAT: - case FRACTION: - return decodeDimensionOrFloat(valueType, data); - case INT_HEX: - return decodeHex(data); - case INT_DEC: - return decodeInt(data); - case NULL: - return decodeNull(data); - } - return null; - } - public static String buildReference(String currentPackageName, - String referredPackageName, - char atOrQues, - String typeName, - String resourceName){ - StringBuilder builder=new StringBuilder(); - if(atOrQues!=0){ - builder.append(atOrQues); - } - if(!isEqualString(currentPackageName, referredPackageName)){ - if(!isEmpty(currentPackageName) && !isEmpty(referredPackageName)){ - builder.append(referredPackageName); - if(!referredPackageName.endsWith(":")){ - builder.append(':'); - } - } - } - if(!isEmpty(typeName)){ - builder.append(typeName); - builder.append('/'); - } - builder.append(resourceName); - return builder.toString(); - } - - private static String buildReferenceValue(EntryStore store, Entry entry, ValueType valueType, int resourceId){ - if(entry ==null){ - return null; - } - EntryGroup value=searchEntryGroup(store, entry, resourceId); - if(value==null){ - return null; - } - return buildReferenceValue(valueType, entry, value); - } - private static String buildReferenceValue(ValueType valueType, Entry entry, EntryGroup value){ - char atOrQues; - if(valueType==ValueType.REFERENCE){ - atOrQues='@'; - }else if(valueType==ValueType.ATTRIBUTE){ - atOrQues='?'; - }else { - atOrQues=0; - } - String currentPackageName=getPackageName(entry); - String referredPackageName=getPackageName(value); - String typeName=value.getTypeName(); - String name=value.getSpecName(); - return buildReference(currentPackageName, referredPackageName, atOrQues, typeName, name); - } - private static String buildReferenceValue(EntryStore entryStore, ValueType valueType, String currentPackageName, int resourceId){ - char atOrQues; - if(valueType==ValueType.REFERENCE){ - if(resourceId==0){ - return "@null"; - } - atOrQues='@'; - }else if(valueType==ValueType.ATTRIBUTE){ - if(resourceId==0){ - return "?null"; - } - atOrQues='?'; - }else { - return null; - } - EntryGroup value=null; - if(entryStore!=null){ - value=entryStore.getEntryGroup(resourceId); - } - if(value==null){ - return atOrQues+toHexResourceId(resourceId); - } - String referredPackageName=getPackageName(value); - String typeName=value.getTypeName(); - String name=value.getSpecName(); - return buildReference(currentPackageName, referredPackageName, atOrQues, typeName, name); - } - private static String getPackageName(EntryStore entryStore, int packageOrResourceId){ - if(entryStore==null || packageOrResourceId==0){ - return null; - } - int pkgId=(packageOrResourceId>>24)&0xFF; - if(pkgId==0){ - pkgId=packageOrResourceId; - } - pkgId = pkgId & 0xff; - Collection allPkg = entryStore.getPackageBlocks(pkgId); - if(allPkg==null){ - return null; - } - for(PackageBlock packageBlock:allPkg){ - String name=packageBlock.getName(); - if(name!=null){ - return name; - } - } - return null; - } - private static String getPackageName(EntryGroup entryGroup){ - if(entryGroup==null){ - return null; - } - return getPackageName(entryGroup.pickOne()); - } - private static String getPackageName(Entry entry){ - if(entry ==null){ - return null; - } - PackageBlock packageBlock= entry.getPackageBlock(); - if(packageBlock==null){ - return null; - } - return packageBlock.getName(); - } - private static EntryGroup searchEntryGroup(EntryStore store, Entry entry, int resourceId){ - EntryGroup entryGroup=searchEntryGroup(entry, resourceId); - if(entryGroup!=null){ - return entryGroup; - } - if(store==null){ - return null; - } - return store.getEntryGroup(resourceId); - } - private static EntryGroup searchEntryGroup(Entry entry, int resourceId){ - if(entry ==null){ - return null; - } - PackageBlock packageBlock= entry.getPackageBlock(); - if(packageBlock==null){ - return null; - } - TableBlock tableBlock=packageBlock.getTableBlock(); - if(tableBlock==null){ - return null; - } - for(PackageBlock pkg:tableBlock.listPackages()){ - EntryGroup entryGroup=pkg.getEntryGroup(resourceId); - if(entryGroup!=null){ - return entryGroup; - } - } - return null; - } - private static EntryGroup searchEntryGroup(EntryStore store, PackageBlock packageBlock, int resourceId){ - if(packageBlock!=null){ - TableBlock tableBlock=packageBlock.getTableBlock(); - if(tableBlock!=null){ - for(PackageBlock pkg:tableBlock.listPackages()){ - EntryGroup entryGroup=pkg.getEntryGroup(resourceId); - if(entryGroup!=null){ - return entryGroup; - } - } - } - } - if(store!=null){ - return store.getEntryGroup(resourceId); - } - return null; - } - private static String decodeIntEntryString(Entry entry, int data){ - if(entry ==null){ - return null; - } - PackageBlock packageBlock= entry.getPackageBlock(); - if(packageBlock==null){ - return null; - } - TableBlock tableBlock=packageBlock.getTableBlock(); - if(tableBlock==null){ - return null; - } - TableStringPool pool = tableBlock.getTableStringPool(); - TableString tableString=pool.get(data); - if(tableString==null){ - return null; - } - return escapeSpecialCharacter(tableString.getHtml()); - } - private static String decodeString(EntryStore entryStore, int packageOrResourceId, int stringRef){ - if(entryStore==null||packageOrResourceId==0){ - return null; - } - int pkgId=(packageOrResourceId>>24)&0xFF; - if(pkgId==0){ - pkgId=packageOrResourceId; - } - Collection allPkg = entryStore.getPackageBlocks((byte) pkgId); - if(allPkg==null){ - return null; - } - TableString tableString=null; - for(PackageBlock packageBlock:allPkg){ - TableBlock tableBlock=packageBlock.getTableBlock(); - if(tableBlock==null){ - continue; - } - TableString ts=tableBlock.getTableStringPool().get(stringRef); - if(ts==null){ - continue; - } - if(tableString==null){ - tableString=ts; - }else { - // Duplicate result, could be from split apks - return null; - } - } - if(tableString!=null){ - return escapeSpecialCharacter(tableString.getHtml()); - } - return null; - } - private static String decodeIntEntryString(PackageBlock packageBlock, int data){ - if(packageBlock==null){ - return null; - } - TableBlock tableBlock=packageBlock.getTableBlock(); - if(tableBlock==null){ - return null; - } - TableStringPool pool = tableBlock.getTableStringPool(); - TableString tableString=pool.get(data); - if(tableString==null){ - return null; - } - return escapeSpecialCharacter(tableString.getHtml()); - } - - private static String decodeHex(int rawVal){ - return HexUtil.toHex(rawVal, 1); - } - private static String decodeInt(int rawVal){ - return String.valueOf(rawVal); - } - private static String decodeNull(int data){ - if(data == 1){ - return "@empty"; - } - return "@null"; - } - - private static String decodeBoolean(int data){ - if(data == 0xFFFFFFFF){ - return "true"; - } - return "false"; - } - - private static String decodeDimensionOrFloat(ValueType valueType, int rawVal){ - if(valueType==ValueType.FLOAT){ - float f=Float.intBitsToFloat(rawVal); - return Float.toString(f); - } - return ComplexUtil.decodeComplex(valueType == ValueType.FRACTION, rawVal); - } - private static AttributeBag getAttributeBag(EntryStore store, int resourceId){ - ResTableMapEntry mapEntry=getAttributeValueBag(store, resourceId); - if(mapEntry==null){ - return null; - } - return AttributeBag.create(mapEntry.getValue()); - } - private static ResTableMapEntry getAttributeValueBag(EntryStore store, int resourceId){ - if(store==null){ - return null; - } - Collection foundGroups = store.getEntryGroups(resourceId); - ResTableMapEntry best=null; - for(EntryGroup group:foundGroups){ - ResTableMapEntry valueBag = getAttributeValueBag(group); - best=chooseBest(best, valueBag); - } - return best; - } - private static ResTableMapEntry getAttributeValueBag(EntryGroup entryGroup){ - if(entryGroup==null){ - return null; - } - ResTableMapEntry best=null; - Iterator iterator=entryGroup.iterator(true); - while (iterator.hasNext()){ - Entry entry =iterator.next(); - ResTableMapEntry valueBag = getAttributeValueBag(entry); - best=chooseBest(best, valueBag); - } - return best; - } - private static ResTableMapEntry getAttributeValueBag(Entry entry){ - if(entry ==null){ - return null; - } - TableEntry tableEntry = entry.getTableEntry(); - if(tableEntry instanceof ResTableMapEntry){ - return (ResTableMapEntry) tableEntry; - } - return null; - } - private static ResTableMapEntry chooseBest(ResTableMapEntry entry1, ResTableMapEntry entry2){ - if(entry1==null){ - return entry2; - } - if(entry2==null){ - return entry1; - } - if(entry2.getValue().childesCount()>entry1.getValue().childesCount()){ - return entry2; - } - return entry1; - } - private static String toHexResourceId(int resourceId){ - return HexUtil.toHex8(resourceId); - } - private static boolean isEqualString(String str1, String str2){ - if(isEmpty(str1)){ - return isEmpty(str2); - } - return str1.equals(str2); - } - private static boolean isEmpty(String str){ - if(str==null){ - return true; - } - str=str.trim(); - return str.length()==0; - } - - public static ReferenceString parseReference(String ref){ - if(ref == null || ref.length() < 2){ - return null; - } - char first = ref.charAt(0); - if(first != '@' && first != '?'){ - return null; - } - Matcher matcher = PATTERN_REFERENCE.matcher(ref); - if(!matcher.find()){ - return null; - } - String prefix = matcher.group(1); - String packageName = matcher.group(2); - if(packageName != null){ - if(packageName.endsWith(":")){ - packageName = packageName.substring(0, packageName.length()-1); - } - if(packageName.length() == 0){ - packageName = null; - } - } - String type = matcher.group(4); - String name = matcher.group(5); - return new ReferenceString(prefix, packageName, type, name); - } - public static class ReferenceString{ - public final String prefix; - public final String packageName; - public final String type; - public final String name; - public ReferenceString(String prefix, String packageName, String type, String name){ - this.prefix = prefix; - this.packageName = packageName; - this.type = type; - this.name = name; - } - @Override - public String toString(){ - StringBuilder builder = new StringBuilder(); - if(prefix != null){ - builder.append(prefix); - } - if(packageName != null){ - builder.append(packageName); - builder.append(':'); - } - if(type != null){ - builder.append(type); - builder.append('/'); - } - builder.append(name); - return builder.toString(); - } - - } - public static class EncodeResult{ - public final ValueType valueType; - public final int value; - public EncodeResult(ValueType valueType, int value){ - this.valueType=valueType; - this.value=value; - } - @Override - public String toString(){ - return valueType+": "+HexUtil.toHex8(value); - } - } - - public static final Pattern PATTERN_DIMEN = Pattern.compile("^([+\\-]?[0-9]+(\\.[0-9]+(E\\+?-?[0-9]+)?)?)(px|di?p|sp|pt|in|mm|%p?)$"); - private static final Pattern PATTERN_INTEGER = Pattern.compile("^(-?)([0-9]+)$"); - private static final Pattern PATTERN_HEX = Pattern.compile("^0x[0-9a-fA-F]+$"); - public static final Pattern PATTERN_REFERENCE = Pattern.compile("^([?@])(([^\\s:@?/]+:)?)([^\\s:@?/]+)/([^\\s:@?/]+)$"); - public static final Pattern PATTERN_HEX_REFERENCE = Pattern.compile("^([?@])(0x[0-9a-f]{7,8})$"); -} diff --git a/src/ARSCLib/com/reandroid/arsc/group/EntryGroup.java b/src/ARSCLib/com/reandroid/arsc/group/EntryGroup.java deleted file mode 100755 index 97c1f152..00000000 --- a/src/ARSCLib/com/reandroid/arsc/group/EntryGroup.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.group; - -import com.reandroid.arsc.base.BlockArrayCreator; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.TypeBlock; -import com.reandroid.arsc.item.SpecString; -import com.reandroid.arsc.item.TypeString; -import com.reandroid.arsc.pool.SpecStringPool; -import com.reandroid.arsc.value.Entry; -import com.reandroid.arsc.value.ResConfig; - -import java.util.Iterator; - -public class EntryGroup extends ItemGroup { - private final int resourceId; - public EntryGroup(int resId) { - super(ARRAY_CREATOR, String.valueOf(resId)); - this.resourceId=resId; - } - public Entry getEntry(ResConfig resConfig){ - Entry[] items = getItems(); - if(items == null || resConfig == null){ - return null; - } - int length = items.length; - for(int i=0; i itr=iterator(skipNull); - while (itr.hasNext()){ - Entry entry =itr.next(); - if(entry.isDefault()){ - return entry; - } - } - return null; - } - public TypeString getTypeString(){ - Entry entry =pickOne(); - if(entry !=null){ - return entry.getTypeString(); - } - return null; - } - public SpecString getSpecString(){ - Entry entry =pickOne(); - if(entry !=null){ - return entry.getSpecString(); - } - return null; - } - public String getTypeName(){ - TypeString typeString=getTypeString(); - if(typeString==null){ - return null; - } - return typeString.get(); - } - public String getSpecName(){ - SpecString specString=getSpecString(); - if(specString==null){ - return null; - } - return specString.get(); - } - private SpecStringPool getSpecStringPool(){ - Entry entry =get(0); - if(entry ==null){ - return null; - } - TypeBlock typeBlock= entry.getTypeBlock(); - if(typeBlock==null){ - return null; - } - PackageBlock packageBlock=typeBlock.getPackageBlock(); - if(packageBlock==null){ - return null; - } - return packageBlock.getSpecStringPool(); - } - @Override - public int hashCode(){ - return resourceId; - } - @Override - public String toString(){ - Entry entry =pickOne(); - if(entry ==null){ - return super.toString(); - } - return super.toString()+"{"+ entry.toString()+"}"; - } - - private static final BlockArrayCreator ARRAY_CREATOR = new BlockArrayCreator(){ - @Override - public Entry newInstance() { - return new Entry(); - } - - @Override - public Entry[] newInstance(int len) { - return new Entry[len]; - } - }; - -} diff --git a/src/ARSCLib/com/reandroid/arsc/group/ItemGroup.java b/src/ARSCLib/com/reandroid/arsc/group/ItemGroup.java deleted file mode 100755 index 83b3ac9f..00000000 --- a/src/ARSCLib/com/reandroid/arsc/group/ItemGroup.java +++ /dev/null @@ -1,196 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.group; - -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.base.BlockArrayCreator; - -import java.util.AbstractList; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; - - public class ItemGroup { - private final BlockArrayCreator mBlockArrayCreator; - private final String name; - private T[] items; - public ItemGroup(BlockArrayCreator blockArrayCreator, String name){ - this.mBlockArrayCreator=blockArrayCreator; - this.name=name; - this.items=blockArrayCreator.newInstance(0); - } - public Iterator iterator(){ - return iterator(false); - } - public Iterator iterator(boolean skipNullBlock){ - return new GroupIterator(skipNullBlock); - } - public List listItems(){ - return new AbstractList() { - private final int mSize = ItemGroup.this.size(); - @Override - public T get(int i) { - return ItemGroup.this.get(i); - } - - @Override - public int size() { - return mSize; - } - }; - } - public T get(int i){ - if(i<0||i>= size()){ - return null; - } - return items[i]; - } - public int size(){ - if(items==null){ - return 0; - } - return items.length; - } - public boolean contains(T block){ - if(block==null){ - return false; - } - int len=items.length; - for(int i=0;i { - private int mCursor; - private final int mMaxSize; - private final boolean mSkipNullBlock; - GroupIterator(boolean skipNullBlock){ - mSkipNullBlock=skipNullBlock; - mCursor=0; - mMaxSize=ItemGroup.this.size(); - } - @Override - public boolean hasNext() { - checkCursor(); - return !isFinished(); - } - @Override - public T next() { - if(!isFinished()){ - T item=ItemGroup.this.get(mCursor); - mCursor++; - checkCursor(); - return item; - } - return null; - } - private boolean isFinished(){ - return mCursor>=mMaxSize; - } - private void checkCursor(){ - if(!mSkipNullBlock || isFinished()){ - return; - } - T item=ItemGroup.this.get(mCursor); - while (item==null||item.isNull()){ - mCursor++; - item=ItemGroup.this.get(mCursor); - if(mCursor>=mMaxSize){ - break; - } - } - } - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/group/StringGroup.java b/src/ARSCLib/com/reandroid/arsc/group/StringGroup.java deleted file mode 100755 index 73ccdbca..00000000 --- a/src/ARSCLib/com/reandroid/arsc/group/StringGroup.java +++ /dev/null @@ -1,25 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.group; - -import com.reandroid.arsc.base.BlockArrayCreator; -import com.reandroid.arsc.item.StringItem; - -public class StringGroup extends ItemGroup{ - public StringGroup(BlockArrayCreator blockArrayCreator, String name){ - super(blockArrayCreator, name); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/header/HeaderBlock.java b/src/ARSCLib/com/reandroid/arsc/header/HeaderBlock.java deleted file mode 100755 index fded9c44..00000000 --- a/src/ARSCLib/com/reandroid/arsc/header/HeaderBlock.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.header; - -import com.reandroid.arsc.base.BlockContainer; -import com.reandroid.arsc.chunk.ChunkType; -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.container.BlockList; -import com.reandroid.arsc.container.ExpandableBlockContainer; -import com.reandroid.arsc.io.BlockLoad; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.item.BlockItem; -import com.reandroid.arsc.item.ByteArray; -import com.reandroid.arsc.item.IntegerItem; -import com.reandroid.arsc.item.ShortItem; -import com.reandroid.arsc.util.HexBytesWriter; -import com.reandroid.arsc.util.HexUtil; - -import java.io.*; -import java.util.List; - -public class HeaderBlock extends ExpandableBlockContainer implements BlockLoad { - private final ShortItem mType; - private final ShortItem mHeaderSize; - private final IntegerItem mChunkSize; - private HeaderLoaded mHeaderLoaded; - private final ByteArray extraBytes; - public HeaderBlock(short type){ - super(3); - this.mType=new ShortItem(type); - this.mHeaderSize=new ShortItem(); - this.mChunkSize=new IntegerItem(); - this.extraBytes=new ByteArray(); - addChild(mType); - addChild(mHeaderSize); - addChild(mChunkSize); - this.mType.setBlockLoad(this); - this.mHeaderSize.setBlockLoad(this); - this.mChunkSize.setBlockLoad(this); - } - public HeaderBlock(ChunkType chunkType){ - this(chunkType.ID); - } - public int getMinimumSize(){ - return countBytes(); - } - public ByteArray getExtraBytes() { - return extraBytes; - } - public void setHeaderLoaded(HeaderLoaded headerLoaded){ - this.mHeaderLoaded=headerLoaded; - } - public ChunkType getChunkType(){ - return ChunkType.get(mType.get()); - } - public short getType(){ - return mType.get(); - } - public void setType(ChunkType chunkType){ - short type; - if(chunkType==null){ - type=0; - }else { - type=chunkType.ID; - } - setType(type); - } - public void setType(short type){ - mType.set(type); - } - - public int getHeaderSize(){ - return mHeaderSize.unsignedInt(); - } - public void setHeaderSize(short headerSize){ - mHeaderSize.set(headerSize); - } - public int getChunkSize(){ - return mChunkSize.get(); - } - public void setChunkSize(int chunkSize){ - mChunkSize.set(chunkSize); - } - - public final void refreshHeader(){ - refreshHeaderSize(); - refreshChunkSize(); - } - private void refreshHeaderSize(){ - setHeaderSize((short)countBytes()); - } - private void refreshChunkSize(){ - Block parent=getParent(); - if(parent==null){ - return; - } - int count=parent.countBytes(); - setChunkSize(count); - } - /**Non buffering reader*/ - public int readBytes(InputStream inputStream) throws IOException{ - int result = onReadBytes(inputStream); - super.notifyBlockLoad(); - return result; - } - private int onReadBytes(InputStream inputStream) throws IOException { - int readCount = readBytes(inputStream, this); - int difference = getHeaderSize() - readCount; - initExtraBytes(this.extraBytes, difference); - if(this.extraBytes.size()>0){ - readCount += extraBytes.readBytes(inputStream); - } - return readCount; - } - private int readBytes(InputStream inputStream, Block block) throws IOException{ - int result=0; - if(block instanceof BlockItem){ - result = ((BlockItem)block).readBytes(inputStream); - }else if(block instanceof BlockList){ - List childes= - ((BlockList) block).getChildes(); - for(Block child:childes){ - result+=readBytes(inputStream, child); - } - }else if(block instanceof BlockContainer){ - Block[] childes = - ((BlockContainer) block).getChildes(); - for(Block child:childes){ - result+=readBytes(inputStream, child); - } - }else { - throw new IOException("Can not read block type: "+block.getClass()); - } - return result; - } - @Override - public void onReadBytes(BlockReader reader) throws IOException { - int start=reader.getPosition(); - super.onReadBytes(reader); - int readActual=reader.getPosition() - start; - int difference=getHeaderSize()-readActual; - initExtraBytes(this.extraBytes, difference); - if(this.extraBytes.size()>0){ - this.extraBytes.readBytes(reader); - } - } - @Override - public void onBlockLoaded(BlockReader reader, Block sender) throws IOException { - if(sender==this.mType){ - onChunkTypeLoaded(mType.get()); - }else if(sender==this.mHeaderSize){ - onHeaderSizeLoaded(mHeaderSize.unsignedInt()); - }else if(sender==this.mChunkSize){ - onChunkSizeLoaded(mHeaderSize.unsignedInt(), - mChunkSize.get()); - } - } - - @Override - protected void onRefreshed() { - // Not required, the parent should call refreshHeader() - } - @Override - protected void refreshChildes(){ - // Not required - } - void initExtraBytes(ByteArray extraBytes, int difference){ - if(difference==0){ - return; - } - if(extraBytes.getParent()==null){ - addChild(extraBytes); - } - extraBytes.setSize(difference); - } - void onChunkTypeLoaded(short chunkType){ - HeaderLoaded headerLoaded = mHeaderLoaded; - if(headerLoaded!=null){ - headerLoaded.onChunkTypeLoaded(chunkType); - } - } - void onHeaderSizeLoaded(int size){ - HeaderLoaded headerLoaded = mHeaderLoaded; - if(headerLoaded!=null){ - headerLoaded.onHeaderSizeLoaded(size); - } - } - void onChunkSizeLoaded(int headerSize, int chunkSize){ - HeaderLoaded headerLoaded = mHeaderLoaded; - if(headerLoaded!=null){ - headerLoaded.onChunkSizeLoaded(headerSize, chunkSize); - } - } - /** - * Prints bytes in hex for debug/testing - * */ - public String toHex(){ - return HexBytesWriter.toHex(getBytes()); - } - @Override - public String toString(){ - short t = getType(); - ChunkType type = ChunkType.get(t); - StringBuilder builder = new StringBuilder(); - if(type!=null){ - builder.append(type.toString()); - }else { - builder.append("Unknown type="); - builder.append(HexUtil.toHex4(t)); - } - builder.append("{ValueHeader="); - builder.append(getHeaderSize()); - builder.append(", Chunk="); - builder.append(getChunkSize()); - builder.append("}"); - return builder.toString(); - } - - public interface HeaderLoaded{ - void onChunkTypeLoaded(short type); - void onHeaderSizeLoaded(int headerSize); - void onChunkSizeLoaded(int headerSize, int chunkSize); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/header/InfoHeader.java b/src/ARSCLib/com/reandroid/arsc/header/InfoHeader.java deleted file mode 100644 index 0a5efe80..00000000 --- a/src/ARSCLib/com/reandroid/arsc/header/InfoHeader.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.header; - -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.item.ByteArray; -import com.reandroid.common.FileChannelInputStream; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; - -public class InfoHeader extends HeaderBlock{ - public InfoHeader(short type) { - super(type); - } - public InfoHeader() { - this((short) 0); - } - - @Override - public int getMinimumSize(){ - return INFO_MIN_SIZE; - } - - @Override - void initExtraBytes(ByteArray extraBytes, int difference){ - } - @Override - public int countBytes() { - return 8; - } - - - public static InfoHeader readHeaderBlock(File file) throws IOException { - return readHeaderBlock(FileChannelInputStream.read(file, INFO_MIN_SIZE)); - } - public static InfoHeader readHeaderBlock(InputStream inputStream) throws IOException { - InfoHeader infoHeader=new InfoHeader(); - infoHeader.readBytes(inputStream); - return infoHeader; - } - public static InfoHeader readHeaderBlock(BlockReader blockReader) throws IOException { - InfoHeader infoHeader=new InfoHeader(); - infoHeader.readBytes(blockReader); - return infoHeader; - } - public static InfoHeader readHeaderBlock(byte[] bytes) throws IOException { - BlockReader reader = new BlockReader(bytes); - InfoHeader infoHeader = new InfoHeader(); - infoHeader.readBytes(reader); - return infoHeader; - } - - public static final int INFO_MIN_SIZE = 8; -} diff --git a/src/ARSCLib/com/reandroid/arsc/header/LibraryHeader.java b/src/ARSCLib/com/reandroid/arsc/header/LibraryHeader.java deleted file mode 100644 index 1bf03a16..00000000 --- a/src/ARSCLib/com/reandroid/arsc/header/LibraryHeader.java +++ /dev/null @@ -1,41 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.header; - -import com.reandroid.arsc.chunk.ChunkType; -import com.reandroid.arsc.item.IntegerItem; - -public class LibraryHeader extends HeaderBlock{ - private final IntegerItem count; - public LibraryHeader() { - super(ChunkType.LIBRARY.ID); - this.count = new IntegerItem(); - - addChild(this.count); - } - - public IntegerItem getCount() { - return count; - } - @Override - public String toString(){ - if(getChunkType()!=ChunkType.LIBRARY){ - return super.toString(); - } - return getClass().getSimpleName() - +" {count="+getCount() + '}'; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/header/OverlayableHeader.java b/src/ARSCLib/com/reandroid/arsc/header/OverlayableHeader.java deleted file mode 100644 index 6292ab5e..00000000 --- a/src/ARSCLib/com/reandroid/arsc/header/OverlayableHeader.java +++ /dev/null @@ -1,49 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.header; - -import com.reandroid.arsc.chunk.ChunkType; -import com.reandroid.arsc.item.FixedLengthString; - -public class OverlayableHeader extends HeaderBlock{ - private final FixedLengthString name; - private final FixedLengthString actor; - public OverlayableHeader() { - super(ChunkType.OVERLAYABLE.ID); - this.name = new FixedLengthString(512); - this.actor = new FixedLengthString(512); - - addChild(this.name); - addChild(this.actor); - } - - public FixedLengthString getName() { - return name; - } - public FixedLengthString getActor() { - return actor; - } - - @Override - public String toString(){ - if(getChunkType()!=ChunkType.OVERLAYABLE){ - return super.toString(); - } - return getClass().getSimpleName() - +" {count="+getName() - +", actor=" + getActor() + '}'; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/header/OverlayablePolicyHeader.java b/src/ARSCLib/com/reandroid/arsc/header/OverlayablePolicyHeader.java deleted file mode 100644 index e6c9316b..00000000 --- a/src/ARSCLib/com/reandroid/arsc/header/OverlayablePolicyHeader.java +++ /dev/null @@ -1,47 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.header; - -import com.reandroid.arsc.chunk.ChunkType; -import com.reandroid.arsc.item.IntegerItem; - -public class OverlayablePolicyHeader extends HeaderBlock{ - private final IntegerItem flags; - private final IntegerItem entryCount; - public OverlayablePolicyHeader() { - super(ChunkType.OVERLAYABLE_POLICY.ID); - this.flags = new IntegerItem(); - this.entryCount = new IntegerItem(); - - addChild(this.flags); - addChild(this.entryCount); - } - public IntegerItem getFlags() { - return flags; - } - public IntegerItem getEntryCount() { - return entryCount; - } - @Override - public String toString(){ - if(getChunkType()!=ChunkType.OVERLAYABLE_POLICY){ - return super.toString(); - } - return getClass().getSimpleName() - +" {flags="+getFlags().toHex() - +", entryCount=" + getEntryCount() + '}'; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/header/PackageHeader.java b/src/ARSCLib/com/reandroid/arsc/header/PackageHeader.java deleted file mode 100644 index 8094e66e..00000000 --- a/src/ARSCLib/com/reandroid/arsc/header/PackageHeader.java +++ /dev/null @@ -1,96 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.header; - -import com.reandroid.arsc.chunk.ChunkType; -import com.reandroid.arsc.container.SingleBlockContainer; -import com.reandroid.arsc.item.FixedLengthString; -import com.reandroid.arsc.item.IntegerItem; - -public class PackageHeader extends HeaderBlock{ - private final IntegerItem packageId; - private final FixedLengthString packageName; - - private final IntegerItem typeStringPoolOffset; - private final IntegerItem typeStringPoolCount; - private final IntegerItem specStringPoolOffset; - private final IntegerItem specStringPoolCount; - private final SingleBlockContainer typeIdOffsetContainer; - private final IntegerItem typeIdOffset; - - public PackageHeader() { - super(ChunkType.PACKAGE.ID); - this.packageId = new IntegerItem(); - this.packageName = new FixedLengthString(256); - - this.typeStringPoolOffset = new IntegerItem(); - this.typeStringPoolCount = new IntegerItem(); - this.specStringPoolOffset = new IntegerItem(); - this.specStringPoolCount = new IntegerItem(); - - this.typeIdOffsetContainer = new SingleBlockContainer<>(); - this.typeIdOffset = new IntegerItem(); - this.typeIdOffsetContainer.setItem(typeIdOffset); - - addChild(this.packageId); - addChild(this.packageName); - addChild(this.typeStringPoolOffset); - addChild(this.typeStringPoolCount); - addChild(this.specStringPoolOffset); - addChild(this.specStringPoolCount); - addChild(this.typeIdOffsetContainer); - } - - public IntegerItem getPackageId() { - return packageId; - } - public FixedLengthString getPackageName() { - return packageName; - } - public IntegerItem getTypeStringPoolOffset() { - return typeStringPoolOffset; - } - public IntegerItem getTypeStringPoolCount() { - return typeStringPoolCount; - } - public IntegerItem getSpecStringPoolOffset() { - return specStringPoolOffset; - } - public IntegerItem getSpecStringPoolCount() { - return specStringPoolCount; - } - public IntegerItem getTypeIdOffsetItem() { - return typeIdOffset; - } - public void setTypeIdOffset(int offset){ - typeIdOffset.set(offset); - typeIdOffsetContainer.setItem(typeIdOffset); - } - public int getTypeIdOffset() { - if(typeIdOffset.getParent()==null){ - typeIdOffset.set(0); - } - return typeIdOffset.get(); - } - @Override - void onHeaderSizeLoaded(int size){ - super.onHeaderSizeLoaded(size); - if(size<288){ - typeIdOffset.set(0); - typeIdOffsetContainer.setItem(null); - } - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/header/SpecHeader.java b/src/ARSCLib/com/reandroid/arsc/header/SpecHeader.java deleted file mode 100644 index d1135491..00000000 --- a/src/ARSCLib/com/reandroid/arsc/header/SpecHeader.java +++ /dev/null @@ -1,52 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.header; - -import com.reandroid.arsc.chunk.ChunkType; -import com.reandroid.arsc.item.ByteItem; -import com.reandroid.arsc.item.IntegerItem; -import com.reandroid.arsc.item.ShortItem; - -public class SpecHeader extends HeaderBlock{ - private final ByteItem id; - private final IntegerItem entryCount; - public SpecHeader() { - super(ChunkType.SPEC.ID); - this.id = new ByteItem(); - ByteItem res0 = new ByteItem(); - ShortItem res1 = new ShortItem(); - this.entryCount = new IntegerItem(); - addChild(id); - addChild(res0); - addChild(res1); - addChild(entryCount); - } - public ByteItem getId() { - return id; - } - public IntegerItem getEntryCount() { - return entryCount; - } - @Override - public String toString(){ - if(getChunkType() != ChunkType.SPEC){ - return super.toString(); - } - return getClass().getSimpleName() - +" {id="+getId().toHex() - +", entryCount=" + getEntryCount() + '}'; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/header/StagedAliasHeader.java b/src/ARSCLib/com/reandroid/arsc/header/StagedAliasHeader.java deleted file mode 100644 index 38996da6..00000000 --- a/src/ARSCLib/com/reandroid/arsc/header/StagedAliasHeader.java +++ /dev/null @@ -1,41 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.header; - -import com.reandroid.arsc.chunk.ChunkType; -import com.reandroid.arsc.item.IntegerItem; - -public class StagedAliasHeader extends HeaderBlock{ - private final IntegerItem count; - public StagedAliasHeader() { - super(ChunkType.STAGED_ALIAS.ID); - this.count = new IntegerItem(); - - addChild(count); - } - - public IntegerItem getCount() { - return count; - } - @Override - public String toString(){ - if(getChunkType()!=ChunkType.STAGED_ALIAS){ - return super.toString(); - } - return getClass().getSimpleName() - +" {count="+getCount()+ '}'; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/header/StringPoolHeader.java b/src/ARSCLib/com/reandroid/arsc/header/StringPoolHeader.java deleted file mode 100644 index 09c41f60..00000000 --- a/src/ARSCLib/com/reandroid/arsc/header/StringPoolHeader.java +++ /dev/null @@ -1,99 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.header; - -import com.reandroid.arsc.chunk.ChunkType; -import com.reandroid.arsc.item.ByteItem; -import com.reandroid.arsc.item.IntegerItem; -import com.reandroid.arsc.item.ShortItem; - - -public class StringPoolHeader extends HeaderBlock{ - private final IntegerItem countStrings; - private final IntegerItem countStyles; - private final ByteItem flagSorted; - private final ByteItem flagUtf8; - private final ShortItem flagExtra; - private final IntegerItem startStrings; - private final IntegerItem startStyles; - public StringPoolHeader() { - super(ChunkType.STRING.ID); - this.countStrings = new IntegerItem(); - this.countStyles = new IntegerItem(); - this.flagSorted = new ByteItem(); - this.flagUtf8 = new ByteItem(); - this.flagExtra = new ShortItem(); - this.startStrings = new IntegerItem(); - this.startStyles = new IntegerItem(); - - addChild(countStrings); - addChild(countStyles); - addChild(flagSorted); - addChild(flagUtf8); - addChild(flagExtra); - addChild(startStrings); - addChild(startStyles); - } - public IntegerItem getCountStrings() { - return countStrings; - } - public IntegerItem getCountStyles() { - return countStyles; - } - public ByteItem getFlagUtf8() { - return flagUtf8; - } - public ByteItem getFlagSorted() { - return flagSorted; - } - public ShortItem getFlagExtra(){ - return flagExtra; - } - public IntegerItem getStartStrings() { - return startStrings; - } - public IntegerItem getStartStyles() { - return startStyles; - } - - public boolean isUtf8(){ - return (getFlagUtf8().get() & 0x01) !=0; - } - public void setUtf8(boolean utf8){ - getFlagUtf8().set((byte) (utf8 ? 0x01 : 0x00)); - } - public boolean isSorted(){ - return (getFlagSorted().get() & 0x01) !=0; - } - public void setSorted(boolean sorted){ - getFlagSorted().set((byte) (sorted ? 0x01 : 0x00)); - } - - @Override - public String toString(){ - if(getChunkType()!=ChunkType.STRING){ - return super.toString(); - } - return getClass().getSimpleName() - +" {strings="+getCountStrings() - +", styles="+getCountStyles() - +", utf8="+isUtf8() - +", sorted="+isSorted() - +", flagExtra="+getFlagExtra().toHex() - +", offset-strings="+getStartStrings().get() - +", offset-styles="+getStartStyles().get() + '}'; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/header/TableHeader.java b/src/ARSCLib/com/reandroid/arsc/header/TableHeader.java deleted file mode 100644 index 3a8aed78..00000000 --- a/src/ARSCLib/com/reandroid/arsc/header/TableHeader.java +++ /dev/null @@ -1,39 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.header; - -import com.reandroid.arsc.chunk.ChunkType; -import com.reandroid.arsc.item.IntegerItem; - -public class TableHeader extends HeaderBlock{ - private final IntegerItem packageCount; - public TableHeader() { - super(ChunkType.TABLE.ID); - this.packageCount = new IntegerItem(); - addChild(packageCount); - } - public IntegerItem getPackageCount() { - return packageCount; - } - @Override - public String toString(){ - if(getChunkType()!=ChunkType.TABLE){ - return super.toString(); - } - return getClass().getSimpleName() - +" {packageCount=" + getPackageCount() + '}'; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/header/TypeHeader.java b/src/ARSCLib/com/reandroid/arsc/header/TypeHeader.java deleted file mode 100644 index ed1f9d91..00000000 --- a/src/ARSCLib/com/reandroid/arsc/header/TypeHeader.java +++ /dev/null @@ -1,97 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.header; - -import com.reandroid.arsc.chunk.ChunkType; -import com.reandroid.arsc.item.ByteItem; -import com.reandroid.arsc.item.IntegerItem; -import com.reandroid.arsc.item.ShortItem; -import com.reandroid.arsc.value.ResConfig; - -public class TypeHeader extends HeaderBlock{ - private final ByteItem id; - private final ByteItem flags; - private final IntegerItem count; - private final IntegerItem entriesStart; - private final ResConfig config; - public TypeHeader(boolean sparse) { - super(ChunkType.TYPE.ID); - this.id = new ByteItem(); - this.flags = new ByteItem(); - ShortItem reserved = new ShortItem(); - this.count = new IntegerItem(); - this.entriesStart = new IntegerItem(); - this.config = new ResConfig(); - - addChild(id); - addChild(flags); - addChild(reserved); - addChild(count); - addChild(entriesStart); - addChild(config); - setSparse(sparse); - } - public boolean isSparse(){ - return (getFlags().get() & FLAG_SPARSE) == FLAG_SPARSE; - } - public void setSparse(boolean sparse){ - byte flag = getFlags().get(); - if(sparse){ - flag = (byte) (flag | FLAG_SPARSE); - }else { - flag = (byte) (flag & (~FLAG_SPARSE & 0xff)); - } - getFlags().set(flag); - } - - @Override - public int getMinimumSize(){ - return TYPE_MIN_SIZE; - } - public ByteItem getId() { - return id; - } - public ByteItem getFlags() { - return flags; - } - public IntegerItem getCount() { - return count; - } - public IntegerItem getEntriesStart() { - return entriesStart; - } - public ResConfig getConfig() { - return config; - } - - @Override - public String toString(){ - if(getChunkType()!=ChunkType.TYPE){ - return super.toString(); - } - return getClass().getSimpleName() - +" {id="+getId().toHex() - +", flags=" + getFlags().toHex() - +", count=" + getCount() - +", entriesStart=" + getEntriesStart() - +", config=" + getConfig() + '}'; - } - - private static final byte FLAG_SPARSE = 0x1; - - //typeHeader.countBytes() - getConfig().countBytes() + ResConfig.SIZE_16 - private static final int TYPE_MIN_SIZE = 36; -} diff --git a/src/ARSCLib/com/reandroid/arsc/header/XmlNodeHeader.java b/src/ARSCLib/com/reandroid/arsc/header/XmlNodeHeader.java deleted file mode 100644 index 1feba224..00000000 --- a/src/ARSCLib/com/reandroid/arsc/header/XmlNodeHeader.java +++ /dev/null @@ -1,49 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.header; - -import com.reandroid.arsc.chunk.ChunkType; -import com.reandroid.arsc.item.IntegerItem; - -public class XmlNodeHeader extends HeaderBlock{ - private final IntegerItem lineNumber; - private final IntegerItem commentReference; - private final ChunkType chunkType; - public XmlNodeHeader(ChunkType chunkType) { - super(chunkType.ID); - this.chunkType = chunkType; - this.lineNumber = new IntegerItem(); - this.commentReference = new IntegerItem(-1); - - addChild(lineNumber); - addChild(commentReference); - } - public IntegerItem getLineNumber() { - return lineNumber; - } - public IntegerItem getCommentReference() { - return commentReference; - } - @Override - public String toString(){ - if(getChunkType() != chunkType){ - return super.toString(); - } - return getClass().getSimpleName() - +" {lineNumber="+getLineNumber() - +", commentReference=" + getCommentReference() + '}'; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/io/BlockLoad.java b/src/ARSCLib/com/reandroid/arsc/io/BlockLoad.java deleted file mode 100755 index 7728ae91..00000000 --- a/src/ARSCLib/com/reandroid/arsc/io/BlockLoad.java +++ /dev/null @@ -1,24 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.io; - -import com.reandroid.arsc.base.Block; - -import java.io.IOException; - -public interface BlockLoad { - public void onBlockLoaded(BlockReader reader, Block sender) throws IOException; -} diff --git a/src/ARSCLib/com/reandroid/arsc/io/BlockReader.java b/src/ARSCLib/com/reandroid/arsc/io/BlockReader.java deleted file mode 100755 index d0fe59bc..00000000 --- a/src/ARSCLib/com/reandroid/arsc/io/BlockReader.java +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.io; - -import com.reandroid.arsc.header.InfoHeader; -import com.reandroid.arsc.header.SpecHeader; -import com.reandroid.arsc.header.TypeHeader; - -import java.io.*; - - -public class BlockReader extends InputStream { - private final Object mLock=new Object(); - private byte[] BUFFER; - private final int mStart; - private final int mLength; - private int mPosition; - private boolean mIsClosed; - private int mMark; - public BlockReader(byte[] buffer, int start, int length) { - this.BUFFER=buffer; - this.mStart=start; - this.mLength=length; - this.mPosition =0; - } - public BlockReader(byte[] buffer) { - this(buffer, 0, buffer.length); - } - public BlockReader(InputStream in) throws IOException { - this(loadBuffer(in)); - } - public BlockReader(InputStream in, int length) throws IOException { - this(loadBuffer(in, length)); - } - public BlockReader(File file) throws IOException { - this(loadBuffer(file)); - } - public int readUnsignedShort() throws IOException { - return 0x0000ffff & readShort(); - } - public short readShort() throws IOException { - int pos = getPosition(); - byte[] bts = new byte[2]; - readFully(bts); - seek(pos); - return toShort(bts, 0); - } - public SpecHeader readSpecHeader() throws IOException{ - SpecHeader specHeader = new SpecHeader(); - if(available() < specHeader.countBytes()){ - return null; - } - int pos = getPosition(); - specHeader.readBytes(this); - seek(pos); - return specHeader; - } - public TypeHeader readTypeHeader() throws IOException{ - TypeHeader typeHeader = new TypeHeader(false); - if(available() < typeHeader.getMinimumSize()){ - return null; - } - int pos = getPosition(); - typeHeader.readBytes(this); - seek(pos); - return typeHeader; - } - public InfoHeader readHeaderBlock() throws IOException { - InfoHeader infoHeader = new InfoHeader(); - if(available() < infoHeader.getMinimumSize()){ - return null; - } - int pos = getPosition(); - infoHeader.readBytes(this); - seek(pos); - return infoHeader; - } - public int searchNextIntPosition(int bytesOffset, int value){ - if(mIsClosed || mPosition>=mLength){ - return -1; - } - synchronized (mLock){ - int actPos=mStart+mPosition+bytesOffset; - int max=available()/4; - for(int i=0;i this.mLength){ - len = this.mLength - start; - } - start = start + this.mStart; - return new BlockReader(BUFFER, start, len); - } - public boolean isAvailable(){ - if(mIsClosed){ - return false; - } - return available()>0; - } - public void offset(int off){ - int pos=getPosition()+off; - seek(pos); - } - public void seek(int relPos){ - if(relPos<0){ - relPos=0; - }else if(relPos>length()){ - relPos=length(); - } - setPosition(relPos); - } - private void setPosition(int pos){ - if(pos==mPosition){ - return; - } - synchronized (mLock){ - mPosition=pos; - } - } - public int length(){ - return mLength; - } - public byte[] readBytes(int len) throws IOException { - byte[] result=new byte[len]; - if(len==0){ - return result; - } - int len2=read(result); - if(len2<0){ - throw new EOFException("Finished reading: "+ mPosition); - } - if(len==len2){ - return result; - } - byte[] result2=new byte[len2]; - System.arraycopy(result, 0, result2, 0, len2); - return result2; - } - public int readFully(byte[] bts) throws IOException{ - return readFully(bts, 0, bts.length); - } - public int readFully(byte[] bts, int length) throws IOException{ - if(length==0){ - return 0; - } - return readFully(bts, 0, length); - } - - public int readFully(byte[] bts, int start, int length) throws IOException { - if(length==0){ - return 0; - } - if(mIsClosed){ - throw new IOException("Stream is closed"); - } - if(mPosition>=mLength){ - throw new EOFException("Finished reading: "+mPosition); - } - int len=bts.length; - if(length=mLength){ - i++; - break; - } - } - return i; - } - } - public int getPosition(){ - return mPosition; - } - public int getActualPosition(){ - return mStart + mPosition; - } - public int getStartPosition(){ - return mStart; - } - @Override - public int read() throws IOException { - if(mIsClosed){ - throw new IOException("Stream is closed"); - } - int i=mPosition; - if(i>=mLength){ - throw new EOFException("Finished reading: "+i); - } - synchronized (mLock){ - int actPos=mStart+i; - int val=BUFFER[actPos] & 0xff; - mPosition++; - return val; - } - } - @Override - public void mark(int pos){ - mMark=pos; - } - @Override - public int available(){ - return mLength-mPosition; - } - @Override - public void reset() throws IOException{ - if(mIsClosed){ - throw new IOException("Can not reset stream is closed"); - } - mPosition=mMark; - } - @Override - public void close(){ - mIsClosed=true; - BUFFER=null; - mMark=0; - } - @Override - public String toString(){ - StringBuilder builder=new StringBuilder(); - builder.append(getClass().getSimpleName()); - builder.append(": "); - if(mIsClosed){ - builder.append("Closed"); - }else{ - int av=available(); - if(av==0){ - builder.append("Finished: "); - builder.append(getPosition()); - }else { - if(mStart>0){ - builder.append("START="); - builder.append(mStart); - builder.append(", ACTUAL="); - builder.append(getActualPosition()); - builder.append(", "); - } - builder.append("POS="); - builder.append(getPosition()); - builder.append(", available="); - builder.append(av); - } - } - return builder.toString(); - } - - - private static byte[] loadBuffer(File file) throws IOException { - FileInputStream in=new FileInputStream(file); - byte[] result = loadBuffer(in); - in.close(); - return result; - } - private static byte[] loadBuffer(InputStream in) throws IOException { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - byte[] buff=new byte[40960]; - int len; - while((len=in.read(buff))>0){ - outputStream.write(buff, 0, len); - } - if(in instanceof FileInputStream){ - in.close(); - } - outputStream.close(); - return outputStream.toByteArray(); - } - private static byte[] loadBuffer(InputStream in, int length) throws IOException { - byte[] buff=new byte[length]; - if(length==0){ - return buff; - } - int readLength = in.read(buff, 0, length); - if(readLength < length){ - throw new IOException("Read length is less than expected: length=" - +length+", read="+readLength); - } - return buff; - } - public static InfoHeader readHeaderBlock(File file) throws IOException{ - return InfoHeader.readHeaderBlock(file); - } - public static InfoHeader readHeaderBlock(InputStream inputStream) throws IOException{ - return InfoHeader.readHeaderBlock(inputStream); - } - public static InfoHeader readHeaderBlock(byte[] bytes) throws IOException{ - return InfoHeader.readHeaderBlock(bytes); - } - - private static final int MAX_FILE_SIZE = 1024 * 1000 * 40; -} diff --git a/src/ARSCLib/com/reandroid/arsc/item/BlockItem.java b/src/ARSCLib/com/reandroid/arsc/item/BlockItem.java deleted file mode 100755 index c34c07c6..00000000 --- a/src/ARSCLib/com/reandroid/arsc/item/BlockItem.java +++ /dev/null @@ -1,186 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.item; - -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.base.BlockCounter; -import com.reandroid.arsc.io.BlockReader; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -public abstract class BlockItem extends Block { - - private byte[] mBytes; - public BlockItem(int bytesLength){ - super(); - mBytes=new byte[bytesLength]; - } - protected void onBytesChanged(){ - } - protected byte[] getBytesInternal() { - return mBytes; - } - void setBytesInternal(byte[] bts){ - if(bts==null){ - bts=new byte[0]; - } - if(bts==mBytes){ - return; - } - mBytes=bts; - onBytesChanged(); - } - final void setBytesLength(int length){ - setBytesLength(length, true); - } - protected final void setBytesLength(int length, boolean notify){ - if(length<0){ - length=0; - } - int old=mBytes.length; - if(length==old){ - return; - } - byte[] bts=new byte[length]; - if(length0 && read>0){ - read = inputStream.read(bts, offset, length); - length-=read; - offset+=read; - } - onBytesChanged(); - super.notifyBlockLoad(); - return bts.length; - } - - protected static int getInteger(byte[] bts, int offset){ - if((offset+4)>bts.length){ - return 0; - } - return bts[offset] & 0xff | - (bts[offset+1] & 0xff) << 8 | - (bts[offset+2] & 0xff) << 16 | - (bts[offset+3] & 0xff) << 24; - } - protected static short getShort(byte[] bts, int offset){ - return (short) (bts[offset] & 0xff | (bts[offset+1] & 0xff) << 8); - } - protected static void putInteger(byte[] bts, int offset, int val){ - if((offset+4)>bts.length){ - return; - } - bts[offset+3]= (byte) (val >>> 24 & 0xff); - bts[offset+2]= (byte) (val >>> 16 & 0xff); - bts[offset+1]= (byte) (val >>> 8 & 0xff); - bts[offset]= (byte) (val & 0xff); - } - protected static void putShort(byte[] bts, int offset, short val){ - bts[offset+1]= (byte) (val >>> 8 & 0xff); - bts[offset]= (byte) (val & 0xff); - } - protected static boolean getBit(byte[] bts, int byteOffset, int bitIndex){ - return (((bts[byteOffset] & 0xff) >>bitIndex) & 0x1) == 1; - } - protected static void putBit(byte[] bytes, int byteOffset, int bitIndex, boolean bit){ - int mask = 1 << bitIndex; - int add = bit ? mask : 0; - mask = (~mask) & 0xff; - int value = (bytes[byteOffset] & mask) | add; - bytes[byteOffset] = (byte) value; - } - protected static long getLong(byte[] bytes, int offset){ - if((offset + 8)>bytes.length){ - return 0; - } - long result = 0; - int index = offset + 7; - while (index>=offset){ - result = result << 8; - result |= (bytes[index] & 0xff); - index --; - } - return result; - } - protected static void putLong(byte[] bytes, int offset, long value){ - if((offset + 8) > bytes.length){ - return; - } - int index = offset; - offset = index + 8; - while (index>> 8; - index++; - } - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/item/ByteArray.java b/src/ARSCLib/com/reandroid/arsc/item/ByteArray.java deleted file mode 100755 index 8b777a12..00000000 --- a/src/ARSCLib/com/reandroid/arsc/item/ByteArray.java +++ /dev/null @@ -1,235 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.item; - -import java.util.AbstractList; -import java.util.List; - -public class ByteArray extends BlockItem { - public ByteArray(int bytesLength) { - super(bytesLength); - } - public ByteArray() { - this(0); - } - public final void clear(){ - setSize(0); - } - public final void add(byte[] values){ - if(values==null || values.length==0){ - return; - } - int old=size(); - int len=values.length; - setBytesLength(old+len, false); - byte[] bts = getBytesInternal(); - System.arraycopy(values, 0, bts, old, len); - } - public final void set(byte[] values){ - super.setBytesInternal(values); - } - public final byte[] toArray(){ - return getBytes(); - } - public final void fill(byte value){ - byte[] bts=getBytesInternal(); - int max=bts.length; - for(int i=0;i=s){ - return; - } - setSize(s); - } - public final void setSize(int s){ - if(s<0){ - s=0; - } - setBytesLength(s); - } - public final int size(){ - return getBytesLength(); - } - public Byte get(int index){ - if(index<0 || index>=size()){ - return null; - } - return getBytesInternal()[index]; - } - public int getByteUnsigned(int index){ - Byte b = get(index); - if(b==null){ - return 0; - } - return 0xff & b; - } - public final void putByte(int index, int byteValue){ - put(index, (byte) byteValue); - } - public final void put(int index, byte value){ - byte[] bts = getBytesInternal(); - bts[index]=value; - } - public boolean getBit(int byteOffset, int bitIndex){ - return getBit(getBytesInternal(), byteOffset, bitIndex); - } - public void putBit(int byteOffset, int bitIndex, boolean bit){ - putBit(getBytesInternal(), byteOffset, bitIndex, bit); - } - public final void putShort(int offset, int value){ - putShort(offset, (short) value); - } - public final void putShort(int offset, short val){ - byte[] bts = getBytesInternal(); - bts[offset+1]= (byte) (val >>> 8 & 0xff); - bts[offset]= (byte) (val & 0xff); - } - public final int getShortUnsigned(int offset){ - return 0xffff & getShort(offset); - } - public final short getShort(int offset){ - byte[] bts = getBytesInternal(); - return (short) (bts[offset] & 0xff | (bts[offset+1] & 0xff) << 8); - } - public final void putInteger(int offset, int val){ - byte[] bts = getBytesInternal(); - if((offset+4)>bts.length){ - return; - } - bts[offset+3]= (byte) (val >>> 24 & 0xff); - bts[offset+2]= (byte) (val >>> 16 & 0xff); - bts[offset+1]= (byte) (val >>> 8 & 0xff); - bts[offset]= (byte) (val & 0xff); - } - public final int getInteger(int offset){ - byte[] bts = getBytesInternal(); - if((offset+4)>bts.length){ - return 0; - } - return bts[offset] & 0xff | - (bts[offset+1] & 0xff) << 8 | - (bts[offset+2] & 0xff) << 16 | - (bts[offset+3] & 0xff) << 24; - } - public final void putByteArray(int offset, byte[] val){ - byte[] bts = getBytesInternal(); - int avail = bts.length-offset; - if(avail<=0){ - return; - } - int len = val.length; - if(len>avail){ - len=avail; - } - System.arraycopy(val, 0, bts, offset, len); - } - public final byte[] getByteArray(int offset, int length){ - byte[] bts = getBytesInternal(); - byte[] result = new byte[length]; - if (result.length >= 0) { - System.arraycopy(bts, offset, result, 0, result.length); - } - return result; - } - - public final List toByteList(){ - return new AbstractList() { - @Override - public Byte get(int i) { - return ByteArray.this.get(i); - } - @Override - public int size() { - return ByteArray.this.size(); - } - }; - } - public final List toShortList(){ - return new AbstractList() { - @Override - public Short get(int i) { - return ByteArray.this.getShort(i); - } - @Override - public int size() { - return ByteArray.this.size()/2; - } - }; - } - public final List toIntegerList(){ - return new AbstractList() { - @Override - public Integer get(int i) { - return ByteArray.this.getInteger(i); - } - @Override - public int size() { - return ByteArray.this.size()/4; - } - }; - } - @Override - public String toString(){ - return "size="+size(); - } - - public static byte[] trimTrailZeros(byte[] bts){ - if(bts==null){ - return new byte[0]; - } - int len=0; - for(int i=0;i0){ - System.arraycopy(bts, 0, result, 0, result.length); - } - return result; - } - public static boolean equals(byte[] bts1, byte[] bts2){ - if(bts1==bts2){ - return true; - } - if(bts1==null || bts1.length==0){ - return bts2==null || bts2.length==0; - } - if(bts2==null || bts2.length==0){ - return false; - } - if(bts1.length!=bts2.length){ - return false; - } - for(int i=0;i>index) & 0x1) == 1; - } - public void putBit(int index, boolean bit){ - int val=get(); - int left=val>>index; - if(bit){ - left=left|0x1; - }else { - left=left & 0xFE; - } - left=left<>index) & val; - val=left|right; - set((byte) val); - } - public void set(byte b){ - getBytesInternal()[0]=b; - } - public byte get(){ - return getBytesInternal()[0]; - } - public int unsignedInt(){ - return 0xff & get(); - } - public String toHex(){ - return HexUtil.toHex2(get()); - } - @Override - public String toString(){ - return String.valueOf(get()); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/item/FixedLengthString.java b/src/ARSCLib/com/reandroid/arsc/item/FixedLengthString.java deleted file mode 100644 index 172197dd..00000000 --- a/src/ARSCLib/com/reandroid/arsc/item/FixedLengthString.java +++ /dev/null @@ -1,85 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ - package com.reandroid.arsc.item; - - import com.reandroid.arsc.io.BlockReader; - - import java.nio.charset.StandardCharsets; - - public class FixedLengthString extends StringItem{ - private final int bytesLength; - public FixedLengthString(int bytesLength){ - super(true); - this.bytesLength=bytesLength; - setBytesLength(bytesLength); - } - @Override - byte[] encodeString(String str){ - if(str==null){ - return new byte[bytesLength]; - } - byte[] bts=getUtf16Bytes(str); - byte[] results=new byte[bytesLength]; - int len=bts.length; - if(len>bytesLength){ - len=bytesLength; - } - System.arraycopy(bts, 0, results, 0, len); - return results; - } - @Override - String decodeString(){ - return decodeUtf16Bytes(getBytesInternal()); - } - @Override - public StyleItem getStyle(){ - return null; - } - @Override - int calculateReadLength(BlockReader reader){ - return bytesLength; - } - private static String decodeUtf16Bytes(byte[] bts){ - if(isNullBytes(bts)){ - return null; - } - int len=getEndNullPosition(bts); - return new String(bts,0, len, StandardCharsets.UTF_16LE); - } - private static int getEndNullPosition(byte[] bts){ - int max=bts.length; - int result=0; - boolean found=false; - for(int i=1; i { - private final T blockItem; - private final int offset; - public IndirectItem(T blockItem, int offset){ - this.blockItem = blockItem; - this.offset = offset; - } - public T getBlockItem() { - return blockItem; - } - public int getOffset() { - return offset; - } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - IndirectItem other = (IndirectItem) obj; - return this.getOffset() == other.getOffset() && this.getBlockItem() == other.getBlockItem(); - } - @Override - public int hashCode(){ - return Objects.hash(this.getOffset(), this.getBlockItem()); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/item/IntegerArray.java b/src/ARSCLib/com/reandroid/arsc/item/IntegerArray.java deleted file mode 100755 index b9e1fd8b..00000000 --- a/src/ARSCLib/com/reandroid/arsc/item/IntegerArray.java +++ /dev/null @@ -1,139 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.item; - - -import java.util.AbstractList; -import java.util.List; - -public class IntegerArray extends BlockItem { - public IntegerArray() { - super(0); - } - public final boolean contains(int value){ - int s=size(); - for(int i=0;i toList(){ - return new AbstractList() { - @Override - public Integer get(int i) { - return IntegerArray.this.get(i); - } - @Override - public int size() { - return IntegerArray.this.size(); - } - }; - } - public final int[] toArray(){ - int s=size(); - int[] result=new int[s]; - for(int i=0;i=s){ - return; - } - setSize(s); - } - public final void setSize(int s){ - if(s<0){ - s=0; - } - int len=s*4; - setBytesLength(len); - } - public Integer get(int index){ - if(index<0 || index>=size()){ - return null; - } - int i=index*4; - byte[] bts = getBytesInternal(); - return bts[i] & 0xff | - (bts[i+1] & 0xff) << 8 | - (bts[i+2] & 0xff) << 16 | - (bts[i+3] & 0xff) << 24; - } - public int getAt(int index){ - int i=index*4; - byte[] bts = getBytesInternal(); - return bts[i] & 0xff | - (bts[i+1] & 0xff) << 8 | - (bts[i+2] & 0xff) << 16 | - (bts[i+3] & 0xff) << 24; - } - public final int size(){ - return getBytesLength()/4; - } - public final void put(int index, int value){ - int i=index*4; - byte[] bts = getBytesInternal(); - bts[i+3]= (byte) (value >>> 24 & 0xff); - bts[i+2]= (byte) (value >>> 16 & 0xff); - bts[i+1]= (byte) (value >>> 8 & 0xff); - bts[i]= (byte) (value & 0xff); - } - @Override - public String toString(){ - return "size="+size(); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/item/IntegerItem.java b/src/ARSCLib/com/reandroid/arsc/item/IntegerItem.java deleted file mode 100755 index cb3c45a9..00000000 --- a/src/ARSCLib/com/reandroid/arsc/item/IntegerItem.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.item; - -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.util.HexUtil; - -import java.io.IOException; -import java.io.InputStream; - -public class IntegerItem extends BlockItem implements ReferenceItem{ - private int mCache; - public IntegerItem(){ - super(4); - } - public IntegerItem(int val){ - this(); - set(val); - } - @Override - public void set(int val){ - if(val==mCache){ - return; - } - mCache=val; - byte[] bts = getBytesInternal(); - bts[3]= (byte) (val >>> 24 & 0xff); - bts[2]= (byte) (val >>> 16 & 0xff); - bts[1]= (byte) (val >>> 8 & 0xff); - bts[0]= (byte) (val & 0xff); - } - @Override - public int get(){ - return mCache; - } - public long unsignedLong(){ - return get() & 0x00000000ffffffffL; - } - public String toHex(){ - return HexUtil.toHex8(get()); - } - @Override - protected void onBytesChanged() { - // To save cpu usage, better to calculate once only when bytes changed - mCache=readIntBytes(); - } - private int readIntBytes(){ - byte[] bts = getBytesInternal(); - return bts[0] & 0xff | - (bts[1] & 0xff) << 8 | - (bts[2] & 0xff) << 16 | - (bts[3] & 0xff) << 24; - } - @Override - public String toString(){ - return String.valueOf(get()); - } - - public static int readInteger(BlockReader reader) throws IOException { - IntegerItem integerItem = new IntegerItem(); - integerItem.readBytes(reader); - return integerItem.get(); - } - public static int readInteger(InputStream inputStream) throws IOException { - IntegerItem integerItem = new IntegerItem(); - integerItem.readBytes(inputStream); - return integerItem.get(); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/item/LongItem.java b/src/ARSCLib/com/reandroid/arsc/item/LongItem.java deleted file mode 100644 index 7ca372b1..00000000 --- a/src/ARSCLib/com/reandroid/arsc/item/LongItem.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.item; - -import com.reandroid.arsc.util.HexUtil; - -public class LongItem extends BlockItem{ - private long mCache; - public LongItem() { - super(8); - } - public void set(long value){ - if(value == mCache){ - return; - } - mCache = value; - putLong(getBytesInternal(), 0, value); - } - public long get(){ - return mCache; - } - public String toHex(){ - return HexUtil.toHex(get(), 16); - } - - @Override - protected void onBytesChanged() { - mCache = getLong(getBytesInternal(), 0); - } - @Override - public String toString(){ - return String.valueOf(get()); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/item/ReferenceBlock.java b/src/ARSCLib/com/reandroid/arsc/item/ReferenceBlock.java deleted file mode 100644 index 9a1302f2..00000000 --- a/src/ARSCLib/com/reandroid/arsc/item/ReferenceBlock.java +++ /dev/null @@ -1,42 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.item; - -import com.reandroid.arsc.base.Block; - -public class ReferenceBlock implements ReferenceItem{ - private final T block; - private final int offset; - public ReferenceBlock(T block, int offset){ - this.block = block; - this.offset = offset; - } - public T getBlock(){ - return this.block; - } - @Override - public void set(int val) { - BlockItem.putInteger(this.block.getBytes(), this.offset, val); - } - @Override - public int get() { - return BlockItem.getInteger(this.block.getBytes(), this.offset); - } - @Override - public String toString(){ - return get()+":"+this.block; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/item/ReferenceItem.java b/src/ARSCLib/com/reandroid/arsc/item/ReferenceItem.java deleted file mode 100755 index f3b40510..00000000 --- a/src/ARSCLib/com/reandroid/arsc/item/ReferenceItem.java +++ /dev/null @@ -1,21 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.item; - -public interface ReferenceItem { - void set(int val); - int get(); -} diff --git a/src/ARSCLib/com/reandroid/arsc/item/ResXmlID.java b/src/ARSCLib/com/reandroid/arsc/item/ResXmlID.java deleted file mode 100755 index 3535ec0d..00000000 --- a/src/ARSCLib/com/reandroid/arsc/item/ResXmlID.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.item; - -import com.reandroid.arsc.chunk.xml.ResXmlDocument; -import com.reandroid.arsc.pool.ResXmlStringPool; -import com.reandroid.arsc.util.HexUtil; - -import java.util.ArrayList; -import java.util.List; - -public class ResXmlID extends IntegerItem { - private final List mReferencedList; - public ResXmlID(int resId){ - super(resId); - this.mReferencedList=new ArrayList<>(); - } - public ResXmlID(){ - this(0); - } - public boolean removeReference(ReferenceItem ref){ - return mReferencedList.remove(ref); - } - public List getReferencedList(){ - return mReferencedList; - } - public void addReference(ReferenceItem ref){ - if(ref!=null){ - mReferencedList.add(ref); - } - } - public boolean hasReference(){ - return mReferencedList.size()>0; - } - public int getReferenceCount(){ - return mReferencedList.size(); - } - private void reUpdateReferences(int newIndex){ - for(ReferenceItem ref:mReferencedList){ - ref.set(newIndex); - } - } - @Override - public void onIndexChanged(int oldIndex, int newIndex){ - //TODO: We have to ignore this to avoid conflict with ResXmlIDMap.removeSafely - } - public String getName(){ - ResXmlString xmlString = getResXmlString(); - if(xmlString==null){ - return null; - } - return xmlString.getHtml(); - } - public ResXmlString getResXmlString(){ - ResXmlStringPool stringPool=getXmlStringPool(); - if(stringPool==null){ - return null; - } - return stringPool.get(getIndex()); - } - private ResXmlStringPool getXmlStringPool(){ - ResXmlDocument resXmlDocument = getParentInstance(ResXmlDocument.class); - if(resXmlDocument!=null){ - return resXmlDocument.getStringPool(); - } - return null; - } - @Override - public String toString(){ - StringBuilder builder = new StringBuilder(); - builder.append("USED-BY="); - builder.append(getReferenceCount()); - builder.append('{'); - String name = getName(); - if(name!=null){ - builder.append(name); - }else { - builder.append(getIndex()); - } - builder.append(':'); - builder.append(HexUtil.toHex8(get())); - builder.append('}'); - return builder.toString(); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/item/ResXmlString.java b/src/ARSCLib/com/reandroid/arsc/item/ResXmlString.java deleted file mode 100755 index 3cacfb84..00000000 --- a/src/ARSCLib/com/reandroid/arsc/item/ResXmlString.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.item; - -public class ResXmlString extends StringItem { - public ResXmlString(boolean utf8) { - super(utf8); - } - public ResXmlString(boolean utf8, String value) { - this(utf8); - set(value); - } - @Override - void ensureStringLinkUnlocked(){ - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/item/ShortItem.java b/src/ARSCLib/com/reandroid/arsc/item/ShortItem.java deleted file mode 100755 index 15addb4f..00000000 --- a/src/ARSCLib/com/reandroid/arsc/item/ShortItem.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.item; - -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.util.HexUtil; - -import java.io.IOException; -import java.io.InputStream; - -public class ShortItem extends BlockItem { - private short mCache; - - public ShortItem(){ - super(2); - } - public ShortItem(short val){ - this(); - set(val); - } - public void set(short val){ - if(val==mCache){ - return; - } - mCache=val; - byte[] bts = getBytesInternal(); - bts[1]= (byte) (val >>> 8 & 0xff); - bts[0]= (byte) (val & 0xff); - } - public short get(){ - return mCache; - } - public int unsignedInt(){ - return 0xffff & get(); - } - public String toHex(){ - return HexUtil.toHex4(get()); - } - @Override - protected void onBytesChanged() { - // To save cpu usage, better to calculate once only when bytes changed - mCache=readShortBytes(); - } - private short readShortBytes(){ - byte[] bts = getBytesInternal(); - return (short) (bts[0] & 0xff | (bts[1] & 0xff) << 8); - } - @Override - public String toString(){ - return String.valueOf(get()); - } - - public static short readShort(BlockReader reader) throws IOException { - ShortItem shortItem = new ShortItem(); - shortItem.readBytes(reader); - return shortItem.get(); - } - public static short readShort(InputStream inputStream) throws IOException { - ShortItem shortItem = new ShortItem(); - shortItem.readBytes(inputStream); - return shortItem.get(); - } - public static int readUnsignedShort(BlockReader reader) throws IOException { - return 0x0000ffff & readShort(reader); - } - public static int readUnsignedShort(InputStream inputStream) throws IOException { - return 0x0000ffff & readShort(inputStream); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/item/SpecFlag.java b/src/ARSCLib/com/reandroid/arsc/item/SpecFlag.java deleted file mode 100644 index 7808b059..00000000 --- a/src/ARSCLib/com/reandroid/arsc/item/SpecFlag.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.item; - -import com.reandroid.arsc.chunk.SpecBlock; -import com.reandroid.arsc.util.HexUtil; - -public class SpecFlag extends IndirectItem { - public SpecFlag(SpecFlagsArray specFlagsArray, int offset) { - super(specFlagsArray, offset); - } - public byte getFlagByte(){ - return getBlockItem().getBytesInternal()[getOffset() + OFFSET_FLAG]; - } - public void setFlagByte(byte flag){ - getBlockItem().getBytesInternal()[getOffset() + OFFSET_FLAG] = flag; - } - public void addFlagByte(byte flag){ - flag = (byte) ((getFlagByte() & 0xff) | (flag & 0xff)); - setFlagByte(flag); - } - public void addFlag(SpecBlock.Flag flag){ - addFlagByte(flag.getFlag()); - } - public void setPublic(){ - addFlag(SpecBlock.Flag.SPEC_PUBLIC); - } - public boolean isPublic(){ - return SpecBlock.Flag.isPublic(getFlagByte()); - } - public int getInteger(){ - return BlockItem.getInteger(this.getBlockItem().getBytesInternal(), this.getOffset()); - } - public void setInteger(int value){ - if(value == getInteger()){ - return; - } - BlockItem.putInteger(this.getBlockItem().getBytesInternal(), this.getOffset(), value); - this.getBlockItem().onBytesChanged(); - } - @Override - public String toString(){ - byte flag = getFlagByte(); - if(flag != 0){ - return SpecBlock.Flag.toString(getFlagByte()); - } - int val = getInteger(); - if(val != 0){ - return HexUtil.toHex8(val); - } - return ""; - } - - private static final int OFFSET_FLAG = 3; - -} diff --git a/src/ARSCLib/com/reandroid/arsc/item/SpecFlagsArray.java b/src/ARSCLib/com/reandroid/arsc/item/SpecFlagsArray.java deleted file mode 100644 index b967a236..00000000 --- a/src/ARSCLib/com/reandroid/arsc/item/SpecFlagsArray.java +++ /dev/null @@ -1,146 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.item; - -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.chunk.SpecBlock; -import com.reandroid.arsc.io.BlockLoad; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.value.Entry; -import com.reandroid.json.JSONArray; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONObject; - -import java.io.IOException; -import java.util.AbstractList; - -public class SpecFlagsArray extends IntegerArray implements BlockLoad, JSONConvert { - private final IntegerItem entryCount; - private AbstractList specFlagList; - public SpecFlagsArray(IntegerItem entryCount) { - super(); - this.entryCount = entryCount; - this.entryCount.setBlockLoad(this); - setBlockLoad(this); - } - public AbstractList listSpecFlags(){ - if(specFlagList==null){ - specFlagList = new AbstractList() { - @Override - public SpecFlag get(int i) { - return SpecFlagsArray.this.getFlag(i); - } - @Override - public int size() { - return SpecFlagsArray.this.size(); - } - }; - } - return specFlagList; - } - public SpecFlag getFlag(int id){ - id = id & 0xffff; - if(id >= size()){ - return null; - } - int offset = id * 4; - return new SpecFlag(this, offset); - } - public void set(int entryId, int value){ - setFlag(entryId, value); - refresh(); - } - private void setFlag(int id, int flag){ - id = 0xffff & id; - ensureArraySize(id+1); - super.put(id, flag); - } - @Override - public Integer get(int entryId){ - entryId = 0xffff & entryId; - return super.get(entryId); - } - @Override - public void onBlockLoaded(BlockReader reader, Block sender) throws IOException { - if(sender==this.entryCount){ - super.setSize(entryCount.get()); - } - } - public void refresh(){ - entryCount.set(size()); - } - - public void merge(SpecFlagsArray specFlagsArray){ - if(specFlagsArray == null || specFlagsArray==this){ - return; - } - this.ensureArraySize(specFlagsArray.size()); - int[] comingValues = specFlagsArray.toArray(); - int[] existValues = this.toArray(); - for(int i=0; i { - private String mCache; - private boolean mUtf8; - private final Set mReferencedList; - public StringItem(boolean utf8) { - super(0); - this.mUtf8=utf8; - this.mReferencedList = new HashSet<>(); - } - public boolean removeReference(ReferenceItem ref){ - return mReferencedList.remove(ref); - } - public boolean removeAllReference(Collection referenceItems){ - return mReferencedList.removeAll(referenceItems); - } - public void removeAllReference(){ - mReferencedList.clear(); - } - public boolean hasReference(){ - ensureStringLinkUnlocked(); - return mReferencedList.size()>0; - } - public Collection getReferencedList(){ - ensureStringLinkUnlocked(); - return mReferencedList; - } - void ensureStringLinkUnlocked(){ - StringPool stringPool = getParentInstance(StringPool.class); - if(stringPool != null){ - stringPool.ensureStringLinkUnlockedInternal(); - } - } - public void addReference(ReferenceItem ref){ - if(ref!=null){ - mReferencedList.add(ref); - } - } - public void addReferenceIfAbsent(ReferenceItem ref){ - if(ref!=null){ - mReferencedList.add(ref); - } - } - public void addReference(Collection refList){ - if(refList == null){ - return; - } - for(ReferenceItem ref:refList){ - if(ref != null){ - this.mReferencedList.add(ref); - } - } - } - private void reUpdateReferences(int newIndex){ - List referenceItems=new ArrayList<>(mReferencedList); - for(ReferenceItem ref:referenceItems){ - ref.set(newIndex); - } - } - public void onRemoved(){ - StyleItem style = getStyle(); - if(style!=null){ - style.onRemoved(); - } - setParent(null); - } - @Override - public void onIndexChanged(int oldIndex, int newIndex){ - reUpdateReferences(newIndex); - } - public String getHtml(){ - String str=get(); - if(str==null){ - return null; - } - StyleItem styleItem=getStyle(); - if(styleItem==null){ - return str; - } - return styleItem.applyHtml(str, false); - } - public String getXml(){ - String str=get(); - if(str==null){ - return null; - } - StyleItem styleItem=getStyle(); - if(styleItem==null){ - return str; - } - return styleItem.applyHtml(str, true); - } - public String get(){ - return mCache; - } - public void set(String str){ - String old=get(); - if(str==null){ - if(old==null){ - return; - } - }else if(str.equals(old)){ - return; - } - if(str==null){ - StyleItem styleItem = getStyle(); - if(styleItem!=null){ - styleItem.onRemoved(); - } - } - byte[] bts=encodeString(str); - setBytesInternal(bts); - } - - public boolean isUtf8(){ - return mUtf8; - } - public void setUtf8(boolean utf8){ - if(utf8==mUtf8){ - return; - } - mUtf8=utf8; - onBytesChanged(); - } - @Override - protected void onBytesChanged() { - // To save cpu/memory usage, better to decode once only when bytes changed - mCache=decodeString(); - } - @Override - public void onReadBytes(BlockReader reader) throws IOException { - if(reader.available()<4){ - return; - } - int len=calculateReadLength(reader); - setBytesLength(len, false); - byte[] bts=getBytesInternal(); - reader.readFully(bts); - onBytesChanged(); - } - int calculateReadLength(BlockReader reader) throws IOException { - if(reader.available()<4){ - return reader.available(); - } - byte[] bts=new byte[4]; - reader.readFully(bts); - reader.offset(-4); - int[] len; - if(isUtf8()){ - len=decodeUtf8StringByteLength(bts); - }else { - len=decodeUtf16StringByteLength(bts); - } - int add=isUtf8()?1:2; - return len[0]+len[1]+add; - } - String decodeString(){ - return decodeString(getBytesInternal(), mUtf8); - } - byte[] encodeString(String str){ - if(mUtf8){ - return encodeUtf8ToBytes(str); - }else { - return encodeUtf16ToBytes(str); - } - } - private String decodeString(byte[] allStringBytes, boolean isUtf8) { - if(isNullBytes(allStringBytes)){ - if(allStringBytes==null||allStringBytes.length==0){ - return null; - } - return ""; - } - int[] offLen; - if(isUtf8){ - offLen=decodeUtf8StringByteLength(allStringBytes); - }else { - offLen=decodeUtf16StringByteLength(allStringBytes); - } - CharsetDecoder charsetDecoder; - if(isUtf8){ - charsetDecoder=UTF8_DECODER; - }else { - charsetDecoder=UTF16LE_DECODER; - } - try { - ByteBuffer buf=ByteBuffer.wrap(allStringBytes, offLen[0], offLen[1]); - CharBuffer charBuffer=charsetDecoder.decode(buf); - return charBuffer.toString(); - } catch (CharacterCodingException ex) { - if(isUtf8){ - return tryThreeByteDecoder(allStringBytes, offLen[0], offLen[1]); - } - return new String(allStringBytes, offLen[0], offLen[1], StandardCharsets.UTF_16LE); - } - } - private String tryThreeByteDecoder(byte[] bytes, int offset, int length){ - try { - ByteBuffer byteBuffer = ByteBuffer.wrap(bytes, offset, length); - CharBuffer charBuffer = DECODER_3B.decode(byteBuffer); - return charBuffer.toString(); - } catch (CharacterCodingException e) { - return new String(bytes, offset, length, StandardCharsets.UTF_8); - } - } - public boolean hasStyle(){ - StyleItem styleItem=getStyle(); - if(styleItem==null){ - return false; - } - return styleItem.getSpanInfoList().size()>0; - } - public StyleItem getStyle(){ - StringPool stringPool = getParentInstance(StringPool.class); - if(stringPool==null){ - return null; - } - int index=getIndex(); - return stringPool.getStyle(index); - } - @Override - public JSONObject toJson() { - if(isNull()){ - return null; - } - StyleItem styleItem=getStyle(); - if(styleItem == null){ - return null; - } - JSONObject jsonObject=new JSONObject(); - jsonObject.put(NAME_string, get()); - JSONObject styleJson = styleItem.toJson(); - if(styleJson == null){ - return null; - } - jsonObject.put(NAME_style, styleJson); - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - String str = json.getString(NAME_string); - set(str); - throw new IllegalArgumentException("Not implemented"); - } - @Override - public String toString(){ - String str = getHtml(); - if(str == null){ - return "NULL"; - } - return "USED BY=" + mReferencedList.size() + "{" + str + "}"; - } - - private static int[] decodeUtf8StringByteLength(byte[] lengthBytes) { - int offset=0; - int val = lengthBytes[offset]; - int length; - if ((val & 0x80) != 0) { - offset += 2; - } else { - offset += 1; - } - val = lengthBytes[offset]; - offset += 1; - if ((val & 0x80) != 0) { - int low = (lengthBytes[offset] & 0xFF); - length = val & 0x7F; - length = length << 8; - length = length + low; - offset += 1; - } else { - length = val; - } - return new int[] { offset, length}; - } - private static int[] decodeUtf16StringByteLength(byte[] lengthBytes) { - int val = ((lengthBytes[1] & 0xFF) << 8 | lengthBytes[0] & 0xFF); - if ((val & 0x8000) != 0) { - int high = (lengthBytes[3] & 0xFF) << 8; - int low = (lengthBytes[2] & 0xFF); - int len_value = ((val & 0x7FFF) << 16) + (high + low); - return new int[] {4, len_value * 2}; - - } - return new int[] {2, val * 2}; - } - static boolean isNullBytes(byte[] bts){ - if(bts==null){ - return true; - } - int max=bts.length; - if(max<2){ - return true; - } - for(int i=2; i>8; - lenBytes[3]=(byte) (l2); - lenBytes[2]=(byte) (l1|0x80); - strLen=str.length(); - l2=strLen&0xff; - l1=(strLen-l2)>>8; - lenBytes[1]=(byte) (l2); - lenBytes[0]=(byte) (l1|0x80); - }else{ - lenBytes=new ShortItem((short) strLen).getBytesInternal(); - lenBytes[1]=lenBytes[0]; - lenBytes[0]=(byte)str.length(); - } - }else { - bts=new byte[0]; - } - return addBytes(lenBytes, bts, new byte[1]); - } - private static byte[] encodeUtf16ToBytes(String str){ - if(str==null){ - return null; - } - byte[] lenBytes; - byte[] bts=getUtf16Bytes(str); - int strLen=bts.length; - strLen=strLen/2; - if((strLen & 0xffff8000)!=0){ - lenBytes=new byte[4]; - int low=strLen&0xff; - int high=(strLen-low)&0xff00; - int rem=strLen-low-high; - lenBytes[3]=(byte) (high>>8); - lenBytes[2]=(byte) (low); - low=rem&0xff; - high=(rem&0xff00)>>8; - lenBytes[1]=(byte) (high|0x80); - lenBytes[0]=(byte) (low); - }else{ - lenBytes=new ShortItem((short) strLen).getBytesInternal(); - } - return addBytes(lenBytes, bts, new byte[2]); - } - static byte[] getUtf16Bytes(String str){ - return str.getBytes(StandardCharsets.UTF_16LE); - } - - private static byte[] addBytes(byte[] bts1, byte[] bts2, byte[] bts3){ - if(bts1==null && bts2==null && bts3==null){ - return null; - } - int len=0; - if(bts1!=null){ - len=bts1.length; - } - if(bts2!=null){ - len+=bts2.length; - } - if(bts3!=null){ - len+=bts3.length; - } - byte[] result=new byte[len]; - int start=0; - if(bts1!=null){ - start=bts1.length; - System.arraycopy(bts1, 0, result, 0, start); - } - if(bts2!=null){ - System.arraycopy(bts2, 0, result, start, bts2.length); - start+=bts2.length; - } - if(bts3!=null){ - System.arraycopy(bts3, 0, result, start, bts3.length); - } - return result; - } - - private static final CharsetDecoder UTF16LE_DECODER = StandardCharsets.UTF_16LE.newDecoder(); - private static final CharsetDecoder UTF8_DECODER = StandardCharsets.UTF_8.newDecoder(); - private static final CharsetDecoder DECODER_3B = ThreeByteCharsetDecoder.INSTANCE; - - public static final String NAME_string="string"; - public static final String NAME_style="style"; -} diff --git a/src/ARSCLib/com/reandroid/arsc/item/StyleItem.java b/src/ARSCLib/com/reandroid/arsc/item/StyleItem.java deleted file mode 100755 index dd0bbb44..00000000 --- a/src/ARSCLib/com/reandroid/arsc/item/StyleItem.java +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.item; - -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.model.StyleSpanInfo; -import com.reandroid.arsc.model.StyledStringBuilder; -import com.reandroid.arsc.pool.StringPool; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONArray; -import com.reandroid.json.JSONObject; - -import java.io.IOException; -import java.util.*; - -public class StyleItem extends IntegerArray implements JSONConvert { - private List mSpanInfoList; - private final Set mReferences; - public StyleItem() { - super(); - this.mReferences = new HashSet<>(); - } - public void onRemoved(){ - setStylePieceCount(0); - mSpanInfoList = null; - setParent(null); - } - public void onDataLoaded(){ - linkAll(); - } - private void setEndValue(int negOne){ - super.put(size()-1, negOne); - } - final Integer getEndValue(){ - return super.get(size()-1); - } - final Integer getStringRef(int index){ - int i=index * INTEGERS_COUNT + INDEX_STRING_REF; - return super.get(i); - } - final void setStringRef(int index, int val){ - setStringRef(index, val, true); - } - final void setStringRef(int index, int val, boolean link){ - if(link){ - unLink(index); - } - int i=index * INTEGERS_COUNT + INDEX_STRING_REF; - super.put(i, val); - if(link){ - link(getStringItem(val), index); - } - } - private void linkAll(){ - int count = getStylePieceCount(); - for(int i=0; i stringPool = getStringPool(); - if(stringPool==null){ - throw new IllegalArgumentException("Null string pool, must be added to parent StyleArray first"); - } - StringItem stringItem=stringPool.getOrCreate(tag); - addStylePiece(stringItem.getIndex(), firstChar, lastChar); - } - public void addStylePiece(int refString, int firstChar, int lastChar){ - int index=getStylePieceCount(); - setStylePieceCount(index+1); - setStylePiece(index, refString, firstChar, lastChar); - } - final void setStylePiece(int index, int refString, int firstChar, int lastChar){ - unLink(index); - int i=index * INTEGERS_COUNT; - super.put(i+ INDEX_STRING_REF, refString); - super.put(i+ INDEX_CHAR_FIRST, firstChar); - super.put(i+ INDEX_CHAR_LAST, lastChar); - link(getStringItem(refString), index); - } - final int[] getStylePiece(int index){ - if(index<0||index>= getStylePieceCount()){ - return null; - } - int[] result=new int[INTEGERS_COUNT]; - int i=index * INTEGERS_COUNT; - result[INDEX_STRING_REF]=super.get(i); - result[INDEX_CHAR_FIRST]=super.get(i+ INDEX_CHAR_FIRST); - result[INDEX_CHAR_LAST]=super.get(i+ INDEX_CHAR_LAST); - return result; - } - final void setStylePiece(int index, int[] three){ - if(three==null || three.length< INTEGERS_COUNT){ - return; - } - int i = index * INTEGERS_COUNT; - super.put(i + INDEX_STRING_REF, three[INDEX_STRING_REF]); - super.put(i + INDEX_CHAR_FIRST, three[INDEX_CHAR_FIRST]); - super.put(i + INDEX_CHAR_LAST, three[INDEX_CHAR_LAST]); - } - final int getStylePieceCount(){ - int sz=size()-1; - if(sz<0){ - sz=0; - } - return sz/ INTEGERS_COUNT; - } - final void setStylePieceCount(int count){ - if(count<0){ - count=0; - } - int cur = getStylePieceCount(); - if(count==cur){ - return; - } - if(count == 0){ - unlinkAll(); - } - int max=count * INTEGERS_COUNT + 1; - if(size()==0 || count==0){ - super.setSize(max); - setEndValue(END_VALUE); - return; - } - List copy=new ArrayList<>(getIntSpanInfoList()); - Integer end= getEndValue(); - if(end==null){ - end=END_VALUE; - } - super.setSize(max); - max=count; - int copyMax=copy.size(); - if(copyMax>max){ - copyMax=max; - } - for(int i=0;i getIntSpanInfoList(){ - return new AbstractList() { - @Override - public int[] get(int i) { - return StyleItem.this.getStylePiece(i); - } - @Override - public int size() { - return StyleItem.this.getStylePieceCount(); - } - }; - } - public final List getSpanInfoList(){ - if(mSpanInfoList!=null){ - return mSpanInfoList; - } - mSpanInfoList = new AbstractList() { - @Override - public StyleSpanInfo get(int i) { - int ref=getStringRef(i); - if(ref<=0){ - return null; - } - StyleSpanInfo spanInfo = new StyleSpanInfo( - getStringFromPool(ref), - getFirstChar(i), - getLastChar(i)); - if(!spanInfo.isValid()){ - return null; - } - return spanInfo; - } - @Override - public int size() { - return getStylePieceCount(); - } - }; - return mSpanInfoList; - } - private String getStringFromPool(int ref){ - StringItem stringItem = getStringItem(ref); - if(stringItem!=null){ - return stringItem.get(); - } - return null; - } - private StringItem getStringItem(int ref){ - StringPool stringPool = getStringPool(); - if(stringPool!=null){ - return stringPool.get(ref); - } - return null; - } - private StringPool getStringPool(){ - return getParentInstance(StringPool.class); - } - - public String applyHtml(String str, boolean xml){ - if(str == null){ - return null; - } - return StyledStringBuilder.build(str, getSpanInfoList(), xml); - } - @Override - public void setNull(boolean is_null){ - if(!is_null){ - return; - } - setStylePieceCount(0); - } - @Override - public void onReadBytes(BlockReader reader) throws IOException { - int nextPos=reader.searchNextIntPosition(4, END_VALUE); - if(nextPos<0){ - return; - } - int len=nextPos-reader.getPosition()+4; - super.setBytesLength(len, false); - byte[] bts=getBytesInternal(); - reader.readFully(bts); - onBytesChanged(); - } - public void addSpanInfo(String tag, int first, int last){ - int index=getStylePieceCount(); - setStylePieceCount(index+1); - StringPool stringPool = getStringPool(); - if(stringPool==null){ - throw new IllegalArgumentException("Null string pool, must be added to parent StyleArray first"); - } - StringItem stringItem=stringPool.getOrCreate(tag); - setStylePiece(index, stringItem.getIndex(), first, last); - } - @Override - public JSONObject toJson() { - if(isNull()){ - return null; - } - JSONObject jsonObject=new JSONObject(); - JSONArray jsonArray=new JSONArray(); - int i=0; - for(StyleSpanInfo spanInfo:getSpanInfoList()){ - if(spanInfo==null){ - continue; - } - JSONObject jsonObjectSpan=spanInfo.toJson(); - jsonArray.put(i, jsonObjectSpan); - i++; - } - if(i==0){ - return null; - } - jsonObject.put(NAME_spans, jsonArray); - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - setNull(true); - if(json==null){ - return; - } - JSONArray jsonArray= json.getJSONArray(NAME_spans); - int length = jsonArray.length(); - for(int i=0;i listReferencedResValueEntries(){ - List results=new ArrayList<>(); - for(ReferenceItem ref:getReferencedList()){ - if(!(ref instanceof ReferenceBlock)){ - continue; - } - Block block = ((ReferenceBlock)ref).getBlock(); - if(block ==null){ - continue; - } - if(!(block instanceof ResValue)){ - continue; - } - ResValue resValue = (ResValue) block; - results.add(resValue.getEntry()); - } - return results; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/item/TypeString.java b/src/ARSCLib/com/reandroid/arsc/item/TypeString.java deleted file mode 100755 index 55ebba34..00000000 --- a/src/ARSCLib/com/reandroid/arsc/item/TypeString.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.item; - - -import com.reandroid.arsc.pool.TypeStringPool; -import com.reandroid.arsc.util.HexUtil; - -public class TypeString extends StringItem { - public TypeString(boolean utf8) { - super(utf8); - } - public int getId(){ - TypeStringPool stringPool = getParent(TypeStringPool.class); - if(stringPool!=null){ - return stringPool.idOf(this); - } - // Should not reach here , this means it not added to string pool - return getIndex()+1; - } - @Override - public StyleItem getStyle(){ - // Type don't have style unless to obfuscate/confuse other decompilers - return null; - } - @Override - void ensureStringLinkUnlocked(){ - } - @Override - public String toString(){ - return HexUtil.toHex2((byte) getId())+':'+get(); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/list/OverlayableList.java b/src/ARSCLib/com/reandroid/arsc/list/OverlayableList.java deleted file mode 100644 index 800311d0..00000000 --- a/src/ARSCLib/com/reandroid/arsc/list/OverlayableList.java +++ /dev/null @@ -1,73 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.list; - -import com.reandroid.arsc.chunk.Overlayable; -import com.reandroid.arsc.container.BlockList; -import com.reandroid.json.JSONArray; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONObject; - -public class OverlayableList extends BlockList implements JSONConvert { - public OverlayableList(){ - super(); - } - public Overlayable get(String name){ - for(Overlayable overlayable:getChildes()){ - if(name.equals(overlayable.getName())){ - return overlayable; - } - } - return null; - } - @Override - public JSONArray toJson() { - if(size()==0){ - return null; - } - JSONArray jsonArray = new JSONArray(); - for(Overlayable overlayable:getChildes()){ - JSONObject jsonOverlayble = overlayable.toJson(); - jsonArray.put(jsonOverlayble); - } - return jsonArray; - } - @Override - public void fromJson(JSONArray json) { - if(json==null){ - return; - } - int length = json.length(); - for(int i=0;i { - public StagedAliasList(){ - super(); - } - private StagedAlias pickOne(){ - for(StagedAlias stagedAlias:getChildes()){ - if(stagedAlias!=null){ - return stagedAlias; - } - } - return null; - } - public void merge(StagedAliasList stagedAliasList){ - if(stagedAliasList==null || stagedAliasList==this || stagedAliasList.size()==0){ - return; - } - StagedAlias exist = pickOne(); - if(exist==null){ - exist=new StagedAlias(); - add(exist); - } - for(StagedAlias stagedAlias:stagedAliasList.getChildes()){ - exist.merge(stagedAlias); - } - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/model/StyleSpanInfo.java b/src/ARSCLib/com/reandroid/arsc/model/StyleSpanInfo.java deleted file mode 100755 index 89b61e46..00000000 --- a/src/ARSCLib/com/reandroid/arsc/model/StyleSpanInfo.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.model; - -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONObject; - -public class StyleSpanInfo implements JSONConvert { - private String mTag; - private int mFirst; - private int mLast; - public StyleSpanInfo(String tag, int first, int last){ - this.mTag = tag; - this.mFirst = first; - this.mLast = last; - } - public boolean isValid(){ - return mFirst < mLast; - } - public int getFirst() { - return mFirst; - } - public void setFirst(int first) { - this.mFirst = first; - } - public int getLast() { - return mLast; - } - public void setLast(int last) { - this.mLast = last; - } - public String getTag() { - return mTag; - } - public void setTag(String tag) { - this.mTag = tag; - } - - public String getStartTag(boolean xml){ - int i= mTag.indexOf(';'); - StringBuilder builder=new StringBuilder(); - builder.append('<'); - if(i<0){ - builder.append(mTag); - }else { - builder.append(mTag, 0, i); - builder.append(' '); - String attrs = mTag.substring(i+1); - if(xml){ - appendXmlAttrs(builder, attrs); - }else { - builder.append(attrs); - } - } - builder.append('>'); - return builder.toString(); - } - private void appendXmlAttrs(StringBuilder builder, String rawAttr){ - String[] split=rawAttr.split("(\\s*;\\s*)"); - for(int i=0;i'); - return builder.toString(); - } - @Override - public JSONObject toJson() { - JSONObject jsonObject=new JSONObject(); - jsonObject.put(NAME_tag, mTag); - jsonObject.put(NAME_first, mFirst); - jsonObject.put(NAME_last, mLast); - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - setTag(json.getString(NAME_tag)); - setFirst(json.getInt(NAME_first)); - setLast(json.getInt(NAME_last)); - } - @Override - public String toString(){ - return mTag +" ("+ mFirst +", "+ mLast +")"; - } - - public static final String NAME_tag="tag"; - public static final String NAME_first="first"; - public static final String NAME_last="last"; -} diff --git a/src/ARSCLib/com/reandroid/arsc/model/StyledStringBuilder.java b/src/ARSCLib/com/reandroid/arsc/model/StyledStringBuilder.java deleted file mode 100644 index f736da9f..00000000 --- a/src/ARSCLib/com/reandroid/arsc/model/StyledStringBuilder.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.model; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -public class StyledStringBuilder { - - public static String build(String text, Collection spanInfoList, boolean xml){ - if(isEmpty(spanInfoList)){ - return text; - } - CharPiece[] charPieceArray = toCharPieceArray(text); - boolean spansOk = initializeTags(charPieceArray, spanInfoList, xml); - if(!spansOk){ - // TODO: should throw here ? - return text; - } - if(xml){ - escapeXmlChars(charPieceArray); - } - StringBuilder builder = new StringBuilder(); - int length = charPieceArray.length; - for(int i = 0; i < length; i++){ - CharPiece charPiece = charPieceArray[i]; - charPiece.append(builder); - } - return builder.toString(); - } - - private static boolean isEmpty(Collection spanInfoList){ - if(spanInfoList == null || spanInfoList.size()==0){ - return true; - } - for(StyleSpanInfo spanInfo:spanInfoList){ - if(spanInfo != null){ - return false; - } - } - return true; - } - private static boolean initializeTags(CharPiece[] charPieceArray, Collection spanInfoList, boolean xml){ - for(StyleSpanInfo spanInfo : spanInfoList){ - if(spanInfo == null){ - continue; - } - boolean spanOk = initializeTag(charPieceArray, spanInfo, xml); - if(!spanOk){ - return false; - } - } - return true; - } - private static boolean initializeTag(CharPiece[] charPieceArray, StyleSpanInfo spanInfo, boolean xml){ - int length = charPieceArray.length; - int pos = spanInfo.getFirst(); - if(pos < 0 || pos >= length){ - return false; - } - CharPiece charPiece = charPieceArray[pos]; - charPiece.addFirstTag(spanInfo.getStartTag(xml)); - - pos = spanInfo.getLast(); - if(pos < 0 || pos >= length){ - return false; - } - charPiece = charPieceArray[pos]; - charPiece.addLastTag(spanInfo.getEndTag()); - return true; - } - - private static void escapeXmlChars(CharPiece[] charPieceArray){ - int length = charPieceArray.length; - for(int i = 0; i < length; i++){ - CharPiece charPiece = charPieceArray[i]; - if(isSpecialXmlChar(charPiece.mChar) && !isAlreadyEscaped(charPieceArray, i)){ - charPiece.escapedXml = escapeXmlChar(charPiece.mChar); - } - } - } - private static boolean isAlreadyEscaped(CharPiece[] charPieceArray, int position){ - if(charPieceArray[position].mChar != '&'){ - return false; - } - if((position + 3) >= charPieceArray.length){ - return false; - } - if(charPieceArray[position + 3].mChar == ';'){ - char ch = charPieceArray[position + 1].mChar; - return charPieceArray[position + 2].mChar == 't' - && (ch == 'l' || ch == 'g') ; - } - if((position + 4) >= charPieceArray.length){ - return false; - } - if(charPieceArray[position + 4].mChar == ';'){ - return charPieceArray[position + 1].mChar == 'a' - && charPieceArray[position + 2].mChar == 'm' - && charPieceArray[position + 3].mChar == 'p'; - } - return false; - } - private static String escapeXmlChar(char ch){ - switch (ch){ - case '&': - return "&"; - case '<': - return "<"; - case '>': - return ">"; - default: - throw new IllegalArgumentException("Not special xml char: '" + ch + "'"); - } - } - private static boolean isSpecialXmlChar(char ch){ - switch (ch){ - case '&': - case '<': - case '>': - return true; - default: - return false; - } - } - private static CharPiece[] toCharPieceArray(String text){ - char[] chars = text.toCharArray(); - int length = chars.length; - CharPiece[] results = new CharPiece[length]; - for(int i = 0; i < length; i++){ - results[i] = new CharPiece(i, chars[i]); - } - return results; - } - - static class CharPiece{ - final int position; - private List firstTagList; - final char mChar; - private List lastTagList; - String escapedXml; - CharPiece(int position, char ch){ - this.position = position; - this.mChar = ch; - } - void append(StringBuilder builder){ - if(firstTagList != null){ - for(String tag : firstTagList){ - builder.append(tag); - } - } - if(escapedXml != null){ - builder.append(escapedXml); - }else { - builder.append(mChar); - } - if(lastTagList != null){ - for(String tag : lastTagList){ - builder.append(tag); - } - } - } - void addFirstTag(String tag){ - if(tag == null){ - return; - } - if(this.firstTagList == null){ - this.firstTagList = new ArrayList<>(2); - } - this.firstTagList.add(tag); - } - void addLastTag(String tag){ - if(tag == null){ - return; - } - if(this.lastTagList == null){ - this.lastTagList = new ArrayList<>(2); - } - this.lastTagList.add(0, tag); - } - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/pool/JsonStringPoolHelper.java b/src/ARSCLib/com/reandroid/arsc/pool/JsonStringPoolHelper.java deleted file mode 100644 index 2f69fbcb..00000000 --- a/src/ARSCLib/com/reandroid/arsc/pool/JsonStringPoolHelper.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.pool; - -import com.reandroid.arsc.array.StringArray; -import com.reandroid.arsc.array.StyleArray; -import com.reandroid.arsc.item.StringItem; -import com.reandroid.arsc.item.StyleItem; -import com.reandroid.arsc.model.StyleSpanInfo; -import com.reandroid.json.JSONArray; -import com.reandroid.json.JSONObject; - -import java.util.*; - -class JsonStringPoolHelper { - - private final StringPool stringPool; - JsonStringPoolHelper(StringPool stringPool){ - this.stringPool=stringPool; - } - void loadStyledStrings(JSONArray jsonArray) { - //Styled strings should be at first rows of string pool thus we clear all before adding - stringPool.getStringsArray().clearChildes(); - stringPool.getStyleArray().clearChildes(); - - List styledStringList = StyledString.fromJson(jsonArray); - loadText(styledStringList); - Map tagIndexMap = loadStyleTags(styledStringList); - loadStyles(styledStringList, tagIndexMap); - stringPool.refreshUniqueIdMap(); - } - private void loadText(List styledStringList) { - StringArray stringsArray = stringPool.getStringsArray(); - int size=styledStringList.size(); - stringsArray.ensureSize(size); - for(int i=0;i loadStyleTags(List styledStringList) { - Map indexMap=new HashMap<>(); - List tagList=new ArrayList<>(getStyleTags(styledStringList)); - tagList.sort(stringPool); - StringArray stringsArray = stringPool.getStringsArray(); - int tagsSize = tagList.size(); - int initialSize = stringsArray.childesCount(); - stringsArray.ensureSize(initialSize + tagsSize); - for(int i=0;i styledStringList, Map tagIndexMap){ - StyleArray styleArray = stringPool.getStyleArray(); - int size=styledStringList.size(); - styleArray.ensureSize(size); - for(int i=0;i getStyleTags(List styledStringList){ - Set results=new HashSet<>(); - for(StyledString ss:styledStringList){ - for(StyleSpanInfo spanInfo:ss.spanInfoList){ - results.add(spanInfo.getTag()); - } - } - return results; - } - private static class StyledString{ - final String text; - final List spanInfoList; - StyledString(String text, List spanInfoList){ - this.text=text; - this.spanInfoList=spanInfoList; - } - @Override - public String toString(){ - return text; - } - static List fromJson(JSONArray jsonArray){ - int length = jsonArray.length(); - List results = new ArrayList<>(length); - for(int i=0; i < length; i++){ - StyledString styledString = - fromJson(jsonArray.getJSONObject(i)); - if(styledString != null){ - results.add(styledString); - } - } - return results; - } - private static StyledString fromJson(JSONObject jsonObject){ - if(!jsonObject.has(StringItem.NAME_style)){ - return null; - } - String text = jsonObject.getString(StringItem.NAME_string); - JSONObject style=jsonObject.getJSONObject(StringItem.NAME_style); - JSONArray spansArray=style.getJSONArray(StyleItem.NAME_spans); - List spanInfoList = toSpanInfoList(spansArray); - return new StyledString(text, spanInfoList); - } - private static List toSpanInfoList(JSONArray jsonArray){ - int length = jsonArray.length(); - List results=new ArrayList<>(length); - for(int i=0;i { - public ResXmlStringPool(boolean is_utf8) { - super(is_utf8, false); - } - @Override - public ResXmlString removeReference(ReferenceItem referenceItem){ - if(referenceItem==null){ - return null; - } - ResXmlString stringItem = super.removeReference(referenceItem); - removeNotUsedItem(stringItem); - return stringItem; - } - private void removeNotUsedItem(ResXmlString xmlString){ - if(xmlString == null || xmlString.hasReference()){ - return; - } - ResXmlIDMap idMap = getResXmlIDMap(); - int lastIdIndex = -1; - if(idMap!=null){ - lastIdIndex = idMap.countId() - 1; - } - if(idMap!=null && xmlString.getIndex()>lastIdIndex){ - removeString(xmlString); - }else { - xmlString.set(""); - } - } - @Override - StringArray newInstance(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { - return new ResXmlStringArray(offsets, itemCount, itemStart, is_utf8); - } - public ResXmlString getOrCreate(String str){ - return getOrCreateAttribute(0, str); - } - public ResXmlString createNew(String str){ - StringArray stringsArray = getStringsArray(); - ResXmlString xmlString = stringsArray.createNext(); - xmlString.set(str); - return xmlString; - } - public ResXmlString getOrCreateAttribute(int resourceId, String str){ - ResXmlIDMap resXmlIDMap = getResXmlIDMap(); - if(resXmlIDMap == null){ - return super.getOrCreate(str); - } - ResXmlIDArray idArray = resXmlIDMap.getResXmlIDArray(); - int count = idArray.childesCount(); - if(resourceId == 0){ - return getOrCreateAfter(count, str); - } - StringArray stringsArray = getStringsArray(); - ResXmlID xmlID = idArray.getByResId(resourceId); - if(xmlID != null){ - ResXmlString xmlString = stringsArray.get(xmlID.getIndex()); - if(xmlString!=null && Objects.equals(str, xmlString.get())){ - return xmlString; - } - } - count = idArray.childesCount() + 1; - stringsArray.ensureSize(count); - idArray.setChildesCount(count); - int index = count - 1; - xmlID = idArray.get(index); - xmlID.set(resourceId); - idArray.refreshIdMap(); - - ResXmlString xmlString = stringsArray.newInstance(); - xmlString.set(str); - stringsArray.insertItem(index, xmlString); - - updateUniqueIdMap(xmlString); - return xmlString; - } - private ResXmlString getOrCreateAfter(int position, String str){ - if(position<0){ - position=0; - } - StringGroup group = get(str); - if(group!=null){ - for(ResXmlString xmlString:group.listItems()){ - int index = xmlString.getIndex(); - if(index > position || (position==0 && position == index)){ - return xmlString; - } - } - } - StringArray stringsArray = getStringsArray(); - int count = stringsArray.childesCount(); - if(count < position){ - count = position; - } - stringsArray.ensureSize(count+1); - ResXmlString xmlString = stringsArray.get(count); - xmlString.set(str); - super.updateUniqueIdMap(xmlString); - return xmlString; - } - private ResXmlIDMap getResXmlIDMap(){ - ResXmlDocument resXmlDocument = getParentInstance(ResXmlDocument.class); - if(resXmlDocument!=null){ - return resXmlDocument.getResXmlIDMap(); - } - return null; - } - public ResXmlString getOrCreateAttributeName(int idMapCount, String str){ - StringGroup group = get(str); - if(group!=null){ - for(ResXmlString xmlString:group.listItems()){ - if(xmlString.getIndex()>idMapCount){ - return xmlString; - } - } - } - StringArray stringsArray = getStringsArray(); - stringsArray.ensureSize(idMapCount); - int i=stringsArray.childesCount(); - stringsArray.ensureSize(i+1); - ResXmlString xmlString=stringsArray.get(i); - xmlString.set(str); - refreshUniqueIdMap(); - return xmlString; - } - @Override - public void onChunkLoaded() { - super.onChunkLoaded(); - StyleArray styleArray = getStyleArray(); - if(styleArray.childesCount()>0){ - notifyResXmlStringPoolHasStyles(styleArray.childesCount()); - } - } - private static void notifyResXmlStringPoolHasStyles(int styleArrayCount){ - if(HAS_STYLE_NOTIFIED){ - return; - } - String msg="Not expecting ResXmlStringPool to have styles count=" - +styleArrayCount+",\n please create issue along with this apk/file on https://github.com/REAndroid/ARSCEditor"; - System.err.println(msg); - HAS_STYLE_NOTIFIED=true; - } - private static boolean HAS_STYLE_NOTIFIED; -} diff --git a/src/ARSCLib/com/reandroid/arsc/pool/SpecStringPool.java b/src/ARSCLib/com/reandroid/arsc/pool/SpecStringPool.java deleted file mode 100755 index a7ec8aef..00000000 --- a/src/ARSCLib/com/reandroid/arsc/pool/SpecStringPool.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.pool; - -import com.reandroid.arsc.array.OffsetArray; -import com.reandroid.arsc.array.SpecStringArray; -import com.reandroid.arsc.array.StringArray; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.item.IntegerItem; -import com.reandroid.arsc.item.SpecString; - -public class SpecStringPool extends StringPool { - public SpecStringPool(boolean is_utf8){ - super(is_utf8); - } - - @Override - StringArray newInstance(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { - return new SpecStringArray(offsets, itemCount, itemStart, is_utf8); - } - public PackageBlock getPackageBlock(){ - return getParent(PackageBlock.class); - } - - @Override - void linkStrings(){ - PackageBlock packageBlock = getPackageBlock(); - if(packageBlock != null){ - packageBlock.linkSpecStringsInternal(this); - } - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/pool/StringPool.java b/src/ARSCLib/com/reandroid/arsc/pool/StringPool.java deleted file mode 100755 index 1f1cf466..00000000 --- a/src/ARSCLib/com/reandroid/arsc/pool/StringPool.java +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.pool; - -import com.reandroid.arsc.array.OffsetArray; -import com.reandroid.arsc.array.StringArray; -import com.reandroid.arsc.array.StyleArray; -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.chunk.Chunk; -import com.reandroid.arsc.group.StringGroup; -import com.reandroid.arsc.header.StringPoolHeader; -import com.reandroid.arsc.io.BlockLoad; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.item.*; -import com.reandroid.json.JSONArray; -import com.reandroid.json.JSONConvert; - -import java.io.IOException; -import java.util.*; - - -public abstract class StringPool extends Chunk implements BlockLoad, JSONConvert, Comparator { - private final Object mLock = new Object(); - private final StringArray mArrayStrings; - private final StyleArray mArrayStyles; - - private final Map> mUniqueMap; - private boolean stringLinkLocked; - - StringPool(boolean is_utf8, boolean stringLinkLocked){ - super(new StringPoolHeader(), 4); - - OffsetArray offsetStrings = new OffsetArray(); - OffsetArray offsetStyles = new OffsetArray(); - - StringPoolHeader header = getHeaderBlock(); - - this.mArrayStrings = newInstance( - offsetStrings, - header.getCountStrings(), - header.getStartStrings(), - is_utf8); - - this.mArrayStyles = new StyleArray( - offsetStyles, - header.getCountStyles(), - header.getStartStyles()); - - - addChild(offsetStrings); - addChild(offsetStyles); - addChild(mArrayStrings); - addChild(mArrayStyles); - - setUtf8(is_utf8, false); - - header.getFlagUtf8().setBlockLoad(this); - - mUniqueMap = new HashMap<>(); - this.stringLinkLocked = stringLinkLocked; - } - StringPool(boolean is_utf8){ - this(is_utf8, true); - } - - public boolean isStringLinkLocked(){ - return stringLinkLocked; - } - public void ensureStringLinkUnlockedInternal(){ - if(!stringLinkLocked){ - return; - } - synchronized (mLock){ - if(!stringLinkLocked){ - return; - } - stringLinkLocked = false; - linkStrings(); - } - } - void linkStrings(){ - } - - public void removeString(T item){ - getStringsArray().remove(item); - } - public void destroy(){ - getStyleArray().clearChildes(); - getStringsArray().clearChildes(); - } - public List toStringList(){ - return getStringsArray().toStringList(); - } - public void addStrings(Collection stringList){ - if(stringList==null || stringList.size()==0){ - return; - } - Set uniqueSet; - if(stringList instanceof HashSet){ - uniqueSet=(HashSet)stringList; - }else { - uniqueSet=new HashSet<>(stringList); - } - refreshUniqueIdMap(); - Set keySet=mUniqueMap.keySet(); - for(String key:keySet){ - uniqueSet.remove(key); - } - List sortedList=new ArrayList<>(stringList); - sortedList.sort(this); - insertStringList(sortedList); - } - private void insertStringList(List stringList){ - StringArray stringsArray = getStringsArray(); - int initialSize=stringsArray.childesCount(); - stringsArray.ensureSize(initialSize + stringList.size()); - int size=stringsArray.childesCount(); - int j=0; - for (int i=initialSize;i insertStrings(List stringList){ - Map results=new HashMap<>(); - StringArray stringsArray = getStringsArray(); - int initialSize=stringsArray.childesCount(); - stringsArray.ensureSize(initialSize + stringList.size()); - int size=stringsArray.childesCount(); - int j=0; - for (int i=initialSize;i group= getOrCreateGroup(str); - group.add(item); - } - } - void updateUniqueIdMap(T item){ - if(item==null){ - return; - } - StringGroup group = getOrCreateGroup(item.getHtml()); - group.add(item); - } - public List removeUnusedStrings(){ - return getStringsArray().removeUnusedStrings(); - } - public List listUnusedStrings(){ - return getStringsArray().listUnusedStrings(); - } - public Collection listStrings(){ - return getStringsArray().listItems(); - } - public StyleArray getStyleArray(){ - return mArrayStyles; - } - public StringArray getStringsArray(){ - return mArrayStrings; - } - public void removeReferences(Collection referenceList){ - if(referenceList==null){ - return; - } - for(ReferenceItem ref:referenceList){ - removeReference(ref); - } - } - public T removeReference(ReferenceItem ref){ - if(ref==null){ - return null; - } - T item=get(ref.get()); - if(item!=null){ - item.removeReference(ref); - return item; - } - return null; - } - public void addReference(ReferenceItem ref){ - if(ref==null){ - return; - } - T item=get(ref.get()); - if(item!=null){ - item.addReference(ref); - } - } - public void addReferences(Collection referenceList){ - if(referenceList==null){ - return; - } - for(ReferenceItem ref:referenceList){ - addReference(ref); - } - } - - public boolean contains(String str){ - return mUniqueMap.containsKey(str); - } - public final T get(int index){ - return mArrayStrings.get(index); - } - public final StringGroup get(String str){ - return mUniqueMap.get(str); - } - public T getOrCreate(String str){ - StringGroup group=getOrCreateGroup(str); - T[] items=group.getItems(); - if(items.length==0){ - T t=createNewString(str); - group.add(t); - items=group.getItems(); - } - return items[0]; - } - private StringGroup getOrCreateGroup(String str){ - StringGroup group=get(str); - if(group!=null){ - return group; - } - group=new StringGroup<>(mArrayStrings, str); - mUniqueMap.put(str, group); - return group; - } - private T createNewString(String str){ - T item=mArrayStrings.createNext(); - item.set(str); - getHeaderBlock().getCountStrings().set(mArrayStrings.childesCount()); - return item; - } - public final StyleItem getStyle(int index){ - return mArrayStyles.get(index); - } - public final int countStrings(){ - return mArrayStrings.childesCount(); - } - public final int countStyles(){ - return mArrayStyles.childesCount(); - } - public final T[] getStrings(){ - return mArrayStrings.getChildes(); - } - public final StyleItem[] getStyles(){ - return mArrayStyles.getChildes(); - } - public void setUtf8(boolean is_utf8){ - setUtf8(is_utf8, true); - } - private void setUtf8(boolean is_utf8, boolean updateAll){ - StringPoolHeader header = getHeaderBlock(); - if(is_utf8 == header.isUtf8()){ - return; - } - ByteItem flagUtf8 = header.getFlagUtf8(); - if(is_utf8){ - flagUtf8.set((byte) 0x01); - }else { - flagUtf8.set((byte) 0x00); - } - if(!updateAll){ - return; - } - mArrayStrings.setUtf8(is_utf8); - } - public void setFlagSorted(boolean sorted){ - getHeaderBlock().setSorted(sorted); - } - - abstract StringArray newInstance(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8); - @Override - protected void onChunkRefreshed() { - mArrayStrings.refreshCountAndStart(); - mArrayStyles.refreshCountAndStart(); - } - @Override - public void onChunkLoaded() { - refreshUniqueIdMap(); - StyleItem[] styles = getStyles(); - if(styles!=null){ - for(StyleItem styleItem:styles){ - styleItem.onDataLoaded(); - } - } - } - - @Override - public void onBlockLoaded(BlockReader reader, Block sender) throws IOException { - StringPoolHeader header = getHeaderBlock(); - if(sender == header.getFlagUtf8()){ - mArrayStrings.setUtf8(header.isUtf8()); - } - } - @Override - public JSONArray toJson() { - return getStringsArray().toJson(); - } - //Only for styled strings - @Override - public void fromJson(JSONArray json) { - if(json==null){ - return; - } - JsonStringPoolHelper helper=new JsonStringPoolHelper<>(this); - helper.loadStyledStrings(json); - refresh(); - } - @Override - public int compare(String s1, String s2) { - return s1.compareTo(s2); - } - -} diff --git a/src/ARSCLib/com/reandroid/arsc/pool/TableStringPool.java b/src/ARSCLib/com/reandroid/arsc/pool/TableStringPool.java deleted file mode 100755 index 02481897..00000000 --- a/src/ARSCLib/com/reandroid/arsc/pool/TableStringPool.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.pool; - -import com.reandroid.arsc.array.OffsetArray; -import com.reandroid.arsc.array.StringArray; -import com.reandroid.arsc.array.TableStringArray; -import com.reandroid.arsc.chunk.ChunkType; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.chunk.UnknownChunk; -import com.reandroid.arsc.header.HeaderBlock; -import com.reandroid.arsc.header.TableHeader; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.item.IntegerItem; -import com.reandroid.arsc.item.TableString; - -import java.io.IOException; -import java.io.InputStream; - -public class TableStringPool extends StringPool { - public TableStringPool(boolean is_utf8) { - super(is_utf8); - } - - @Override - void linkStrings(){ - TableBlock tableBlock = getParentInstance(TableBlock.class); - if(tableBlock != null){ - tableBlock.linkTableStringsInternal(this); - } - } - @Override - StringArray newInstance(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { - return new TableStringArray(offsets, itemCount, itemStart, is_utf8); - } - public void merge(TableStringPool stringPool){ - if(stringPool==null||stringPool==this){ - return; - } - StringArray existArray = getStringsArray(); - if(existArray.childesCount()!=0){ - return; - } - StringArray comingArray = stringPool.getStringsArray(); - int count=comingArray.childesCount(); - existArray.ensureSize(count); - for(int i=0;i { - private final IntegerItem mTypeIdOffset; - public TypeStringPool(boolean is_utf8, IntegerItem typeIdOffset) { - super(is_utf8, false); - this.mTypeIdOffset = typeIdOffset; - } - public int getLastId(){ - int count = countStrings(); - if(count == 0){ - return 0; - } - return get(count - 1).getId(); - } - public int idOf(String typeName){ - return idOf(getByName(typeName)); - } - /** - * Resolves id of {@link TypeBlock} - * Not recommend to use unless unless you are sure of proper pool - **/ - public int idOf(TypeString typeString){ - if(typeString==null){ - return 0; - } - return (typeString.getIndex()+mTypeIdOffset.get()+1); - } - /** - * Searches string entry {@link TypeBlock} - * {@param name} is name of {@link TypeBlock} - * This might not working if duplicate type names are present - **/ - public TypeString getByName(String name){ - for(TypeString typeString:listStrings()){ - if(name.equals(typeString.get())){ - return typeString; - } - } - return null; - } - public TypeString getById(int id){ - int index=id-mTypeIdOffset.get()-1; - return super.get(index); - } - public TypeString getOrCreate(int typeId, String typeName){ - StringArray stringsArray = getStringsArray(); - int old = stringsArray.childesCount(); - int size = typeId - mTypeIdOffset.get(); - stringsArray.ensureSize(size); - TypeString typeString = getById(typeId); - typeString.set(typeName); - if(old != stringsArray.childesCount()){ - updateUniqueIdMap(typeString); - } - return typeString; - } - /** - * Use getOrCreate(typeId, typeName)} - **/ - @Deprecated - @Override - public final TypeString getOrCreate(String str){ - StringGroup group = get(str); - if(group==null||group.size()==0){ - throw new IllegalArgumentException("Can not create TypeString (" + str - +") without type id. use getOrCreate(typeId, typeName)"); - } - return group.get(0); - } - @Override - StringArray newInstance(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) { - return new TypeStringArray(offsets, itemCount, itemStart, is_utf8); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/pool/builder/StringPoolMerger.java b/src/ARSCLib/com/reandroid/arsc/pool/builder/StringPoolMerger.java deleted file mode 100644 index 3e21ce9e..00000000 --- a/src/ARSCLib/com/reandroid/arsc/pool/builder/StringPoolMerger.java +++ /dev/null @@ -1,160 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.pool.builder; - -import com.reandroid.arsc.array.StringArray; -import com.reandroid.arsc.array.StyleArray; -import com.reandroid.arsc.item.StyleItem; -import com.reandroid.arsc.item.TableString; -import com.reandroid.arsc.model.StyleSpanInfo; -import com.reandroid.arsc.pool.TableStringPool; - -import java.util.*; - -public class StringPoolMerger implements Comparator { - private final Set mPools; - private int mMergedPools; - private int mMergedStrings; - private int mMergedStyleStrings; - public StringPoolMerger(){ - this.mPools=new HashSet<>(); - } - public void mergeTo(TableStringPool destination){ - mMergedPools=0; - mMergedStrings=0; - mMergedStyleStrings=0; - if(destination.countStrings()>0 || destination.countStyles()>0){ - throw new IllegalArgumentException("Destination string pool is not empty"); - } - mergeStyledStrings(destination); - mergeNonStyledStrings(destination); - mMergedPools = mPools.size(); - mPools.clear(); - destination.refresh(); - } - public void add(TableStringPool stringPool){ - mPools.add(stringPool); - } - public int getMergedPools() { - return mMergedPools; - } - public int getMergedStyleStrings() { - return mMergedStyleStrings; - } - public int getMergedStrings() { - return mMergedStrings; - } - - private void mergeStyledStrings(TableStringPool destination){ - List styledStrings = getStyledStrings(); - Map mapTableStrings = - destination.insertStrings(toStringList(styledStrings)); - Map mapTags = - destination.insertStrings(listStyleTags(styledStrings)); - - StyleArray styleArray = destination.getStyleArray(); - styleArray.setChildesCount(styledStrings.size()); - - for(TableString tableString:styledStrings){ - TableString createdString = mapTableStrings.get(tableString.get()); - StyleItem createdStyle = styleArray.get(createdString.getIndex()); - - StyleItem styleItem = tableString.getStyle(); - for(StyleSpanInfo spanInfo:styleItem.getSpanInfoList()){ - if(spanInfo!=null && createdStyle!=null){ - int tagReference = mapTags.get(spanInfo.getTag()) - .getIndex(); - createdStyle.addStylePiece( - tagReference, - spanInfo.getFirst(), - spanInfo.getLast()); - } - } - } - mMergedStyleStrings=styledStrings.size(); - } - private void mergeNonStyledStrings(TableStringPool destination){ - List nonStyledStrings=getNonStyledStrings(); - destination.insertStrings(nonStyledStrings); - mMergedStrings=nonStyledStrings.size(); - } - private List getStyledStrings(){ - Map mapUniqueHtml = new HashMap<>(); - for(TableStringPool pool:mPools){ - int styleCount = pool.countStyles(); - StringArray stringArray = pool.getStringsArray(); - for(int i=0;i(mapUniqueHtml.values()); - } - private List getNonStyledStrings(){ - Set uniqueSet = new HashSet<>(); - for(TableStringPool pool:mPools){ - TableString[] tableStrings = pool.getStrings(); - if(tableStrings==null){ - continue; - } - for(int i=0;i results=new ArrayList<>(uniqueSet); - results.sort(this); - return results; - } - private List toStringList(Collection tableStringList){ - List results=new ArrayList<>(tableStringList.size()); - for(TableString tableString:tableStringList){ - String str=tableString.get(); - if(str!=null){ - results.add(str); - } - } - results.sort(this); - return results; - } - private List listStyleTags(List styledStrings){ - Set resultSet=new HashSet<>(); - for(TableString tableString:styledStrings){ - StyleItem style = tableString.getStyle(); - if(style==null){ - continue; - } - for(StyleSpanInfo spanInfo:style.getSpanInfoList()){ - if(spanInfo!=null){ - resultSet.add(spanInfo.getTag()); - } - } - } - List results=new ArrayList<>(resultSet); - results.sort(this); - return results; - } - @Override - public int compare(String s1, String s2) { - return s1.compareTo(s2); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/pool/builder/StyleBuilder.java b/src/ARSCLib/com/reandroid/arsc/pool/builder/StyleBuilder.java deleted file mode 100755 index e41e1efa..00000000 --- a/src/ARSCLib/com/reandroid/arsc/pool/builder/StyleBuilder.java +++ /dev/null @@ -1,43 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.pool.builder; - -import com.reandroid.arsc.item.StringItem; - -import java.util.regex.Pattern; - -public class StyleBuilder { - public static void buildStyle(StringItem stringItem){ - } - public static boolean hasStyle(StringItem stringItem){ - if(stringItem==null){ - return false; - } - return hasStyle(stringItem.getHtml()); - } - public static boolean hasStyle(String text){ - if(text==null){ - return false; - } - int i=text.indexOf('<'); - if(i<0){ - return false; - } - i=text.indexOf('>'); - return i>1; - } - private static final Pattern PATTERN_STYLE=Pattern.compile(""); -} diff --git a/src/ARSCLib/com/reandroid/arsc/util/FrameworkTable.java b/src/ARSCLib/com/reandroid/arsc/util/FrameworkTable.java deleted file mode 100755 index 3d4501ad..00000000 --- a/src/ARSCLib/com/reandroid/arsc/util/FrameworkTable.java +++ /dev/null @@ -1,435 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.util; - -import com.reandroid.arsc.BuildInfo; -import com.reandroid.arsc.array.SpecTypePairArray; -import com.reandroid.arsc.array.TypeBlockArray; -import com.reandroid.arsc.chunk.ChunkType; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.chunk.TypeBlock; -import com.reandroid.arsc.container.SpecTypePair; -import com.reandroid.arsc.group.EntryGroup; -import com.reandroid.arsc.header.HeaderBlock; -import com.reandroid.arsc.item.ReferenceItem; -import com.reandroid.arsc.item.TableString; -import com.reandroid.arsc.pool.TableStringPool; -import com.reandroid.arsc.value.Entry; -import com.reandroid.arsc.value.ResConfig; -import com.reandroid.common.FileChannelInputStream; - -import java.io.*; -import java.util.*; - -public class FrameworkTable extends TableBlock { - - private String frameworkName; - private int versionCode; - private int mainPackageId; - private ResNameMap mNameGroupMap; - private boolean mOptimized; - private boolean mOptimizeChecked; - public FrameworkTable(){ - super(); - } - - public boolean isAndroid(){ - return "android".equals(getFrameworkName()) - && getMainPackageId() == 0x01; - } - - public int getMainPackageId() { - if(mainPackageId!=0){ - return mainPackageId; - } - PackageBlock packageBlock = pickOne(); - if(packageBlock!=null){ - mainPackageId = packageBlock.getId(); - } - return mainPackageId; - } - - @Override - public void destroy(){ - clearResourceNameMap(); - this.frameworkName = null; - this.versionCode = 0; - this.mainPackageId = 0; - super.destroy(); - } - public int resolveResourceId(String typeName, String entryName){ - Entry entry = searchEntry(typeName, entryName); - if(entry !=null){ - return entry.getResourceId(); - } - return 0; - } - /** - * Loads all resource name map to memory for faster use - * Call this if you plan to search entries frequently - */ - public void loadResourceNameMap(){ - ResNameMap resNameMap = mNameGroupMap; - if(resNameMap == null){ - resNameMap = new ResNameMap<>(); - for(PackageBlock packageBlock:listPackages()){ - for(EntryGroup group:packageBlock.listEntryGroup()){ - resNameMap.add(group.getTypeName(), - group.getSpecName(), - group); - } - } - mNameGroupMap = resNameMap; - } - } - /** - * Clears resource name map from memory - */ - public void clearResourceNameMap(){ - if(mNameGroupMap!=null){ - mNameGroupMap.clear(); - mNameGroupMap =null; - } - } - private boolean hasResourceGroupMap(){ - return mNameGroupMap!=null; - } - private Entry searchEntryFromMap(String typeName, String entryName){ - if(mNameGroupMap ==null){ - return null; - } - EntryGroup entryGroup = mNameGroupMap.get(typeName, entryName); - if(entryGroup!=null){ - return entryGroup.pickOne(); - } - return null; - } - public Entry searchEntry(String typeName, String entryName){ - if(hasResourceGroupMap()){ - return searchEntryFromMap(typeName, entryName); - } - return searchEntryFromTable(typeName, entryName); - } - /** - * Since this is framework, we are sure of proper names. - */ - public Entry searchEntryFromTable(String typeName, String entryName){ - for(PackageBlock packageBlock:listPackages()){ - SpecTypePair specTypePair = packageBlock.getSpecTypePair(typeName); - if(specTypePair!=null){ - return specTypePair.getAnyEntry(entryName); - } - } - return null; - } - public int getVersionCode(){ - if(versionCode == 0 && isOptimized()){ - String version = loadProperty(PROP_VERSION_CODE); - if(version!=null){ - try{ - versionCode = Integer.parseInt(version); - }catch (NumberFormatException ignored){ - } - } - } - return versionCode; - } - public void setVersionCode(int value){ - versionCode = value; - if(isOptimized()){ - writeVersionCode(value); - } - } - public String getFrameworkName(){ - if(frameworkName == null){ - frameworkName = loadProperty(PROP_NAME); - } - if(frameworkName == null){ - PackageBlock packageBlock = pickOne(); - if(packageBlock!=null){ - String name = packageBlock.getName(); - if(name!=null && !name.trim().isEmpty()){ - frameworkName = name; - } - } - } - return frameworkName; - } - public void setFrameworkName(String value){ - frameworkName = value; - if(isOptimized()){ - writeProperty(PROP_NAME, value); - } - } - public void optimize(String name, int version){ - mOptimizeChecked = true; - mOptimized = false; - ensureTypeBlockNonNullEntries(); - optimizeEntries(); - optimizeTableString(); - writeVersionCode(version); - mOptimizeChecked = false; - setFrameworkName(name); - refresh(); - } - private void ensureTypeBlockNonNullEntries(){ - for(PackageBlock packageBlock:listPackages()){ - ensureTypeBlockNonNullEntries(packageBlock); - } - } - private void ensureTypeBlockNonNullEntries(PackageBlock packageBlock){ - for(SpecTypePair specTypePair:packageBlock.listSpecTypePairs()){ - ensureTypeBlockNonNullEntries(specTypePair); - } - } - private void ensureTypeBlockNonNullEntries(SpecTypePair specTypePair){ - Map map = specTypePair.createEntryGroups(); - for(EntryGroup entryGroup:map.values()){ - ensureNonNullDefaultEntry(entryGroup); - } - } - private void ensureNonNullDefaultEntry(EntryGroup entryGroup){ - Entry defEntry = entryGroup.getDefault(false); - Entry entry; - if(defEntry==null){ - entry = entryGroup.pickOne(); - if(entry == null){ - return; - } - SpecTypePair specTypePair = entry.getTypeBlock().getParentSpecTypePair(); - TypeBlock type = specTypePair.getOrCreateTypeBlock(new ResConfig()); - defEntry = type.getOrCreateEntry((short) (entry.getId() & 0xffff)); - } - if(!defEntry.isNull()){ - return; - } - entry = entryGroup.pickOne(); - if(entry.isNull()){ - return; - } - defEntry.merge(entry); - defEntry.isDefault(); - } - private void optimizeEntries(){ - Map groupMap=scanAllEntryGroups(); - for(EntryGroup group:groupMap.values()){ - List entryList = getEntriesToRemove(group); - removeEntries(entryList); - } - for(PackageBlock pkg:listPackages()){ - removeEmptyBlocks(pkg); - } - for(PackageBlock pkg:listPackages()){ - pkg.removeEmpty(); - pkg.refresh(); - } - } - private void removeEmptyBlocks(PackageBlock pkg){ - SpecTypePairArray specTypePairArray = pkg.getSpecTypePairArray(); - specTypePairArray.sort(); - List specTypePairList=new ArrayList<>(specTypePairArray.listItems()); - for(SpecTypePair specTypePair:specTypePairList){ - removeEmptyBlocks(specTypePair); - } - } - private void removeEmptyBlocks(SpecTypePair specTypePair){ - TypeBlockArray typeBlockArray = specTypePair.getTypeBlockArray(); - if(typeBlockArray.childesCount()<2){ - return; - } - typeBlockArray.removeEmptyBlocks(); - } - private void optimizeTableString(){ - removeUnusedTableString(); - shrinkTableString(); - getStringPool().getStyleArray().clearChildes(); - removeUnusedTableString(); - } - private void removeUnusedTableString(){ - TableStringPool tableStringPool=getStringPool(); - tableStringPool.removeUnusedStrings(); - tableStringPool.refresh(); - } - private void shrinkTableString(){ - TableStringPool tableStringPool=getStringPool(); - tableStringPool.getStringsArray().ensureSize(1); - TableString title=tableStringPool.get(0); - title.set(BuildInfo.getRepo()); - for(TableString tableString:tableStringPool.getStringsArray().listItems()){ - if(tableString==title){ - continue; - } - shrinkTableString(title, tableString); - } - tableStringPool.refresh(); - } - private void shrinkTableString(TableString zero, TableString tableString){ - List allRef = new ArrayList<>(tableString.getReferencedList()); - tableString.removeAllReference(); - for(ReferenceItem item:allRef){ - item.set(zero.getIndex()); - } - zero.addReference(allRef); - } - private void removeEntries(List removeList){ - for(Entry entry :removeList){ - removeEntry(entry); - } - } - private void removeEntry(Entry entry){ - TypeBlock typeBlock= entry.getTypeBlock(); - if(typeBlock==null){ - return; - } - typeBlock.removeEntry(entry); - - } - private List getEntriesToRemove(EntryGroup group){ - List results=new ArrayList<>(); - Entry mainEntry=group.pickOne(); - if(mainEntry==null){ - return results; - } - Iterator itr = group.iterator(true); - while (itr.hasNext()){ - Entry entry =itr.next(); - if(entry ==mainEntry){ - continue; - } - results.add(entry); - } - return results; - } - private Map scanAllEntryGroups(){ - Map results=new HashMap<>(); - for(PackageBlock packageBlock:listPackages()){ - Map map=packageBlock.getEntriesGroupMap(); - for(Map.Entry entry:map.entrySet()){ - int id=entry.getKey(); - EntryGroup group=entry.getValue(); - EntryGroup exist=results.get(id); - if(exist!=null && exist.getDefault()!=null){ - if(exist.getDefault()!=null){ - continue; - } - results.remove(id); - } - results.put(id, group); - } - } - return results; - } - private TableString writeProperty(String name, String value){ - if(!name.endsWith(":")){ - name=name+":"; - } - if(value==null){ - value=""; - } - if(!value.startsWith(name)){ - value=name+value; - } - TableString tableString=loadPropertyString(name); - if(tableString!=null){ - tableString.set(value); - }else { - TableStringPool tableStringPool=getStringPool(); - tableString=tableStringPool.getOrCreate(value); - } - return tableString; - } - private String loadProperty(String name){ - if(name==null){ - return null; - } - if(!name.endsWith(":")){ - name=name+":"; - } - TableString tableString=loadPropertyString(name); - if(tableString==null){ - return null; - } - String str=tableString.get().trim(); - return str.substring(name.length()).trim(); - } - private TableString loadPropertyString(String name){ - if(name==null){ - return null; - } - if(!name.endsWith(":")){ - name=name+":"; - } - TableStringPool tableStringPool=getStringPool(); - int max=PROP_COUNT; - for(int i=0;i0){ - writeString(writer,x , length); - } - } - private void writeHex(Writer writer, byte b) throws IOException { - String hex = HexUtil.toHex(null, (0xff & b), 2).toUpperCase(); - writer.write(hex); - } - private void writeString(Writer writer, int width, int position) throws IOException { - if(!mAppendString){ - return; - } - int start = position - width; - if(start<0){ - start=0; - } - int rem = this.width - width; - if(rem > 0){ - fillLastRow(writer, position); - } - writer.write(' '); - writer.write(' '); - writer.write(' '); - writer.write(' '); - String text = new String(this.byteArray, start, width, getEncoding()); - for(char ch:text.toCharArray()){ - printChar(writer, ch); - } - } - private void fillLastRow(Writer writer, int position) throws IOException { - int rem = width - position % width; - for(int i=0; ibase){ - digits++; - max=max/base; - } - lineNumberFormat = "%0"+digits+(decimalLineNumber?"d":"x"); - } - private void writeNewLine(Writer writer) throws IOException { - writer.write('\n'); - } - - public static String printHex(byte[] byteArray){ - return toHex(byteArray, false, false); - } - public static String toHex(byte[] byteArray){ - if(byteArray==null){ - return "null"; - } - return toHex(byteArray, byteArray.length>64); - } - public static String toHex(byte[] byteArray, boolean showLineNumber){ - return toHex(byteArray, showLineNumber, true); - } - public static String toHex(byte[] byteArray, boolean showLineNumber, boolean appendString){ - if(byteArray==null){ - return "null"; - } - StringWriter writer=new StringWriter(); - HexBytesWriter hexBytesWriter = new HexBytesWriter(byteArray); - hexBytesWriter.setShowLineNumber(showLineNumber); - hexBytesWriter.setAppendString(appendString); - try { - hexBytesWriter.write(writer); - writer.flush(); - writer.close(); - } catch (IOException ignored) { - } - return writer.toString(); - } - - private static final int DEFAULT_WIDTH = 16; - private static final int DEFAULT_COLUMNS = 4; - private static final int DEFAULT_INDENT = 0; -} diff --git a/src/ARSCLib/com/reandroid/arsc/util/HexUtil.java b/src/ARSCLib/com/reandroid/arsc/util/HexUtil.java deleted file mode 100644 index 1aa3c26a..00000000 --- a/src/ARSCLib/com/reandroid/arsc/util/HexUtil.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.util; - -public class HexUtil { - public static String toHex2(byte num){ - return toHex((long)(num & 0x00000000000000ffL), 2); - } - public static String toHex4(short num){ - return toHex((long)(num & 0x000000000000ffffL), 4); - } - public static String toHex8(int num){ - return toHex(num, 8); - } - public static String toHex8(long num){ - return toHex(num, 8); - } - public static String toHex(int num, int minLength){ - return toHex((0x00000000ffffffffL & num), minLength); - } - public static String toHex(long num, int minLength){ - String hex = Long.toHexString(num); - StringBuilder builder = new StringBuilder(); - builder.append('0'); - builder.append('x'); - int rem = minLength - hex.length(); - for(int i=0; i < rem; i++){ - builder.append('0'); - } - builder.append(hex); - return builder.toString(); - } - public static String toHexNoPrefix8(int num){ - return toHex(null, (0x00000000ffffffffL & num), 8); - } - public static String toHexNoPrefix(int num, int minLength){ - return toHex(null, (0x00000000ffffffffL & num), minLength); - } - public static String toHex8(String prefix, int num){ - return toHex(prefix, (0x00000000ffffffffL & num), 8); - } - public static String toHex(String prefix, int num, int minLength){ - return toHex(prefix, (0x00000000ffffffffL & num), minLength); - } - public static String toHex(String prefix, long num, int minLength){ - String hex = Long.toHexString(num); - StringBuilder builder = new StringBuilder(); - if(prefix != null){ - builder.append(prefix); - } - int rem = minLength - hex.length(); - for(int i=0; i < rem; i++){ - builder.append('0'); - } - builder.append(hex); - return builder.toString(); - } - public static int parseHex(String hexString){ - hexString = trim0x(hexString); - return (int) Long.parseLong(hexString, 16); - } - private static String trim0x(String hexString){ - if(hexString == null || hexString.length() < 3){ - return hexString; - } - if(hexString.charAt(0) == '0' && hexString.charAt(1) == 'x'){ - hexString = hexString.substring(2); - } - return hexString; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/util/ResNameMap.java b/src/ARSCLib/com/reandroid/arsc/util/ResNameMap.java deleted file mode 100644 index e4db8c66..00000000 --- a/src/ARSCLib/com/reandroid/arsc/util/ResNameMap.java +++ /dev/null @@ -1,65 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.util; - -import java.util.HashMap; -import java.util.Map; - -public class ResNameMap { - private final Object mLock = new Object(); - private final Map> mainMap; - public ResNameMap(){ - this.mainMap = new HashMap<>(); - } - - public VALUE get(String type, String name){ - synchronized (mLock){ - if(type==null || name==null){ - return null; - } - Map valueMap = mainMap.get(type); - if(valueMap!=null){ - return valueMap.get(name); - } - return null; - } - } - public void add(String type, String name, VALUE value){ - synchronized (mLock){ - if(type==null || name==null || value==null){ - return; - } - Map valueMap = mainMap.get(type); - if(valueMap==null){ - valueMap=new HashMap<>(); - mainMap.put(type, valueMap); - } - valueMap.putIfAbsent(name, value); - } - } - public void clear(){ - synchronized (mLock){ - for(Map valueMap:mainMap.values()){ - valueMap.clear(); - } - mainMap.clear(); - } - } - - private static final String TYPE_ATTR = "attr"; - private static final String TYPE_ID = "id"; - -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/AttributeDataFormat.java b/src/ARSCLib/com/reandroid/arsc/value/AttributeDataFormat.java deleted file mode 100644 index 81f983d1..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/AttributeDataFormat.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value; - -public enum AttributeDataFormat { - - REFERENCE(1<<0, - new ValueType[]{ - ValueType.REFERENCE, - ValueType.ATTRIBUTE, - ValueType.DYNAMIC_REFERENCE, - ValueType.DYNAMIC_ATTRIBUTE, - ValueType.NULL, - }), - STRING(1<<1, new ValueType[]{ - ValueType.STRING - }), - INTEGER(1<<2, new ValueType[]{ - ValueType.INT_DEC, - ValueType.INT_HEX - }), - BOOL(1<<3, new ValueType[]{ - ValueType.INT_BOOLEAN - }), - COLOR(1<<4, new ValueType[]{ - ValueType.INT_COLOR_RGB4, - ValueType.INT_COLOR_ARGB4, - ValueType.INT_COLOR_RGB8, - ValueType.INT_COLOR_ARGB8 - }), - FLOAT(1<<5, new ValueType[]{ - ValueType.FLOAT - }), - DIMENSION(1<<6, new ValueType[]{ - ValueType.DIMENSION - }), - FRACTION(1<<7, new ValueType[]{ - ValueType.FRACTION - }), - ANY(0x0000FFFF, ValueType.values().clone()), - - ENUM(1<<16, new ValueType[]{ - ValueType.INT_DEC, - ValueType.INT_HEX - }), - FLAG(1<<17, new ValueType[]{ - ValueType.INT_HEX, - ValueType.INT_DEC - }); - - private final int mask; - private final ValueType[] valueTypes; - - AttributeDataFormat(int mask, ValueType[] valueTypes) { - this.mask = mask; - this.valueTypes = valueTypes; - } - - public int getMask() { - return mask; - } - public boolean matches(int value){ - int mask = this.mask; - return (value & mask) == mask; - } - - public ValueType[] getValueTypes() { - return valueTypes.clone(); - } - public boolean contains(ValueType valueType){ - ValueType[] valueTypes = this.valueTypes; - for(int i = 0; i < valueTypes.length; i++){ - if(valueType == valueTypes[i]){ - return true; - } - } - return false; - } - public String getName(){ - return name().toLowerCase(); - } - @Override - public String toString(){ - StringBuilder builder = new StringBuilder(); - builder.append(getName()); - builder.append('{'); - ValueType[] valueTypes = this.valueTypes; - for(int i = 0; i < valueTypes.length; i++){ - if(i != 0){ - builder.append(','); - } - builder.append(valueTypes[i]); - } - builder.append('}'); - return builder.toString(); - } - - public static String toStringValueTypes(int data){ - return toString(decodeValueTypes(data)); - } - public static String toString(AttributeDataFormat[] typeValues){ - if(typeValues == null || typeValues.length == 0){ - return null; - } - StringBuilder builder = new StringBuilder(); - - boolean appendOnce = false; - int appendedTypes = 0; - for(AttributeDataFormat typeValue : typeValues){ - if(typeValue == ENUM || typeValue == FLAG){ - continue; - } - if(typeValue == AttributeDataFormat.ANY){ - return AttributeDataFormat.ANY.getName(); - } - int mask = typeValue.getMask(); - if((appendedTypes & mask) == mask){ - continue; - } - if(appendOnce){ - builder.append('|'); - } - builder.append(typeValue.getName()); - appendOnce = true; - appendedTypes = appendedTypes | mask; - } - return builder.toString(); - } - public static int sum(AttributeDataFormat[] typeValues){ - if(typeValues == null){ - return 0; - } - int result = 0; - for(AttributeDataFormat typeValue:typeValues){ - if(typeValue==null){ - continue; - } - result |= typeValue.getMask(); - } - return result; - } - - public static AttributeDataFormat[] decodeValueTypes(int data){ - AttributeDataFormat[] tmp = new AttributeDataFormat[VALUE_TYPES.length]; - int length = 0; - for(AttributeDataFormat typeValue : VALUE_TYPES){ - int mask = typeValue.getMask(); - if(mask == data){ - return new AttributeDataFormat[]{typeValue}; - } - if(typeValue == ANY){ - continue; - } - if((data & mask) == mask){ - tmp[length] = typeValue; - length++; - } - } - if(length == 0){ - return null; - } - AttributeDataFormat[] results = new AttributeDataFormat[length]; - System.arraycopy(tmp, 0, results, 0, length); - return results; - } - public static AttributeDataFormat[] parseValueTypes(String valuesTypes){ - if(valuesTypes == null){ - return null; - } - valuesTypes = valuesTypes.trim(); - String[] valueNames = valuesTypes.split("\\s*\\|\\s*"); - AttributeDataFormat[] tmp = new AttributeDataFormat[VALUE_TYPES.length]; - int length = 0; - for(String name:valueNames){ - AttributeDataFormat typeValue = fromValueTypeName(name); - if(typeValue!=null){ - tmp[length] = typeValue; - length++; - } - } - if(length == 0){ - return null; - } - AttributeDataFormat[] results = new AttributeDataFormat[length]; - System.arraycopy(tmp, 0, results, 0, length); - return results; - } - public static AttributeDataFormat valueOf(int mask){ - for(AttributeDataFormat typeValue : VALUE_TYPES){ - if(typeValue.getMask() == mask){ - return typeValue; - } - } - return null; - } - public static AttributeDataFormat typeOfBag(int data){ - for(AttributeDataFormat typeValue : BAG_TYPES){ - if(typeValue.matches(data)){ - return typeValue; - } - } - return null; - } - public static AttributeDataFormat fromValueTypeName(String name){ - if(name == null){ - return null; - } - name = name.trim().toUpperCase(); - for(AttributeDataFormat typeValue : VALUE_TYPES){ - if(name.equals(typeValue.name())){ - return typeValue; - } - } - return null; - } - public static AttributeDataFormat fromBagTypeName(String bagTypeName){ - if(bagTypeName == null){ - return null; - } - bagTypeName = bagTypeName.trim().toUpperCase(); - for(AttributeDataFormat typeValue: BAG_TYPES){ - if(bagTypeName.equals(typeValue.name())){ - return typeValue; - } - } - return null; - } - - private static final AttributeDataFormat[] VALUE_TYPES = new AttributeDataFormat[]{ - REFERENCE, - STRING, - INTEGER, - BOOL, - COLOR, - FLOAT, - DIMENSION, - FRACTION, - ANY - }; - - private static final AttributeDataFormat[] BAG_TYPES = new AttributeDataFormat[]{ - ENUM, - FLAG - }; -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/AttributeType.java b/src/ARSCLib/com/reandroid/arsc/value/AttributeType.java deleted file mode 100644 index 6682ab8e..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/AttributeType.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value; - -public enum AttributeType { - - FORMATS(0x01000000), - MIN(0x01000001), - MAX(0x01000002), - L10N(0x01000003), - - OTHER(0x01000004), - ZERO(0x01000005), - ONE(0x01000006), - TWO(0x01000007), - FEW(0x01000008), - MANY(0x01000009); - - private final int id; - AttributeType(int id) { - this.id = id; - } - - public int getId() { - return id; - } - - public boolean isPlural(){ - int i = id & 0xffff; - return i>=4 && i<=9; - } - - public String getName(){ - return name().toLowerCase(); - } - @Override - public String toString(){ - return getName(); - } - - public static AttributeType valueOf(int value){ - for(AttributeType type:VALUES){ - if(type.getId() == value){ - return type; - } - } - return null; - } - - public static AttributeType fromName(String name){ - if(name == null){ - return null; - } - name = name.toUpperCase(); - if("FORMAT".equals(name)){ - return FORMATS; - } - for(AttributeType type:VALUES){ - if(name.equals(type.name())){ - return type; - } - } - return null; - } - - private static final AttributeType[] VALUES = values(); -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/AttributeValue.java b/src/ARSCLib/com/reandroid/arsc/value/AttributeValue.java deleted file mode 100644 index 751ef9e8..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/AttributeValue.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value; - -public interface AttributeValue extends Value{ - int getNameResourceID(); - void setNameResourceID(int resourceId); - Entry resolveName(); -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/CompoundEntry.java b/src/ARSCLib/com/reandroid/arsc/value/CompoundEntry.java deleted file mode 100644 index 7ff54f1b..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/CompoundEntry.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value; - -import com.reandroid.arsc.array.CompoundItemArray; -import com.reandroid.arsc.pool.TableStringPool; -import com.reandroid.json.JSONObject; - -public abstract class CompoundEntry> extends TableEntry { - public CompoundEntry(ARRAY mapArray){ - super(new EntryHeaderMap(), mapArray); - } - // Valid for type attr - public AttributeDataFormat[] getAttributeTypeFormats(){ - ITEM item = getByType(AttributeType.FORMATS); - if(item != null){ - return item.getAttributeTypeFormats(); - } - return null; - } - public boolean containsType(AttributeType attributeType){ - return getValue().containsType(attributeType); - } - public ITEM getByType(AttributeType attributeType){ - return getValue().getByType(attributeType); - } - public void refresh(){ - getHeader().setValuesCount(getValue().childesCount()); - } - public ITEM[] listResValueMap(){ - return getValue().getChildes(); - } - public int getParentId(){ - return getHeader().getParentId(); - } - public void setParentId(int parentId){ - getHeader().setParentId(parentId); - } - public int getValuesCount(){ - return getHeader().getValuesCount(); - } - public void setValuesCount(int valuesCount){ - getHeader().setValuesCount(valuesCount); - getValue().setChildesCount(valuesCount); - } - @Override - void linkTableStringsInternal(TableStringPool tableStringPool){ - for(ITEM item : listResValueMap()){ - item.linkTableStrings(tableStringPool); - } - } - @Override - void onHeaderLoaded(ValueHeader valueHeader){ - getValue().setChildesCount(getValuesCount()); - } - - @Override - void onRemoved(){ - getHeader().onRemoved(); - getValue().onRemoved(); - } - - @Override - public JSONObject toJson() { - JSONObject jsonObject = new JSONObject(); - getHeader().toJson(jsonObject); - jsonObject.put(NAME_values, getValue().toJson()); - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - getHeader().fromJson(json); - getValue().fromJson(json.optJSONArray(NAME_values)); - refresh(); - } - - @Override - public String toString(){ - StringBuilder builder = new StringBuilder(); - builder.append(getHeader()); - ITEM[] valueMaps = listResValueMap(); - int len = valueMaps.length; - int max = len; - if(max>4){ - max = 4; - } - for(int i=0;i0){ - if(max!=len){ - builder.append("\n ..."); - } - builder.append("\n "); - } - return builder.toString(); - } - - public static final String NAME_values = "values"; -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/Entry.java b/src/ARSCLib/com/reandroid/arsc/value/Entry.java deleted file mode 100755 index ca0fac25..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/Entry.java +++ /dev/null @@ -1,477 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value; - -import com.reandroid.arsc.array.EntryArray; -import com.reandroid.arsc.array.ResValueMapArray; -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.base.BlockCounter; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.SpecBlock; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.chunk.TypeBlock; -import com.reandroid.arsc.container.SpecTypePair; -import com.reandroid.arsc.group.EntryGroup; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.item.*; -import com.reandroid.arsc.pool.SpecStringPool; -import com.reandroid.arsc.pool.TableStringPool; -import com.reandroid.arsc.util.HexUtil; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONObject; - - -import java.io.IOException; -import java.io.OutputStream; - -public class Entry extends Block implements JSONConvert { - private TableEntry mTableEntry; - - public Entry(){ - super(); - } - - public void linkTableStringsInternal(TableStringPool tableStringPool){ - TableEntry tableEntry = getTableEntry(); - tableEntry.linkTableStringsInternal(tableStringPool); - } - public void linkSpecStringsInternal(SpecStringPool specStringPool){ - TableEntry tableEntry = getTableEntry(); - ValueHeader header = tableEntry.getHeader(); - header.linkSpecStringsInternal(specStringPool); - } - public ResValue getResValue(){ - TableEntry tableEntry = getTableEntry(); - if(tableEntry instanceof ResTableEntry){ - return ((ResTableEntry)tableEntry).getValue(); - } - return null; - } - public ResValueMapArray getResValueMapArray(){ - TableEntry tableEntry = getTableEntry(); - if(tableEntry instanceof ResTableMapEntry){ - return ((ResTableMapEntry)tableEntry).getValue(); - } - return null; - } - public SpecFlag getSpecFlag(){ - SpecBlock specBlock = getSpecBlock(); - if(specBlock == null){ - return null; - } - return specBlock.getSpecFlag(getId()); - } - public void ensureComplex(boolean isComplex){ - ensureTableEntry(isComplex); - } - public int getId(){ - int id = getIndex(); - EntryArray entryArray = getParentInstance(EntryArray.class); - if(entryArray != null){ - id = entryArray.getEntryId(id); - } - return id; - } - public String getName(){ - SpecString specString = getSpecString(); - if(specString!=null){ - return specString.get(); - } - return null; - } - public String getTypeName(){ - TypeBlock typeBlock = getTypeBlock(); - if(typeBlock!=null){ - return typeBlock.getTypeName(); - } - return null; - } - public int getResourceId(){ - PackageBlock packageBlock = getPackageBlock(); - if(packageBlock==null){ - return 0; - } - TypeBlock typeBlock = getTypeBlock(); - if(typeBlock==null){ - return 0; - } - return (packageBlock.getId()<<24) - | (typeBlock.getId() << 16) - | getId(); - } - public int getSpecReference(){ - TableEntry tableEntry = getTableEntry(); - if(tableEntry == null){ - return 0; - } - return tableEntry.getHeader().getKey(); - } - public TypeString getTypeString(){ - TypeBlock typeBlock = getTypeBlock(); - if(typeBlock!=null){ - return typeBlock.getTypeString(); - } - return null; - } - public boolean isDefault(){ - ResConfig resConfig = getResConfig(); - if(resConfig!=null){ - return resConfig.isDefault(); - } - return false; - } - public void setSpecReference(StringItem specReference){ - TableEntry tableEntry = getTableEntry(); - if(tableEntry == null){ - return; - } - tableEntry.getHeader().setKey(specReference); - } - public void setSpecReference(int ref){ - TableEntry tableEntry = getTableEntry(); - if(tableEntry == null){ - return; - } - tableEntry.getHeader().setKey(ref); - } - private Entry searchEntry(int resourceId){ - if(resourceId==getResourceId()){ - return this; - } - PackageBlock packageBlock= getPackageBlock(); - if(packageBlock==null){ - return null; - } - TableBlock tableBlock = packageBlock.getTableBlock(); - if(tableBlock==null){ - return null; - } - EntryGroup entryGroup = tableBlock.search(resourceId); - if(entryGroup!=null){ - return entryGroup.pickOne(); - } - return null; - } - public ResValue setValueAsRaw(ValueType valueType, int data){ - TableEntry tableEntry = ensureTableEntry(false); - ResValue resValue = (ResValue) tableEntry.getValue(); - resValue.setTypeAndData(valueType, data); - return resValue; - } - public ResValue setValueAsBoolean(boolean val){ - int data = val?0xffffffff:0; - return setValueAsRaw(ValueType.INT_BOOLEAN, data); - } - public ResValue setValueAsReference(int resourceId){ - return setValueAsRaw(ValueType.REFERENCE, resourceId); - } - public ResValue setValueAsString(String str){ - TableEntry tableEntry = ensureTableEntry(false); - ResValue resValue = (ResValue) tableEntry.getValue(); - resValue.setValueAsString(str); - return resValue; - } - public SpecString getSpecString(){ - TableEntry tableEntry = getTableEntry(); - if(tableEntry == null){ - return null; - } - PackageBlock packageBlock = getPackageBlock(); - if(packageBlock == null){ - return null; - } - return packageBlock.getSpecStringPool() - .get(tableEntry.getHeader().getKey()); - } - public ResConfig getResConfig(){ - TypeBlock typeBlock = getTypeBlock(); - if(typeBlock!=null){ - return typeBlock.getResConfig(); - } - return null; - } - public SpecBlock getSpecBlock(){ - TypeBlock typeBlock = getTypeBlock(); - if(typeBlock == null){ - return null; - } - SpecTypePair specTypePair = typeBlock.getParentSpecTypePair(); - if(specTypePair==null){ - return null; - } - return specTypePair.getSpecBlock(); - } - public TypeBlock getTypeBlock(){ - return getParent(TypeBlock.class); - } - public String getPackageName(){ - PackageBlock packageBlock = getPackageBlock(); - if(packageBlock!=null){ - return packageBlock.getName(); - } - return null; - } - public PackageBlock getPackageBlock(){ - return getParent(PackageBlock.class); - } - private TableEntry ensureTableEntry(boolean is_complex){ - TableEntry tableEntry = getTableEntry(); - - boolean is_correct_type = (is_complex && tableEntry instanceof ResTableMapEntry) || (!is_complex && tableEntry instanceof ResTableEntry); - if (tableEntry == null || !is_correct_type) { - tableEntry = createTableEntry(is_complex); - setTableEntry(tableEntry); - } - return tableEntry; - } - - public TableEntry getTableEntry(){ - return mTableEntry; - } - public ValueHeader getHeader(){ - TableEntry tableEntry = getTableEntry(); - if(tableEntry!=null){ - return tableEntry.getHeader(); - } - return null; - } - - @Override - public boolean isNull(){ - return getTableEntry()==null; - } - @Override - public void setNull(boolean is_null){ - if(is_null){ - setTableEntry(null); - } - } - @Override - public byte[] getBytes() { - if(isNull()){ - return null; - } - return getTableEntry().getBytes(); - } - @Override - public int countBytes() { - if(isNull()){ - return 0; - } - return getTableEntry().countBytes(); - } - @Override - public void onCountUpTo(BlockCounter counter) { - if(counter.FOUND){ - return; - } - if(counter.END==this){ - counter.FOUND=true; - return; - } - if(isNull()){ - return; - } - counter.addCount(getTableEntry().countBytes()); - } - @Override - protected int onWriteBytes(OutputStream stream) throws IOException { - if(isNull()){ - return 0; - } - return getTableEntry().writeBytes(stream); - } - @Override - public void onReadBytes(BlockReader reader) throws IOException { - TableEntry tableEntry = createTableEntry(reader); - setTableEntry(tableEntry); - tableEntry.readBytes(reader); - } - - public boolean isComplex(){ - return getTableEntry() instanceof CompoundEntry; - } - public void setTableEntry(TableEntry tableEntry){ - if(tableEntry==this.mTableEntry){ - return; - } - onTableEntryRemoved(); - if(tableEntry==null){ - return; - } - tableEntry.setIndex(0); - tableEntry.setParent(this); - this.mTableEntry = tableEntry; - onTableEntryAdded(); - } - private void onTableEntryAdded(){ - PackageBlock packageBlock = getPackageBlock(); - if(packageBlock!=null){ - packageBlock.onEntryAdded(this); - } - } - private void onTableEntryRemoved(){ - TableEntry exist = this.mTableEntry; - if(exist == null){ - return; - } - PackageBlock packageBlock = getPackageBlock(); - if(packageBlock!=null){ - packageBlock.removeEntryGroup(this); - } - exist.onRemoved(); - exist.setIndex(-1); - exist.setParent(null); - this.mTableEntry = null; - } - private TableEntry createTableEntry(BlockReader reader) throws IOException { - int startPosition = reader.getPosition(); - reader.offset(2); - boolean is_complex = (0x0001 & reader.readShort()) == 0x0001; - reader.seek(startPosition); - return createTableEntry(is_complex); - } - private TableEntry createTableEntry(boolean is_complex) { - if(is_complex){ - return new ResTableMapEntry(); - }else { - return new ResTableEntry(); - } - } - - @Override - public JSONObject toJson() { - if(isNull()){ - return null; - } - return getTableEntry().toJson(); - } - @Override - public void fromJson(JSONObject json) { - if(json==null){ - setNull(true); - return; - } - boolean is_complex = json.optBoolean(ValueHeader.NAME_is_complex, false); - TableEntry entry = createTableEntry(is_complex); - setTableEntry(entry); - entry.fromJson(json); - } - - public void merge(Entry entry){ - if(!shouldMerge(entry)){ - return; - } - TableEntry tableEntry = entry.getTableEntry(); - TableEntry existEntry = ensureTableEntry(tableEntry instanceof ResTableMapEntry); - existEntry.merge(tableEntry); - } - private boolean shouldMerge(Entry coming){ - if(coming == null || coming == this || coming.isNull()){ - return false; - } - if(this.isNull()){ - return true; - } - return getTableEntry().shouldMerge(coming.getTableEntry()); - } - - public String buildResourceName(int resourceId, char prefix, boolean includeType){ - if(resourceId==0){ - return null; - } - Entry entry=searchEntry(resourceId); - return buildResourceName(entry, prefix, includeType); - } - public String buildResourceName(Entry entry, char prefix, boolean includeType){ - if(entry==null){ - return null; - } - String pkgName=entry.getPackageName(); - if(getResourceId()==entry.getResourceId()){ - pkgName=null; - }else if(pkgName!=null){ - if(pkgName.equals(this.getPackageName())){ - pkgName=null; - } - } - String type=null; - if(includeType){ - type=entry.getTypeName(); - } - String name=entry.getName(); - return buildResourceName(prefix, pkgName, type, name); - } - public String getResourceName(){ - return buildResourceName('@',null, getTypeName(), getName()); - } - public String getResourceName(char prefix){ - return getResourceName(prefix, false, true); - } - public String getResourceName(char prefix, boolean includePackage, boolean includeType){ - String pkg=includePackage?getPackageName():null; - String type=includeType?getTypeName():null; - return buildResourceName(prefix,pkg, type, getName()); - } - - @Override - public String toString(){ - StringBuilder builder = new StringBuilder(); - builder.append(HexUtil.toHex8(getResourceId())); - builder.append(' '); - ResConfig resConfig = getResConfig(); - if(resConfig!=null){ - builder.append(resConfig); - builder.append(' '); - } - SpecFlag specFlag = getSpecFlag(); - if(specFlag!=null){ - builder.append(specFlag); - builder.append(' '); - } - if(isNull()){ - builder.append("NULL"); - return builder.toString(); - } - builder.append('@'); - builder.append(getTypeName()); - builder.append('/'); - builder.append(getName()); - return builder.toString(); - } - - public static String buildResourceName(char prefix, String packageName, String type, String name){ - if(name==null){ - return null; - } - StringBuilder builder=new StringBuilder(); - if(prefix!=0){ - builder.append(prefix); - } - if(packageName!=null){ - builder.append(packageName); - builder.append(':'); - } - if(type!=null){ - builder.append(type); - builder.append('/'); - } - builder.append(name); - return builder.toString(); - } - - public static final String NAME_id = "id"; -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/EntryHeader.java b/src/ARSCLib/com/reandroid/arsc/value/EntryHeader.java deleted file mode 100644 index 375232f9..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/EntryHeader.java +++ /dev/null @@ -1,56 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value; - -public class EntryHeader extends ValueHeader { - public EntryHeader(){ - super(HEADER_SIZE_SCALAR); - } - - @Override - public String toString(){ - if(isNull()){ - return "null"; - } - StringBuilder builder=new StringBuilder(); - int byte_size = getSize(); - int read_size = readSize(); - if(byte_size!=8){ - builder.append("size=").append(byte_size); - } - if(byte_size!=read_size){ - builder.append(" readSize=").append(read_size); - } - if(isComplex()){ - builder.append(" complex"); - } - if(isPublic()){ - builder.append(" public"); - } - if(isWeak()){ - builder.append(" weak"); - } - String name = getName(); - if(name!=null){ - builder.append(" name=").append(name); - }else { - builder.append(" key=").append(getKey()); - } - return builder.toString(); - } - - private static final short HEADER_SIZE_SCALAR = 8; -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/EntryHeaderMap.java b/src/ARSCLib/com/reandroid/arsc/value/EntryHeaderMap.java deleted file mode 100644 index 0714e373..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/EntryHeaderMap.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value; - -import com.reandroid.arsc.util.HexUtil; -import com.reandroid.json.JSONObject; - -public class EntryHeaderMap extends ValueHeader { - public EntryHeaderMap(){ - super(HEADER_SIZE_COMPLEX); - setComplex(true); - } - public int getParentId(){ - return getInteger(getBytesInternal(), OFFSET_PARENT_ID); - } - public void setParentId(int parentId){ - putInteger(getBytesInternal(), OFFSET_PARENT_ID, parentId); - } - public int getValuesCount(){ - return getInteger(getBytesInternal(), OFFSET_VALUE_COUNT); - } - public void setValuesCount(int valuesCount){ - putInteger(getBytesInternal(), OFFSET_VALUE_COUNT, valuesCount); - } - - @Override - public void merge(ValueHeader valueHeader){ - if(valueHeader == this || !(valueHeader instanceof EntryHeaderMap)){ - return; - } - super.merge(valueHeader); - EntryHeaderMap entryHeaderMap = (EntryHeaderMap) valueHeader; - setParentId(entryHeaderMap.getParentId()); - setValuesCount(entryHeaderMap.getValuesCount()); - } - @Override - public void toJson(JSONObject jsonObject) { - super.toJson(jsonObject); - jsonObject.put(NAME_is_complex, true); - int parent_id = getParentId(); - if(parent_id!=0){ - jsonObject.put(NAME_parent_id, parent_id); - } - } - @Override - public void fromJson(JSONObject json) { - super.fromJson(json); - setComplex(json.optBoolean(NAME_is_complex, true)); - setParentId(json.optInt(NAME_parent_id)); - } - @Override - public String toString(){ - if(isNull()){ - return "null"; - } - StringBuilder builder=new StringBuilder(); - int byte_size = getSize(); - int read_size = readSize(); - if(byte_size!=16){ - builder.append("size=").append(byte_size); - } - if(byte_size!=read_size){ - builder.append(", readSize=").append(read_size); - } - if(isComplex()){ - builder.append(" complex"); - } - if(isPublic()){ - builder.append(", public"); - } - if(isWeak()){ - builder.append(", weak"); - } - String name = getName(); - if(name!=null){ - builder.append(", name=").append(name); - }else { - builder.append(", key=").append(getKey()); - } - int parentId = getParentId(); - if(parentId!=0){ - builder.append(", parentId="); - builder.append(HexUtil.toHex8(getParentId())); - } - builder.append(", count=").append(getValuesCount()); - return builder.toString(); - } - - private static final short HEADER_SIZE_COMPLEX = 16; - - private static final int OFFSET_PARENT_ID = 8; - private static final int OFFSET_VALUE_COUNT = 12; - - public static final String NAME_parent_id = "parent_id"; -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/LibraryInfo.java b/src/ARSCLib/com/reandroid/arsc/value/LibraryInfo.java deleted file mode 100755 index 92bacd04..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/LibraryInfo.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value; - -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.base.BlockCounter; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.item.FixedLengthString; -import com.reandroid.arsc.item.IntegerItem; -import com.reandroid.arsc.util.HexUtil; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONObject; - -import java.io.IOException; -import java.io.OutputStream; - -public class LibraryInfo extends Block implements JSONConvert { - private final IntegerItem mPackageId; - private final FixedLengthString mPackageName; - - public LibraryInfo(){ - super(); - this.mPackageId=new IntegerItem(); - this.mPackageName = new FixedLengthString(256); - mPackageId.setIndex(0); - mPackageId.setParent(this); - mPackageName.setIndex(1); - mPackageName.setParent(this); - } - - public int getPackageId(){ - return mPackageId.get(); - } - public void setPackageId(int id){ - mPackageId.set(id); - } - public String getPackageName(){ - return mPackageName.get(); - } - public void setPackageName(String packageName){ - mPackageName.set(packageName); - } - - @Override - public byte[] getBytes() { - if(isNull()){ - return null; - } - return addBytes(mPackageId.getBytes(), mPackageName.getBytes()); - } - @Override - public int countBytes() { - if(isNull()){ - return 0; - } - return mPackageId.countBytes()+mPackageName.countBytes(); - } - @Override - public void onCountUpTo(BlockCounter counter) { - if(counter.FOUND){ - return; - } - if(counter.END==this){ - counter.FOUND=true; - return; - } - mPackageId.onCountUpTo(counter); - mPackageName.onCountUpTo(counter); - } - @Override - protected int onWriteBytes(OutputStream stream) throws IOException { - int result=mPackageId.writeBytes(stream); - result+=mPackageName.writeBytes(stream); - return result; - } - @Override - public void onReadBytes(BlockReader reader) throws IOException{ - mPackageId.readBytes(reader); - mPackageName.readBytes(reader); - } - - @Override - public JSONObject toJson() { - JSONObject jsonObject=new JSONObject(); - jsonObject.put("id", getPackageId()); - jsonObject.put("name", getPackageName()); - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - setPackageId(json.getInt("id")); - setPackageName(json.getString("name")); - } - public void merge(LibraryInfo info){ - if(info==null||info==this){ - return; - } - if(getPackageId()!=info.getPackageId()){ - throw new IllegalArgumentException("Can not add different id libraries: " - +getPackageId()+"!="+info.getPackageId()); - } - setPackageName(info.getPackageName()); - } - @Override - public String toString(){ - StringBuilder builder=new StringBuilder(); - builder.append("LIBRARY{"); - builder.append(HexUtil.toHex2((byte) getPackageId())); - builder.append(':'); - String name=getPackageName(); - if(name==null){ - name="NULL"; - } - builder.append(name); - builder.append('}'); - return builder.toString(); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/ResConfig.java b/src/ARSCLib/com/reandroid/arsc/value/ResConfig.java deleted file mode 100755 index 41da0746..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/ResConfig.java +++ /dev/null @@ -1,2322 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value; - -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.container.FixedBlockContainer; -import com.reandroid.arsc.io.BlockLoad; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.item.ByteArray; -import com.reandroid.arsc.item.IntegerItem; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONObject; - -import java.io.IOException; -import java.util.Arrays; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class ResConfig extends FixedBlockContainer - implements BlockLoad, JSONConvert, Comparable { - - private final IntegerItem configSize; - private final ByteArray mValuesContainer; - - private String mQualifiers; - private int mQualifiersStamp; - - public ResConfig(){ - super(2); - this.configSize = new IntegerItem(SIZE_64); - this.mValuesContainer = new ByteArray(SIZE_64 - 4); - addChild(0, configSize); - addChild(1, mValuesContainer); - this.configSize.setBlockLoad(this); - this.mQualifiersStamp = 0; - } - public boolean isEqualOrMoreSpecificThan(ResConfig resConfig){ - if(resConfig == null){ - return false; - } - if(resConfig == this || resConfig.isDefault()){ - return true; - } - byte[] bytes = ByteArray.trimTrailZeros(this.mValuesContainer.getBytes()); - byte[] otherBytes = ByteArray.trimTrailZeros(resConfig.mValuesContainer.getBytes()); - int max = otherBytes.length; - if(max > bytes.length){ - return false; - } - for(int i = 0; i> 5) + ((in0 & 0x03) << 3)); - byte third = (byte) ((in0 & 0x7c) >> 2); - - out[0] = (char) (first + base); - out[1] = (char) (second + base); - out[2] = (char) (third + base); - }else if (in0 != 0) { - out = new char[2]; - out[0] = (char) in0; - out[1] = (char) in1; - }else { - out = new char[2]; - } - return out; - } - private static byte[] packLanguage(char[] language) { - return packLanguageOrRegion(language, 'a'); - } - private static byte[] packRegion(char[] region) { - return packLanguageOrRegion(region, '0'); - } - private static byte[] packLanguageOrRegion(char[] in, char base) { - byte[] out = new byte[2]; - if(in == null || in.length<2){ - return out; - } - if (in.length == 2 || in[2] == 0 || in[2] == '-') { - out[0] = (byte) in[0]; - out[1] = (byte) in[1]; - } else { - byte first = (byte) ((in[0] - base) & 0x007f); - byte second = (byte) ((in[1] - base) & 0x007f); - byte third = (byte) ((in[2] - base) & 0x007f); - - out[0] = (byte) (0x80 | (third << 2) | (second >> 3)); - out[1] = (byte) ((second << 5) | first); - } - return out; - } - - private static byte[] toByteArray(char[] chs, int len){ - byte[] bts = new byte[len]; - if(chs == null){ - return bts; - } - int sz = chs.length; - for(int i = 0; i < sz; i++){ - bts[i]= (byte) chs[i]; - } - return bts; - } - private static char[] toCharArray(byte[] bts){ - if(isNull(bts)){ - return null; - } - int sz = bts.length; - char[] chs = new char[sz]; - for(int i = 0; i < sz; i++){ - int val = 0xff & bts[i]; - chs[i]= (char) val; - } - return chs; - } - private static char[] trimEndingZero(char[] chars){ - if(chars == null){ - return null; - } - int lastNonZero = -1; - for(int i = 0; i < chars.length; i++){ - if(chars[i]!= 0){ - lastNonZero = i; - } - } - if(lastNonZero==-1){ - return null; - } - lastNonZero = lastNonZero+1; - if(lastNonZero== chars.length){ - return chars; - } - char[] result = new char[lastNonZero]; - System.arraycopy(chars, 0, result, 0, lastNonZero); - return result; - } - private static boolean isNull(char[] chs){ - if(chs == null){ - return true; - } - for(int i = 0; i < chs.length; i++){ - if(chs[i]!= 0){ - return false; - } - } - return true; - } - private static boolean isNull(byte[] bts){ - if(bts == null){ - return true; - } - for(int i = 0; i < bts.length; i++){ - if(bts[i] != 0){ - return false; - } - } - return true; - } - private static byte[] ensureArrayLength(byte[] bts, int length){ - if(bts == null || length == 0){ - return new byte[length]; - } - if(bts.length == length){ - return bts; - } - byte[] result = new byte[length]; - int max = result.length; - if(bts.length < max){ - max = bts.length; - } - System.arraycopy(bts, 0, result, 0, max); - return result; - } - private static String ensureLength(String str, int min, char postfix){ - int length = str.length(); - if(length >= min){ - return str; - } - StringBuilder builder = new StringBuilder(); - builder.append(str); - int remain = min - length; - for(int i = 0; i < remain; i++){ - builder.append(postfix); - } - return builder.toString(); - } - private static String trimPostfix(String str, char postfix){ - if(str == null){ - return null; - } - int length = str.length(); - int index = length-1; - while (length>0 && str.charAt(index) == postfix){ - str = str.substring(0, index); - length = str.length(); - index = length - 1; - } - return str; - } - public static boolean isValidSize(int size){ - switch (size){ - case SIZE_16: - case SIZE_28: - case SIZE_32: - case SIZE_36: - case SIZE_48: - case SIZE_52: - case SIZE_56: - case SIZE_64: - return true; - default: - return size > SIZE_64; - } - } - - public static final class Orientation extends Flag{ - public static final int MASK = 0x0f; - - public static final Orientation PORT = new Orientation("port", 0x01); - public static final Orientation LAND = new Orientation("land", 0x02); - public static final Orientation SQUARE = new Orientation("square", 0x03); - - public static final Orientation[] VALUES = new Orientation[]{ - PORT, - LAND, - SQUARE - }; - private Orientation(String name, int flag) { - super(name, flag); - } - public static Orientation valueOf(int flag){ - return Flag.valueOf(VALUES, MASK, flag); - } - public static Orientation valueOf(String name){ - return Flag.valueOf(VALUES, name); - } - public static Orientation fromQualifiers(String qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static Orientation fromQualifiers(String[] qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static int update(Orientation flag, int value){ - return Flag.update(MASK, flag, value); - } - } - public static final class Touchscreen extends Flag{ - public static final int MASK = 0x0f; - - public static final Touchscreen NOTOUCH = new Touchscreen("notouch", 0x01); - public static final Touchscreen STYLUS = new Touchscreen("stylus", 0x02); - public static final Touchscreen FINGER = new Touchscreen("finger", 0x03); - - public static final Touchscreen[] VALUES = new Touchscreen[]{ - NOTOUCH, - STYLUS, - FINGER - }; - private Touchscreen(String name, int flag) { - super(name, flag); - } - public static Touchscreen valueOf(int flag){ - return Flag.valueOf(VALUES, MASK, flag); - } - public static Touchscreen valueOf(String name){ - return Flag.valueOf(VALUES, name); - } - public static Touchscreen fromQualifiers(String qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static Touchscreen fromQualifiers(String[] qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static int update(Touchscreen flag, int value){ - return Flag.update(MASK, flag, value); - } - } - public static final class Density extends Flag{ - public static final int MASK = 0xffff; - - public static final Density LDPI = new Density("ldpi", 120); - public static final Density MDPI = new Density("mdpi", 160); - public static final Density TVDPI = new Density("tvdpi", 213); - public static final Density HDPI = new Density("hdpi", 240); - public static final Density XHDPI = new Density("xhdpi", 320); - public static final Density XXHDPI = new Density("xxhdpi", 480); - public static final Density XXXHDPI = new Density("xxxhdpi", 640); - public static final Density ANYDPI = new Density("anydpi", 0xfffe); - public static final Density NODPI = new Density("nodpi", 0xffff); - - public static final Density[] VALUES = new Density[]{LDPI, - MDPI, - TVDPI, - HDPI, - XHDPI, - XXHDPI, - XXXHDPI, - ANYDPI, - NODPI - }; - private Density(String name, int flag) { - super(name, flag); - } - public static Density valueOf(int flag){ - if(flag== 0){ - return null; - } - Density density = Flag.valueOf(VALUES, MASK, flag); - if(density == null){ - flag = flag & MASK; - density = new Density(flag+"dpi", flag); - } - return density; - } - public static Density valueOf(String name){ - if(name == null || name.length() < 4){ - return null; - } - name = name.toLowerCase(); - if(name.charAt(0) == '-'){ - name = name.substring(1); - } - Density density = Flag.valueOf(VALUES, name); - if(density == null && name.endsWith("dpi")){ - name = name.substring(0, name.length()-3); - try{ - int flag = Integer.parseInt(name); - density = new Density(flag+"dpi", flag); - }catch (NumberFormatException ignored){ - } - } - return density; - } - public static Density fromQualifiers(String qualifiers){ - return fromQualifiers(qualifiers.split("\\s*-\\s*")); - } - public static Density fromQualifiers(String[] qualifiers){ - if(qualifiers == null){ - return null; - } - for(int i = 0; i < qualifiers.length; i++){ - Density density = valueOf(qualifiers[i]); - if(density== null){ - continue; - } - qualifiers[i] = null; - return density; - } - return null; - } - public static int update(Density flag, int value){ - return Flag.update(MASK, flag, value); - } - } - public static final class Keyboard extends Flag{ - public static final int MASK = 0x0f; - - public static final Keyboard NOKEYS = new Keyboard("nokeys", 0x01); - public static final Keyboard QWERTY = new Keyboard("qwerty", 0x02); - public static final Keyboard KEY12 = new Keyboard("12key", 0x03); - - public static final Keyboard[] VALUES = new Keyboard[]{ - NOKEYS, - QWERTY, - KEY12 - }; - private Keyboard(String name, int flag) { - super(name, flag); - } - public static Keyboard valueOf(int flag){ - return Flag.valueOf(VALUES, MASK, flag); - } - public static Keyboard valueOf(String name){ - return Flag.valueOf(VALUES, name); - } - public static Keyboard fromQualifiers(String qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static Keyboard fromQualifiers(String[] qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static int update(Keyboard flag, int value){ - return Flag.update(MASK, flag, value); - } - } - public static final class Navigation extends Flag{ - public static final int MASK = 0x0f; - - public static final Navigation NONAV = new Navigation("nonav", 0x01); - public static final Navigation DPAD = new Navigation("dpad", 0x02); - public static final Navigation TRACKBALL = new Navigation("trackball", 0x03); - public static final Navigation WHEEL = new Navigation("wheel", 0x04); - public static final Navigation[] VALUES = new Navigation[]{ - NONAV, - DPAD, - TRACKBALL, - WHEEL - }; - private Navigation(String name, int flag) { - super(name, flag); - } - public static Navigation valueOf(int flag){ - return Flag.valueOf(VALUES, MASK, flag); - } - public static Navigation valueOf(String name){ - return Flag.valueOf(VALUES, name); - } - public static Navigation fromQualifiers(String qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static Navigation fromQualifiers(String[] qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static int update(Navigation flag, int value){ - return Flag.update(MASK, flag, value); - } - } - public static final class InputFlagsKeysHidden extends Flag{ - public static final int MASK = 0x03; - - public static final InputFlagsKeysHidden KEYSEXPOSED = new InputFlagsKeysHidden("keysexposed", 0x01); - public static final InputFlagsKeysHidden KEYSHIDDEN = new InputFlagsKeysHidden("keyshidden", 0x02); - public static final InputFlagsKeysHidden KEYSSOFT = new InputFlagsKeysHidden("keyssoft", 0x03); - public static final InputFlagsKeysHidden[] VALUES = new InputFlagsKeysHidden[]{ - KEYSEXPOSED, - KEYSHIDDEN, - KEYSSOFT - }; - private InputFlagsKeysHidden(String name, int flag) { - super(name, flag); - } - public static InputFlagsKeysHidden valueOf(int flag){ - return Flag.valueOf(VALUES, MASK, flag); - } - public static InputFlagsKeysHidden valueOf(String name){ - return Flag.valueOf(VALUES, name); - } - public static InputFlagsKeysHidden fromQualifiers(String qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static InputFlagsKeysHidden fromQualifiers(String[] qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static int update(InputFlagsKeysHidden flag, int value){ - return Flag.update(MASK, flag, value); - } - } - public static final class InputFlagsNavHidden extends Flag{ - public static final int MASK = 0x0C; - - public static final InputFlagsNavHidden NAVEXPOSED = new InputFlagsNavHidden("navexposed", 0x04); - public static final InputFlagsNavHidden NAVHIDDEN = new InputFlagsNavHidden("navhidden", 0x08); - public static final InputFlagsNavHidden[] VALUES = new InputFlagsNavHidden[]{ - NAVEXPOSED, - NAVHIDDEN - }; - private InputFlagsNavHidden(String name, int flag) { - super(name, flag); - } - public static InputFlagsNavHidden valueOf(int flag){ - return Flag.valueOf(VALUES, MASK, flag); - } - public static InputFlagsNavHidden valueOf(String name){ - return Flag.valueOf(VALUES, name); - } - public static InputFlagsNavHidden fromQualifiers(String qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static InputFlagsNavHidden fromQualifiers(String[] qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static int update(InputFlagsNavHidden flag, int value){ - return Flag.update(MASK, flag, value); - } - } - public static final class UiModeType extends Flag{ - public static final int MASK = 0x0f; - - public static final UiModeType NORMAL = new UiModeType("normal", 0x01); - public static final UiModeType DESK = new UiModeType("desk", 0x02); - public static final UiModeType CAR = new UiModeType("car", 0x03); - public static final UiModeType TELEVISION = new UiModeType("television", 0x04); - public static final UiModeType APPLIANCE = new UiModeType("appliance", 0x05); - public static final UiModeType WATCH = new UiModeType("watch", 0x06); - public static final UiModeType VRHEADSET = new UiModeType("vrheadset", 0x07); - public static final UiModeType GODZILLAUI = new UiModeType("godzillaui", 0x0b); - public static final UiModeType SMALLUI = new UiModeType("smallui", 0x0c); - public static final UiModeType MEDIUMUI = new UiModeType("mediumui", 0x0d); - public static final UiModeType LARGEUI = new UiModeType("largeui", 0x0e); - public static final UiModeType HUGEUI = new UiModeType("hugeui", 0x0f); - - private static final UiModeType[] VALUES = new UiModeType[]{ - NORMAL, - DESK, - CAR, - TELEVISION, - APPLIANCE, - WATCH, - VRHEADSET, - GODZILLAUI, - SMALLUI, - MEDIUMUI, - LARGEUI, - HUGEUI - }; - - private UiModeType(String name, int flag) { - super(name, flag); - } - public static UiModeType valueOf(int flag){ - return Flag.valueOf(VALUES, MASK, flag); - } - public static UiModeType valueOf(String name){ - return Flag.valueOf(VALUES, name); - } - public static UiModeType fromQualifiers(String qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static UiModeType fromQualifiers(String[] qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static int update(UiModeType flag, int value){ - return Flag.update(MASK, flag, value); - } - } - public static final class UiModeNight extends Flag{ - public static final int MASK = 0x30; - public static final UiModeNight NOTNIGHT = new UiModeNight("notnight",0x10); - public static final UiModeNight NIGHT = new UiModeNight("night",0x20); - private static final UiModeNight[] VALUES = new UiModeNight[]{ - NOTNIGHT, - NIGHT - }; - private UiModeNight(String name, int flag) { - super(name, flag); - } - public static UiModeNight valueOf(int flag){ - return Flag.valueOf(VALUES, MASK, flag); - } - public static UiModeNight valueOf(String name){ - return Flag.valueOf(VALUES, name); - } - public static UiModeNight fromQualifiers(String qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static UiModeNight fromQualifiers(String[] qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static int update(UiModeNight flag, int value){ - return Flag.update(MASK, flag, value); - } - } - public static final class ScreenLayoutSize extends Flag{ - public static final int MASK = 0x0f; - - public static final ScreenLayoutSize SMALL = new ScreenLayoutSize("small", 0x01); - public static final ScreenLayoutSize NORMAL = new ScreenLayoutSize("normal", 0x02); - public static final ScreenLayoutSize LARGE = new ScreenLayoutSize("large", 0x03); - public static final ScreenLayoutSize XLARGE = new ScreenLayoutSize("xlarge", 0x04); - public static final ScreenLayoutSize[] VALUES = new ScreenLayoutSize[]{ - SMALL, - NORMAL, - LARGE, - XLARGE - }; - private ScreenLayoutSize(String name, int flag) { - super(name, flag); - } - public static ScreenLayoutSize valueOf(int flag){ - return Flag.valueOf(VALUES, MASK, flag); - } - public static ScreenLayoutSize valueOf(String name){ - return Flag.valueOf(VALUES, name); - } - public static ScreenLayoutSize fromQualifiers(String qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static ScreenLayoutSize fromQualifiers(String[] qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static int update(ScreenLayoutSize flag, int value){ - return Flag.update(MASK, flag, value); - } - } - public static final class ScreenLayoutLong extends Flag{ - public static final int MASK = 0x30; - public static final ScreenLayoutLong NOTLONG = new ScreenLayoutLong("notlong", 0x10); - public static final ScreenLayoutLong LONG = new ScreenLayoutLong("long", 0x20); - public static final ScreenLayoutLong[] VALUES = new ScreenLayoutLong[]{ - NOTLONG, - LONG - }; - private ScreenLayoutLong(String name, int flag) { - super(name, flag); - } - public static ScreenLayoutLong valueOf(int flag){ - return Flag.valueOf(VALUES, MASK, flag); - } - public static ScreenLayoutLong valueOf(String name){ - return Flag.valueOf(VALUES, name); - } - public static ScreenLayoutLong fromQualifiers(String qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static ScreenLayoutLong fromQualifiers(String[] qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static int update(ScreenLayoutLong flag, int value){ - return Flag.update(MASK, flag, value); - } - } - public static final class ScreenLayoutDir extends Flag{ - public static final int MASK = 0xC0; - public static final ScreenLayoutDir LDLTR = new ScreenLayoutDir("ldltr", 0x40); - public static final ScreenLayoutDir LDRTL = new ScreenLayoutDir("ldrtl", 0x80); - public static final ScreenLayoutDir[] VALUES = new ScreenLayoutDir[]{ - LDLTR, - LDRTL - }; - private ScreenLayoutDir(String name, int flag) { - super(name, flag); - } - public static ScreenLayoutDir valueOf(int flag){ - return Flag.valueOf(VALUES, MASK, flag); - } - public static ScreenLayoutDir valueOf(String name){ - return Flag.valueOf(VALUES, name); - } - public static ScreenLayoutDir fromQualifiers(String qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static ScreenLayoutDir fromQualifiers(String[] qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static int update(ScreenLayoutDir flag, int value){ - return Flag.update(MASK, flag, value); - } - } - public static final class ScreenLayoutRound extends Flag{ - public static final int MASK = 0x03; - public static final ScreenLayoutRound NOTROUND = new ScreenLayoutRound("notround", 0x01); - public static final ScreenLayoutRound ROUND = new ScreenLayoutRound("round", 0x02); - public static final ScreenLayoutRound[] VALUES = new ScreenLayoutRound[]{ - NOTROUND, - ROUND - }; - private ScreenLayoutRound(String name, int flag) { - super(name, flag); - } - public static ScreenLayoutRound valueOf(int flag){ - return Flag.valueOf(VALUES, MASK, flag); - } - public static ScreenLayoutRound valueOf(String name){ - return Flag.valueOf(VALUES, name); - } - public static ScreenLayoutRound fromQualifiers(String qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static ScreenLayoutRound fromQualifiers(String[] qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static int update(ScreenLayoutRound flag, int value){ - return Flag.update(MASK, flag, value); - } - } - public static final class ColorModeWide extends Flag{ - public static final int MASK = 0x03; - public static final ColorModeWide NOWIDECG = new ColorModeWide("nowidecg", 0x01); - public static final ColorModeWide WIDECG = new ColorModeWide("widecg", 0x02); - public static final ColorModeWide[] VALUES = new ColorModeWide[]{ - NOWIDECG, - WIDECG - }; - private ColorModeWide(String name, int flag) { - super(name, flag); - } - public static ColorModeWide valueOf(int flag){ - return Flag.valueOf(VALUES, MASK, flag); - } - public static ColorModeWide valueOf(String name){ - return Flag.valueOf(VALUES, name); - } - public static ColorModeWide fromQualifiers(String qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static ColorModeWide fromQualifiers(String[] qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static int update(ColorModeWide flag, int value){ - return Flag.update(MASK, flag, value); - } - } - public static final class ColorModeHdr extends Flag{ - public static final int MASK = 0x0C; - public static final ColorModeHdr LOWDR = new ColorModeHdr("lowdr", 0x04); - public static final ColorModeHdr HIGHDR = new ColorModeHdr("highdr", 0x08); - public static final ColorModeHdr[] VALUES = new ColorModeHdr[]{ - LOWDR, - HIGHDR - }; - private ColorModeHdr(String name, int flag) { - super(name, flag); - } - public static ColorModeHdr valueOf(int flag){ - return Flag.valueOf(VALUES, MASK, flag); - } - public static ColorModeHdr valueOf(String name){ - return Flag.valueOf(VALUES, name); - } - public static ColorModeHdr fromQualifiers(String qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static ColorModeHdr fromQualifiers(String[] qualifiers){ - return Flag.fromQualifiers(VALUES, qualifiers); - } - public static int update(ColorModeHdr flag, int value){ - return Flag.update(MASK, flag, value); - } - } - - static class Flag{ - private final String name; - private final int flag; - Flag(String name, int flag){ - this.name = name; - this.flag = flag; - } - public int getFlag() { - return flag; - } - @Override - public boolean equals(Object obj) { - return obj == this; - } - @Override - public int hashCode() { - return super.hashCode(); - } - @Override - public String toString() { - return name; - } - public static String toString(Flag flag){ - if(flag!= null){ - return flag.toString(); - } - return null; - } - static T fromQualifiers(T[] values, String qualifiers){ - if(qualifiers == null){ - return null; - } - return fromQualifiers(values, qualifiers.split("\\s*-\\s*")); - } - static T fromQualifiers(T[] values, String[] qualifiers){ - if(qualifiers == null){ - return null; - } - for(int i = 0; i < qualifiers.length; i++){ - T flag = Flag.valueOf(values, qualifiers[i]); - if(flag != null){ - qualifiers[i] = null; - return flag; - } - } - return null; - } - static T valueOf(T[] values, int mask, int flagValue){ - flagValue = flagValue & mask; - for(T flag:values){ - if(flagValue == flag.getFlag()){ - return flag; - } - } - return null; - } - static T valueOf(T[] values, String name){ - if(name == null || name.length() == 0){ - return null; - } - if(name.charAt(0) == '-'){ - name = name.substring(1); - } - name = name.toLowerCase(); - for(T flag:values){ - if(name.equals(flag.toString())){ - return flag; - } - } - return null; - } - public static int update(int mask, Flag flag, int value){ - int flip = (~mask) & 0xff; - value = value & flip; - if(flag != null){ - value = value | flag.getFlag(); - } - return value; - } - } - - static class QualifierBuilder{ - private final ResConfig mConfig; - private StringBuilder mBuilder; - public QualifierBuilder(ResConfig resConfig){ - this.mConfig = resConfig; - } - public String build(){ - ResConfig resConfig = this.mConfig; - if(resConfig.isDefault()){ - return ""; - } - this.mBuilder = new StringBuilder(); - appendPrefixedNumber("mcc", resConfig.getMcc()); - appendPrefixedNumber("mnc", resConfig.getMnc()); - - appendLanguageAndRegion(); - - appendFlag(resConfig.getOrientation()); - appendFlag(resConfig.getTouchscreen()); - appendFlag(resConfig.getDensity()); - appendFlag(resConfig.getKeyboard()); - appendFlag(resConfig.getNavigation()); - appendFlag(resConfig.getInputFlagsKeysHidden()); - appendFlag(resConfig.getInputFlagsNavHidden()); - - appendScreenWidthHeight(); - - appendPrefixedNumber("v", resConfig.getSdkVersion()); - // append resConfig.getMinorVersion() - appendFlag(resConfig.getScreenLayoutSize()); - appendFlag(resConfig.getScreenLayoutLong()); - appendFlag(resConfig.getScreenLayoutDir()); - - appendFlag(resConfig.getUiModeType()); - appendFlag(resConfig.getUiModeNight()); - - appendDp("sw", resConfig.getSmallestScreenWidthDp()); - appendDp("w", resConfig.getScreenWidthDp()); - appendDp("h", resConfig.getScreenHeightDp()); - - appendFlag(resConfig.getScreenLayoutRound()); - - appendFlag(resConfig.getColorModeWide()); - appendFlag(resConfig.getColorModeHdr()); - - appendLocaleNumberingSystem(); - - return mBuilder.toString(); - } - private void appendScreenWidthHeight(){ - ResConfig resConfig = this.mConfig; - int width = resConfig.getScreenWidth(); - int height = resConfig.getScreenHeight(); - if(width == 0 && height == 0){ - return; - } - mBuilder.append('-').append(width).append('x').append(height); - } - private void appendLanguageAndRegion(){ - ResConfig resConfig = this.mConfig; - String language = resConfig.getLanguage(); - String region = resConfig.getRegion(); - String script = resConfig.getLocaleScript(); - String variant = resConfig.getLocaleVariant(); - if(language == null && region == null){ - return; - } - StringBuilder builder = this.mBuilder; - char separator; - if(script != null || variant != null){ - builder.append('-'); - builder.append('b'); - separator = '+'; - }else { - separator = '-'; - } - if(language!= null){ - builder.append(separator); - builder.append(language); - } - if(region!= null){ - builder.append(separator); - if(region.length() == 2){ - builder.append('r'); - } - builder.append(region); - } - if(script!= null){ - builder.append(separator); - builder.append(script); - } - if(variant!= null){ - builder.append(separator); - builder.append(variant); - } - } - private void appendLocaleNumberingSystem(){ - String numberingSystem = mConfig.getLocaleNumberingSystem(); - if(numberingSystem== null){ - return; - } - StringBuilder builder = mBuilder; - builder.append("-u+nu+"); - builder.append(numberingSystem); - } - private void appendFlag(ResConfig.Flag flag){ - if(flag== null){ - return; - } - mBuilder.append('-').append(flag.toString()); - } - private void appendDp(String prefix, int number){ - if(number == 0){ - return; - } - StringBuilder builder = this.mBuilder; - builder.append('-'); - if(prefix!= null){ - builder.append(prefix); - } - builder.append(number); - builder.append("dp"); - } - private void appendPrefixedNumber(String prefix, int number){ - if(number == 0){ - return; - } - StringBuilder builder = this.mBuilder; - builder.append('-'); - builder.append(prefix); - builder.append(number); - } - } - static class QualifierParser{ - private final ResConfig mConfig; - private final String[] mQualifiers; - private final int mPreferredSize; - private boolean mEmpty; - private boolean mLanguageRegionParsed; - private boolean mParseComplete; - - public QualifierParser(ResConfig resConfig, String[] qualifiers){ - this.mConfig = resConfig; - this.mQualifiers = qualifiers; - this.mPreferredSize = resConfig.getConfigSize(); - } - public QualifierParser(ResConfig resConfig, String qualifiers){ - this(resConfig, splitQualifiers(qualifiers)); - } - - public void parse(){ - if(this.mParseComplete){ - return; - } - if(isEmpty()){ - onParseComplete(); - return; - } - ResConfig resConfig = this.mConfig; - resConfig.setConfigSize(ResConfig.SIZE_64); - parsePrefixedNumber(); - parseDp(); - parseWidthHeight(); - parseLocaleNumberingSystem(); - if(isEmpty()){ - onParseComplete(); - return; - } - String[] qualifiers = this.mQualifiers; - resConfig.setOrientation(ResConfig.Orientation.fromQualifiers(qualifiers)); - resConfig.setTouchscreen(ResConfig.Touchscreen.fromQualifiers(qualifiers)); - resConfig.setDensity(ResConfig.Density.fromQualifiers(qualifiers)); - resConfig.setKeyboard(ResConfig.Keyboard.fromQualifiers(qualifiers)); - resConfig.setNavigation(ResConfig.Navigation.fromQualifiers(qualifiers)); - if(isEmpty()){ - onParseComplete(); - return; - } - resConfig.setInputFlagsKeysHidden(ResConfig.InputFlagsKeysHidden.fromQualifiers(qualifiers)); - resConfig.setInputFlagsNavHidden(ResConfig.InputFlagsNavHidden.fromQualifiers(qualifiers)); - resConfig.setScreenLayoutSize(ResConfig.ScreenLayoutSize.fromQualifiers(qualifiers)); - resConfig.setScreenLayoutLong(ResConfig.ScreenLayoutLong.fromQualifiers(qualifiers)); - resConfig.setScreenLayoutDir(ResConfig.ScreenLayoutDir.fromQualifiers(qualifiers)); - if(isEmpty()){ - onParseComplete(); - return; - } - resConfig.setUiModeType(ResConfig.UiModeType.fromQualifiers(qualifiers)); - resConfig.setUiModeNight(ResConfig.UiModeNight.fromQualifiers(qualifiers)); - - resConfig.setScreenLayoutRound(ResConfig.ScreenLayoutRound.fromQualifiers(qualifiers)); - - resConfig.setColorModeWide(ResConfig.ColorModeWide.fromQualifiers(qualifiers)); - resConfig.setColorModeHdr(ResConfig.ColorModeHdr.fromQualifiers(qualifiers)); - if(isEmpty()){ - onParseComplete(); - return; - } - parseLocaleScriptVariant(); - parseLanguage(); - parseRegion(); - onParseComplete(); - } - public String[] getErrors(){ - if(!this.mParseComplete){ - return null; - } - String[] qualifiers = this.mQualifiers; - if(qualifiers == null || qualifiers.length == 0){ - return null; - } - int length = qualifiers.length; - String[] tmp = new String[length]; - int count = 0; - for(int i = 0; i < length; i++){ - String qualifier = qualifiers[i]; - if(qualifier == null || qualifier.length() == 0){ - continue; - } - tmp[count] = qualifier; - count++; - } - if(count == 0){ - return null; - } - if(count == length){ - return tmp; - } - String[] errors = new String[count]; - System.arraycopy(tmp, 0, errors, 0, count); - return errors; - } - private void onParseComplete(){ - this.mConfig.trimToSize(this.mPreferredSize); - this.mParseComplete = true; - } - - private void parsePrefixedNumber(){ - if(isEmpty()){ - return; - } - String[] qualifiers = this.mQualifiers; - for(int i = 0; i < qualifiers.length; i++){ - if(parsePrefixedNumber(qualifiers[i])){ - qualifiers[i] = null; - } - } - } - private boolean parsePrefixedNumber(String qualifier){ - if(qualifier == null){ - return false; - } - Matcher matcher = PATTERN_PREFIX_NUMBER.matcher(qualifier); - if(!matcher.find()){ - return false; - } - String prefix = matcher.group(1); - int value = Integer.parseInt(matcher.group(2)); - ResConfig resConfig = mConfig; - if("mcc".equals(prefix)){ - resConfig.setMcc(value); - }else if("mnc".equals(prefix)) { - resConfig.setMnc(value); - }else if("v".equals(prefix)){ - resConfig.setSdkVersion(value); - }else { - return false; - } - return true; - } - private void parseDp(){ - if(isEmpty()){ - return; - } - String[] qualifiers = this.mQualifiers; - for(int i = 0; i < qualifiers.length; i++){ - if(parseDp(qualifiers[i])){ - qualifiers[i] = null; - } - } - } - private boolean parseDp(String qualifier){ - if(qualifier == null){ - return false; - } - Matcher matcher = PATTERN_DP.matcher(qualifier); - if(!matcher.find()){ - return false; - } - String prefix = matcher.group(1); - int value = Integer.parseInt(matcher.group(2)); - ResConfig resConfig = this.mConfig; - if("sw".equals(prefix)){ - resConfig.setSmallestScreenWidthDp(value); - }else if("w".equals(prefix)) { - resConfig.setScreenWidthDp(value); - }else if("h".equals(prefix)){ - resConfig.setScreenHeightDp(value); - }else { - return false; - } - return true; - } - private void parseWidthHeight(){ - if(isEmpty()){ - return; - } - String[] qualifiers = this.mQualifiers; - for(int i = 0; i < qualifiers.length; i++){ - if(parseWidthHeight(qualifiers[i])){ - qualifiers[i] = null; - return; - } - } - } - private boolean parseWidthHeight(String qualifier){ - if(qualifier == null){ - return false; - } - Matcher matcher = PATTERN_WIDTH_HEIGHT.matcher(qualifier); - if(!matcher.find()){ - return false; - } - int width = Integer.parseInt(matcher.group(1)); - int height = Integer.parseInt(matcher.group(2)); - ResConfig resConfig = this.mConfig; - resConfig.setScreenWidth(width); - resConfig.setScreenHeight(height); - return true; - } - private void parseLocaleNumberingSystem(){ - if(isEmpty()){ - return; - } - String[] qualifiers = this.mQualifiers; - for(int i = 0; i < qualifiers.length; i++){ - if(parseLocaleNumberingSystem(qualifiers[i])){ - qualifiers[i] = null; - return; - } - } - } - private boolean parseLocaleNumberingSystem(String qualifier){ - if(qualifier == null){ - return false; - } - Matcher matcher = PATTERN_LOCALE_NUMBERING_SYSTEM.matcher(qualifier); - if(!matcher.find()){ - return false; - } - this.mConfig.setLocaleNumberingSystem(matcher.group(1)); - return true; - } - private void parseLocaleScriptVariant(){ - if(this.mLanguageRegionParsed || isEmpty()){ - return; - } - String[] qualifiers = this.mQualifiers; - for(int i = 0; i < qualifiers.length; i++){ - if(parseLocaleScriptVariant(qualifiers[i])){ - qualifiers[i] = null; - this.mLanguageRegionParsed = true; - return; - } - } - } - private boolean parseLocaleScriptVariant(String qualifier){ - if(qualifier == null || qualifier.length() < 4 ){ - return false; - } - char[] chars = qualifier.toCharArray(); - if(chars[0] != 'b' || chars[1] != '+'){ - return false; - } - Matcher matcher = PATTERN_LOCALE_SCRIPT_VARIANT.matcher(qualifier); - if(!matcher.find()){ - return false; - } - String language = trimPlus(matcher.group(1)); - String region = trimPlus(matcher.group(2)); - String script = trimPlus(matcher.group(3)); - String variant = trimPlus(matcher.group(4)); - if(script == null && variant == null){ - return false; - } - ResConfig resConfig = this.mConfig; - resConfig.setLanguage(language); - resConfig.setRegion(region); - resConfig.setLocaleScript(script); - resConfig.setLocaleVariant(variant); - return true; - } - - private void parseLanguage(){ - if(mLanguageRegionParsed || isEmpty()){ - return; - } - String[] qualifiers = this.mQualifiers; - for(int i = 0; i < qualifiers.length; i++){ - if(parseLanguage(qualifiers[i])){ - qualifiers[i] = null; - return; - } - } - } - private boolean parseLanguage(String qualifier){ - if(!isLanguage(qualifier)){ - return false; - } - this.mConfig.setLanguage(qualifier); - return true; - } - private void parseRegion(){ - if(mLanguageRegionParsed || isEmpty()){ - return; - } - String[] qualifiers = this.mQualifiers; - for(int i = 0; i < qualifiers.length; i++){ - if(parseRegion(qualifiers[i])){ - qualifiers[i] = null; - return; - } - } - } - private boolean parseRegion(String qualifier){ - if(!isRegion(qualifier)){ - return false; - } - this.mConfig.setRegion(qualifier); - return true; - } - - - private boolean isEmpty(){ - if(!mEmpty){ - mEmpty = isEmpty(mQualifiers); - } - return mEmpty; - } - - private static boolean isEmpty(String[] qualifiers){ - if(qualifiers == null){ - return true; - } - for(int i = 0; i < qualifiers.length; i++){ - String qualifier = qualifiers[i]; - if(qualifier == null){ - continue; - } - if(qualifier.length() == 0){ - qualifiers[i] = null; - continue; - } - return false; - } - return true; - } - private static String trimPlus(String text){ - if(text == null||text.length() == 0){ - return null; - } - if(text.charAt(0) == '+'){ - text = text.substring(1); - } - return text; - } - private static boolean isLanguage(String qualifier){ - if(qualifier == null){ - return false; - } - char[] chars = qualifier.toCharArray(); - int length = chars.length; - if(length != 2 && length !=3 ){ - return false; - } - for(int i = 0; i < length; i++){ - if(!isAtoZLower(chars[i])) { - return false; - } - } - return true; - } - private static boolean isRegion(String qualifier){ - if(qualifier == null || qualifier.length() != 3){ - return false; - } - char[] chars = qualifier.toCharArray(); - boolean checkDigit = false; - for(int i = 0; i < chars.length; i++){ - char ch = chars[i]; - if(i == 0){ - if(ch == 'r'){ - continue; - } - checkDigit = isDigit(ch); - if(checkDigit){ - continue; - } - return false; - } - if(checkDigit){ - if(!isDigit(ch)){ - return false; - } - }else if(!isAtoZUpper(ch)) { - return false; - } - } - return true; - } - private static String[] splitQualifiers(String qualifier){ - if(qualifier == null || qualifier.length() == 0){ - return null; - } - return qualifier.split("-"); - } - private static boolean isDigit(char ch){ - return ch <= '9' && ch >= '0'; - } - private static boolean isAtoZLower(char ch){ - return ch <= 'z' && ch >= 'a'; - } - private static boolean isAtoZUpper(char ch){ - return ch <= 'Z' && ch >= 'A'; - } - - private static final Pattern PATTERN_PREFIX_NUMBER = Pattern.compile("^([mcnv]+)([0-9]+)$"); - private static final Pattern PATTERN_DP = Pattern.compile("^([swh]+)([0-9]+)dp$"); - private static final Pattern PATTERN_WIDTH_HEIGHT = Pattern.compile("^([0-9]+)[xX]([0-9]+)$"); - private static final Pattern PATTERN_LOCALE_NUMBERING_SYSTEM = Pattern.compile("^u\\+nu\\+(.{1,8})$"); - private static final Pattern PATTERN_LOCALE_SCRIPT_VARIANT = Pattern.compile("^b(\\+[a-z]{2})?(\\+r[A-Z]{2})?(\\+[A-Z][a-z]{3})?(\\+[A-Z]{2,8})?$"); - } - - public static final int SIZE_16 = 16; - public static final int SIZE_28 = 28; - public static final int SIZE_32 = 32; - public static final int SIZE_36 = 36; - public static final int SIZE_48 = 48; - public static final int SIZE_52 = 52; - public static final int SIZE_56 = 56; - public static final int SIZE_64 = 64; - - private static final int OFFSET_mcc = 0; - private static final int OFFSET_mnc = 2; - private static final int OFFSET_language = 4; - private static final int OFFSET_region = 6; - private static final int OFFSET_orientation = 8; - private static final int OFFSET_touchscreen = 9; - private static final int OFFSET_density = 10; - //SIZE=16 - private static final int OFFSET_keyboard = 12; - private static final int OFFSET_navigation = 13; - private static final int OFFSET_inputFlags = 14; - private static final int OFFSET_inputPad0 = 15; - private static final int OFFSET_screenWidth = 16; - private static final int OFFSET_screenHeight = 18; - private static final int OFFSET_sdkVersion = 20; - private static final int OFFSET_minorVersion = 22; - //SIZE=28 - private static final int OFFSET_screenLayout = 24; - private static final int OFFSET_uiMode = 25; - private static final int OFFSET_smallestScreenWidthDp = 26; - //SIZE=32 - private static final int OFFSET_screenWidthDp = 28; - private static final int OFFSET_screenHeightDp = 30; - //SIZE=36 - private static final int OFFSET_localeScript = 32; - private static final int OFFSET_localeVariant = 36; - //SIZE=48 - private static final int OFFSET_screenLayout2 = 44; - private static final int OFFSET_colorMode = 45; - private static final int OFFSET_reservedPadding = 46; - //SIZE=52 - private static final int OFFSET_localeNumberingSystem = 48; - //SIZE=60 - - private static final int LEN_localeScript = 4; - private static final int LEN_localeVariant = 8; - private static final int LEN_localeNumberingSystem = 8; - - private static final String NAME_mcc = "mcc"; - private static final String NAME_mnc = "mnc"; - private static final String NAME_language = "language"; - private static final String NAME_region = "region"; - private static final String NAME_orientation = "orientation"; - private static final String NAME_touchscreen = "touchscreen"; - private static final String NAME_density = "density"; - //SIZE=16 - private static final String NAME_keyboard = "keyboard"; - private static final String NAME_navigation = "navigation"; - private static final String NAME_input_flags_keys_hidden = "input_flags_keys_hidden"; - private static final String NAME_input_flags_nav_hidden = "input_flags_nav_hidden"; - private static final String NAME_inputPad0 = "inputPad0"; - private static final String NAME_screenWidth = "screenWidth"; - private static final String NAME_screenHeight = "screenHeight"; - private static final String NAME_sdkVersion = "sdkVersion"; - private static final String NAME_minorVersion = "minorVersion"; - //SIZE=28 - private static final String NAME_screen_layout_size = "screen_layout_size"; - private static final String NAME_screen_layout_long = "screen_layout_long"; - private static final String NAME_screen_layout_dir = "screen_layout_dir"; - private static final String NAME_ui_mode_type = "ui_mode_type"; - private static final String NAME_ui_mode_night = "ui_mode_night"; - private static final String NAME_smallestScreenWidthDp = "smallestScreenWidthDp"; - //SIZE=32 = ""; - private static final String NAME_screenWidthDp = "screenWidthDp"; - private static final String NAME_screenHeightDp = "screenHeightDp"; - //SIZE=36 - private static final String NAME_localeScript = "localeScript"; - private static final String NAME_localeVariant = "localeVariant"; - private static final String NAME_screen_layout_round = "screen_layout_round"; - private static final String NAME_color_mode_wide = "color_mode_wide"; - private static final String NAME_color_mode_hdr = "color_mode_hdr"; - - private static final String NAME_localeNumberingSystem = "localeNumberingSystem"; - - private static final char POSTFIX_locale = '#'; - -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/ResTableEntry.java b/src/ARSCLib/com/reandroid/arsc/value/ResTableEntry.java deleted file mode 100644 index e3d505c2..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/ResTableEntry.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value; - -import com.reandroid.arsc.pool.TableStringPool; -import com.reandroid.json.JSONObject; - -public class ResTableEntry extends TableEntry { - public ResTableEntry() { - super(new EntryHeader(), new ResValue()); - } - - @Override - void linkTableStringsInternal(TableStringPool tableStringPool){ - getValue().linkTableStrings(tableStringPool); - } - @Override - void onRemoved(){ - getHeader().onRemoved(); - getValue().onRemoved(); - } - @Override - boolean shouldMerge(TableEntry tableEntry){ - if(tableEntry == this || !(tableEntry instanceof ResTableEntry)){ - return false; - } - ResValue coming = ((ResTableEntry) tableEntry).getValue(); - ValueType valueType = coming.getValueType(); - if(valueType == null || valueType == ValueType.NULL){ - return false; - } - valueType = getValue().getValueType(); - return valueType == null || valueType == ValueType.NULL; - } - @Override - public void merge(TableEntry tableEntry){ - if(tableEntry == this || !(tableEntry instanceof ResTableEntry)){ - return; - } - getHeader().merge(tableEntry.getHeader()); - getValue().merge((ValueItem) tableEntry.getValue()); - } - @Override - public JSONObject toJson() { - JSONObject jsonObject = new JSONObject(); - getHeader().toJson(jsonObject); - jsonObject.put(NAME_value, getValue().toJson()); - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - getHeader().fromJson(json); - JSONObject jsonObject = json.getJSONObject(NAME_value); - getValue().fromJson(jsonObject); - } - - public static final String NAME_value = "value"; -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/ResTableMapEntry.java b/src/ARSCLib/com/reandroid/arsc/value/ResTableMapEntry.java deleted file mode 100644 index ef3969a4..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/ResTableMapEntry.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value; - -import com.reandroid.arsc.array.ResValueMapArray; - -public class ResTableMapEntry extends CompoundEntry { - public ResTableMapEntry(){ - super(new ResValueMapArray()); - } - @Override - boolean shouldMerge(TableEntry tableEntry){ - if(tableEntry == this || !(tableEntry instanceof ResTableMapEntry)){ - return false; - } - ResValueMapArray coming = ((ResTableMapEntry) tableEntry).getValue(); - if(coming.childesCount() == 0){ - return false; - } - return getValue().childesCount() == 0; - } - - @Override - public void merge(TableEntry tableEntry){ - if(tableEntry==null || tableEntry==this){ - return; - } - ResTableMapEntry coming = (ResTableMapEntry) tableEntry; - getHeader().merge(coming.getHeader()); - getValue().merge(coming.getValue()); - refresh(); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/ResValue.java b/src/ARSCLib/com/reandroid/arsc/value/ResValue.java deleted file mode 100755 index 8b8247ae..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/ResValue.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value; - -import com.reandroid.arsc.chunk.PackageBlock; - -public class ResValue extends ValueItem { - public ResValue() { - super(8, OFFSET_SIZE); - } - - public Entry getEntry(){ - return getParent(Entry.class); - } - - @Override - public PackageBlock getParentChunk(){ - Entry entry = getEntry(); - if(entry != null){ - return entry.getPackageBlock(); - } - return null; - } - - private static final int OFFSET_SIZE = 0; -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/ResValueMap.java b/src/ARSCLib/com/reandroid/arsc/value/ResValueMap.java deleted file mode 100755 index e7014122..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/ResValueMap.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value; - -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.util.HexUtil; -import com.reandroid.json.JSONObject; - -public class ResValueMap extends ValueItem implements AttributeValue{ - - public ResValueMap() { - super(12, OFFSET_SIZE); - } - - public String decodeData(){ - String value = decodeDataAsAttrFormats(); - if(value != null){ - return value; - } - ValueType valueType = getValueType(); - if(valueType == ValueType.STRING){ - return getValueAsString(); - } - int data = getData(); - if(AttributeDataFormat.REFERENCE.contains(valueType)){ - Entry entry = resolve(data); - if(entry == null){ - return HexUtil.toHex8("@0x", data); - } - return buildReference(entry, valueType, true); - } - return ValueDecoder.decode(valueType, data); - } - private String decodeDataAsAttrFormats(){ - AttributeType attributeType = getAttributeType(); - if(attributeType != AttributeType.FORMATS){ - return null; - } - return AttributeDataFormat.toString(AttributeDataFormat.decodeValueTypes(getData())); - } - public String decodeName(){ - AttributeType attributeType = getAttributeType(); - if(attributeType != null){ - return attributeType.getName(); - } - Entry entry = resolveName(); - return buildReference(entry, null, false); - } - @Override - public Entry resolveName(){ - return resolve(getNameResourceID()); - } - public AttributeType getAttributeType(){ - return AttributeType.valueOf(getNameResourceID()); - } - public void setAttributeType(AttributeType attributeType){ - setNameResourceID(attributeType.getId()); - } - public AttributeDataFormat[] getAttributeTypeFormats(){ - AttributeType attributeType = getAttributeType(); - if(attributeType != AttributeType.FORMATS){ - return null; - } - return AttributeDataFormat.decodeValueTypes(getData()); - } - public void addAttributeTypeFormats(AttributeDataFormat[] formats){ - if(formats == null){ - return; - } - int data = getData() | AttributeDataFormat.sum(formats); - setData(data); - } - public void addAttributeTypeFormat(AttributeDataFormat format){ - if(format == null){ - return; - } - int data = getData() | format.getMask(); - setData(data); - } - public Entry getEntry(){ - return getParent(Entry.class); - } - @Override - public PackageBlock getParentChunk(){ - Entry entry = getEntry(); - if(entry!=null){ - return entry.getPackageBlock(); - } - return null; - } - - public ResTableMapEntry getParentMapEntry(){ - return getParentInstance(ResTableMapEntry.class); - } - - public int getName(){ - return getInteger(getBytesInternal(), OFFSET_NAME); - } - public void setName(int name){ - putInteger(getBytesInternal(), OFFSET_NAME, name); - } - - @Override - public int getNameResourceID() { - return getName(); - } - @Override - public void setNameResourceID(int resourceId){ - setName(resourceId); - } - - @Override - public JSONObject toJson() { - JSONObject jsonObject = super.toJson(); - if(jsonObject==null){ - return null; - } - jsonObject.put(NAME_name, getName()); - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - super.fromJson(json); - setName(json.getInt(NAME_name)); - } - - public void setNameHigh(short val){ - int name = getName() & 0xffff; - name = ((val & 0xffff) <<16 ) | name; - setName(name); - } - public void setNameLow(short val){ - int name = getName() & 0xffff0000; - name = (val & 0xffff) | name; - setName(name); - } - public void setDataHigh(short val){ - int data = getData() & 0xffff; - data = ((val & 0xffff) <<16 ) | data; - setData(data); - } - public void setDataLow(short val){ - int data = getData() & 0xffff0000; - data = (val & 0xffff) | data; - setData(data); - } - @Override - public void merge(ValueItem valueItem){ - if(valueItem==this || !(valueItem instanceof ResValueMap)){ - return; - } - ResValueMap resValueMap = (ResValueMap) valueItem; - super.merge(resValueMap); - setName(resValueMap.getName()); - } - @Override - public String toString(){ - String name = decodeName(); - String data = decodeData(); - if(name != null && data != null){ - return name + "=\"" + data + "\""; - } - return "name=" + HexUtil.toHex8(getName()) - +", "+super.toString(); - } - - private static final int OFFSET_NAME = 0; - private static final int OFFSET_SIZE = 4; - - public static final String NAME_name = "name"; - -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/StagedAliasEntry.java b/src/ARSCLib/com/reandroid/arsc/value/StagedAliasEntry.java deleted file mode 100644 index 714b473b..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/StagedAliasEntry.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value; - -import com.reandroid.arsc.item.ByteArray; -import com.reandroid.arsc.util.HexUtil; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONObject; - -public class StagedAliasEntry extends ByteArray implements JSONConvert { - public StagedAliasEntry(){ - super(8); - } - public boolean isEqual(StagedAliasEntry other){ - if(other==null){ - return false; - } - if(other==this){ - return true; - } - return getStagedResId()==other.getStagedResId() - && getFinalizedResId()==other.getFinalizedResId(); - } - public int getStagedResId(){ - return getInteger(0); - } - public void setStagedResId(int id){ - putInteger(0, id); - } - public int getFinalizedResId(){ - return getInteger(4); - } - public void setFinalizedResId(int id){ - putInteger(4, id); - } - @Override - public String toString(){ - return "stagedResId=" + HexUtil.toHex8(getStagedResId()) - +", finalizedResId=" + HexUtil.toHex8(getFinalizedResId()); - } - @Override - public JSONObject toJson() { - JSONObject jsonObject=new JSONObject(); - jsonObject.put(NAME_staged_resource_id, getStagedResId()); - jsonObject.put(NAME_finalized_resource_id, getFinalizedResId()); - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - setStagedResId(json.getInt(NAME_staged_resource_id)); - setFinalizedResId(json.getInt(NAME_finalized_resource_id)); - } - public static final String NAME_staged_resource_id = "staged_resource_id"; - public static final String NAME_finalized_resource_id = "finalized_resource_id"; -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/TableEntry.java b/src/ARSCLib/com/reandroid/arsc/value/TableEntry.java deleted file mode 100644 index 33e67a21..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/TableEntry.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value; - -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.base.BlockCounter; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.pool.TableStringPool; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONObject; - -import java.io.IOException; -import java.io.OutputStream; - -public abstract class TableEntry

extends Block implements - JSONConvert { - private final HEADER header; - private final VALUE resValue; - - TableEntry(HEADER header, VALUE resValue){ - super(); - this.header = header; - this.resValue = resValue; - - this.header.setParent(this); - this.header.setIndex(0); - this.resValue.setParent(this); - this.resValue.setIndex(1); - } - public Entry getParentEntry(){ - return getParent(Entry.class); - } - public void refresh(){ - } - public final HEADER getHeader() { - return header; - } - public VALUE getValue(){ - return resValue; - } - - @Override - public byte[] getBytes() { - byte[] results = getHeader().getBytes(); - results = addBytes(results, getValue().getBytes()); - return results; - } - @Override - public int countBytes() { - int result = getHeader().countBytes(); - result += getValue().countBytes(); - return result; - } - @Override - public void onCountUpTo(BlockCounter counter) { - if(counter.FOUND){ - return; - } - if(counter.END==this){ - counter.FOUND=true; - return; - } - getHeader().onCountUpTo(counter); - getValue().onCountUpTo(counter); - } - - @Override - public void onReadBytes(BlockReader reader) throws IOException { - ValueHeader valueHeader = getHeader(); - valueHeader.readBytes(reader); - onHeaderLoaded(valueHeader); - getValue().readBytes(reader); - } - - @Override - protected int onWriteBytes(OutputStream stream) throws IOException { - int result; - result = getHeader().writeBytes(stream); - result += getValue().writeBytes(stream); - return result; - } - - void onHeaderLoaded(ValueHeader valueHeader){ - } - abstract void onRemoved(); - abstract boolean shouldMerge(TableEntry tableEntry); - abstract void linkTableStringsInternal(TableStringPool tableStringPool); - - public abstract void merge(TableEntry tableEntry); - @Override - public abstract JSONObject toJson(); - @Override - public abstract void fromJson(JSONObject json); - @Override - public String toString(){ - return getHeader()+", value={"+getValue()+"}"; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/Value.java b/src/ARSCLib/com/reandroid/arsc/value/Value.java deleted file mode 100644 index 33c4b06c..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/Value.java +++ /dev/null @@ -1,35 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ - package com.reandroid.arsc.value; - - import com.reandroid.arsc.chunk.MainChunk; - import com.reandroid.arsc.chunk.ParentChunk; - - public interface Value { - void setValueType(ValueType valueType); - ValueType getValueType(); - int getData(); - void setData(int data); - String getValueAsString(); - ParentChunk getParentChunk(); - default MainChunk getMainChunk(){ - ParentChunk parentChunk = getParentChunk(); - if(parentChunk!=null){ - return parentChunk.getMainChunk(); - } - return null; - } - } diff --git a/src/ARSCLib/com/reandroid/arsc/value/ValueHeader.java b/src/ARSCLib/com/reandroid/arsc/value/ValueHeader.java deleted file mode 100644 index 6f34ef27..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/ValueHeader.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value; - -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.chunk.ParentChunk; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.item.*; -import com.reandroid.arsc.pool.SpecStringPool; -import com.reandroid.arsc.pool.StringPool; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONObject; - -import java.io.IOException; - -public class ValueHeader extends BlockItem implements JSONConvert { - private ReferenceItem mStringReference; - public ValueHeader(int size){ - super(size); - writeSize(); - putInteger(getBytesInternal(), OFFSET_SPEC_REFERENCE, -1); - } - - void linkSpecStringsInternal(SpecStringPool specStringPool){ - int key = getKey(); - SpecString specString = specStringPool.get(key); - if(specString == null){ - mStringReference = null; - return; - } - if(mStringReference != null){ - specString.removeReference(mStringReference); - } - ReferenceItem stringReference = new ReferenceBlock<>(this, OFFSET_SPEC_REFERENCE); - mStringReference = stringReference; - specString.addReference(stringReference); - } - public void onRemoved(){ - unLinkStringReference(); - } - public String getName(){ - StringItem stringItem = getNameString(); - if(stringItem!=null){ - return stringItem.get(); - } - return null; - } - public boolean isComplex(){ - return getBit(getBytesInternal(), OFFSET_FLAGS,0); - } - public void setComplex(boolean complex){ - putBit(getBytesInternal(), OFFSET_FLAGS, 0, complex); - } - public void setPublic(boolean b){ - putBit(getBytesInternal(), OFFSET_FLAGS,1, b); - } - public boolean isPublic(){ - return getBit(getBytesInternal(), OFFSET_FLAGS,1); - } - public void setWeak(boolean b){ - putBit(getBytesInternal(), OFFSET_FLAGS, 2, b); - } - public boolean isWeak(){ - return getBit(getBytesInternal(), OFFSET_FLAGS,2); - } - - public int getKey(){ - return getInteger(getBytesInternal(), OFFSET_SPEC_REFERENCE); - } - public void setKey(int key){ - if(key == getKey()){ - return; - } - unLinkStringReference(); - putInteger(getBytesInternal(), OFFSET_SPEC_REFERENCE, key); - linkStringReference(); - } - public void setKey(StringItem stringItem){ - if(ignoreUpdateKey(stringItem)){ - return; - } - unLinkStringReference(); - int key = -1; - if(stringItem!=null){ - key=stringItem.getIndex(); - } - putInteger(getBytesInternal(), OFFSET_SPEC_REFERENCE, key); - linkStringReference(stringItem); - } - private boolean ignoreUpdateKey(StringItem stringItem){ - int key = getKey(); - ReferenceItem referenceItem = this.mStringReference; - if(stringItem == null){ - return referenceItem == null && key == -1; - } - if(referenceItem == null || key != stringItem.getIndex()){ - return false; - } - return getSpecString(key) == stringItem; - } - public void setSize(int size){ - super.setBytesLength(size, false); - writeSize(); - } - public int getSize(){ - return getBytesInternal().length; - } - int readSize(){ - if(getSize()<2){ - return 0; - } - return 0xffff & getShort(getBytesInternal(), OFFSET_SIZE); - } - private void writeSize(){ - int size = getSize(); - if(size>1){ - putShort(getBytesInternal(), OFFSET_SIZE, (short) size); - } - } - - private void linkStringReference(){ - StringPool specStringPool = getSpecStringPool(); - if(specStringPool == null || specStringPool.isStringLinkLocked()){ - return; - } - linkStringReference(specStringPool.get(getKey())); - } - private void linkStringReference(StringItem stringItem){ - unLinkStringReference(); - if(stringItem==null){ - return; - } - ReferenceItem stringReference = new ReferenceBlock<>(this, OFFSET_SPEC_REFERENCE); - mStringReference = stringReference; - stringItem.addReference(stringReference); - } - private void unLinkStringReference(){ - ReferenceItem stringReference = mStringReference; - if(stringReference==null){ - return; - } - mStringReference = null; - StringItem stringItem = getNameString(); - if(stringItem == null){ - return; - } - stringItem.removeReference(stringReference); - } - public StringItem getNameString(){ - return getSpecString(getKey()); - } - private StringItem getSpecString(int key){ - if(key < 0){ - return null; - } - StringPool specStringPool = getSpecStringPool(); - if(specStringPool==null){ - return null; - } - return specStringPool.get(key); - } - private StringPool getSpecStringPool(){ - Block parent = getParent(); - while (parent!=null){ - if(parent instanceof ParentChunk){ - return ((ParentChunk) parent).getSpecStringPool(); - } - parent = parent.getParent(); - } - return null; - } - @Override - public void onReadBytes(BlockReader reader) throws IOException { - int size = reader.readUnsignedShort(); - setBytesLength(size, false); - reader.readFully(getBytesInternal()); - } - private void setName(String name){ - if(name==null){ - name = ""; - } - StringPool stringPool = getSpecStringPool(); - if(stringPool==null){ - return; - } - StringItem stringItem = stringPool.getOrCreate(name); - setKey(stringItem); - } - public void merge(ValueHeader valueHeader){ - if(valueHeader == null || valueHeader ==this){ - return; - } - setComplex(valueHeader.isComplex()); - setWeak(valueHeader.isWeak()); - setPublic(valueHeader.isPublic()); - setName(valueHeader.getName()); - } - public void toJson(JSONObject jsonObject) { - jsonObject.put(NAME_entry_name, getName()); - if(isWeak()){ - jsonObject.put(NAME_is_weak, true); - } - if(isPublic()){ - jsonObject.put(NAME_is_public, true); - } - } - @Override - public JSONObject toJson() { - JSONObject jsonObject = new JSONObject(); - toJson(jsonObject); - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - setWeak(json.optBoolean(NAME_is_weak, false)); - setPublic(json.optBoolean(NAME_is_public, false)); - setName(json.optString(NAME_entry_name)); - } - @Override - public String toString(){ - if(isNull()){ - return "null"; - } - StringBuilder builder=new StringBuilder(); - int byte_size = getSize(); - int read_size = readSize(); - if(byte_size!=8){ - builder.append("size=").append(byte_size); - } - if(byte_size!=read_size){ - builder.append(", readSize=").append(read_size); - } - if(isComplex()){ - builder.append(", complex"); - } - if(isPublic()){ - builder.append(", public"); - } - if(isWeak()){ - builder.append(", weak"); - } - String name = getName(); - if(name!=null){ - builder.append(", name=").append(name); - }else { - builder.append(", key=").append(getKey()); - } - return builder.toString(); - } - - private static final int OFFSET_SIZE = 0; - private static final int OFFSET_FLAGS = 2; - private static final int OFFSET_SPEC_REFERENCE = 4; - - - public static final String NAME_is_complex = "is_complex"; - public static final String NAME_is_public = "is_public"; - public static final String NAME_is_weak = "is_weak"; - - public static final String NAME_entry_name = "entry_name"; -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/ValueItem.java b/src/ARSCLib/com/reandroid/arsc/value/ValueItem.java deleted file mode 100755 index 62a123cc..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/ValueItem.java +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value; - -import com.reandroid.arsc.base.Block; -import com.reandroid.arsc.chunk.MainChunk; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.ParentChunk; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.io.BlockReader; -import com.reandroid.arsc.item.BlockItem; -import com.reandroid.arsc.item.ReferenceBlock; -import com.reandroid.arsc.item.ReferenceItem; -import com.reandroid.arsc.item.StringItem; -import com.reandroid.arsc.pool.StringPool; -import com.reandroid.arsc.pool.TableStringPool; -import com.reandroid.arsc.util.HexUtil; -import com.reandroid.json.JSONConvert; -import com.reandroid.json.JSONObject; - -import java.io.IOException; -import java.util.Objects; - -public abstract class ValueItem extends BlockItem implements Value, - JSONConvert{ - private ReferenceItem mStringReference; - private final int sizeOffset; - public ValueItem(int bytesLength, int sizeOffset) { - super(bytesLength); - this.sizeOffset = sizeOffset; - - writeSize(); - } - public Entry resolve(int resourceId){ - PackageBlock packageBlock = getPackageBlock(); - if(packageBlock == null){ - return null; - } - Entry entry = packageBlock.getAnyEntry(resourceId); - if(entry != null){ - return entry; - } - TableBlock tableBlock = packageBlock.getTableBlock(); - if(tableBlock == null){ - return null; - } - return tableBlock.getAnyEntry(resourceId); - } - - public String buildReference(Entry entry, ValueType referenceType, boolean addType){ - if(entry == null){ - return null; - } - PackageBlock packageBlock = entry.getPackageBlock(); - PackageBlock myPackageBlock = getPackageBlock(); - StringBuilder builder = new StringBuilder(); - if(referenceType == ValueType.REFERENCE - || referenceType == ValueType.DYNAMIC_REFERENCE){ - builder.append('@'); - }else if(referenceType == ValueType.ATTRIBUTE - || referenceType == ValueType.DYNAMIC_ATTRIBUTE){ - builder.append('?'); - } - if(packageBlock != myPackageBlock && packageBlock != null && myPackageBlock != null){ - String packageName = packageBlock.getName(); - - if(!packageName.equals(myPackageBlock.getName()) - || packageBlock.getId() != myPackageBlock.getId()){ - builder.append(packageName); - builder.append(':'); - } - - } - if(addType){ - builder.append(entry.getTypeName()); - builder.append('/'); - } - builder.append(entry.getName()); - return builder.toString(); - } - public PackageBlock getPackageBlock(){ - ParentChunk parentChunk = getParentChunk(); - if(parentChunk != null){ - return parentChunk.getPackageBlock(); - } - return null; - } - - void linkTableStrings(TableStringPool tableStringPool){ - if(getValueType() == ValueType.STRING){ - linkStringReference(tableStringPool); - } - } - public void onRemoved(){ - unLinkStringReference(); - } - protected void onDataChanged(){ - } - public void refresh(){ - writeSize(); - } - - byte getRes0(){ - return getBytesInternal()[this.sizeOffset + OFFSET_RES0]; - } - public byte getType(){ - return getBytesInternal()[this.sizeOffset + OFFSET_TYPE]; - } - public void setType(byte type){ - if(type == getType()){ - return; - } - byte[] bts = getBytesInternal(); - int offset = this.sizeOffset + OFFSET_TYPE; - byte old = bts[offset]; - bts[offset] = type; - onTypeChanged(old, type); - onDataChanged(); - } - public int getSize(){ - return 0xffff & getShort(getBytesInternal(), this.sizeOffset + OFFSET_SIZE); - } - public void setSize(int size){ - size = this.sizeOffset + size; - setBytesLength(size, false); - writeSize(); - } - private void writeSize(){ - int offset = this.sizeOffset; - int size = countBytes() - offset; - putShort(getBytesInternal(), offset + OFFSET_SIZE, (short) size); - } - protected void onDataLoaded(){ - if(getValueType() == ValueType.STRING){ - linkStringReference(); - }else { - unLinkStringReference(); - } - } - @Override - public ValueType getValueType(){ - return ValueType.valueOf(getType()); - } - @Override - public void setValueType(ValueType valueType){ - byte type = 0; - if(valueType!=null){ - type = valueType.getByte(); - } - setType(type); - } - @Override - public int getData(){ - return getInteger(getBytesInternal(), this.sizeOffset + OFFSET_DATA); - } - @Override - public void setData(int data){ - byte[] bts = getBytesInternal(); - int old = getInteger(bts, this.sizeOffset + OFFSET_DATA); - if(old == data){ - return; - } - unLinkStringReference(); - putInteger(bts, this.sizeOffset + OFFSET_DATA, data); - if(ValueType.STRING==getValueType()){ - linkStringReference(); - } - onDataChanged(); - } - - - public StringItem getDataAsPoolString(){ - if(getValueType()!=ValueType.STRING){ - return null; - } - StringPool stringPool = getStringPool(); - if(stringPool == null){ - return null; - } - return stringPool.get(getData()); - } - private void onTypeChanged(byte old, byte type){ - byte typeString = ValueType.STRING.getByte(); - if(old == typeString){ - unLinkStringReference(); - }else if(type == typeString){ - linkStringReference(); - } - } - private void linkStringReference(){ - StringPool stringPool = getStringPool(); - if(stringPool == null || stringPool.isStringLinkLocked()){ - return; - } - linkStringReference(stringPool); - } - private void linkStringReference(StringPool stringPool){ - StringItem tableString = stringPool.get(getData()); - if(tableString == null){ - unLinkStringReference(); - return; - } - ReferenceItem stringReference = mStringReference; - if(stringReference!=null){ - unLinkStringReference(); - } - stringReference = new ReferenceBlock<>(this, this.sizeOffset + OFFSET_DATA); - mStringReference = stringReference; - tableString.addReference(stringReference); - } - private void unLinkStringReference(){ - ReferenceItem stringReference = mStringReference; - if(stringReference==null){ - return; - } - mStringReference = null; - onUnlinkDataString(stringReference); - } - protected void onUnlinkDataString(ReferenceItem referenceItem){ - StringPool stringPool = getStringPool(); - if(stringPool == null){ - return; - } - stringPool.removeReference(referenceItem); - } - public StringPool getStringPool(){ - Block parent = getParent(); - while (parent!=null){ - if(parent instanceof MainChunk){ - return ((MainChunk) parent).getStringPool(); - } - parent=parent.getParent(); - } - return null; - } - @Override - public void onReadBytes(BlockReader reader) throws IOException { - int readSize = initializeBytes(reader); - super.onReadBytes(reader); - if(readSize<8){ - setBytesLength(this.sizeOffset + 8, false); - writeSize(); - } - } - private int initializeBytes(BlockReader reader) throws IOException { - int position = reader.getPosition(); - int offset = this.sizeOffset; - reader.offset(offset); - int readSize = reader.readUnsignedShort(); - int size = readSize; - if(size<8){ - if(reader.available()>=8){ - size = 8; - } - } - reader.seek(position); - setBytesLength(offset + size, false); - return readSize; - } - @Override - public String getValueAsString(){ - StringItem stringItem = getDataAsPoolString(); - if(stringItem!=null){ - String value = stringItem.getHtml(); - if(value == null){ - value = ""; - } - return value; - } - return null; - } - public void setValueAsString(String str){ - if(getValueType() == ValueType.STRING - && Objects.equals(str, getValueAsString())){ - return; - } - if(str == null){ - str = ""; - } - StringItem stringItem = getStringPool().getOrCreate(str); - setData(stringItem.getIndex()); - setValueType(ValueType.STRING); - } - public boolean getValueAsBoolean(){ - return getData()!=0; - } - public void setValueAsBoolean(boolean val){ - setValueType(ValueType.INT_BOOLEAN); - int data=val?0xffffffff:0; - setData(data); - } - public void setTypeAndData(ValueType valueType, int data){ - setData(data); - setValueType(valueType); - } - public void merge(ValueItem valueItem){ - if(valueItem == null || valueItem==this){ - return; - } - setSize(valueItem.getSize()); - ValueType coming = valueItem.getValueType(); - if(coming == ValueType.STRING){ - setValueAsString(valueItem.getValueAsString()); - }else { - setTypeAndData(coming, valueItem.getData()); - } - } - @Override - public JSONObject toJson() { - if(isNull()){ - return null; - } - JSONObject jsonObject = new JSONObject(); - ValueType valueType = getValueType(); - jsonObject.put(NAME_value_type, valueType.name()); - if(valueType==ValueType.STRING){ - jsonObject.put(NAME_data, getValueAsString()); - }else if(valueType==ValueType.INT_BOOLEAN){ - jsonObject.put(NAME_data, getValueAsBoolean()); - }else { - jsonObject.put(NAME_data, getData()); - } - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - ValueType valueType = ValueType.fromName(json.getString(NAME_value_type)); - if(valueType==ValueType.STRING){ - setValueAsString(json.optString(NAME_data, "")); - }else if(valueType==ValueType.INT_BOOLEAN){ - setValueAsBoolean(json.getBoolean(NAME_data)); - }else { - setValueType(valueType); - setData(json.getInt(NAME_data)); - } - } - - @Override - public String toString(){ - StringBuilder builder = new StringBuilder(); - int size = getSize(); - if(size!=8){ - builder.append("size=").append(getSize()); - builder.append(", "); - } - builder.append("type="); - ValueType valueType=getValueType(); - if(valueType!=null){ - builder.append(valueType); - }else { - builder.append(HexUtil.toHex2(getType())); - } - builder.append(", data="); - int data = getData(); - if(valueType==ValueType.STRING){ - StringItem tableString = getDataAsPoolString(); - if(tableString!=null){ - builder.append(tableString.getHtml()); - }else { - builder.append(HexUtil.toHex8(data)); - } - }else { - builder.append(HexUtil.toHex8(data)); - } - return builder.toString(); - } - - private static final int OFFSET_SIZE = 0; - private static final int OFFSET_RES0 = 2; - private static final int OFFSET_TYPE = 3; - private static final int OFFSET_DATA = 4; - - - public static final String NAME_data = "data"; - public static final String NAME_value_type = "value_type"; -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/ValueType.java b/src/ARSCLib/com/reandroid/arsc/value/ValueType.java deleted file mode 100755 index 7d009dbd..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/ValueType.java +++ /dev/null @@ -1,67 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value; - - -public enum ValueType { - - NULL((byte) 0x00), - REFERENCE((byte) 0x01), - ATTRIBUTE((byte) 0x02), - STRING((byte) 0x03), - FLOAT((byte) 0x04), - DIMENSION((byte) 0x05), - FRACTION((byte) 0x06), - DYNAMIC_REFERENCE((byte) 0x07), - DYNAMIC_ATTRIBUTE((byte) 0x08), - INT_DEC((byte) 0x10), - INT_HEX((byte) 0x11), - INT_BOOLEAN((byte) 0x12), - INT_COLOR_ARGB8((byte) 0x1c), - INT_COLOR_RGB8((byte) 0x1d), - INT_COLOR_ARGB4((byte) 0x1e), - INT_COLOR_RGB4((byte) 0x1f); - - private final byte mByte; - ValueType(byte b) { - this.mByte=b; - } - public byte getByte(){ - return mByte; - } - public static ValueType valueOf(byte b){ - ValueType[] all=values(); - for(ValueType vt:all){ - if(vt.mByte==b){ - return vt; - } - } - return null; - } - public static ValueType fromName(String name){ - if(name==null){ - return null; - } - name=name.toUpperCase(); - ValueType[] all=values(); - for(ValueType vt:all){ - if(name.equals(vt.name())){ - return vt; - } - } - return null; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/array/ArrayBag.java b/src/ARSCLib/com/reandroid/arsc/value/array/ArrayBag.java deleted file mode 100644 index 29413259..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/array/ArrayBag.java +++ /dev/null @@ -1,175 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ - package com.reandroid.arsc.value.array; - - import com.reandroid.arsc.array.ResValueMapArray; - import com.reandroid.arsc.value.Entry; - import com.reandroid.arsc.value.ResTableMapEntry; - import com.reandroid.arsc.value.ResValueMap; - import com.reandroid.arsc.value.bag.Bag; - - import java.util.AbstractList; - import java.util.RandomAccess; - - public class ArrayBag extends AbstractList implements Bag, RandomAccess { - private final Entry entry; - - private ArrayBag(Entry entry) { - this.entry = entry; - } - - private ResTableMapEntry getTableEntry() { - return (ResTableMapEntry) entry.getTableEntry(); - } - - private ResValueMapArray getMapArray() { - return getTableEntry().getValue(); - } - - private void updateStructure(int regenStart) { - getTableEntry().setValuesCount(size()); - modCount += 1; - if (regenStart < 1) { - return; - } - - ResValueMapArray array = getMapArray(); - for (int i = regenStart; i < array.childesCount(); i++) { - setIndex(array.get(i), i); - } - } - - @Override - public Entry getEntry() { - return entry; - } - - public ArrayBagItem[] getBagItems() { - return toArray(new ArrayBagItem[0]); - } - - @Override - public int size() { - return getMapArray().childesCount(); - } - - @Override - public ArrayBagItem get(int i) { - return ArrayBagItem.create(getMapArray().get(i)); - } - - @Override - public ArrayBagItem set(int index, ArrayBagItem value) { - ArrayBagItem target = get(index); - value.copyTo(target.getBagItem()); - return target; - } - - private void setIndex(ResValueMap valueMap, int index) { - valueMap.setName(0x01000001 + index); - } - - @Override - public void add(int index, ArrayBagItem value) { - if (index < 0 || index > size()) { - throw new IndexOutOfBoundsException(); - } - if (value == null) { - throw new NullPointerException("value is null"); - } - - ResValueMap valueMap = new ResValueMap(); - setIndex(valueMap, index); - getMapArray().insertItem(index, valueMap); - value.copyTo(valueMap); - updateStructure(index); - } - - @Override - public ArrayBagItem remove(int index) { - ResValueMapArray array = getMapArray(); - ResValueMap target = array.getChildes()[index]; - array.remove(target); - updateStructure(index); - return ArrayBagItem.copyOf(target); - } - - @Override - public void clear() { - getMapArray().clearChildes(); - updateStructure(-1); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("<"); - String type = getTypeName(); - builder.append(type); - builder.append(" name=\""); - builder.append(getName()); - builder.append("\">"); - ArrayBagItem[] allItems = getBagItems(); - for (ArrayBagItem allItem : allItems) { - builder.append("\n "); - builder.append(allItem.toString()); - } - builder.append("\n"); - return builder.toString(); - } - - /** - * The result of this is not always 100% accurate, - * in addition to this use your methods to cross check like type-name == "array" - **/ - public static boolean isArray(Entry entry) { - ArrayBag array = create(entry); - if (array == null) { - return false; - } - ResTableMapEntry tableEntry = array.getTableEntry(); - if (tableEntry.getParentId() != 0) { - return false; - } - ResValueMap[] items = tableEntry.listResValueMap(); - if (items.length == 0) { - return false; - } - - for (int i = 0; i < items.length; i++) { - ResValueMap resValueMap = items[i]; - int name = resValueMap.getName(); - int high = (name >> 16) & 0xffff; - if(high!=0x0100){ - return false; - } - int low = name & 0xffff; - if(low != (i+1)){ - return false; - } - } - return true; - } - - public static ArrayBag create(Entry entry) { - if (entry == null || !entry.isComplex()) { - return null; - } - return new ArrayBag(entry); - } - } diff --git a/src/ARSCLib/com/reandroid/arsc/value/array/ArrayBagItem.java b/src/ARSCLib/com/reandroid/arsc/value/array/ArrayBagItem.java deleted file mode 100644 index fa9cf2ff..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/array/ArrayBagItem.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value.array; - -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.item.StringItem; -import com.reandroid.arsc.item.TableString; -import com.reandroid.arsc.util.HexUtil; -import com.reandroid.arsc.value.ValueType; -import com.reandroid.arsc.value.bag.BagItem; -import com.reandroid.arsc.value.ResValueMap; - -public class ArrayBagItem extends BagItem { - private ArrayBagItem(ResValueMap valueMap) { - super(valueMap); - } - - private ArrayBagItem(StringItem str) { - super(str); - } - - private ArrayBagItem(ValueType valueType, int value) { - super(valueType, value); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(""); - if (hasStringValue()) { - builder.append(getStringValue()); - } else { - builder.append(HexUtil.toHex8(getValue())); - } - builder.append(""); - return builder.toString(); - } - - protected static ArrayBagItem create(ResValueMap valueMap) { - if (valueMap == null) { - return null; - } - return new ArrayBagItem(valueMap); - } - - public static ArrayBagItem create(ValueType valueType, int value) { - if (valueType == null || valueType == ValueType.STRING) { - return null; - } - return new ArrayBagItem(valueType, value); - } - - protected static ArrayBagItem copyOf(ResValueMap resValueMap) { - ValueType valueType = resValueMap.getValueType(); - if (valueType == ValueType.STRING) { - return new ArrayBagItem(resValueMap.getDataAsPoolString()); - } else { - return new ArrayBagItem(valueType, resValueMap.getData()); - } - } - - public static ArrayBagItem encoded(ValueDecoder.EncodeResult encodeResult) { - if (encodeResult == null) { - return null; - } - return create(encodeResult.valueType, encodeResult.value); - } - - public static ArrayBagItem integer(int n) { - return create(ValueType.INT_DEC, n); - } - - public static ArrayBagItem string(TableString str) { - if (str == null) { - return null; - } - return new ArrayBagItem(str); - } - - public static ArrayBagItem reference(int resourceId) { - return create(ValueType.REFERENCE, resourceId); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/attribute/AttributeBag.java b/src/ARSCLib/com/reandroid/arsc/value/attribute/AttributeBag.java deleted file mode 100755 index 287f80c0..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/attribute/AttributeBag.java +++ /dev/null @@ -1,248 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value.attribute; - -import com.reandroid.arsc.array.ResValueMapArray; -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.value.*; -import com.reandroid.common.EntryStore; - - -public class AttributeBag { - private final AttributeBagItem[] mBagItems; - public AttributeBag(AttributeBagItem[] bagItems){ - this.mBagItems=bagItems; - } - - public boolean contains(AttributeDataFormat valueType){ - return getFormat().contains(valueType); - } - public boolean isEqualType(AttributeDataFormat valueType){ - return getFormat().isEqualType(valueType); - } - public ValueDecoder.EncodeResult encodeEnumOrFlagValue(String valueString){ - if(valueString==null || !isEnumOrFlag()){ - return null; - } - int value=0; - boolean foundOnce=false; - String[] names=valueString.split("[\\s|]+"); - for(String name:names){ - AttributeBagItem item=searchByName(name); - if(item==null){ - continue; - } - value|=item.getBagItem().getData(); - foundOnce=true; - } - if(!foundOnce){ - return null; - } - ValueType valueType = isFlag()?ValueType.INT_HEX:ValueType.INT_DEC; - return new ValueDecoder.EncodeResult(valueType, value); - } - public String decodeAttributeValue(EntryStore entryStore, int attrValue){ - AttributeBagItem[] bagItems=searchValue(attrValue); - return AttributeBagItem.toString(entryStore, bagItems); - } - public AttributeBagItem searchByName(String entryName){ - AttributeBagItem[] bagItems= getBagItems(); - for(AttributeBagItem item:bagItems){ - if(item.isType()){ - continue; - } - if(entryName.equals(item.getNameOrHex())){ - return item; - } - } - return null; - } - public AttributeBagItem[] searchValue(int attrValue){ - if(isFlag()){ - return searchFlagValue(attrValue); - } - AttributeBagItem item = searchEnumValue(attrValue); - if(item != null){ - return new AttributeBagItem[]{item}; - } - return null; - } - private AttributeBagItem searchEnumValue(int attrValue){ - AttributeBagItem[] bagItems= getBagItems(); - for(AttributeBagItem item:bagItems){ - if(item.isType()){ - continue; - } - int data=item.getData(); - if(attrValue==data){ - return item; - } - } - return null; - } - - private AttributeBagItem[] searchFlagValue(int attrValue){ - AttributeBagItem[] bagItems= getBagItems(); - int len=bagItems.length; - AttributeBagItem[] foundBags = new AttributeBagItem[len]; - for(int i=0;i= 0) { - foundBags[index] = item; - } - } - return removeNull(foundBags); - } - - private int indexOf(AttributeBagItem[] foundFlag, int data) { - for (int i = 0; i < foundFlag.length; i++) { - AttributeBagItem item=foundFlag[i]; - if(item==null){ - return i; - } - int flag=item.getData(); - if(flag==0){ - return i; - } - if ((flag & data) == data) { - return -1; - } - if ((flag & data) == flag) { - return i; - } - } - return -1; - } - - private AttributeBagItem[] removeNull(AttributeBagItem[] bagItems){ - int count=countNonNull(bagItems); - if(count==0){ - return null; - } - AttributeBagItem[] results=new AttributeBagItem[count]; - int index=0; - int len=bagItems.length; - for(int i=0;i extends AbstractMap implements Bag { - protected final com.reandroid.arsc.value.Entry entry; - private int modCount = 0; - - protected MapBag(com.reandroid.arsc.value.Entry entry) { - this.entry = entry; - } - - protected ResTableMapEntry getTableEntry() { - return (ResTableMapEntry) entry.getTableEntry(); - } - - protected ResValueMapArray getMapArray() { - return getTableEntry().getValue(); - } - - private void updateSize() { - getTableEntry().setValuesCount(size()); - modCount += 1; - } - - @Override - public com.reandroid.arsc.value.Entry getEntry() { - return entry; - } - - protected abstract V createBagItem(ResValueMap valueMap, boolean copied); - - protected abstract ResValueMap newKey(K key); - - protected abstract K getKeyFor(ResValueMap valueMap); - - protected TableStringPool getStringPool() { - com.reandroid.arsc.value.Entry entry = getEntry(); - if (entry == null) { - return null; - } - PackageBlock pkg = entry.getPackageBlock(); - if (pkg == null) { - return null; - } - TableBlock tableBlock = pkg.getTableBlock(); - if (tableBlock == null) { - return null; - } - return tableBlock.getTableStringPool(); - } - - private class MapEntry implements Map.Entry { - private final ResValueMap item; - - private MapEntry(ResValueMap item) { - this.item = item; - } - - @Override - public K getKey() { - return getKeyFor(item); - } - - @Override - public V getValue() { - return createBagItem(item, false); - } - - @Override - public V setValue(V v) { - v.copyTo(item); - return getValue(); - } - } - - private class EntrySet extends AbstractSet> { - @Override - public Iterator> iterator() { - return new Iterator>() { - private final Iterator iterator = getMapArray().iterator(); - private final int expectedModCount = modCount; - - private void checkValidity() { - if (expectedModCount != modCount) { - throw new ConcurrentModificationException("Iterator is no longer valid because the size has changed."); - } - } - - @Override - public boolean hasNext() { - checkValidity(); - return iterator.hasNext(); - } - - @Override - public Entry next() { - checkValidity(); - return new MapEntry(iterator.next()); - } - }; - } - - @Override - public int size() { - return getMapArray().childesCount(); - } - } - - @Override - public V remove(Object key) { - ResValueMapArray array = getMapArray(); - for (ResValueMap item : array.getChildes()) { - if (getKeyFor(item).equals(key)) { - if (!array.remove(item)) { - throw new IllegalStateException("Could not remove item"); - } - updateSize(); - return createBagItem(item, true); - } - } - return null; - } - - @Override - public void clear() { - getMapArray().clearChildes(); - updateSize(); - } - - @Override - public Set> entrySet() { - return new EntrySet(); - } - - @Override - public V put(K key, V value) { - if (key == null) { - throw new NullPointerException("key is null"); - } - if (value == null) { - throw new NullPointerException("value is null"); - } - ResValueMapArray array = getMapArray(); - ResValueMap valueMap = null; - for (ResValueMap item : array.getChildes()) { - if (getKeyFor(item).equals(key)) { - valueMap = item; - break; - } - } - - if (valueMap == null) { - valueMap = newKey(key); - array.add(valueMap); - updateSize(); - } - - value.copyTo(valueMap); - return createBagItem(valueMap, false); - } - - @Override - public void putAll(Map m) { - LinkedHashSet keys = new LinkedHashSet<>(m.keySet()); - ResValueMapArray array = getMapArray(); - - for (ResValueMap item : array.getChildes()) { - K currentKey = getKeyFor(item); - - if (keys.remove(currentKey)) { - V src = m.get(currentKey); - src.copyTo(item); - } - } - - for (K key : keys) { - if (key == null) { - throw new NullPointerException("Key is null"); - } - ResValueMap item = newKey(key); - array.add(item); - V src = m.get(key); - src.copyTo(item); - } - - updateSize(); - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/plurals/PluralsBag.java b/src/ARSCLib/com/reandroid/arsc/value/plurals/PluralsBag.java deleted file mode 100644 index 4c03194c..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/plurals/PluralsBag.java +++ /dev/null @@ -1,126 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ - package com.reandroid.arsc.value.plurals; - - import com.reandroid.arsc.value.ResConfig; - import com.reandroid.arsc.value.ResValueMap; - import com.reandroid.arsc.value.ValueType; - import com.reandroid.arsc.value.bag.MapBag; - - import java.util.Arrays; - import java.util.HashSet; - import java.util.Set; - - public class PluralsBag extends MapBag { - private PluralsBag(com.reandroid.arsc.value.Entry entry) { - super(entry); - } - - @Override - protected PluralsBagItem createBagItem(ResValueMap valueMap, boolean copied) { - if (copied) { - return PluralsBagItem.copyOf(valueMap); - } - return PluralsBagItem.create(valueMap); - } - - @Override - protected ResValueMap newKey(PluralsQuantity key) { - ResValueMap valueMap = new ResValueMap(); - valueMap.setParent(getMapArray()); - valueMap.setNameHigh((short) 0x0100); - valueMap.setNameLow(key.getId()); - return valueMap; - } - - @Override - protected PluralsQuantity getKeyFor(ResValueMap valueMap) { - return PluralsQuantity.valueOf(valueMap); - } - - public String getQuantityString(PluralsQuantity quantity, ResConfig resConfig) { - PluralsBagItem item = get(quantity); - if (item == null) { - return null; - } - return item.getQualityString(resConfig); - } - public String getQuantityString(PluralsQuantity quantity) { - return getQuantityString(quantity, null); - } - - public void setQuantityString(PluralsQuantity quantity, String str) { - if (quantity == null || str == null) { - return; - } - put(quantity, PluralsBagItem.string(getStringPool().getOrCreate(str))); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("<"); - String type = getTypeName(); - builder.append(type); - builder.append(" name=\""); - builder.append(getName()); - builder.append("\">"); - for (PluralsBagItem pluralsBagItem : values()) { - builder.append("\n "); - builder.append(pluralsBagItem.toString()); - } - builder.append("\n"); - return builder.toString(); - } - - private final static Set validTypes = new HashSet<>(Arrays.asList(ValueType.NULL, ValueType.STRING, ValueType.REFERENCE)); - - /** - * The result of this is not always 100% accurate, - * in addition to this use your methods to cross check like type-name == "plurals" - **/ - public static boolean isPlurals(com.reandroid.arsc.value.Entry entry) { - PluralsBag plurals = create(entry); - if (plurals == null) { - return false; - } - ResValueMap[] items = plurals.getMapArray().getChildes(); - if (items.length == 0) { - return false; - } - - for (ResValueMap item : items) { - if (item == null || !validTypes.contains(item.getValueType())) { - return false; - } - int name = item.getName(); - int high = (name >> 16) & 0xffff; - if (PluralsQuantity.valueOf(item) == null || high != 0x0100) { - return false; - } - } - return true; - } - - public static PluralsBag create(com.reandroid.arsc.value.Entry entry) { - if (entry == null || !entry.isComplex()) { - return null; - } - return new PluralsBag(entry); - } - } diff --git a/src/ARSCLib/com/reandroid/arsc/value/plurals/PluralsBagItem.java b/src/ARSCLib/com/reandroid/arsc/value/plurals/PluralsBagItem.java deleted file mode 100644 index 34b5ba79..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/plurals/PluralsBagItem.java +++ /dev/null @@ -1,131 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ - package com.reandroid.arsc.value.plurals; - - import com.reandroid.arsc.chunk.TableBlock; - import com.reandroid.arsc.item.StringItem; - import com.reandroid.arsc.item.TableString; - import com.reandroid.arsc.util.HexUtil; - import com.reandroid.arsc.value.*; - import com.reandroid.arsc.value.bag.BagItem; - - import java.util.List; - - public class PluralsBagItem extends BagItem { - private PluralsBagItem(ResValueMap bagItem) { - super(bagItem); - } - - private PluralsBagItem(StringItem str) { - super(str); - } - - private PluralsBagItem(ValueType valueType, int data) { - super(valueType, data); - } - - public PluralsQuantity getQuantity() { - if (mBagItem == null || mBagItem.getName() == 0) { - return null; - } - return PluralsQuantity.valueOf(mBagItem); - } - - public String getQualityString(ResConfig resConfig) { - switch (getValueType()) { - case STRING: - return getStringValue(); - case REFERENCE: - Entry entry = null; - if (mBagItem != null) { - entry = mBagItem.getEntry(); - } - if (entry == null) { - return null; - } - - if (resConfig == null) { - resConfig = entry.getResConfig(); - } - - Entry stringRes = null; - if (resConfig != null) { - TableBlock tableBlock = entry.getPackageBlock().getTableBlock(); - List resolvedList = tableBlock.resolveReferenceWithConfig(getValue(), resConfig); - if (resolvedList.size() > 0) { - stringRes = resolvedList.get(0); - } - } - - if (stringRes == null) { - return null; - } - ResValue resValue = stringRes.getResValue(); - if (resValue == null || resValue.getValueType() != ValueType.STRING) { - throw new IllegalArgumentException("Not a STR reference: " + formattedRefValue()); - } - return resValue.getValueAsString(); - default: - throw new IllegalArgumentException("Not STR/REFERENCE ValueType=" + getValueType()); - } - } - - private String formattedRefValue() { - return HexUtil.toHex8("@0x", getValue()); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(""); - if (hasStringValue()) { - builder.append(getStringValue()); - } else { - builder.append(formattedRefValue()); - } - builder.append(""); - return builder.toString(); - } - - protected static PluralsBagItem create(ResValueMap resValueMap) { - if (resValueMap == null) { - return null; - } - return new PluralsBagItem(resValueMap); - } - - protected static PluralsBagItem copyOf(ResValueMap resValueMap) { - ValueType valueType = resValueMap.getValueType(); - if (valueType == ValueType.STRING) { - return new PluralsBagItem(resValueMap.getDataAsPoolString()); - } else { - return new PluralsBagItem(valueType, resValueMap.getData()); - } - } - - public static PluralsBagItem string(TableString str) { - if (str == null) { - return null; - } - return new PluralsBagItem(str); - } - - public static PluralsBagItem reference(int resourceId) { - return new PluralsBagItem(ValueType.REFERENCE, resourceId); - } - } diff --git a/src/ARSCLib/com/reandroid/arsc/value/plurals/PluralsQuantity.java b/src/ARSCLib/com/reandroid/arsc/value/plurals/PluralsQuantity.java deleted file mode 100755 index d02f05e4..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/plurals/PluralsQuantity.java +++ /dev/null @@ -1,69 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value.plurals; - - - import com.reandroid.arsc.value.ResValueMap; - - public enum PluralsQuantity { - OTHER((short) 0x0004), - ZERO((short) 0x0005), - ONE((short) 0x0006), - TWO((short) 0x0007), - FEW((short) 0x0008), - MANY((short) 0x0009); - - private final short mId; - PluralsQuantity(short id) { - this.mId=id; - } - public short getId() { - return mId; - } - @Override - public String toString(){ - return name().toLowerCase(); - } - public static PluralsQuantity valueOf(short id){ - PluralsQuantity[] all=values(); - for(PluralsQuantity pq:all){ - if(id==pq.mId){ - return pq; - } - } - return null; - } - public static PluralsQuantity valueOf(ResValueMap valueMap){ - if (valueMap == null) { - return null; - } - int low = valueMap.getName() & 0xffff; - return valueOf((short) low); - } - public static PluralsQuantity value(String name){ - if(name==null){ - return null; - } - name=name.trim().toUpperCase(); - PluralsQuantity[] all=values(); - for(PluralsQuantity pq:all){ - if(name.equals(pq.name())){ - return pq; - } - } - return null; - } -} diff --git a/src/ARSCLib/com/reandroid/arsc/value/style/StyleBag.java b/src/ARSCLib/com/reandroid/arsc/value/style/StyleBag.java deleted file mode 100644 index 752749b8..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/style/StyleBag.java +++ /dev/null @@ -1,139 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ - package com.reandroid.arsc.value.style; - - import com.reandroid.apk.xmlencoder.EncodeMaterials; - import com.reandroid.arsc.chunk.TableBlock; - import com.reandroid.arsc.value.ResValueMap; - import com.reandroid.arsc.value.bag.MapBag; - - public class StyleBag extends MapBag { - private StyleBag(com.reandroid.arsc.value.Entry entry) { - super(entry); - } - - public String getParentResourceName() { - int id = getParentId(); - if (id == 0) { - return null; - } - com.reandroid.arsc.value.Entry entry = getEntry(); - if (entry == null) { - return null; - } - return entry.buildResourceName(id, '@', true); - } - - public int getParentId() { - return getTableEntry().getParentId(); - } - public void setParentId(int id) { - getTableEntry().setParentId(id); - } - - public int getResourceId() { - com.reandroid.arsc.value.Entry entry = getEntry(); - if (entry == null) { - return 0; - } - return entry.getResourceId(); - } - - @Override - protected StyleBagItem createBagItem(ResValueMap valueMap, boolean copied) { - if (copied) { - return StyleBagItem.copyOf(valueMap); - } - return StyleBagItem.create(valueMap); - } - - @Override - protected ResValueMap newKey(Integer attrId) { - ResValueMap valueMap = new ResValueMap(); - valueMap.setParent(getMapArray()); - valueMap.setName(attrId); - return valueMap; - } - - @Override - protected Integer getKeyFor(ResValueMap valueMap) { - return valueMap.getName(); - } - - public static int resolve(EncodeMaterials materials, String name) { - return materials.getAttributeBlock(name).getResourceId(); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("<"); - String type = getTypeName(); - builder.append(type); - builder.append(" name=\""); - builder.append(getName()); - builder.append("\""); - String parent = getParentResourceName(); - if (parent != null) { - builder.append(" parent=\""); - builder.append(parent); - builder.append("\""); - } - builder.append("\">"); - for (StyleBagItem item : values()) { - builder.append("\n "); - builder.append(item.toString()); - } - builder.append("\n"); - return builder.toString(); - } - - /** - * The result of this is not always 100% accurate, - * in addition to this use your methods to cross check like type-name == "plurals" - **/ - public static boolean isStyle(com.reandroid.arsc.value.Entry entry) { - StyleBag style = create(entry); - if (style == null) { - return false; - } - - TableBlock tableBlock = entry.getPackageBlock().getTableBlock(); - if (tableBlock == null) { - return false; - } - ResValueMap[] items = style.getMapArray().getChildes(); - if (items.length == 0) { - return false; - } - - for (ResValueMap item : items) { - if (item == null || tableBlock.search(item.getNameResourceID()) == null) { - return false; - } - } - return true; - } - - public static StyleBag create(com.reandroid.arsc.value.Entry entry) { - if (entry == null || !entry.isComplex()) { - return null; - } - return new StyleBag(entry); - } - } diff --git a/src/ARSCLib/com/reandroid/arsc/value/style/StyleBagItem.java b/src/ARSCLib/com/reandroid/arsc/value/style/StyleBagItem.java deleted file mode 100644 index b6d78389..00000000 --- a/src/ARSCLib/com/reandroid/arsc/value/style/StyleBagItem.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.arsc.value.style; - -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.item.StringItem; -import com.reandroid.arsc.item.TableString; -import com.reandroid.arsc.util.HexUtil; -import com.reandroid.arsc.value.attribute.AttributeBag; -import com.reandroid.arsc.value.attribute.AttributeBagItem; -import com.reandroid.arsc.value.bag.BagItem; -import com.reandroid.arsc.value.Entry; -import com.reandroid.arsc.value.ResValueMap; -import com.reandroid.arsc.value.ValueType; -import com.reandroid.common.EntryStore; - -public class StyleBagItem extends BagItem { - private StyleBagItem(ResValueMap bagItem) { - super(bagItem); - } - - private StyleBagItem(ValueType valueType, int data) { - super(valueType, data); - } - - private StyleBagItem(StringItem str) { - super(str); - } - - public String getName() { - if (mBagItem == null) { - return null; - } - Entry block = mBagItem.getEntry(); - if (block == null) { - return null; - } - char prefix = 0; - return block.buildResourceName(mBagItem.getName(), prefix, false); - } - public Entry getAttributeEntry(EntryStore entryStore) { - if (mBagItem == null) { - return null; - } - return entryStore.getEntryGroup(mBagItem.getName()).pickOne(); - } - - public int getNameId() { - if (mBagItem == null) { - return 0; - } - return mBagItem.getName(); - } - - public boolean hasAttributeValue() { - return getValueType() == ValueType.ATTRIBUTE; - } - public boolean hasIntValue() { - ValueType valueType = getValueType(); - return valueType == ValueType.INT_DEC || valueType == ValueType.INT_HEX; - } - - public String getValueAsReference() { - ValueType valueType = getValueType(); - if (valueType != ValueType.REFERENCE && valueType != ValueType.ATTRIBUTE) { - throw new IllegalArgumentException("Not REF ValueType=" + valueType); - } - Entry entry = getBagItem().getEntry(); - if (entry == null) { - return null; - } - char prefix = '@'; - boolean includeType = true; - if (valueType == ValueType.ATTRIBUTE) { - prefix = '?'; - includeType = false; - } - int id = getValue(); - return entry.buildResourceName(id, prefix, includeType); - } - public String decodeAttributeValue(AttributeBag attr, EntryStore entryStore) { - if (!hasIntValue()) { - return null; - } - return attr.decodeAttributeValue(entryStore, getValue()); - } - public AttributeBagItem[] getFlagsOrEnum(AttributeBag attr) { - if (!hasIntValue()) { - return null; - } - return attr.searchValue(getValue()); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(""); - if (hasStringValue()) { - builder.append(getStringValue()); - } - String val = null; - if (hasReferenceValue() || hasAttributeValue()) { - val = getValueAsReference(); - } - if (val == null) { - val = HexUtil.toHex8(getValue()); - } - builder.append(val); - builder.append(""); - return builder.toString(); - } - - protected static StyleBagItem create(ResValueMap resValueMap) { - if (resValueMap == null) { - return null; - } - return new StyleBagItem(resValueMap); - } - - public static StyleBagItem create(ValueType valueType, int value) { - if (valueType == null || valueType == ValueType.STRING) { - return null; - } - return new StyleBagItem(valueType, value); - } - - protected static StyleBagItem copyOf(ResValueMap resValueMap) { - ValueType valueType = resValueMap.getValueType(); - if (valueType == ValueType.STRING) { - return new StyleBagItem(resValueMap.getDataAsPoolString()); - } else { - return new StyleBagItem(valueType, resValueMap.getData()); - } - } - - public static StyleBagItem integer(int n) { - return new StyleBagItem(ValueType.INT_DEC, n); - } - - public static StyleBagItem string(TableString str) { - if (str == null) { - return null; - } - return new StyleBagItem(str); - } - - public static StyleBagItem reference(int resourceId) { - return new StyleBagItem(ValueType.REFERENCE, resourceId); - } - public static StyleBagItem attribute(int resourceId) { - return new StyleBagItem(ValueType.ATTRIBUTE, resourceId); - } - public static StyleBagItem encoded(ValueDecoder.EncodeResult encodeResult) { - if (encodeResult == null) { - return null; - } - return create(encodeResult.valueType, encodeResult.value); - } - public static StyleBagItem color(String color) { - return encoded(ValueDecoder.encodeColor(color)); - } - public static StyleBagItem dimensionOrFraction(String str) { - return encoded(ValueDecoder.encodeDimensionOrFraction(str)); - } - public static StyleBagItem createFloat(float n) { - return new StyleBagItem(ValueType.FLOAT, Float.floatToIntBits(n)); - } - public static StyleBagItem enumOrFlag(AttributeBag attr, String valueString) { - return encoded(attr.encodeEnumOrFlagValue(valueString)); - } -} diff --git a/src/ARSCLib/com/reandroid/common/EntryStore.java b/src/ARSCLib/com/reandroid/common/EntryStore.java deleted file mode 100755 index 4d6e24de..00000000 --- a/src/ARSCLib/com/reandroid/common/EntryStore.java +++ /dev/null @@ -1,28 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.common; - -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.group.EntryGroup; -import com.reandroid.arsc.item.TableString; - -import java.util.Collection; - -public interface EntryStore { - Collection getEntryGroups(int resourceId); - EntryGroup getEntryGroup(int resourceId); - Collection getPackageBlocks(int packageId); -} diff --git a/src/ARSCLib/com/reandroid/common/FileChannelInputStream.java b/src/ARSCLib/com/reandroid/common/FileChannelInputStream.java deleted file mode 100644 index fffad55e..00000000 --- a/src/ARSCLib/com/reandroid/common/FileChannelInputStream.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.common; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.file.StandardOpenOption; - -public class FileChannelInputStream extends InputStream { - private final FileChannel fileChannel; - private final long totalLength; - private long startOffset; - private long position; - private final byte[] buffer; - private int bufferPosition; - private int bufferLength; - private boolean mAutoClosable; - private boolean mIsClosed; - - public FileChannelInputStream(FileChannel fileChannel, long length, int bufferSize) throws IOException { - this.fileChannel = fileChannel; - this.totalLength = length; - if(bufferSize <= 0){ - bufferSize = 8; - } - if(length < bufferSize){ - bufferSize = (int) length; - } - this.buffer = new byte[bufferSize]; - this.bufferLength = bufferSize; - this.bufferPosition = bufferSize; - this.startOffset = fileChannel.position(); - } - public FileChannelInputStream(FileChannel fileChannel, long length) throws IOException { - this(fileChannel, length, DEFAULT_BUFFER_SIZE); - } - public FileChannelInputStream(File file, long length, int bufferSize) throws IOException { - this(FileChannel.open(file.toPath(), StandardOpenOption.READ), length, bufferSize); - this.mAutoClosable = true; - } - public FileChannelInputStream(File file) throws IOException { - this(FileChannel.open(file.toPath(), StandardOpenOption.READ), file.length()); - this.mAutoClosable = true; - } - - @Override - public int read(byte[] bytes) throws IOException { - return read(bytes, 0, bytes.length); - } - @Override - public int read(byte[] bytes, int offset, int length) throws IOException { - if(isFinished()){ - return -1; - } - if(length==0){ - return 0; - } - loadBuffer(); - int result = 0; - int read = readBuffer(bytes, offset, length); - result += read; - length = length - read; - offset = offset + read; - while (length>0 && !isFinished()){ - loadBuffer(); - read = readBuffer(bytes, offset, length); - result += read; - length = length - read; - offset = offset + read; - } - return result; - } - private int readBuffer(byte[] bytes, int offset, int length){ - int avail = bufferLength - bufferPosition; - if(avail == 0){ - return 0; - } - int read = length; - if(read > avail){ - read = avail; - } - System.arraycopy(buffer, bufferPosition, bytes, offset, read); - bufferPosition += read; - position += read; - return read; - } - private void loadBuffer() throws IOException { - byte[] buffer = this.buffer; - if(this.bufferPosition < bufferLength){ - return; - } - int length = buffer.length; - long available = totalLength - position; - boolean is_last = false; - if(length > available){ - length = (int) available; - is_last = true; - } - ByteBuffer byteBuffer = ByteBuffer.wrap(buffer, 0, length); - bufferLength = fileChannel.read(byteBuffer); - bufferPosition = 0; - if(is_last){ - closeAuto(); - } - } - private boolean isFinished() throws IOException { - boolean finished = position >= totalLength; - if(finished){ - closeAuto(); - } - return finished; - } - @Override - public int read() throws IOException { - byte[] bytes = new byte[1]; - int read = read(bytes); - if(read < 0){ - return read; - } - return bytes[0] & 0xff; - } - public long transferTo(OutputStream out) throws IOException{ - long transferred = 0; - if(isFinished()){ - return transferred; - } - while (!isFinished()){ - loadBuffer(); - int offset = bufferPosition; - int length = bufferLength - bufferPosition; - if(length <= 0){ - break; - } - out.write(buffer, offset, length); - bufferPosition += length; - position += length; - transferred += length; - } - return transferred; - } - @Override - public long skip(long amount) throws IOException { - if(amount <= 0){ - return amount; - } - long remaining = amount; - remaining = remaining - skipBuffer((int) remaining); - if(remaining == 0){ - return amount; - } - long availableChannel = totalLength - position; - if(availableChannel > remaining){ - availableChannel = remaining; - } - position += availableChannel; - remaining = remaining - availableChannel; - amount = amount - remaining; - fileChannel.position(fileChannel.position() + availableChannel); - return amount; - } - private int skipBuffer(int amount){ - int availableBuffer = bufferLength - bufferPosition; - if(availableBuffer > amount){ - availableBuffer = amount; - } - bufferPosition += availableBuffer; - position += availableBuffer; - return availableBuffer; - } - public FileChannel getFileChannel() { - return fileChannel; - } - - public void setAutoClosable(boolean autoClosable) { - this.mAutoClosable = autoClosable; - } - private void closeAuto() throws IOException { - if(mAutoClosable && !mIsClosed){ - mIsClosed = true; - fileChannel.close(); - } - } - - @Override - public void close() throws IOException { - closeAuto(); - } - @Override - public void reset() throws IOException { - position = 0; - bufferPosition = bufferLength; - fileChannel.position(startOffset); - } - @Override - public int available(){ - return (int) (totalLength - position); - } - @Override - public boolean markSupported() { - return true; - } - @Override - public synchronized void mark(int readLimit){ - if(readLimit < 0){ - readLimit = 0; - } - startOffset = readLimit; - } - @Override - public String toString(){ - return position + " / " + totalLength; - } - - public static byte[] read(File file, int length) throws IOException{ - FileChannelInputStream inputStream = new FileChannelInputStream(file,length, length); - inputStream.loadBuffer(); - inputStream.closeAuto(); - return inputStream.buffer; - } - - private static final int DEFAULT_BUFFER_SIZE = 1024 * 100; -} diff --git a/src/ARSCLib/com/reandroid/common/Frameworks.java b/src/ARSCLib/com/reandroid/common/Frameworks.java deleted file mode 100755 index f3fd9c24..00000000 --- a/src/ARSCLib/com/reandroid/common/Frameworks.java +++ /dev/null @@ -1,43 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.common; - -import com.reandroid.apk.AndroidFrameworks; -import com.reandroid.arsc.util.FrameworkTable; - -import java.io.IOException; -import java.io.InputStream; - -/**Use {@link AndroidFrameworks} */ -@Deprecated -public class Frameworks { - private static FrameworkTable android_table; - private static boolean load_once; - @Deprecated - public static FrameworkTable getAndroid(){ - if(android_table!=null || load_once){ - return android_table; - } - load_once=true; - FrameworkTable frameworkTable=null; - try { - frameworkTable = AndroidFrameworks.getLatest().getTableBlock(); - } catch (IOException e) { - } - android_table=frameworkTable; - return android_table; - } -} diff --git a/src/ARSCLib/com/reandroid/common/ReferenceResolver.java b/src/ARSCLib/com/reandroid/common/ReferenceResolver.java deleted file mode 100644 index a82a32bd..00000000 --- a/src/ARSCLib/com/reandroid/common/ReferenceResolver.java +++ /dev/null @@ -1,144 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.common; - -import com.reandroid.arsc.group.EntryGroup; -import com.reandroid.arsc.value.Entry; -import com.reandroid.arsc.value.ResConfig; -import com.reandroid.arsc.value.ResValue; -import com.reandroid.arsc.value.ValueType; - -import java.util.*; -import java.util.function.Predicate; - -public class ReferenceResolver{ - private final EntryStore entryStore; - private final List results; - private final Set resolvedIds; - private int limit; - public ReferenceResolver(EntryStore entryStore){ - this.entryStore = entryStore; - this.results = new ArrayList<>(); - this.resolvedIds = new HashSet<>(); - this.limit = -1; - } - public Entry resolve(int referenceId){ - return resolve(referenceId, null); - } - public synchronized Entry resolve(int referenceId, Predicate filter){ - resolveReference(referenceId, filter); - List results = new ArrayList<>(this.results); - reset(); - if(results.size() > 0){ - return results.get(0); - } - return null; - } - - public List resolveWithConfig(int referenceId, ResConfig resConfig){ - ConfigFilter configFilter = new ConfigFilter(resConfig); - List results = resolveAll(referenceId, configFilter); - results.sort(configFilter); - return results; - } - public List resolveAll(int referenceId){ - return resolveAll(referenceId, (Predicate)null); - } - public synchronized List resolveAll(int referenceId, Predicate filter){ - resolveReference(referenceId, filter); - List results = new ArrayList<>(this.results); - reset(); - return results; - } - private void resolveReference(int referenceId, Predicate filter){ - if(referenceId == 0 || isFinished() || this.resolvedIds.contains(referenceId)){ - return; - } - this.resolvedIds.add(referenceId); - List entryList = listNonNullEntries(referenceId); - List results = this.results; - for(Entry entry:entryList){ - if(isFinished()){ - return; - } - if(results.contains(entry)){ - continue; - } - if(entry.isComplex()){ - addResult(filter, entry); - continue; - } - ResValue resValue = entry.getResValue(); - if(resValue.getValueType() != ValueType.REFERENCE){ - addResult(filter, entry); - continue; - } - resolveReference(resValue.getData(), filter); - } - } - private void reset(){ - this.results.clear(); - this.resolvedIds.clear(); - this.limit = -1; - } - private boolean isFinished(){ - return this.limit >= this.results.size(); - } - private void addResult(Predicate filter, Entry entry){ - if(filter == null || filter.test(entry)){ - this.results.add(entry); - } - } - private List listNonNullEntries(int resourceId){ - List results = new ArrayList<>(); - EntryGroup entryGroup = this.entryStore.getEntryGroup(resourceId); - if(entryGroup==null){ - return results; - } - Iterator itr = entryGroup.iterator(true); - while (itr.hasNext()){ - results.add(itr.next()); - } - return results; - } - - public static class ConfigFilter implements Predicate, Comparator{ - private final ResConfig config; - public ConfigFilter(ResConfig config){ - this.config = config; - } - @Override - public boolean test(Entry entry) { - ResConfig resConfig = entry.getResConfig(); - if(resConfig == null){ - return false; - } - return resConfig.isEqualOrMoreSpecificThan(this.config); - } - @Override - public int compare(Entry entry1, Entry entry2) { - ResConfig config1 = entry1.getResConfig(); - ResConfig config2 = entry1.getResConfig(); - if (config.equals(config1)){ - return -1; - } - if(config.equals(config2)){ - return 1; - } - return 0; - } - } -} diff --git a/src/ARSCLib/com/reandroid/common/TableEntryStore.java b/src/ARSCLib/com/reandroid/common/TableEntryStore.java deleted file mode 100755 index 8404410f..00000000 --- a/src/ARSCLib/com/reandroid/common/TableEntryStore.java +++ /dev/null @@ -1,224 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.common; - -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.TableBlock; -import com.reandroid.arsc.group.EntryGroup; -import com.reandroid.arsc.util.FrameworkTable; -import com.reandroid.arsc.value.Entry; -import com.reandroid.arsc.value.StagedAliasEntry; - -import java.util.*; - -public class TableEntryStore implements EntryStore{ - private final Map> mLocalPackagesMap; - private final Map> mFrameworkPackagesMap; - public TableEntryStore(){ - this.mLocalPackagesMap = new HashMap<>(); - this.mFrameworkPackagesMap = new HashMap<>(); - } - - public String getEntryName(int resourceId){ - Entry entry = getEntry(resourceId); - if(entry ==null){ - return null; - } - return entry.getName(); - } - public Entry getEntry(int resourceId){ - if(resourceId==0){ - return null; - } - EntryGroup entryGroup=getEntryGroup(resourceId); - if(entryGroup==null){ - return null; - } - return entryGroup.pickOne(); - } - public void add(TableBlock tableBlock){ - if(tableBlock==null){ - return; - } - for(PackageBlock packageBlock:tableBlock.listPackages()){ - add(packageBlock); - } - } - public void add(PackageBlock packageBlock){ - if(packageBlock==null){ - return; - } - Set packageBlockSet; - if(packageBlock.getTableBlock() instanceof FrameworkTable){ - packageBlockSet = getOrCreateFrameworks(packageBlock.getId()); - }else { - packageBlockSet = getOrCreateLocal(packageBlock.getId()); - } - if(packageBlockSet.contains(packageBlock)){ - return; - } - packageBlockSet.add(packageBlock); - } - private Set getOrCreateLocal(int packageId){ - Integer id=packageId; - Set packageBlockSet = mLocalPackagesMap.get(id); - if(packageBlockSet==null){ - packageBlockSet=new HashSet<>(); - mLocalPackagesMap.put(id, packageBlockSet); - } - return packageBlockSet; - } - private Set getOrCreateFrameworks(int packageId){ - Integer id=packageId; - Set packageBlockSet = mFrameworkPackagesMap.get(id); - if(packageBlockSet==null){ - packageBlockSet=new HashSet<>(); - mFrameworkPackagesMap.put(id, packageBlockSet); - } - return packageBlockSet; - } - @Override - public List getEntryGroups(int resourceId) { - List results = searchEntryGroupsLocal(resourceId); - if(results.size()>0){ - return results; - } - int alias = searchIdAliasLocal(resourceId); - results = searchEntryGroupsLocal(alias); - if(results.size()>0){ - return results; - } - results = searchEntryGroupsFramework(resourceId); - if(results.size()>0){ - return results; - } - alias = searchIdAliasFramework(resourceId); - return searchEntryGroupsFramework(alias); - } - @Override - public EntryGroup getEntryGroup(int resourceId) { - EntryGroup entryGroup = searchEntryLocal(resourceId); - if(entryGroup==null){ - entryGroup = searchEntryLocal(searchIdAliasLocal(resourceId)); - } - if(entryGroup==null){ - entryGroup = searchEntryFramework(resourceId); - } - if(entryGroup==null){ - entryGroup = searchEntryFramework(searchIdAliasFramework(resourceId)); - } - return entryGroup; - } - @Override - public List getPackageBlocks(int packageId) { - List results=new ArrayList<>(); - packageId = 0xff & packageId; - Set packageBlockSet = mLocalPackagesMap.get(packageId); - if(packageBlockSet==null){ - packageBlockSet = mFrameworkPackagesMap.get(packageId); - } - if(packageBlockSet!=null){ - results.addAll(packageBlockSet); - } - return results; - } - private List searchEntryGroupsLocal(int resourceId) { - if(resourceId==0){ - return new ArrayList<>(); - } - List results=new ArrayList<>(); - int pkgId = (resourceId>>24)&0xff; - Set packageBlockSet = mLocalPackagesMap.get(pkgId); - if(packageBlockSet==null){ - return results; - } - for(PackageBlock packageBlock: packageBlockSet){ - EntryGroup group=packageBlock.getEntryGroup(resourceId); - if(group!=null){ - results.add(group); - } - } - return results; - } - private List searchEntryGroupsFramework(int resourceId) { - if(resourceId==0){ - return new ArrayList<>(); - } - List results=new ArrayList<>(); - int pkgId = (resourceId>>24)&0xff; - Set packageBlockSet = mFrameworkPackagesMap.get(pkgId); - if(packageBlockSet==null){ - return results; - } - for(PackageBlock packageBlock: packageBlockSet){ - EntryGroup group=packageBlock.getEntryGroup(resourceId); - if(group!=null){ - results.add(group); - } - } - return results; - } - private EntryGroup searchEntryLocal(int resourceId) { - int packageId = (resourceId>>24)&0xff; - Set packageBlockSet = mLocalPackagesMap.get(packageId); - if(packageBlockSet==null){ - return null; - } - for(PackageBlock packageBlock: packageBlockSet){ - EntryGroup group=packageBlock.getEntryGroup(resourceId); - if(group!=null && group.pickOne()!=null){ - return group; - } - } - return null; - } - private EntryGroup searchEntryFramework(int resourceId) { - int packageId = (resourceId>>24)&0xff; - Set packageBlockSet = mFrameworkPackagesMap.get(packageId); - if(packageBlockSet==null){ - return null; - } - for(PackageBlock packageBlock: packageBlockSet){ - EntryGroup group=packageBlock.getEntryGroup(resourceId); - if(group!=null && group.pickOne()!=null){ - return group; - } - } - return null; - } - private int searchIdAliasLocal(int resourceId) { - for(Set packageBlockSet : mLocalPackagesMap.values()){ - for(PackageBlock packageBlock:packageBlockSet){ - StagedAliasEntry stagedAliasEntry = packageBlock.searchByStagedResId(resourceId); - if(stagedAliasEntry!=null){ - return stagedAliasEntry.getFinalizedResId(); - } - } - } - return 0; - } - private int searchIdAliasFramework(int resourceId) { - for(Set packageBlockSet : mLocalPackagesMap.values()){ - for(PackageBlock packageBlock:packageBlockSet){ - StagedAliasEntry stagedAliasEntry = packageBlock.searchByStagedResId(resourceId); - if(stagedAliasEntry!=null){ - return stagedAliasEntry.getFinalizedResId(); - } - } - } - return 0; - } -} diff --git a/src/ARSCLib/com/reandroid/identifiers/Identifier.java b/src/ARSCLib/com/reandroid/identifiers/Identifier.java deleted file mode 100644 index 76cc4859..00000000 --- a/src/ARSCLib/com/reandroid/identifiers/Identifier.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.identifiers; - -import com.reandroid.arsc.util.HexUtil; - -public class Identifier implements Comparable{ - private int id; - private String name; - private Identifier mParent; - private Object mTag; - public Identifier(int id, String name){ - this.id = id; - this.name = name; - } - - public Object getTag() { - return mTag; - } - public void setTag(Object tag) { - this.mTag = tag; - } - - public int getId() { - return id; - } - public void setId(int id) { - this.id = id; - } - public String getName() { - return name; - } - public void setName(String name) { - this.name = name; - } - Identifier getParent() { - return mParent; - } - void setParent(Identifier parent) { - if(parent == this){ - return; - } - this.mParent = parent; - } - public String getHexId(){ - return HexUtil.toHex2((byte) getId()); - } - long getUniqueId(){ - return getId(); - } - - @Override - public int compareTo(Identifier identifier) { - return Long.compare(getUniqueId(), identifier.getUniqueId()); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - Identifier other = (Identifier) obj; - return this.getUniqueId() == other.getUniqueId(); - } - @Override - public int hashCode() { - return Long.hashCode(getUniqueId()); - } - @Override - public String toString(){ - return getName() + "(" + getHexId() + ")"; - } - - static final String XML_TAG_RESOURCES = "resources"; - static final String XML_TAG_PUBLIC = "public"; - - static final String XML_ATTRIBUTE_ID = "id"; - static final String XML_ATTRIBUTE_NAME = "name"; - static final String XML_ATTRIBUTE_PACKAGE = "package"; - static final String XML_ATTRIBUTE_TYPE = "type"; -} diff --git a/src/ARSCLib/com/reandroid/identifiers/IdentifierMap.java b/src/ARSCLib/com/reandroid/identifiers/IdentifierMap.java deleted file mode 100644 index 0dba7372..00000000 --- a/src/ARSCLib/com/reandroid/identifiers/IdentifierMap.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.identifiers; - -import java.util.*; - -class IdentifierMap extends Identifier - implements Comparator { - private final Object mLock = new Object(); - private final Map idMap; - private final Map nameMap; - - public IdentifierMap(int id, String name){ - super(id, name); - this.idMap = new HashMap<>(); - this.nameMap = new HashMap<>(); - } - public List listDuplicates(){ - List results = new ArrayList<>(getItems()); - Set uniques = new HashSet<>(); - for(CHILD item : getItems()){ - String name = item.getName(); - if(uniques.contains(name)){ - results.add(item); - }else { - uniques.add(name); - } - } - results.sort(this); - return results; - } - public boolean hasDuplicates(){ - Set uniques = new HashSet<>(); - for(CHILD item : getItems()){ - String name = item.getName(); - if(uniques.contains(name)){ - return true; - }else { - uniques.add(name); - } - } - return false; - } - public List listNames(){ - List results = new ArrayList<>(size()); - for(CHILD item : list()){ - results.add(item.getName()); - } - return results; - } - public List list(){ - List childList = new ArrayList<>(getItems()); - childList.sort(this); - return childList; - } - public Collection getItems(){ - synchronized (mLock){ - return this.idMap.values(); - } - } - public void clear(){ - synchronized (mLock){ - this.idMap.clear(); - this.nameMap.clear(); - } - } - public CHILD getByTag(Object tag){ - for(CHILD item : getItems()){ - if(Objects.equals(tag, item.getTag())){ - return item; - } - } - return null; - } - public int size(){ - synchronized (mLock){ - return this.idMap.size(); - } - } - public CHILD get(String childName){ - synchronized (mLock){ - return this.nameMap.get(childName); - } - } - public CHILD get(int childId){ - synchronized (mLock){ - return this.idMap.get(childId); - } - } - public void remove(CHILD entry){ - synchronized (mLock){ - if(entry == null){ - return; - } - this.idMap.remove(entry.getId()); - this.nameMap.remove(entry.getName()); - } - } - public CHILD add(CHILD child){ - synchronized (mLock){ - if(child == null){ - return null; - } - child.setParent(this); - Integer entryId = child.getId(); - CHILD exist = this.idMap.get(entryId); - if(exist != null){ - if(exist.getName() == null){ - exist.setName(child.getName()); - addNameMap(exist); - } - return exist; - } - this.idMap.put(entryId, child); - addNameMap(child); - return child; - } - } - private void addNameMap(CHILD child){ - String childName = child.getName(); - if(childName == null){ - return; - } - CHILD exist = this.nameMap.get(childName); - if(exist != null){ - return; - } - this.nameMap.put(childName, child); - } - @Override - public int compare(CHILD child1, CHILD child2) { - return child1.compareTo(child2); - } - @Override - public String toString(){ - return super.toString() + " entries = " + size(); - } -} diff --git a/src/ARSCLib/com/reandroid/identifiers/PackageIdentifier.java b/src/ARSCLib/com/reandroid/identifiers/PackageIdentifier.java deleted file mode 100644 index 8f4334c5..00000000 --- a/src/ARSCLib/com/reandroid/identifiers/PackageIdentifier.java +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.identifiers; - -import com.android.org.kxml2.io.KXmlParser; -import com.android.org.kxml2.io.KXmlSerializer; -import com.reandroid.arsc.array.EntryArray; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.TypeBlock; -import com.reandroid.arsc.decoder.ValueDecoder; -import com.reandroid.arsc.group.EntryGroup; -import com.reandroid.arsc.item.SpecString; -import com.reandroid.arsc.pool.SpecStringPool; -import com.reandroid.arsc.pool.TypeStringPool; -import com.reandroid.arsc.util.HexUtil; -import com.reandroid.arsc.value.Entry; -import com.reandroid.arsc.value.ValueHeader; -import com.reandroid.json.JSONObject; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; - -public class PackageIdentifier extends IdentifierMap{ - private PackageBlock mPackageBlock; - public PackageIdentifier(int id, String name){ - super(id, name); - } - public PackageIdentifier(){ - this(0, null); - } - - public void initialize(PackageBlock packageBlock){ - initialize(packageBlock, true); - } - public void initialize(PackageBlock packageBlock, boolean initialize_ids){ - packageBlock.setId(getId()); - String name = getName(); - if(name != null){ - packageBlock.setName(name); - } - initializeTypeName(packageBlock.getTypeStringPool()); - initializeSpecNames(packageBlock.getSpecStringPool()); - if(initialize_ids){ - initializeIds(packageBlock); - } - initializePackageJson(packageBlock); - setPackageBlock(packageBlock); - } - private void initializeTypeName(TypeStringPool typeStringPool){ - for(TypeIdentifier ti : list()){ - typeStringPool.getOrCreate(ti.getId(), ti.getName()); - } - } - private void initializeSpecNames(SpecStringPool specStringPool){ - List nameList = new ArrayList<>(getResourcesCount()); - for(TypeIdentifier ti : list()){ - nameList.addAll(ti.listNames()); - } - specStringPool.addStrings(nameList); - } - private void initializeIds(PackageBlock packageBlock){ - TypeIdentifier identifierID = get("id"); - if(identifierID == null){ - return; - } - TypeBlock typeBlock = packageBlock - .getOrCreateTypeBlock("", "id"); - EntryArray entryArray = typeBlock.getEntryArray(); - entryArray.ensureSize(identifierID.size()); - SpecStringPool specStringPool = packageBlock.getSpecStringPool(); - for(ResourceIdentifier ri : identifierID.list()){ - Entry entry = entryArray.getOrCreate((short) ri.getId()); - SpecString specString = specStringPool.getOrCreate(ri.getName()); - if(!entry.isNull() && !entry.isComplex()){ - entry.setSpecReference(specString); - continue; - } - entry.setValueAsBoolean(false); - entry.setSpecReference(specString); - setIdEntryVisibility(entry); - } - } - private void setIdEntryVisibility(Entry entry){ - ValueHeader valueHeader = entry.getHeader(); - valueHeader.setWeak(true); - valueHeader.setPublic(true); - } - private void initializePackageJson(PackageBlock packageBlock){ - File jsonFile = searchPackageJsonFromTag(); - if(jsonFile == null){ - return; - } - try { - JSONObject jsonObject = new JSONObject(new FileInputStream(jsonFile)); - packageBlock.fromJson(jsonObject); - if(getName() == null){ - setName(packageBlock.getName()); - } - } catch (FileNotFoundException ignored) { - } - } - // public.xml file is assumed to be stored via setTag during loadPublicXml(File) - private File searchPackageJsonFromTag(){ - Object tag = getTag(); - if(!(tag instanceof File)){ - return null; - } - File publicXml = (File) tag; - File dir = publicXml.getParentFile(); - //values - if(dir == null || !"values".equals(dir.getName())){ - return null; - } - dir = dir.getParentFile(); - //res - if(dir == null){ - return null; - } - dir = dir.getParentFile(); - if(dir == null){ - return null; - } - File json = new File(dir, "package.json"); - if(!json.isFile()){ - return null; - } - return json; - } - public List listDuplicateResources(){ - List results = new ArrayList<>(); - for(TypeIdentifier typeIdentifier : list()){ - results.addAll(typeIdentifier.listDuplicates()); - } - return results; - } - public boolean hasDuplicateResources(){ - for(TypeIdentifier typeIdentifier : getItems()){ - if(typeIdentifier.hasDuplicates()){ - return true; - } - } - return false; - } - public ResourceIdentifier getResourceIdentifier(int resourceId){ - TypeIdentifier typeIdentifier = get((resourceId >> 16) & 0xff); - if(typeIdentifier != null){ - return typeIdentifier.get(resourceId & 0xffff); - } - return null; - } - public ResourceIdentifier getResourceIdentifier(String referenceString){ - if(referenceString == null){ - return null; - } - Matcher matcher = ValueDecoder.PATTERN_REFERENCE.matcher(referenceString); - if(!matcher.find()){ - return null; - } - return getResourceIdentifier(matcher.group(4), matcher.group(5)); - } - public ResourceIdentifier getResourceIdentifier(String type, String name){ - TypeIdentifier typeIdentifier = get(type); - if(typeIdentifier != null){ - return typeIdentifier.get(name); - } - return null; - } - public int getResourcesCount(){ - int result = 0; - for(TypeIdentifier ti : getItems()){ - result += ti.size(); - } - return result; - } - - public void writePublicXml(File file) throws IOException { - File dir = file.getParentFile(); - if(dir != null && !dir.exists()){ - dir.mkdirs(); - } - FileOutputStream outputStream = new FileOutputStream(file); - writePublicXml(outputStream); - outputStream.close(); - } - public void writePublicXml(OutputStream outputStream) throws IOException { - XmlSerializer serializer = new KXmlSerializer(); - serializer.setOutput(outputStream, StandardCharsets.UTF_8.name()); - write(serializer); - } - public void write(XmlSerializer serializer) throws IOException { - serializer.startDocument("utf-8", null); - serializer.text("\n"); - serializer.startTag(null, XML_TAG_RESOURCES); - writePackageInfo(serializer); - writeTypes(serializer); - serializer.text("\n"); - serializer.endTag(null, XML_TAG_RESOURCES); - serializer.endDocument(); - closeSerializer(serializer); - } - private void writePackageInfo(XmlSerializer serializer) throws IOException { - String name = getName(); - if(name != null){ - serializer.attribute(null, XML_ATTRIBUTE_PACKAGE, name); - } - int id = getId(); - if(id != 0){ - serializer.attribute(null, XML_ATTRIBUTE_ID, HexUtil.toHex2((byte)id)); - } - } - private void writeTypes(XmlSerializer serializer) throws IOException { - for(TypeIdentifier typeIdentifier : list()){ - typeIdentifier.write(serializer); - } - } - public void load(PackageBlock packageBlock){ - setId(packageBlock.getId()); - setName(packageBlock.getName()); - for(EntryGroup entryGroup : packageBlock.listEntryGroup()){ - add(entryGroup); - } - setTag(packageBlock); - } - public void loadPublicXml(File file) throws IOException, XmlPullParserException { - FileInputStream fileInputStream = new FileInputStream(file); - loadPublicXml(fileInputStream); - fileInputStream.close(); - } - public void loadPublicXml(InputStream inputStream) throws IOException, XmlPullParserException { - XmlPullParser parser = new KXmlParser(); - parser.setInput(inputStream, StandardCharsets.UTF_8.name()); - loadPublicXml(parser); - } - public void loadPublicXml(Reader reader) throws IOException, XmlPullParserException { - XmlPullParser parser = new KXmlParser(); - parser.setInput(reader); - loadPublicXml(parser); - } - public void loadPublicXml(XmlPullParser parser) throws IOException, XmlPullParserException { - boolean resourcesFound = false; - int event; - while ((event = parser.nextToken()) != XmlPullParser.END_DOCUMENT){ - if(event != XmlPullParser.START_TAG){ - continue; - } - if(!resourcesFound){ - resourcesFound = parser.getName().equals(XML_TAG_RESOURCES); - if(!resourcesFound){ - throw new XmlPullParserException("Invalid public.xml, expecting first tag '" - + getName() + "' " + parser.getPositionDescription()); - } - loadPackageInfo(parser); - continue; - } - parseEntry(parser); - } - closeParser(parser); - } - private void closeParser(XmlPullParser parser){ - if(!(parser instanceof Closeable)){ - return; - } - Closeable closeable = (Closeable)parser; - try { - closeable.close(); - } catch (IOException ignored) { - } - } - private void closeSerializer(XmlSerializer serializer){ - if(!(serializer instanceof Closeable)){ - return; - } - Closeable closeable = (Closeable)serializer; - try { - closeable.close(); - } catch (IOException ignored) { - } - } - private void loadPackageInfo(XmlPullParser parser){ - int count = parser.getAttributeCount(); - for(int i = 0; i < count; i++){ - if(XML_ATTRIBUTE_PACKAGE.equals(parser.getAttributeName(i))){ - setName(parser.getAttributeValue(i)); - }else if(XML_ATTRIBUTE_ID.equals(parser.getAttributeName(i))){ - int id = Integer.decode(parser.getAttributeValue(i)); - if(id != 0){ - setId(id); - } - } - } - } - private void parseEntry(XmlPullParser parser) throws XmlPullParserException { - if(!XML_TAG_PUBLIC.equals(parser.getName())){ - throw new XmlPullParserException("Invalid tag, expecting '" - + XML_TAG_PUBLIC + "' " + parser.getPositionDescription()); - } - String resourceIdStr = null; - String typeName = null; - String entryName = null; - int count = parser.getAttributeCount(); - for(int i = 0; i < count; i++){ - String attrName = parser.getAttributeName(i); - String value = parser.getAttributeValue(i); - if(XML_ATTRIBUTE_ID.equals(attrName)){ - resourceIdStr = value; - }else if(XML_ATTRIBUTE_TYPE.equals(attrName)){ - typeName = value; - }else if(XML_ATTRIBUTE_NAME.equals(attrName)){ - entryName = value; - } - } - if(typeName == null){ - throw new XmlPullParserException("Missing attribute '" - + XML_ATTRIBUTE_TYPE + "' " + parser.getPositionDescription()); - } - if(resourceIdStr == null){ - throw new XmlPullParserException("Missing attribute '" - + XML_ATTRIBUTE_ID + "' " + parser.getPositionDescription()); - } - if(entryName == null){ - throw new XmlPullParserException("Missing attribute '" - + XML_ATTRIBUTE_NAME + "' " + parser.getPositionDescription()); - } - - int resourceId = (int) Long.decode(resourceIdStr).longValue(); - int packageId = (resourceId >> 24) & 0xff; - int typeId = (resourceId >> 16) & 0xff; - int entryId = resourceId & 0xffff; - - TypeIdentifier typeIdentifier = getOrCreate(typeId, typeName); - ResourceIdentifier entry = new ResourceIdentifier(entryId, entryName); - typeIdentifier.add(entry); - if(getId() == 0){ - setId(packageId); - } - } - - public PackageBlock getPackageBlock() { - return mPackageBlock; - } - public void setPackageBlock(PackageBlock packageBlock) { - this.mPackageBlock = packageBlock; - } - - public void add(EntryGroup entryGroup){ - add(entryGroup.pickOne()); - } - public void add(Entry entry){ - if(entry == null || entry.isNull()){ - return; - } - TypeBlock typeBlock = entry.getTypeBlock(); - TypeIdentifier typeIdentifier = getOrCreate(typeBlock.getId(), typeBlock.getTypeName()); - ResourceIdentifier resourceIdentifier = new ResourceIdentifier(entry.getId(), entry.getName()); - typeIdentifier.add(resourceIdentifier); - } - public TypeIdentifier getOrCreate(int typeId, String typeName){ - TypeIdentifier identifier = get(typeId); - if(identifier == null){ - return super.add(new TypeIdentifier(typeId, typeName)); - } - if(typeName !=null && identifier.getName() == null){ - identifier.setName(typeName); - identifier = super.add(identifier); - } - return identifier; - } - @Override - public void clear(){ - for(TypeIdentifier identifier : getItems()){ - identifier.clear(); - } - super.clear(); - } -} diff --git a/src/ARSCLib/com/reandroid/identifiers/ResourceIdentifier.java b/src/ARSCLib/com/reandroid/identifiers/ResourceIdentifier.java deleted file mode 100644 index 4bbb78a4..00000000 --- a/src/ARSCLib/com/reandroid/identifiers/ResourceIdentifier.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.identifiers; - -import com.reandroid.arsc.util.HexUtil; -import org.xmlpull.v1.XmlSerializer; - -import java.io.IOException; - -public class ResourceIdentifier extends Identifier{ - public ResourceIdentifier(int id, String name){ - super(id, name); - } - public ResourceIdentifier(){ - this(0, null); - } - - - public void write(XmlSerializer serializer) throws IOException { - serializer.text("\n "); - serializer.startTag(null, XML_TAG_PUBLIC); - serializer.attribute(null, XML_ATTRIBUTE_ID, getHexId()); - serializer.attribute(null, TypeIdentifier.XML_ATTRIBUTE_TYPE, getTypeName()); - serializer.attribute(null, XML_ATTRIBUTE_NAME, getName()); - serializer.endTag(null, XML_TAG_PUBLIC); - } - public TypeIdentifier getTypeIdentifier() { - return (TypeIdentifier) getParent(); - } - public void setTypeIdentifier(TypeIdentifier typeIdentifier) { - setParent(typeIdentifier); - } - public PackageIdentifier getPackageIdentifier(){ - TypeIdentifier typeIdentifier = getTypeIdentifier(); - if(typeIdentifier != null){ - return typeIdentifier.getPackageIdentifier(); - } - return null; - } - public String getTypeName(){ - TypeIdentifier typeIdentifier = getTypeIdentifier(); - if(typeIdentifier != null){ - return typeIdentifier.getName(); - } - return null; - } - public String getPackageName(){ - TypeIdentifier typeIdentifier = getTypeIdentifier(); - if(typeIdentifier != null){ - return typeIdentifier.getPackageName(); - } - return null; - } - public int getTypeId(){ - TypeIdentifier typeIdentifier = getTypeIdentifier(); - if(typeIdentifier != null){ - return typeIdentifier.getId(); - } - return 0; - } - public int getPackageId(){ - TypeIdentifier typeIdentifier = getTypeIdentifier(); - if(typeIdentifier != null){ - return typeIdentifier.getPackageId(); - } - return 0; - } - public int getResourceId(){ - int resourceId = getPackageId() << 24; - resourceId |= getTypeId() << 16; - resourceId |= getId(); - return resourceId; - } - @Override - public void setId(int id) { - super.setId(id & 0xffff); - } - @Override - public String getHexId(){ - return HexUtil.toHex8(getResourceId()); - } - public String getResourceName(){ - return getResourceName(null); - } - public String getResourceName(PackageIdentifier context){ - boolean appendPackage = context != getPackageIdentifier(); - return getResourceName('@', appendPackage, true); - } - public String getResourceName(char prefix, boolean appendPackage, boolean appendType){ - String packageName = appendPackage ? getPackageName() : null; - String typeName = appendType ? getTypeName() : null; - return buildResourceName(prefix, packageName, typeName, getName()); - } - @Override - long getUniqueId(){ - return 0x00000000ffffffffL & this.getResourceId(); - } - @Override - public void setTag(Object tag){ - TypeIdentifier ti = getTypeIdentifier(); - if(ti == null){ - super.setTag(tag); - return; - } - Object exist = getTag(); - if(exist != null){ - ti.removeTag(exist); - } - ti.addTag(tag, this); - super.setTag(tag); - } - @Override - public String toString(){ - return getHexId() + " " + getResourceName(); - } - - public static String buildResourceName(char prefix, String packageName, String type, String entry){ - StringBuilder builder = new StringBuilder(); - if(prefix != 0){ - builder.append(prefix); - } - if(packageName != null){ - builder.append(packageName); - builder.append(':'); - } - if(type != null){ - builder.append(type); - builder.append('/'); - } - builder.append(entry); - return builder.toString(); - } - -} diff --git a/src/ARSCLib/com/reandroid/identifiers/TableIdentifier.java b/src/ARSCLib/com/reandroid/identifiers/TableIdentifier.java deleted file mode 100644 index 97e3c2c0..00000000 --- a/src/ARSCLib/com/reandroid/identifiers/TableIdentifier.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.identifiers; - -import com.reandroid.arsc.array.PackageArray; -import com.reandroid.arsc.chunk.PackageBlock; -import com.reandroid.arsc.chunk.TableBlock; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.*; -import java.util.*; - -public class TableIdentifier{ - private final List mPackages; - private final Map mNameMap; - public TableIdentifier() { - this.mPackages = new ArrayList<>(); - this.mNameMap = new HashMap<>(); - } - - public void initialize(TableBlock tableBlock){ - initialize(tableBlock, true); - } - public void initialize(TableBlock tableBlock, boolean initialize_ids){ - PackageArray packageArray = tableBlock.getPackageArray(); - for(PackageIdentifier pi : getPackages()){ - PackageBlock packageBlock = packageArray.createNext(); - pi.initialize(packageBlock, initialize_ids); - } - } - - public void load(TableBlock tableBlock){ - for(PackageBlock packageBlock : tableBlock.listPackages()){ - load(packageBlock); - } - } - public PackageIdentifier load(PackageBlock packageBlock){ - PackageIdentifier packageIdentifier = new PackageIdentifier(); - packageIdentifier.load(packageBlock); - add(packageIdentifier); - mNameMap.put(packageIdentifier.getName(), packageIdentifier); - return packageIdentifier; - } - public void loadPublicXml(Collection pubXmlFileList) throws IOException { - for(File file : pubXmlFileList){ - try { - loadPublicXml(file); - } catch (XmlPullParserException ex) { - throw new IOException(ex); - } - } - } - public PackageIdentifier loadPublicXml(File file) throws IOException, XmlPullParserException { - PackageIdentifier packageIdentifier = new PackageIdentifier(); - packageIdentifier.loadPublicXml(file); - add(packageIdentifier); - packageIdentifier.setTag(file); - return packageIdentifier; - } - public PackageIdentifier loadPublicXml(InputStream inputStream) throws IOException, XmlPullParserException { - PackageIdentifier packageIdentifier = new PackageIdentifier(); - packageIdentifier.loadPublicXml(inputStream); - add(packageIdentifier); - return packageIdentifier; - } - public PackageIdentifier loadPublicXml(Reader reader) throws IOException, XmlPullParserException {PackageIdentifier packageIdentifier = new PackageIdentifier(); - packageIdentifier.loadPublicXml(reader); - add(packageIdentifier); - return packageIdentifier; - } - public PackageIdentifier loadPublicXml(XmlPullParser parser) throws IOException, XmlPullParserException { - PackageIdentifier packageIdentifier = new PackageIdentifier(); - packageIdentifier.loadPublicXml(parser); - add(packageIdentifier); - return packageIdentifier; - } - public ResourceIdentifier get(String packageName, String type, String name){ - PackageIdentifier packageIdentifier = mNameMap.get(packageName); - if(packageIdentifier != null){ - ResourceIdentifier ri = packageIdentifier.getResourceIdentifier(type, name); - if(ri != null){ - return ri; - } - } - for(PackageIdentifier pi : getPackages()){ - if(Objects.equals(packageName, pi.getName())){ - ResourceIdentifier ri = pi.getResourceIdentifier(type, name); - if(ri != null){ - return ri; - } - } - } - return null; - } - public ResourceIdentifier get(String type, String name){ - for(PackageIdentifier pi : getPackages()){ - ResourceIdentifier ri = pi.getResourceIdentifier(type, name); - if(ri != null){ - return ri; - } - } - return null; - } - public int countPackages(){ - return getPackages().size(); - } - public void add(PackageIdentifier packageIdentifier){ - if(packageIdentifier != null){ - mPackages.add(packageIdentifier); - } - } - public List getPackages() { - return mPackages; - } - public PackageIdentifier getByTag(Object tag){ - for(PackageIdentifier pi : getPackages()){ - if(Objects.equals(tag, pi.getTag())){ - return pi; - } - } - return null; - } - public PackageIdentifier getByPackage(PackageBlock packageBlock){ - for(PackageIdentifier pi : getPackages()){ - if(packageBlock == pi.getPackageBlock()){ - return pi; - } - } - return null; - } - public void clear(){ - for(PackageIdentifier identifier : getPackages()){ - identifier.clear(); - } - mPackages.clear(); - mNameMap.clear(); - } - - @Override - public String toString(){ - return getClass().getSimpleName() - + ": packages = " - + countPackages(); - } -} diff --git a/src/ARSCLib/com/reandroid/identifiers/TypeIdentifier.java b/src/ARSCLib/com/reandroid/identifiers/TypeIdentifier.java deleted file mode 100644 index b51a1555..00000000 --- a/src/ARSCLib/com/reandroid/identifiers/TypeIdentifier.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.identifiers; - -import org.xmlpull.v1.XmlSerializer; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -public class TypeIdentifier extends IdentifierMap { - private final Map tagMap; - public TypeIdentifier(int id, String name){ - super(id, name); - this.tagMap = new HashMap<>(); - } - public TypeIdentifier(){ - this(0, null); - } - - - public void write(XmlSerializer serializer) throws IOException { - for(ResourceIdentifier resourceIdentifier : list()){ - resourceIdentifier.write(serializer); - } - } - public PackageIdentifier getPackageIdentifier() { - return (PackageIdentifier) getParent(); - } - public void setPackageIdentifier(PackageIdentifier packageIdentifier) { - setParent(packageIdentifier); - } - public String getPackageName(){ - PackageIdentifier packageIdentifier = getPackageIdentifier(); - if(packageIdentifier != null){ - return packageIdentifier.getName(); - } - return null; - } - public int getPackageId(){ - PackageIdentifier packageIdentifier = getPackageIdentifier(); - if(packageIdentifier != null){ - return packageIdentifier.getId(); - } - return 0; - } - - @Override - public ResourceIdentifier getByTag(Object tag){ - ResourceIdentifier ri = this.tagMap.get(tag); - if(ri != null){ - return ri; - } - return super.getByTag(tag); - } - @Override - public void clear(){ - tagMap.clear(); - super.clear(); - } - @Override - long getUniqueId(){ - int uniqueId = getPackageId() << 8; - uniqueId |= getId(); - return uniqueId; - } - void addTag(Object tag, ResourceIdentifier ri){ - if(tag != null){ - tagMap.put(tag, ri); - } - } - void removeTag(Object tag){ - tagMap.remove(tag); - } - -} diff --git a/src/ARSCLib/com/reandroid/json/CDL.java b/src/ARSCLib/com/reandroid/json/CDL.java deleted file mode 100644 index ae47086d..00000000 --- a/src/ARSCLib/com/reandroid/json/CDL.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -public class CDL { - - private static String getValue(JSONTokener x) throws JSONException { - char c; - char q; - StringBuilder sb; - do { - c = x.next(); - } while (c == ' ' || c == '\t'); - switch (c) { - case 0: - return null; - case '"': - case '\'': - q = c; - sb = new StringBuilder(); - for (;;) { - c = x.next(); - if (c == q) { - //Handle escaped double-quote - char nextC = x.next(); - if(nextC != '\"') { - // if our quote was the end of the file, don't step - if(nextC > 0) { - x.back(); - } - break; - } - } - if (c == 0 || c == '\n' || c == '\r') { - throw x.syntaxError("Missing close quote '" + q + "'."); - } - sb.append(c); - } - return sb.toString(); - case ',': - x.back(); - return ""; - default: - x.back(); - return x.nextTo(','); - } - } - - public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException { - JSONArray ja = new JSONArray(); - for (;;) { - String value = getValue(x); - char c = x.next(); - if (value == null || - (ja.length() == 0 && value.length() == 0 && c != ',')) { - return null; - } - ja.put(value); - for (;;) { - if (c == ',') { - break; - } - if (c != ' ') { - if (c == '\n' || c == '\r' || c == 0) { - return ja; - } - throw x.syntaxError("Bad character '" + c + "' (" + - (int)c + ")."); - } - c = x.next(); - } - } - } - - public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x) - throws JSONException { - JSONArray ja = rowToJSONArray(x); - return ja != null ? ja.toJSONObject(names) : null; - } - - public static String rowToString(JSONArray ja) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < ja.length(); i += 1) { - if (i > 0) { - sb.append(','); - } - Object object = ja.opt(i); - if (object != null) { - String string = object.toString(); - if (string.length() > 0 && (string.indexOf(',') >= 0 || - string.indexOf('\n') >= 0 || string.indexOf('\r') >= 0 || - string.indexOf(0) >= 0 || string.charAt(0) == '"')) { - sb.append('"'); - int length = string.length(); - for (int j = 0; j < length; j += 1) { - char c = string.charAt(j); - if (c >= ' ' && c != '"') { - sb.append(c); - } - } - sb.append('"'); - } else { - sb.append(string); - } - } - } - sb.append('\n'); - return sb.toString(); - } - - public static JSONArray toJSONArray(String string) throws JSONException { - return toJSONArray(new JSONTokener(string)); - } - - public static JSONArray toJSONArray(JSONTokener x) throws JSONException { - return toJSONArray(rowToJSONArray(x), x); - } - - public static JSONArray toJSONArray(JSONArray names, String string) - throws JSONException { - return toJSONArray(names, new JSONTokener(string)); - } - - public static JSONArray toJSONArray(JSONArray names, JSONTokener x) - throws JSONException { - if (names == null || names.length() == 0) { - return null; - } - JSONArray ja = new JSONArray(); - for (;;) { - JSONObject jo = rowToJSONObject(names, x); - if (jo == null) { - break; - } - ja.put(jo); - } - if (ja.length() == 0) { - return null; - } - return ja; - } - public static String toString(JSONArray ja) throws JSONException { - JSONObject jo = ja.optJSONObject(0); - if (jo != null) { - JSONArray names = jo.names(); - if (names != null) { - return rowToString(names) + toString(names, ja); - } - } - return null; - } - - public static String toString(JSONArray names, JSONArray ja) - throws JSONException { - if (names == null || names.length() == 0) { - return null; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < ja.length(); i += 1) { - JSONObject jo = ja.optJSONObject(i); - if (jo != null) { - sb.append(rowToString(jo.toJSONArray(names))); - } - } - return sb.toString(); - } -} diff --git a/src/ARSCLib/com/reandroid/json/Cookie.java b/src/ARSCLib/com/reandroid/json/Cookie.java deleted file mode 100644 index 1443fac2..00000000 --- a/src/ARSCLib/com/reandroid/json/Cookie.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -import java.util.Locale; - -public class Cookie { - - public static String escape(String string) { - char c; - String s = string.trim(); - int length = s.length(); - StringBuilder sb = new StringBuilder(length); - for (int i = 0; i < length; i += 1) { - c = s.charAt(i); - if (c < ' ' || c == '+' || c == '%' || c == '=' || c == ';') { - sb.append('%'); - sb.append(Character.forDigit((char)((c >>> 4) & 0x0f), 16)); - sb.append(Character.forDigit((char)(c & 0x0f), 16)); - } else { - sb.append(c); - } - } - return sb.toString(); - } - public static JSONObject toJSONObject(String string) { - final JSONObject jo = new JSONObject(); - String name; - Object value; - - - JSONTokener x = new JSONTokener(string); - - name = unescape(x.nextTo('=').trim()); - //per RFC6265, if the name is blank, the cookie should be ignored. - if("".equals(name)) { - throw new JSONException("Cookies must have a 'name'"); - } - jo.put("name", name); - // per RFC6265, if there is no '=', the cookie should be ignored. - // the 'next' call here throws an exception if the '=' is not found. - x.next('='); - jo.put("value", unescape(x.nextTo(';')).trim()); - // discard the ';' - x.next(); - // parse the remaining cookie attributes - while (x.more()) { - name = unescape(x.nextTo("=;")).trim().toLowerCase(Locale.ROOT); - // don't allow a cookies attributes to overwrite it's name or value. - if("name".equalsIgnoreCase(name)) { - throw new JSONException("Illegal attribute name: 'name'"); - } - if("value".equalsIgnoreCase(name)) { - throw new JSONException("Illegal attribute name: 'value'"); - } - // check to see if it's a flag property - if (x.next() != '=') { - value = Boolean.TRUE; - } else { - value = unescape(x.nextTo(';')).trim(); - x.next(); - } - // only store non-blank attributes - if(!"".equals(name) && !"".equals(value)) { - jo.put(name, value); - } - } - return jo; - } - public static String toString(JSONObject jo) throws JSONException { - StringBuilder sb = new StringBuilder(); - - String name = null; - Object value = null; - for(String key : jo.keySet()){ - if("name".equalsIgnoreCase(key)) { - name = jo.getString(key).trim(); - } - if("value".equalsIgnoreCase(key)) { - value=jo.getString(key).trim(); - } - if(name != null && value != null) { - break; - } - } - - if(name == null || "".equals(name.trim())) { - throw new JSONException("Cookie does not have a name"); - } - if(value == null) { - value = ""; - } - - sb.append(escape(name)); - sb.append("="); - sb.append(escape((String)value)); - - for(String key : jo.keySet()){ - if("name".equalsIgnoreCase(key) - || "value".equalsIgnoreCase(key)) { - // already processed above - continue; - } - value = jo.opt(key); - if(value instanceof Boolean) { - if(Boolean.TRUE.equals(value)) { - sb.append(';').append(escape(key)); - } - // don't emit false values - } else { - sb.append(';') - .append(escape(key)) - .append('=') - .append(escape(value.toString())); - } - } - - return sb.toString(); - } - - public static String unescape(String string) { - int length = string.length(); - StringBuilder sb = new StringBuilder(length); - for (int i = 0; i < length; ++i) { - char c = string.charAt(i); - if (c == '+') { - c = ' '; - } else if (c == '%' && i + 2 < length) { - int d = JSONTokener.dehexchar(string.charAt(i + 1)); - int e = JSONTokener.dehexchar(string.charAt(i + 2)); - if (d >= 0 && e >= 0) { - c = (char)(d * 16 + e); - i += 2; - } - } - sb.append(c); - } - return sb.toString(); - } -} diff --git a/src/ARSCLib/com/reandroid/json/CookieList.java b/src/ARSCLib/com/reandroid/json/CookieList.java deleted file mode 100644 index 52a63399..00000000 --- a/src/ARSCLib/com/reandroid/json/CookieList.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -public class CookieList { - - public static JSONObject toJSONObject(String string) throws JSONException { - JSONObject jo = new JSONObject(); - JSONTokener x = new JSONTokener(string); - while (x.more()) { - String name = Cookie.unescape(x.nextTo('=')); - x.next('='); - jo.put(name, Cookie.unescape(x.nextTo(';'))); - x.next(); - } - return jo; - } - - public static String toString(JSONObject jo) throws JSONException { - boolean b = false; - final StringBuilder sb = new StringBuilder(); - // Don't use the new entrySet API to maintain Android support - for (final String key : jo.keySet()) { - final Object value = jo.opt(key); - if (!JSONObject.NULL.equals(value)) { - if (b) { - sb.append(';'); - } - sb.append(Cookie.escape(key)); - sb.append("="); - sb.append(Cookie.escape(value.toString())); - b = true; - } - } - return sb.toString(); - } -} diff --git a/src/ARSCLib/com/reandroid/json/HTTP.java b/src/ARSCLib/com/reandroid/json/HTTP.java deleted file mode 100644 index 10f5e42c..00000000 --- a/src/ARSCLib/com/reandroid/json/HTTP.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -import java.util.Locale; - -public class HTTP { - - /** Carriage return/line feed. */ - public static final String CRLF = "\r\n"; - - public static JSONObject toJSONObject(String string) throws JSONException { - JSONObject jo = new JSONObject(); - HTTPTokener x = new HTTPTokener(string); - String token; - - token = x.nextToken(); - if (token.toUpperCase(Locale.ROOT).startsWith("HTTP")) { - -// Response - - jo.put("HTTP-Version", token); - jo.put("Status-Code", x.nextToken()); - jo.put("Reason-Phrase", x.nextTo('\0')); - x.next(); - - } else { - -// Request - - jo.put("Method", token); - jo.put("Request-URI", x.nextToken()); - jo.put("HTTP-Version", x.nextToken()); - } - -// Fields - - while (x.more()) { - String name = x.nextTo(':'); - x.next(':'); - jo.put(name, x.nextTo('\0')); - x.next(); - } - return jo; - } - - - public static String toString(JSONObject jo) throws JSONException { - StringBuilder sb = new StringBuilder(); - if (jo.has("Status-Code") && jo.has("Reason-Phrase")) { - sb.append(jo.getString("HTTP-Version")); - sb.append(' '); - sb.append(jo.getString("Status-Code")); - sb.append(' '); - sb.append(jo.getString("Reason-Phrase")); - } else if (jo.has("Method") && jo.has("Request-URI")) { - sb.append(jo.getString("Method")); - sb.append(' '); - sb.append('"'); - sb.append(jo.getString("Request-URI")); - sb.append('"'); - sb.append(' '); - sb.append(jo.getString("HTTP-Version")); - } else { - throw new JSONException("Not enough material for an HTTP header."); - } - sb.append(CRLF); - // Don't use the new entrySet API to maintain Android support - for (final String key : jo.keySet()) { - String value = jo.optString(key); - if (!"HTTP-Version".equals(key) && !"Status-Code".equals(key) && - !"Reason-Phrase".equals(key) && !"Method".equals(key) && - !"Request-URI".equals(key) && !JSONObject.NULL.equals(value)) { - sb.append(key); - sb.append(": "); - sb.append(jo.optString(key)); - sb.append(CRLF); - } - } - sb.append(CRLF); - return sb.toString(); - } -} \ No newline at end of file diff --git a/src/ARSCLib/com/reandroid/json/HTTPTokener.java b/src/ARSCLib/com/reandroid/json/HTTPTokener.java deleted file mode 100644 index 67f559d0..00000000 --- a/src/ARSCLib/com/reandroid/json/HTTPTokener.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -public class HTTPTokener extends JSONTokener { - - public HTTPTokener(String string) { - super(string); - } - public String nextToken() throws JSONException { - char c; - char q; - StringBuilder sb = new StringBuilder(); - do { - c = next(); - } while (Character.isWhitespace(c)); - if (c == '"' || c == '\'') { - q = c; - for (;;) { - c = next(); - if (c < ' ') { - throw syntaxError("Unterminated string."); - } - if (c == q) { - return sb.toString(); - } - sb.append(c); - } - } - for (;;) { - if (c == 0 || Character.isWhitespace(c)) { - return sb.toString(); - } - sb.append(c); - c = next(); - } - } -} diff --git a/src/ARSCLib/com/reandroid/json/JSONArray.java b/src/ARSCLib/com/reandroid/json/JSONArray.java deleted file mode 100644 index b51848a0..00000000 --- a/src/ARSCLib/com/reandroid/json/JSONArray.java +++ /dev/null @@ -1,777 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -import com.reandroid.common.FileChannelInputStream; - -import java.io.*; -import java.lang.reflect.Array; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -public class JSONArray extends JSONItem implements Iterable { - - private final ArrayList myArrayList; - - public JSONArray() { - this.myArrayList = new ArrayList(); - } - - public JSONArray(JSONTokener x) throws JSONException { - this(); - if (x.nextClean() != '[') { - throw x.syntaxError("A JSONArray text must start with '['"); - } - - char nextChar = x.nextClean(); - if (nextChar == 0) { - // array is unclosed. No ']' found, instead EOF - throw x.syntaxError("Expected a ',' or ']'"); - } - if (nextChar != ']') { - x.back(); - for (;;) { - if (x.nextClean() == ',') { - x.back(); - this.myArrayList.add(JSONObject.NULL); - } else { - x.back(); - this.myArrayList.add(x.nextValue()); - } - switch (x.nextClean()) { - case 0: - // array is unclosed. No ']' found, instead EOF - throw x.syntaxError("Expected a ',' or ']'"); - case ',': - nextChar = x.nextClean(); - if (nextChar == 0) { - // array is unclosed. No ']' found, instead EOF - throw x.syntaxError("Expected a ',' or ']'"); - } - if (nextChar == ']') { - return; - } - x.back(); - break; - case ']': - return; - default: - throw x.syntaxError("Expected a ',' or ']'"); - } - } - } - } - - public JSONArray(String source) throws JSONException { - this(new JSONTokener(source)); - } - - public JSONArray(Collection collection) { - if (collection == null) { - this.myArrayList = new ArrayList(); - } else { - this.myArrayList = new ArrayList(collection.size()); - this.addAll(collection, true); - } - } - - public JSONArray(Iterable iter) { - this(); - if (iter == null) { - return; - } - this.addAll(iter, true); - } - - public JSONArray(JSONArray array) { - if (array == null) { - this.myArrayList = new ArrayList(); - } else { - // shallow copy directly the internal array lists as any wrapping - // should have been done already in the original JSONArray - this.myArrayList = new ArrayList(array.myArrayList); - } - } - - JSONArray(Object array) throws JSONException { - this(); - if (!array.getClass().isArray()) { - throw new JSONException( - "JSONArray initial value should be a string or collection or array."); - } - this.addAll(array, true); - } - - public JSONArray(int initialCapacity) throws JSONException { - if (initialCapacity < 0) { - throw new JSONException( - "JSONArray initial capacity cannot be negative."); - } - this.myArrayList = new ArrayList(initialCapacity); - } - - public JSONArray(File file) throws IOException { - this(new FileChannelInputStream(file)); - } - public JSONArray(Reader reader){ - this(new JSONTokener(reader)); - } - public JSONArray(InputStream inputStream) throws JSONException { - this(new JSONTokener(inputStream)); - try { - inputStream.close(); - } catch (IOException ignored) { - } - } - public ArrayList getArrayList(){ - return myArrayList; - } - - @Override - public Iterator iterator() { - return this.myArrayList.iterator(); - } - - public Object get(int index) throws JSONException { - Object object = this.opt(index); - if (object == null) { - throw new JSONException("JSONArray[" + index + "] not found."); - } - return object; - } - - public boolean getBoolean(int index) throws JSONException { - Object object = this.get(index); - if (object.equals(Boolean.FALSE) - || (object instanceof String && ((String) object) - .equalsIgnoreCase("false"))) { - return false; - } else if (object.equals(Boolean.TRUE) - || (object instanceof String && ((String) object) - .equalsIgnoreCase("true"))) { - return true; - } - throw wrongValueFormatException(index, "boolean", null); - } - - public double getDouble(int index) throws JSONException { - final Object object = this.get(index); - if(object instanceof Number) { - return ((Number)object).doubleValue(); - } - try { - return Double.parseDouble(object.toString()); - } catch (Exception e) { - throw wrongValueFormatException(index, "double", e); - } - } - - public float getFloat(int index) throws JSONException { - final Object object = this.get(index); - if(object instanceof Number) { - return ((Float)object).floatValue(); - } - try { - return Float.parseFloat(object.toString()); - } catch (Exception e) { - throw wrongValueFormatException(index, "float", e); - } - } - - public Number getNumber(int index) throws JSONException { - Object object = this.get(index); - try { - if (object instanceof Number) { - return (Number)object; - } - return JSONObject.stringToNumber(object.toString()); - } catch (Exception e) { - throw wrongValueFormatException(index, "number", e); - } - } - - public > E getEnum(Class clazz, int index) throws JSONException { - E val = optEnum(clazz, index); - if(val==null) { - // JSONException should really take a throwable argument. - // If it did, I would re-implement this with the Enum.valueOf - // method and place any thrown exception in the JSONException - throw wrongValueFormatException(index, "enum of type " - + JSONObject.quote(clazz.getSimpleName()), null); - } - return val; - } - - public BigDecimal getBigDecimal (int index) throws JSONException { - Object object = this.get(index); - BigDecimal val = JSONObject.objectToBigDecimal(object, null); - if(val == null) { - throw wrongValueFormatException(index, "BigDecimal", object, null); - } - return val; - } - - public BigInteger getBigInteger (int index) throws JSONException { - Object object = this.get(index); - BigInteger val = JSONObject.objectToBigInteger(object, null); - if(val == null) { - throw wrongValueFormatException(index, "BigInteger", object, null); - } - return val; - } - - public int getInt(int index) throws JSONException { - final Object object = this.get(index); - if(object instanceof Number) { - return ((Number)object).intValue(); - } - try { - return Integer.parseInt(object.toString()); - } catch (Exception e) { - throw wrongValueFormatException(index, "int", e); - } - } - - public JSONArray getJSONArray(int index) throws JSONException { - Object object = this.get(index); - if (object instanceof JSONArray) { - return (JSONArray) object; - } - throw wrongValueFormatException(index, "JSONArray", null); - } - - public JSONObject getJSONObject(int index) throws JSONException { - Object object = this.get(index); - if (object instanceof JSONObject) { - return (JSONObject) object; - } - throw wrongValueFormatException(index, "JSONObject", null); - } - - public long getLong(int index) throws JSONException { - final Object object = this.get(index); - if(object instanceof Number) { - return ((Number)object).longValue(); - } - try { - return Long.parseLong(object.toString()); - } catch (Exception e) { - throw wrongValueFormatException(index, "long", e); - } - } - - public String getString(int index) throws JSONException { - Object object = this.get(index); - if (object instanceof String) { - return (String) object; - } - throw wrongValueFormatException(index, "String", null); - } - - public boolean isNull(int index) { - return JSONObject.NULL.equals(this.opt(index)); - } - - public String join(String separator) throws JSONException { - int len = this.length(); - if (len == 0) { - return ""; - } - - StringBuilder sb = new StringBuilder( - JSONObject.valueToString(this.myArrayList.get(0))); - - for (int i = 1; i < len; i++) { - sb.append(separator) - .append(JSONObject.valueToString(this.myArrayList.get(i))); - } - return sb.toString(); - } - - public int length() { - return this.myArrayList.size(); - } - - public Object opt(int index) { - return (index < 0 || index >= this.length()) ? null : this.myArrayList - .get(index); - } - - public boolean optBoolean(int index) { - return this.optBoolean(index, false); - } - - public boolean optBoolean(int index, boolean defaultValue) { - try { - return this.getBoolean(index); - } catch (Exception e) { - return defaultValue; - } - } - - public double optDouble(int index) { - return this.optDouble(index, Double.NaN); - } - - public double optDouble(int index, double defaultValue) { - final Number val = this.optNumber(index, null); - if (val == null) { - return defaultValue; - } - final double doubleValue = val.doubleValue(); - // if (Double.isNaN(doubleValue) || Double.isInfinite(doubleValue)) { - // return defaultValue; - // } - return doubleValue; - } - - public float optFloat(int index) { - return this.optFloat(index, Float.NaN); - } - - public float optFloat(int index, float defaultValue) { - final Number val = this.optNumber(index, null); - if (val == null) { - return defaultValue; - } - final float floatValue = val.floatValue(); - // if (Float.isNaN(floatValue) || Float.isInfinite(floatValue)) { - // return floatValue; - // } - return floatValue; - } - - public int optInt(int index) { - return this.optInt(index, 0); - } - - public int optInt(int index, int defaultValue) { - final Number val = this.optNumber(index, null); - if (val == null) { - return defaultValue; - } - return val.intValue(); - } - - public > E optEnum(Class clazz, int index) { - return this.optEnum(clazz, index, null); - } - - public > E optEnum(Class clazz, int index, E defaultValue) { - try { - Object val = this.opt(index); - if (JSONObject.NULL.equals(val)) { - return defaultValue; - } - if (clazz.isAssignableFrom(val.getClass())) { - // we just checked it! - @SuppressWarnings("unchecked") - E myE = (E) val; - return myE; - } - return Enum.valueOf(clazz, val.toString()); - } catch (IllegalArgumentException e) { - return defaultValue; - } catch (NullPointerException e) { - return defaultValue; - } - } - - public BigInteger optBigInteger(int index, BigInteger defaultValue) { - Object val = this.opt(index); - return JSONObject.objectToBigInteger(val, defaultValue); - } - - public BigDecimal optBigDecimal(int index, BigDecimal defaultValue) { - Object val = this.opt(index); - return JSONObject.objectToBigDecimal(val, defaultValue); - } - - public JSONArray optJSONArray(int index) { - Object o = this.opt(index); - return o instanceof JSONArray ? (JSONArray) o : null; - } - - public JSONObject optJSONObject(int index) { - Object o = this.opt(index); - return o instanceof JSONObject ? (JSONObject) o : null; - } - - public long optLong(int index) { - return this.optLong(index, 0); - } - - public long optLong(int index, long defaultValue) { - final Number val = this.optNumber(index, null); - if (val == null) { - return defaultValue; - } - return val.longValue(); - } - - public Number optNumber(int index) { - return this.optNumber(index, null); - } - - public Number optNumber(int index, Number defaultValue) { - Object val = this.opt(index); - if (JSONObject.NULL.equals(val)) { - return defaultValue; - } - if (val instanceof Number){ - return (Number) val; - } - - if (val instanceof String) { - try { - return JSONObject.stringToNumber((String) val); - } catch (Exception e) { - return defaultValue; - } - } - return defaultValue; - } - - public String optString(int index) { - return this.optString(index, ""); - } - - public String optString(int index, String defaultValue) { - Object object = this.opt(index); - return JSONObject.NULL.equals(object) ? defaultValue : object - .toString(); - } - - public JSONArray put(boolean value) { - return this.put(value ? Boolean.TRUE : Boolean.FALSE); - } - - public JSONArray put(Collection value) { - return this.put(new JSONArray(value)); - } - - public JSONArray put(double value) throws JSONException { - return this.put(Double.valueOf(value)); - } - - - public JSONArray put(float value) throws JSONException { - return this.put(Float.valueOf(value)); - } - - public JSONArray put(int value) { - return this.put(Integer.valueOf(value)); - } - - public JSONArray put(long value) { - return this.put(Long.valueOf(value)); - } - - public JSONArray put(Map value) { - return this.put(new JSONObject(value)); - } - - public JSONArray put(Object value) { - JSONObject.testValidity(value); - this.myArrayList.add(value); - return this; - } - - public JSONArray put(int index, boolean value) throws JSONException { - return this.put(index, value ? Boolean.TRUE : Boolean.FALSE); - } - - public JSONArray put(int index, Collection value) throws JSONException { - return this.put(index, new JSONArray(value)); - } - - public JSONArray put(int index, double value) throws JSONException { - return this.put(index, Double.valueOf(value)); - } - - public JSONArray put(int index, float value) throws JSONException { - return this.put(index, Float.valueOf(value)); - } - - public JSONArray put(int index, int value) throws JSONException { - return this.put(index, Integer.valueOf(value)); - } - - public JSONArray put(int index, long value) throws JSONException { - return this.put(index, Long.valueOf(value)); - } - - public JSONArray put(int index, Map value) throws JSONException { - this.put(index, new JSONObject(value)); - return this; - } - - public JSONArray put(int index, Object value) throws JSONException { - if (index < 0) { - throw new JSONException("JSONArray[" + index + "] not found."); - } - if (index < this.length()) { - JSONObject.testValidity(value); - this.myArrayList.set(index, value); - return this; - } - if(index == this.length()){ - // simple append - return this.put(value); - } - // if we are inserting past the length, we want to grow the array all at once - // instead of incrementally. - this.myArrayList.ensureCapacity(index + 1); - while (index != this.length()) { - // we don't need to test validity of NULL objects - this.myArrayList.add(JSONObject.NULL); - } - return this.put(value); - } - - public JSONArray putAll(Collection collection) { - this.addAll(collection, false); - return this; - } - - - public JSONArray putAll(Iterable iter) { - this.addAll(iter, false); - return this; - } - - public JSONArray putAll(JSONArray array) { - // directly copy the elements from the source array to this one - // as all wrapping should have been done already in the source. - this.myArrayList.addAll(array.myArrayList); - return this; - } - - public JSONArray putAll(Object array) throws JSONException { - this.addAll(array, false); - return this; - } - - - public Object query(String jsonPointer) { - return query(new JSONPointer(jsonPointer)); - } - - - public Object query(JSONPointer jsonPointer) { - return jsonPointer.queryFrom(this); - } - - - public Object optQuery(String jsonPointer) { - return optQuery(new JSONPointer(jsonPointer)); - } - - - public Object optQuery(JSONPointer jsonPointer) { - try { - return jsonPointer.queryFrom(this); - } catch (JSONPointerException e) { - return null; - } - } - - public Object remove(int index) { - return index >= 0 && index < this.length() - ? this.myArrayList.remove(index) - : null; - } - - public boolean similar(Object other) { - if (!(other instanceof JSONArray)) { - return false; - } - int len = this.length(); - if (len != ((JSONArray)other).length()) { - return false; - } - for (int i = 0; i < len; i += 1) { - Object valueThis = this.myArrayList.get(i); - Object valueOther = ((JSONArray)other).myArrayList.get(i); - if(valueThis == valueOther) { - continue; - } - if(valueThis == null) { - return false; - } - if (valueThis instanceof JSONObject) { - if (!((JSONObject)valueThis).similar(valueOther)) { - return false; - } - } else if (valueThis instanceof JSONArray) { - if (!((JSONArray)valueThis).similar(valueOther)) { - return false; - } - } else if (!valueThis.equals(valueOther)) { - return false; - } - } - return true; - } - - public JSONObject toJSONObject(JSONArray names) throws JSONException { - if (names == null || names.isEmpty() || this.isEmpty()) { - return null; - } - JSONObject jo = new JSONObject(names.length()); - for (int i = 0; i < names.length(); i += 1) { - jo.put(names.getString(i), this.opt(i)); - } - return jo; - } - - @Override - public Writer write(Writer writer, int indentFactor, int indent) - throws JSONException { - try { - boolean needsComma = false; - int length = this.length(); - writer.write('['); - - if (length == 1) { - try { - JSONObject.writeValue(writer, this.myArrayList.get(0), - indentFactor, indent); - } catch (Exception e) { - throw new JSONException("Unable to write JSONArray value at index: 0", e); - } - } else if (length != 0) { - final int newIndent = indent + indentFactor; - - for (int i = 0; i < length; i += 1) { - if (needsComma) { - writer.write(','); - } - if (indentFactor > 0) { - writer.write('\n'); - } - JSONObject.indent(writer, newIndent); - try { - JSONObject.writeValue(writer, this.myArrayList.get(i), - indentFactor, newIndent); - } catch (Exception e) { - throw new JSONException("Unable to write JSONArray value at index: " + i, e); - } - needsComma = true; - } - if (indentFactor > 0) { - writer.write('\n'); - } - JSONObject.indent(writer, indent); - } - writer.write(']'); - return writer; - } catch (IOException e) { - throw new JSONException(e); - } - } - - public List toList() { - List results = new ArrayList(this.myArrayList.size()); - for (Object element : this.myArrayList) { - if (element == null || JSONObject.NULL.equals(element)) { - results.add(null); - } else if (element instanceof JSONArray) { - results.add(((JSONArray) element).toList()); - } else if (element instanceof JSONObject) { - results.add(((JSONObject) element).toMap()); - } else { - results.add(element); - } - } - return results; - } - - public boolean isEmpty() { - return this.myArrayList.isEmpty(); - } - - private void addAll(Collection collection, boolean wrap) { - this.myArrayList.ensureCapacity(this.myArrayList.size() + collection.size()); - if (wrap) { - for (Object o: collection){ - this.put(JSONObject.wrap(o)); - } - } else { - for (Object o: collection){ - this.put(o); - } - } - } - - private void addAll(Iterable iter, boolean wrap) { - if (wrap) { - for (Object o: iter){ - this.put(JSONObject.wrap(o)); - } - } else { - for (Object o: iter){ - this.put(o); - } - } - } - - - private void addAll(Object array, boolean wrap) throws JSONException { - if (array.getClass().isArray()) { - int length = Array.getLength(array); - this.myArrayList.ensureCapacity(this.myArrayList.size() + length); - if (wrap) { - for (int i = 0; i < length; i += 1) { - this.put(JSONObject.wrap(Array.get(array, i))); - } - } else { - for (int i = 0; i < length; i += 1) { - this.put(Array.get(array, i)); - } - } - } else if (array instanceof JSONArray) { - // use the built in array list `addAll` as all object - // wrapping should have been completed in the original - // JSONArray - this.myArrayList.addAll(((JSONArray)array).myArrayList); - } else if (array instanceof Collection) { - this.addAll((Collection)array, wrap); - } else if (array instanceof Iterable) { - this.addAll((Iterable)array, wrap); - } else { - throw new JSONException( - "JSONArray initial value should be a string or collection or array."); - } - } - - - private static JSONException wrongValueFormatException( - int idx, - String valueType, - Throwable cause) { - return new JSONException( - "JSONArray[" + idx + "] is not a " + valueType + "." - , cause); - } - - - private static JSONException wrongValueFormatException( - int idx, - String valueType, - Object value, - Throwable cause) { - return new JSONException( - "JSONArray[" + idx + "] is not a " + valueType + " (" + value + ")." - , cause); - } - -} diff --git a/src/ARSCLib/com/reandroid/json/JSONConvert.java b/src/ARSCLib/com/reandroid/json/JSONConvert.java deleted file mode 100644 index 358caf2a..00000000 --- a/src/ARSCLib/com/reandroid/json/JSONConvert.java +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -public interface JSONConvert { - public T toJson(); - public void fromJson(T json); -} diff --git a/src/ARSCLib/com/reandroid/json/JSONException.java b/src/ARSCLib/com/reandroid/json/JSONException.java deleted file mode 100644 index 13b72cdf..00000000 --- a/src/ARSCLib/com/reandroid/json/JSONException.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -public class JSONException extends IllegalArgumentException { - /** Serialization ID */ - private static final long serialVersionUID = 0; - - public JSONException(final String message) { - super(message); - } - - public JSONException(final String message, final Throwable cause) { - super(message, cause); - } - - public JSONException(final Throwable cause) { - super(cause.getMessage(), cause); - } - -} diff --git a/src/ARSCLib/com/reandroid/json/JSONItem.java b/src/ARSCLib/com/reandroid/json/JSONItem.java deleted file mode 100644 index 86b630f1..00000000 --- a/src/ARSCLib/com/reandroid/json/JSONItem.java +++ /dev/null @@ -1,64 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.json; - -import java.io.*; -import java.nio.charset.StandardCharsets; - -public abstract class JSONItem { - public abstract Writer write(Writer writer, int indentFactor, int indent) throws JSONException; - - public void write(File file) throws IOException{ - write(file, INDENT_FACTOR); - } - public void write(File file, int indentFactor) throws IOException{ - File dir=file.getParentFile(); - if(dir!=null && !dir.exists()){ - dir.mkdirs(); - } - FileOutputStream outputStream=new FileOutputStream(file); - write(outputStream, indentFactor); - outputStream.close(); - } - public void write(OutputStream outputStream) throws IOException { - write(outputStream, INDENT_FACTOR); - } - public void write(OutputStream outputStream, int indentFactor) throws IOException { - Writer writer=new OutputStreamWriter(outputStream, StandardCharsets.UTF_8); - writer= write(writer, indentFactor, 0); - writer.flush(); - writer.close(); - } - public Writer write(Writer writer) throws JSONException { - return this.write(writer, 0, 0); - } - @Override - public String toString() { - try { - return this.toString(0); - } catch (Exception e) { - return null; - } - } - public String toString(int indentFactor) throws JSONException { - StringWriter w = new StringWriter(); - synchronized (w.getBuffer()) { - return this.write(w, indentFactor, 0).toString(); - } - } - - private static final int INDENT_FACTOR=1; -} diff --git a/src/ARSCLib/com/reandroid/json/JSONML.java b/src/ARSCLib/com/reandroid/json/JSONML.java deleted file mode 100644 index 9b15ea3a..00000000 --- a/src/ARSCLib/com/reandroid/json/JSONML.java +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -public class JSONML { - - private static Object parse( - XMLTokener x, - boolean arrayForm, - JSONArray ja, - boolean keepStrings - ) throws JSONException { - String attribute; - char c; - String closeTag = null; - int i; - JSONArray newja = null; - JSONObject newjo = null; - Object token; - String tagName = null; - -// Test for and skip past these forms: -// -// -// -// - - while (true) { - if (!x.more()) { - throw x.syntaxError("Bad XML"); - } - token = x.nextContent(); - if (token == XML.LT) { - token = x.nextToken(); - if (token instanceof Character) { - if (token == XML.SLASH) { - -// Close tag "); - } else { - x.back(); - } - } else if (c == '[') { - token = x.nextToken(); - if (token.equals("CDATA") && x.next() == '[') { - if (ja != null) { - ja.put(x.nextCDATA()); - } - } else { - throw x.syntaxError("Expected 'CDATA['"); - } - } else { - i = 1; - do { - token = x.nextMeta(); - if (token == null) { - throw x.syntaxError("Missing '>' after ' 0); - } - } else if (token == XML.QUEST) { - -// "); - } else { - throw x.syntaxError("Misshaped tag"); - } - -// Open tag < - - } else { - if (!(token instanceof String)) { - throw x.syntaxError("Bad tagName '" + token + "'."); - } - tagName = (String)token; - newja = new JSONArray(); - newjo = new JSONObject(); - if (arrayForm) { - newja.put(tagName); - if (ja != null) { - ja.put(newja); - } - } else { - newjo.put("tagName", tagName); - if (ja != null) { - ja.put(newjo); - } - } - token = null; - for (;;) { - if (token == null) { - token = x.nextToken(); - } - if (token == null) { - throw x.syntaxError("Misshaped tag"); - } - if (!(token instanceof String)) { - break; - } - -// attribute = value - - attribute = (String)token; - if (!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute))) { - throw x.syntaxError("Reserved attribute."); - } - token = x.nextToken(); - if (token == XML.EQ) { - token = x.nextToken(); - if (!(token instanceof String)) { - throw x.syntaxError("Missing value"); - } - newjo.accumulate(attribute, keepStrings ? ((String)token) :XML.stringToValue((String)token)); - token = null; - } else { - newjo.accumulate(attribute, ""); - } - } - if (arrayForm && newjo.length() > 0) { - newja.put(newjo); - } - -// Empty tag <.../> - - if (token == XML.SLASH) { - if (x.nextToken() != XML.GT) { - throw x.syntaxError("Misshaped tag"); - } - if (ja == null) { - if (arrayForm) { - return newja; - } - return newjo; - } - -// Content, between <...> and - - } else { - if (token != XML.GT) { - throw x.syntaxError("Misshaped tag"); - } - closeTag = (String)parse(x, arrayForm, newja, keepStrings); - if (closeTag != null) { - if (!closeTag.equals(tagName)) { - throw x.syntaxError("Mismatched '" + tagName + - "' and '" + closeTag + "'"); - } - tagName = null; - if (!arrayForm && newja.length() > 0) { - newjo.put("childNodes", newja); - } - if (ja == null) { - if (arrayForm) { - return newja; - } - return newjo; - } - } - } - } - } else { - if (ja != null) { - ja.put(token instanceof String - ? keepStrings ? XML.unescape((String)token) :XML.stringToValue((String)token) - : token); - } - } - } - } - public static JSONArray toJSONArray(String string) throws JSONException { - return (JSONArray)parse(new XMLTokener(string), true, null, false); - } - public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException { - return (JSONArray)parse(new XMLTokener(string), true, null, keepStrings); - } - public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException { - return (JSONArray)parse(x, true, null, keepStrings); - } - public static JSONArray toJSONArray(XMLTokener x) throws JSONException { - return (JSONArray)parse(x, true, null, false); - } - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONObject using the JsonML transform. Each XML tag is represented as - * a JSONObject with a "tagName" property. If the tag has attributes, then - * the attributes will be in the JSONObject as properties. If the tag - * contains children, the object will have a "childNodes" property which - * will be an array of strings and JsonML JSONObjects. - - * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. - * @param string The XML source text. - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONObject - */ - public static JSONObject toJSONObject(String string) throws JSONException { - return (JSONObject)parse(new XMLTokener(string), false, null, false); - } - - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONObject using the JsonML transform. Each XML tag is represented as - * a JSONObject with a "tagName" property. If the tag has attributes, then - * the attributes will be in the JSONObject as properties. If the tag - * contains children, the object will have a "childNodes" property which - * will be an array of strings and JsonML JSONObjects. - - * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. - * @param string The XML source text. - * @param keepStrings If true, then values will not be coerced into boolean - * or numeric values and will instead be left as strings - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONObject - */ - public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { - return (JSONObject)parse(new XMLTokener(string), false, null, keepStrings); - } - - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONObject using the JsonML transform. Each XML tag is represented as - * a JSONObject with a "tagName" property. If the tag has attributes, then - * the attributes will be in the JSONObject as properties. If the tag - * contains children, the object will have a "childNodes" property which - * will be an array of strings and JsonML JSONObjects. - - * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. - * @param x An XMLTokener of the XML source text. - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONObject - */ - public static JSONObject toJSONObject(XMLTokener x) throws JSONException { - return (JSONObject)parse(x, false, null, false); - } - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONObject using the JsonML transform. Each XML tag is represented as - * a JSONObject with a "tagName" property. If the tag has attributes, then - * the attributes will be in the JSONObject as properties. If the tag - * contains children, the object will have a "childNodes" property which - * will be an array of strings and JsonML JSONObjects. - - * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. - * @param x An XMLTokener of the XML source text. - * @param keepStrings If true, then values will not be coerced into boolean - * or numeric values and will instead be left as strings - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONObject - */ - public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException { - return (JSONObject)parse(x, false, null, keepStrings); - } - public static String toString(JSONArray ja) throws JSONException { - int i; - JSONObject jo; - int length; - Object object; - StringBuilder sb = new StringBuilder(); - String tagName; - -// Emit = length) { - sb.append('/'); - sb.append('>'); - } else { - sb.append('>'); - do { - object = ja.get(i); - i += 1; - if (object != null) { - if (object instanceof String) { - sb.append(XML.escape(object.toString())); - } else if (object instanceof JSONObject) { - sb.append(toString((JSONObject)object)); - } else if (object instanceof JSONArray) { - sb.append(toString((JSONArray)object)); - } else { - sb.append(object.toString()); - } - } - } while (i < length); - sb.append('<'); - sb.append('/'); - sb.append(tagName); - sb.append('>'); - } - return sb.toString(); - } - - public static String toString(JSONObject jo) throws JSONException { - StringBuilder sb = new StringBuilder(); - int i; - JSONArray ja; - int length; - Object object; - String tagName; - Object value; - -//Emit '); - } else { - sb.append('>'); - length = ja.length(); - for (i = 0; i < length; i += 1) { - object = ja.get(i); - if (object != null) { - if (object instanceof String) { - sb.append(XML.escape(object.toString())); - } else if (object instanceof JSONObject) { - sb.append(toString((JSONObject)object)); - } else if (object instanceof JSONArray) { - sb.append(toString((JSONArray)object)); - } else { - sb.append(object.toString()); - } - } - } - sb.append('<'); - sb.append('/'); - sb.append(tagName); - sb.append('>'); - } - return sb.toString(); - } -} diff --git a/src/ARSCLib/com/reandroid/json/JSONObject.java b/src/ARSCLib/com/reandroid/json/JSONObject.java deleted file mode 100644 index daedbf0a..00000000 --- a/src/ARSCLib/com/reandroid/json/JSONObject.java +++ /dev/null @@ -1,1398 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -import com.reandroid.common.FileChannelInputStream; - -import java.io.*; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.*; -import java.util.Map.Entry; -import java.util.regex.Pattern; - -public class JSONObject extends JSONItem { - - private static final class Null { - - @Override - protected final Object clone() { - return this; - } - - @Override - public boolean equals(Object object) { - return object == null || object == this; - } - - @Override - public int hashCode() { - return 0; - } - - @Override - public String toString() { - return "null"; - } - } - - - static final Pattern NUMBER_PATTERN = Pattern.compile("-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?"); - - private final LinkedHashMap map; - - public static final Object NULL = new Null(); - - public JSONObject() { - this.map = new LinkedHashMap<>(); - } - - public JSONObject(JSONObject jo, String ... names) { - this(names.length); - for (int i = 0; i < names.length; i += 1) { - try { - this.putOnce(names[i], jo.opt(names[i])); - } catch (Exception ignore) { - } - } - } - - public JSONObject(JSONTokener x) throws JSONException { - this(); - char c; - String key; - - if (x.nextClean() != '{') { - throw x.syntaxError("A JSONObject text must begin with '{'"); - } - for (;;) { - c = x.nextClean(); - switch (c) { - case 0: - throw x.syntaxError("A JSONObject text must end with '}'"); - case '}': - return; - default: - x.back(); - key = x.nextValue().toString(); - } - - // The key is followed by ':'. - - c = x.nextClean(); - if (c != ':') { - throw x.syntaxError("Expected a ':' after a key"); - } - - // Use syntaxError(..) to include error location - - if (key != null) { - // Check if key exists - if (this.opt(key) != null) { - // key already exists - throw x.syntaxError("Duplicate key \"" + key + "\""); - } - // Only add value if non-null - Object value = x.nextValue(); - if (value!=null) { - this.put(key, value); - } - } - - // Pairs are separated by ','. - - switch (x.nextClean()) { - case ';': - case ',': - if (x.nextClean() == '}') { - return; - } - x.back(); - break; - case '}': - return; - default: - throw x.syntaxError("Expected a ',' or '}'"); - } - } - } - - public JSONObject(Map m) { - if (m == null) { - this.map = new LinkedHashMap(); - } else { - this.map = new LinkedHashMap(m.size()); - for (final Entry e : m.entrySet()) { - if(e.getKey() == null) { - throw new NullPointerException("Null key."); - } - final Object value = e.getValue(); - if (value != null) { - this.map.put(String.valueOf(e.getKey()), wrap(value)); - } - } - } - } - - private JSONObject(Object bean) { - this(); - this.populateMap(bean); - } - - public JSONObject(String source) throws JSONException { - this(new JSONTokener(source)); - } - - public JSONObject(String baseName, Locale locale) throws JSONException { - this(); - ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale, - Thread.currentThread().getContextClassLoader()); - -// Iterate through the keys in the bundle. - - Enumeration keys = bundle.getKeys(); - while (keys.hasMoreElements()) { - Object key = keys.nextElement(); - if (key != null) { - -// Go through the path, ensuring that there is a nested JSONObject for each -// segment except the last. Add the value using the last segment's name into -// the deepest nested JSONObject. - - String[] path = ((String) key).split("\\."); - int last = path.length - 1; - JSONObject target = this; - for (int i = 0; i < last; i += 1) { - String segment = path[i]; - JSONObject nextTarget = target.optJSONObject(segment); - if (nextTarget == null) { - nextTarget = new JSONObject(); - target.put(segment, nextTarget); - } - target = nextTarget; - } - target.put(path[last], bundle.getString((String) key)); - } - } - } - - - protected JSONObject(int initialCapacity){ - this.map = new LinkedHashMap(initialCapacity); - } - - - public JSONObject(File file) throws IOException { - this(new FileChannelInputStream(file)); - } - public JSONObject(Reader reader){ - this(new JSONTokener(reader)); - } - public JSONObject(InputStream inputStream) throws JSONException { - this(new JSONTokener(inputStream)); - try { - inputStream.close(); - } catch (IOException ignored) { - } - } - public JSONObject accumulate(String key, Object value) throws JSONException { - testValidity(value); - Object object = this.opt(key); - if (object == null) { - this.put(key, - value instanceof JSONArray ? new JSONArray().put(value) - : value); - } else if (object instanceof JSONArray) { - ((JSONArray) object).put(value); - } else { - this.put(key, new JSONArray().put(object).put(value)); - } - return this; - } - - public JSONObject append(String key, Object value) throws JSONException { - testValidity(value); - Object object = this.opt(key); - if (object == null) { - this.put(key, new JSONArray().put(value)); - } else if (object instanceof JSONArray) { - this.put(key, ((JSONArray) object).put(value)); - } else { - throw wrongValueFormatException(key, "JSONArray", null, null); - } - return this; - } - - public static String doubleToString(double d) { - if (Double.isInfinite(d) || Double.isNaN(d)) { - return "null"; - } - -// Shave off trailing zeros and decimal point, if possible. - - String string = Double.toString(d); - if (string.indexOf('.') > 0 && string.indexOf('e') < 0 - && string.indexOf('E') < 0) { - while (string.endsWith("0")) { - string = string.substring(0, string.length() - 1); - } - if (string.endsWith(".")) { - string = string.substring(0, string.length() - 1); - } - } - return string; - } - - public Object get(String key) throws JSONException { - if (key == null) { - throw new JSONException("Null key."); - } - Object object = this.opt(key); - if (object == null) { - throw new JSONException("JSONObject[" + quote(key) + "] not found."); - } - return object; - } - - public > E getEnum(Class clazz, String key) throws JSONException { - E val = optEnum(clazz, key); - if(val==null) { - // JSONException should really take a throwable argument. - // If it did, I would re-implement this with the Enum.valueOf - // method and place any thrown exception in the JSONException - throw wrongValueFormatException(key, "enum of type " + quote(clazz.getSimpleName()), null); - } - return val; - } - - public boolean getBoolean(String key) throws JSONException { - Object object = this.get(key); - if (object.equals(Boolean.FALSE) - || (object instanceof String && ((String) object) - .equalsIgnoreCase("false"))) { - return false; - } else if (object.equals(Boolean.TRUE) - || (object instanceof String && ((String) object) - .equalsIgnoreCase("true"))) { - return true; - } - throw wrongValueFormatException(key, "Boolean", null); - } - - public BigInteger getBigInteger(String key) throws JSONException { - Object object = this.get(key); - BigInteger ret = objectToBigInteger(object, null); - if (ret != null) { - return ret; - } - throw wrongValueFormatException(key, "BigInteger", object, null); - } - - public BigDecimal getBigDecimal(String key) throws JSONException { - Object object = this.get(key); - BigDecimal ret = objectToBigDecimal(object, null); - if (ret != null) { - return ret; - } - throw wrongValueFormatException(key, "BigDecimal", object, null); - } - - public double getDouble(String key) throws JSONException { - final Object object = this.get(key); - if(object instanceof Number) { - return ((Number)object).doubleValue(); - } - try { - return Double.parseDouble(object.toString()); - } catch (Exception e) { - throw wrongValueFormatException(key, "double", e); - } - } - - public float getFloat(String key) throws JSONException { - final Object object = this.get(key); - if(object instanceof Number) { - return ((Number)object).floatValue(); - } - try { - return Float.parseFloat(object.toString()); - } catch (Exception e) { - throw wrongValueFormatException(key, "float", e); - } - } - - public Number getNumber(String key) throws JSONException { - Object object = this.get(key); - try { - if (object instanceof Number) { - return (Number)object; - } - return stringToNumber(object.toString()); - } catch (Exception e) { - throw wrongValueFormatException(key, "number", e); - } - } - - public int getInt(String key) throws JSONException { - final Object object = this.get(key); - if(object instanceof Number) { - return ((Number)object).intValue(); - } - try { - return Integer.parseInt(object.toString()); - } catch (Exception e) { - throw wrongValueFormatException(key, "int", e); - } - } - - public JSONArray getJSONArray(String key) throws JSONException { - Object object = this.get(key); - if (object instanceof JSONArray) { - return (JSONArray) object; - } - throw wrongValueFormatException(key, "JSONArray", null); - } - - public JSONObject getJSONObject(String key) throws JSONException { - Object object = this.get(key); - if (object instanceof JSONObject) { - return (JSONObject) object; - } - throw wrongValueFormatException(key, "JSONObject", null); - } - - public long getLong(String key) throws JSONException { - final Object object = this.get(key); - if(object instanceof Number) { - return ((Number)object).longValue(); - } - try { - return Long.parseLong(object.toString()); - } catch (Exception e) { - throw wrongValueFormatException(key, "long", e); - } - } - - public static String[] getNames(JSONObject jo) { - if (jo.isEmpty()) { - return null; - } - return jo.keySet().toArray(new String[jo.length()]); - } - - public static String[] getNames(Object object) { - if (object == null) { - return null; - } - Class klass = object.getClass(); - Field[] fields = klass.getFields(); - int length = fields.length; - if (length == 0) { - return null; - } - String[] names = new String[length]; - for (int i = 0; i < length; i += 1) { - names[i] = fields[i].getName(); - } - return names; - } - - public String getString(String key) throws JSONException { - Object object = this.get(key); - if (object instanceof String) { - return (String) object; - } - throw wrongValueFormatException(key, "string", null); - } - - public boolean has(String key) { - return this.map.containsKey(key); - } - - public JSONObject increment(String key) throws JSONException { - Object value = this.opt(key); - if (value == null) { - this.put(key, 1); - } else if (value instanceof Integer) { - this.put(key, ((Integer) value).intValue() + 1); - } else if (value instanceof Long) { - this.put(key, ((Long) value).longValue() + 1L); - } else if (value instanceof BigInteger) { - this.put(key, ((BigInteger)value).add(BigInteger.ONE)); - } else if (value instanceof Float) { - this.put(key, ((Float) value).floatValue() + 1.0f); - } else if (value instanceof Double) { - this.put(key, ((Double) value).doubleValue() + 1.0d); - } else if (value instanceof BigDecimal) { - this.put(key, ((BigDecimal)value).add(BigDecimal.ONE)); - } else { - throw new JSONException("Unable to increment [" + quote(key) + "]."); - } - return this; - } - - public boolean isNull(String key) { - return JSONObject.NULL.equals(this.opt(key)); - } - - public Iterator keys() { - return this.keySet().iterator(); - } - - public Set keySet() { - return this.map.keySet(); - } - - protected Set> entrySet() { - return this.map.entrySet(); - } - - public int length() { - return this.map.size(); - } - - public boolean isEmpty() { - return this.map.isEmpty(); - } - - public JSONArray names() { - if(this.map.isEmpty()) { - return null; - } - return new JSONArray(this.map.keySet()); - } - - public static String numberToString(Number number) throws JSONException { - if (number == null) { - throw new JSONException("Null pointer"); - } - testValidity(number); - - // Shave off trailing zeros and decimal point, if possible. - - String string = number.toString(); - if (string.indexOf('.') > 0 && string.indexOf('e') < 0 - && string.indexOf('E') < 0) { - while (string.endsWith("0")) { - string = string.substring(0, string.length() - 1); - } - if (string.endsWith(".")) { - string = string.substring(0, string.length() - 1); - } - } - return string; - } - - public Object opt(String key) { - return key == null ? null : this.map.get(key); - } - - public > E optEnum(Class clazz, String key) { - return this.optEnum(clazz, key, null); - } - - public > E optEnum(Class clazz, String key, E defaultValue) { - try { - Object val = this.opt(key); - if (NULL.equals(val)) { - return defaultValue; - } - if (clazz.isAssignableFrom(val.getClass())) { - // we just checked it! - @SuppressWarnings("unchecked") - E myE = (E) val; - return myE; - } - return Enum.valueOf(clazz, val.toString()); - } catch (IllegalArgumentException e) { - return defaultValue; - } catch (NullPointerException e) { - return defaultValue; - } - } - - public boolean optBoolean(String key) { - return this.optBoolean(key, false); - } - - public boolean optBoolean(String key, boolean defaultValue) { - Object val = this.opt(key); - if (NULL.equals(val)) { - return defaultValue; - } - if (val instanceof Boolean){ - return ((Boolean) val).booleanValue(); - } - try { - // we'll use the get anyway because it does string conversion. - return this.getBoolean(key); - } catch (Exception e) { - return defaultValue; - } - } - - public BigDecimal optBigDecimal(String key, BigDecimal defaultValue) { - Object val = this.opt(key); - return objectToBigDecimal(val, defaultValue); - } - - static BigDecimal objectToBigDecimal(Object val, BigDecimal defaultValue) { - if (NULL.equals(val)) { - return defaultValue; - } - if (val instanceof BigDecimal){ - return (BigDecimal) val; - } - if (val instanceof BigInteger){ - return new BigDecimal((BigInteger) val); - } - if (val instanceof Double || val instanceof Float){ - final double d = ((Number) val).doubleValue(); - if(Double.isNaN(d)) { - return defaultValue; - } - return new BigDecimal(((Number) val).doubleValue()); - } - if (val instanceof Long || val instanceof Integer - || val instanceof Short || val instanceof Byte){ - return new BigDecimal(((Number) val).longValue()); - } - // don't check if it's a string in case of unchecked Number subclasses - try { - return new BigDecimal(val.toString()); - } catch (Exception e) { - return defaultValue; - } - } - - public BigInteger optBigInteger(String key, BigInteger defaultValue) { - Object val = this.opt(key); - return objectToBigInteger(val, defaultValue); - } - - static BigInteger objectToBigInteger(Object val, BigInteger defaultValue) { - if (NULL.equals(val)) { - return defaultValue; - } - if (val instanceof BigInteger){ - return (BigInteger) val; - } - if (val instanceof BigDecimal){ - return ((BigDecimal) val).toBigInteger(); - } - if (val instanceof Double || val instanceof Float){ - final double d = ((Number) val).doubleValue(); - if(Double.isNaN(d)) { - return defaultValue; - } - return new BigDecimal(d).toBigInteger(); - } - if (val instanceof Long || val instanceof Integer - || val instanceof Short || val instanceof Byte){ - return BigInteger.valueOf(((Number) val).longValue()); - } - // don't check if it's a string in case of unchecked Number subclasses - try { - // the other opt functions handle implicit conversions, i.e. - // jo.put("double",1.1d); - // jo.optInt("double"); -- will return 1, not an error - // this conversion to BigDecimal then to BigInteger is to maintain - // that type cast support that may truncate the decimal. - final String valStr = val.toString(); - if(isDecimalNotation(valStr)) { - return new BigDecimal(valStr).toBigInteger(); - } - return new BigInteger(valStr); - } catch (Exception e) { - return defaultValue; - } - } - - public double optDouble(String key) { - return this.optDouble(key, Double.NaN); - } - - public double optDouble(String key, double defaultValue) { - Number val = this.optNumber(key); - if (val == null) { - return defaultValue; - } - final double doubleValue = val.doubleValue(); - // if (Double.isNaN(doubleValue) || Double.isInfinite(doubleValue)) { - // return defaultValue; - // } - return doubleValue; - } - - public float optFloat(String key) { - return this.optFloat(key, Float.NaN); - } - - public float optFloat(String key, float defaultValue) { - Number val = this.optNumber(key); - if (val == null) { - return defaultValue; - } - final float floatValue = val.floatValue(); - // if (Float.isNaN(floatValue) || Float.isInfinite(floatValue)) { - // return defaultValue; - // } - return floatValue; - } - - public int optInt(String key) { - return this.optInt(key, 0); - } - - public int optInt(String key, int defaultValue) { - final Number val = this.optNumber(key, null); - if (val == null) { - return defaultValue; - } - return val.intValue(); - } - - public JSONArray optJSONArray(String key) { - Object o = this.opt(key); - return o instanceof JSONArray ? (JSONArray) o : null; - } - - public JSONObject optJSONObject(String key) { - Object object = this.opt(key); - return object instanceof JSONObject ? (JSONObject) object : null; - } - - public long optLong(String key) { - return this.optLong(key, 0); - } - - public long optLong(String key, long defaultValue) { - final Number val = this.optNumber(key, null); - if (val == null) { - return defaultValue; - } - - return val.longValue(); - } - - - public Number optNumber(String key) { - return this.optNumber(key, null); - } - - public Number optNumber(String key, Number defaultValue) { - Object val = this.opt(key); - if (NULL.equals(val)) { - return defaultValue; - } - if (val instanceof Number){ - return (Number) val; - } - - try { - return stringToNumber(val.toString()); - } catch (Exception e) { - return defaultValue; - } - } - - - public String optString(String key) { - return this.optString(key, ""); - } - - public String optString(String key, String defaultValue) { - Object object = this.opt(key); - return NULL.equals(object) ? defaultValue : object.toString(); - } - - private void populateMap(Object bean) { - Class klass = bean.getClass(); - - // If klass is a System class then set includeSuperClass to false. - - boolean includeSuperClass = klass.getClassLoader() != null; - - Method[] methods = includeSuperClass ? klass.getMethods() : klass.getDeclaredMethods(); - for (final Method method : methods) { - final int modifiers = method.getModifiers(); - if (Modifier.isPublic(modifiers) - && !Modifier.isStatic(modifiers) - && method.getParameterTypes().length == 0 - && !method.isBridge() - && method.getReturnType() != Void.TYPE - && isValidMethodName(method.getName())) { - final String key = getKeyNameFromMethod(method); - if (key != null && !key.isEmpty()) { - try { - final Object result = method.invoke(bean); - if (result != null) { - this.map.put(key, wrap(result)); - // we don't use the result anywhere outside of wrap - // if it's a resource we should be sure to close it - // after calling toString - if (result instanceof Closeable) { - try { - ((Closeable) result).close(); - } catch (IOException ignore) { - } - } - } - } catch (IllegalAccessException ignore) { - } catch (IllegalArgumentException ignore) { - } catch (InvocationTargetException ignore) { - } - } - } - } - } - - private static boolean isValidMethodName(String name) { - return !"getClass".equals(name) && !"getDeclaringClass".equals(name); - } - - private static String getKeyNameFromMethod(Method method) { - final int ignoreDepth = getAnnotationDepth(method, JSONPropertyIgnore.class); - if (ignoreDepth > 0) { - final int forcedNameDepth = getAnnotationDepth(method, JSONPropertyName.class); - if (forcedNameDepth < 0 || ignoreDepth <= forcedNameDepth) { - // the hierarchy asked to ignore, and the nearest name override - // was higher or non-existent - return null; - } - } - JSONPropertyName annotation = getAnnotation(method, JSONPropertyName.class); - if (annotation != null && annotation.value() != null && !annotation.value().isEmpty()) { - return annotation.value(); - } - String key; - final String name = method.getName(); - if (name.startsWith("get") && name.length() > 3) { - key = name.substring(3); - } else if (name.startsWith("is") && name.length() > 2) { - key = name.substring(2); - } else { - return null; - } - // if the first letter in the key is not uppercase, then skip. - // This is to maintain backwards compatibility before PR406 - // (https://github.com/stleary/JSON-java/pull/406/) - if (Character.isLowerCase(key.charAt(0))) { - return null; - } - if (key.length() == 1) { - key = key.toLowerCase(Locale.ROOT); - } else if (!Character.isUpperCase(key.charAt(1))) { - key = key.substring(0, 1).toLowerCase(Locale.ROOT) + key.substring(1); - } - return key; - } - - private static A getAnnotation(final Method m, final Class annotationClass) { - // if we have invalid data the result is null - if (m == null || annotationClass == null) { - return null; - } - - if (m.isAnnotationPresent(annotationClass)) { - return m.getAnnotation(annotationClass); - } - - // if we've already reached the Object class, return null; - Class c = m.getDeclaringClass(); - if (c.getSuperclass() == null) { - return null; - } - - // check directly implemented interfaces for the method being checked - for (Class i : c.getInterfaces()) { - try { - Method im = i.getMethod(m.getName(), m.getParameterTypes()); - return getAnnotation(im, annotationClass); - } catch (final SecurityException ex) { - continue; - } catch (final NoSuchMethodException ex) { - continue; - } - } - - try { - return getAnnotation( - c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()), - annotationClass); - } catch (final SecurityException ex) { - return null; - } catch (final NoSuchMethodException ex) { - return null; - } - } - - private static int getAnnotationDepth(final Method m, final Class annotationClass) { - // if we have invalid data the result is -1 - if (m == null || annotationClass == null) { - return -1; - } - - if (m.isAnnotationPresent(annotationClass)) { - return 1; - } - - // if we've already reached the Object class, return -1; - Class c = m.getDeclaringClass(); - if (c.getSuperclass() == null) { - return -1; - } - - // check directly implemented interfaces for the method being checked - for (Class i : c.getInterfaces()) { - try { - Method im = i.getMethod(m.getName(), m.getParameterTypes()); - int d = getAnnotationDepth(im, annotationClass); - if (d > 0) { - // since the annotation was on the interface, add 1 - return d + 1; - } - } catch (final SecurityException ex) { - continue; - } catch (final NoSuchMethodException ex) { - continue; - } - } - - try { - int d = getAnnotationDepth( - c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()), - annotationClass); - if (d > 0) { - // since the annotation was on the superclass, add 1 - return d + 1; - } - return -1; - } catch (final SecurityException ex) { - return -1; - } catch (final NoSuchMethodException ex) { - return -1; - } - } - - public JSONObject put(String key, boolean value) throws JSONException { - return this.put(key, value ? Boolean.TRUE : Boolean.FALSE); - } - - public JSONObject put(String key, Collection value) throws JSONException { - return this.put(key, new JSONArray(value)); - } - - public JSONObject put(String key, double value) throws JSONException { - return this.put(key, Double.valueOf(value)); - } - - - public JSONObject put(String key, float value) throws JSONException { - return this.put(key, Float.valueOf(value)); - } - - public JSONObject put(String key, int value) throws JSONException { - return this.put(key, Integer.valueOf(value)); - } - - public JSONObject put(String key, long value) throws JSONException { - return this.put(key, Long.valueOf(value)); - } - - public JSONObject put(String key, Map value) throws JSONException { - return this.put(key, new JSONObject(value)); - } - - public JSONObject put(String key, Object value) throws JSONException { - if (key == null) { - throw new NullPointerException("Null key."); - } - if (value != null) { - testValidity(value); - this.map.put(key, value); - } else { - this.remove(key); - } - return this; - } - - public JSONObject putOnce(String key, Object value) throws JSONException { - if (key != null && value != null) { - if (this.opt(key) != null) { - throw new JSONException("Duplicate key \"" + key + "\""); - } - return this.put(key, value); - } - return this; - } - - public JSONObject putOpt(String key, Object value) throws JSONException { - if (key != null && value != null) { - return this.put(key, value); - } - return this; - } - - public Object query(String jsonPointer) { - return query(new JSONPointer(jsonPointer)); - } - - public Object query(JSONPointer jsonPointer) { - return jsonPointer.queryFrom(this); - } - - - public Object optQuery(String jsonPointer) { - return optQuery(new JSONPointer(jsonPointer)); - } - - - public Object optQuery(JSONPointer jsonPointer) { - try { - return jsonPointer.queryFrom(this); - } catch (JSONPointerException e) { - return null; - } - } - - public static String quote(String string) { - StringWriter sw = new StringWriter(); - synchronized (sw.getBuffer()) { - try { - return quote(string, sw).toString(); - } catch (IOException ignored) { - // will never happen - we are writing to a string writer - return ""; - } - } - } - - public static Writer quote(String string, Writer w) throws IOException { - if (string == null || string.isEmpty()) { - w.write("\"\""); - return w; - } - - char b; - char c = 0; - String hhhh; - int i; - int len = string.length(); - - w.write('"'); - for (i = 0; i < len; i += 1) { - b = c; - c = string.charAt(i); - switch (c) { - case '\\': - case '"': - w.write('\\'); - w.write(c); - break; - case '/': - if (b == '<') { - w.write('\\'); - } - w.write(c); - break; - case '\b': - w.write("\\b"); - break; - case '\t': - w.write("\\t"); - break; - case '\n': - w.write("\\n"); - break; - case '\f': - w.write("\\f"); - break; - case '\r': - w.write("\\r"); - break; - default: - if (c < ' ' || (c >= '\u0080' && c < '\u00a0') - || (c >= '\u2000' && c < '\u2100')) { - w.write("\\u"); - hhhh = Integer.toHexString(c); - w.write("0000", 0, 4 - hhhh.length()); - w.write(hhhh); - } else { - w.write(c); - } - } - } - w.write('"'); - return w; - } - - public Object remove(String key) { - return this.map.remove(key); - } - - public boolean similar(Object other) { - try { - if (!(other instanceof JSONObject)) { - return false; - } - if (!this.keySet().equals(((JSONObject)other).keySet())) { - return false; - } - for (final Entry entry : this.entrySet()) { - String name = entry.getKey(); - Object valueThis = entry.getValue(); - Object valueOther = ((JSONObject)other).get(name); - if(valueThis == valueOther) { - continue; - } - if(valueThis == null) { - return false; - } - if (valueThis instanceof JSONObject) { - if (!((JSONObject)valueThis).similar(valueOther)) { - return false; - } - } else if (valueThis instanceof JSONArray) { - if (!((JSONArray)valueThis).similar(valueOther)) { - return false; - } - } else if (!valueThis.equals(valueOther)) { - return false; - } - } - return true; - } catch (Throwable exception) { - return false; - } - } - - - protected static boolean isDecimalNotation(final String val) { - return val.indexOf('.') > -1 || val.indexOf('e') > -1 - || val.indexOf('E') > -1 || "-0".equals(val); - } - - - protected static Number stringToNumber(final String val) throws NumberFormatException { - char initial = val.charAt(0); - if ((initial >= '0' && initial <= '9') || initial == '-') { - // decimal representation - if (isDecimalNotation(val)) { - // Use a BigDecimal all the time so we keep the original - // representation. BigDecimal doesn't support -0.0, ensure we - // keep that by forcing a decimal. - try { - BigDecimal bd = new BigDecimal(val); - if(initial == '-' && BigDecimal.ZERO.compareTo(bd)==0) { - return Double.valueOf(-0.0); - } - return bd; - } catch (NumberFormatException retryAsDouble) { - // this is to support "Hex Floats" like this: 0x1.0P-1074 - try { - Double d = Double.valueOf(val); - if(d.isNaN() || d.isInfinite()) { - throw new NumberFormatException("val ["+val+"] is not a valid number."); - } - return d; - } catch (NumberFormatException ignore) { - throw new NumberFormatException("val ["+val+"] is not a valid number."); - } - } - } - // block items like 00 01 etc. Java number parsers treat these as Octal. - if(initial == '0' && val.length() > 1) { - char at1 = val.charAt(1); - if(at1 >= '0' && at1 <= '9') { - throw new NumberFormatException("val ["+val+"] is not a valid number."); - } - } else if (initial == '-' && val.length() > 2) { - char at1 = val.charAt(1); - char at2 = val.charAt(2); - if(at1 == '0' && at2 >= '0' && at2 <= '9') { - throw new NumberFormatException("val ["+val+"] is not a valid number."); - } - } - // integer representation. - // This will narrow any values to the smallest reasonable Object representation - // (Integer, Long, or BigInteger) - - // BigInteger down conversion: We use a similar bitLenth compare as - // BigInteger#intValueExact uses. Increases GC, but objects hold - // only what they need. i.e. Less runtime overhead if the value is - // long lived. - BigInteger bi = new BigInteger(val); - if(bi.bitLength() <= 31){ - return Integer.valueOf(bi.intValue()); - } - if(bi.bitLength() <= 63){ - return Long.valueOf(bi.longValue()); - } - return bi; - } - throw new NumberFormatException("val ["+val+"] is not a valid number."); - } - - // Changes to this method must be copied to the corresponding method in - // the XML class to keep full support for Android - public static Object stringToValue(String string) { - if ("".equals(string)) { - return string; - } - - // check JSON key words true/false/null - if ("true".equalsIgnoreCase(string)) { - return Boolean.TRUE; - } - if ("false".equalsIgnoreCase(string)) { - return Boolean.FALSE; - } - if ("null".equalsIgnoreCase(string)) { - return JSONObject.NULL; - } - - /* - * If it might be a number, try converting it. If a number cannot be - * produced, then the value will just be a string. - */ - - char initial = string.charAt(0); - if ((initial >= '0' && initial <= '9') || initial == '-') { - try { - return stringToNumber(string); - } catch (Exception ignore) { - } - } - return string; - } - - public static void testValidity(Object o) throws JSONException { - if (o != null) { - if (o instanceof Double) { - if (((Double) o).isInfinite() || ((Double) o).isNaN()) { - throw new JSONException( - "JSON does not allow non-finite numbers."); - } - } else if (o instanceof Float) { - if (((Float) o).isInfinite() || ((Float) o).isNaN()) { - throw new JSONException( - "JSON does not allow non-finite numbers."); - } - } - } - } - - public JSONArray toJSONArray(JSONArray names) throws JSONException { - if (names == null || names.isEmpty()) { - return null; - } - JSONArray ja = new JSONArray(); - for (int i = 0; i < names.length(); i += 1) { - ja.put(this.opt(names.getString(i))); - } - return ja; - } - - - public static String valueToString(Object value) throws JSONException { - // moves the implementation to JSONWriter as: - // 1. It makes more sense to be part of the writer class - // 2. For Android support this method is not available. By implementing it in the Writer - // Android users can use the writer with the built in Android JSONObject implementation. - return JSONWriter.valueToString(value); - } - - public static Object wrap(Object object) { - try { - if (object == null) { - return NULL; - } - if (object instanceof JSONObject || object instanceof JSONArray - || NULL.equals(object) || object instanceof JSONString - || object instanceof Byte || object instanceof Character - || object instanceof Short || object instanceof Integer - || object instanceof Long || object instanceof Boolean - || object instanceof Float || object instanceof Double - || object instanceof String || object instanceof BigInteger - || object instanceof BigDecimal || object instanceof Enum) { - return object; - } - - if (object instanceof Collection) { - Collection coll = (Collection) object; - return new JSONArray(coll); - } - if (object.getClass().isArray()) { - return new JSONArray(object); - } - if (object instanceof Map) { - Map map = (Map) object; - return new JSONObject(map); - } - Package objectPackage = object.getClass().getPackage(); - String objectPackageName = objectPackage != null ? objectPackage - .getName() : ""; - if (objectPackageName.startsWith("java.") - || objectPackageName.startsWith("javax.") - || object.getClass().getClassLoader() == null) { - return object.toString(); - } - return new JSONObject(object); - } catch (Exception exception) { - return null; - } - } - static final Writer writeValue(Writer writer, Object value, - int indentFactor, int indent) throws JSONException, IOException { - if (value == null || value.equals(null)) { - writer.write("null"); - } else if (value instanceof JSONString) { - Object o; - try { - o = ((JSONString) value).toJSONString(); - } catch (Exception e) { - throw new JSONException(e); - } - writer.write(o != null ? o.toString() : quote(value.toString())); - } else if (value instanceof Number) { - // not all Numbers may match actual JSON Numbers. i.e. fractions or Imaginary - final String numberAsString = numberToString((Number) value); - if(NUMBER_PATTERN.matcher(numberAsString).matches()) { - writer.write(numberAsString); - } else { - // The Number value is not a valid JSON number. - // Instead we will quote it as a string - quote(numberAsString, writer); - } - } else if (value instanceof Boolean) { - writer.write(value.toString()); - } else if (value instanceof Enum) { - writer.write(quote(((Enum)value).name())); - } else if (value instanceof JSONObject) { - ((JSONObject) value).write(writer, indentFactor, indent); - } else if (value instanceof JSONArray) { - ((JSONArray) value).write(writer, indentFactor, indent); - } else if (value instanceof Map) { - Map map = (Map) value; - new JSONObject(map).write(writer, indentFactor, indent); - } else if (value instanceof Collection) { - Collection coll = (Collection) value; - new JSONArray(coll).write(writer, indentFactor, indent); - } else if (value.getClass().isArray()) { - new JSONArray(value).write(writer, indentFactor, indent); - } else { - quote(value.toString(), writer); - } - return writer; - } - - static final void indent(Writer writer, int indent) throws IOException { - for (int i = 0; i < indent; i += 1) { - writer.write(' '); - } - } - - @Override - public Writer write(Writer writer, int indentFactor, int indent) throws JSONException { - try { - boolean needsComma = false; - final int length = this.length(); - writer.write('{'); - - if (length == 1) { - final Entry entry = this.entrySet().iterator().next(); - final String key = entry.getKey(); - writer.write(quote(key)); - writer.write(':'); - if (indentFactor > 0) { - writer.write(' '); - } - try{ - writeValue(writer, entry.getValue(), indentFactor, indent); - } catch (Exception e) { - throw new JSONException("Unable to write JSONObject value for key: " + key, e); - } - } else if (length != 0) { - final int newIndent = indent + indentFactor; - for (final Entry entry : this.entrySet()) { - if (needsComma) { - writer.write(','); - } - if (indentFactor > 0) { - writer.write('\n'); - } - indent(writer, newIndent); - final String key = entry.getKey(); - writer.write(quote(key)); - writer.write(':'); - if (indentFactor > 0) { - writer.write(' '); - } - try { - writeValue(writer, entry.getValue(), indentFactor, newIndent); - } catch (Exception e) { - throw new JSONException("Unable to write JSONObject value for key: " + key, e); - } - needsComma = true; - } - if (indentFactor > 0) { - writer.write('\n'); - } - indent(writer, indent); - } - writer.write('}'); - return writer; - } catch (IOException exception) { - throw new JSONException(exception); - } - } - - public LinkedHashMap toMap() { - LinkedHashMap results = new LinkedHashMap(); - for (Entry entry : this.entrySet()) { - Object value; - if (entry.getValue() == null || NULL.equals(entry.getValue())) { - value = null; - } else if (entry.getValue() instanceof JSONObject) { - value = ((JSONObject) entry.getValue()).toMap(); - } else if (entry.getValue() instanceof JSONArray) { - value = ((JSONArray) entry.getValue()).toList(); - } else { - value = entry.getValue(); - } - results.put(entry.getKey(), value); - } - return results; - } - - - private static JSONException wrongValueFormatException( - String key, - String valueType, - Throwable cause) { - return new JSONException( - "JSONObject[" + quote(key) + "] is not a " + valueType + "." - , cause); - } - - - private static JSONException wrongValueFormatException( - String key, - String valueType, - Object value, - Throwable cause) { - return new JSONException( - "JSONObject[" + quote(key) + "] is not a " + valueType + " (" + value + ")." - , cause); - } -} diff --git a/src/ARSCLib/com/reandroid/json/JSONPointer.java b/src/ARSCLib/com/reandroid/json/JSONPointer.java deleted file mode 100644 index 1512969b..00000000 --- a/src/ARSCLib/com/reandroid/json/JSONPointer.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -import static java.lang.String.format; - -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class JSONPointer { - - // used for URL encoding and decoding - private static final String ENCODING = "utf-8"; - - public static class Builder { - - // Segments for the eventual JSONPointer string - private final List refTokens = new ArrayList(); - - public JSONPointer build() { - return new JSONPointer(this.refTokens); - } - - public Builder append(String token) { - if (token == null) { - throw new NullPointerException("token cannot be null"); - } - this.refTokens.add(token); - return this; - } - - public Builder append(int arrayIndex) { - this.refTokens.add(String.valueOf(arrayIndex)); - return this; - } - } - - public static Builder builder() { - return new Builder(); - } - - // Segments for the JSONPointer string - private final List refTokens; - - public JSONPointer(final String pointer) { - if (pointer == null) { - throw new NullPointerException("pointer cannot be null"); - } - if (pointer.isEmpty() || pointer.equals("#")) { - this.refTokens = Collections.emptyList(); - return; - } - String refs; - if (pointer.startsWith("#/")) { - refs = pointer.substring(2); - try { - refs = URLDecoder.decode(refs, ENCODING); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } else if (pointer.startsWith("/")) { - refs = pointer.substring(1); - } else { - throw new IllegalArgumentException("a JSON pointer should start with '/' or '#/'"); - } - this.refTokens = new ArrayList(); - int slashIdx = -1; - int prevSlashIdx = 0; - do { - prevSlashIdx = slashIdx + 1; - slashIdx = refs.indexOf('/', prevSlashIdx); - if(prevSlashIdx == slashIdx || prevSlashIdx == refs.length()) { - // found 2 slashes in a row ( obj//next ) - // or single slash at the end of a string ( obj/test/ ) - this.refTokens.add(""); - } else if (slashIdx >= 0) { - final String token = refs.substring(prevSlashIdx, slashIdx); - this.refTokens.add(unescape(token)); - } else { - // last item after separator, or no separator at all. - final String token = refs.substring(prevSlashIdx); - this.refTokens.add(unescape(token)); - } - } while (slashIdx >= 0); - // using split does not take into account consecutive separators or "ending nulls" - //for (String token : refs.split("/")) { - // this.refTokens.add(unescape(token)); - //} - } - - public JSONPointer(List refTokens) { - this.refTokens = new ArrayList(refTokens); - } - - private static String unescape(String token) { - return token.replace("~1", "/").replace("~0", "~") - .replace("\\\"", "\"") - .replace("\\\\", "\\"); - } - - public Object queryFrom(Object document) throws JSONPointerException { - if (this.refTokens.isEmpty()) { - return document; - } - Object current = document; - for (String token : this.refTokens) { - if (current instanceof JSONObject) { - current = ((JSONObject) current).opt(unescape(token)); - } else if (current instanceof JSONArray) { - current = readByIndexToken(current, token); - } else { - throw new JSONPointerException(format( - "value [%s] is not an array or object therefore its key %s cannot be resolved", current, - token)); - } - } - return current; - } - - private static Object readByIndexToken(Object current, String indexToken) throws JSONPointerException { - try { - int index = Integer.parseInt(indexToken); - JSONArray currentArr = (JSONArray) current; - if (index >= currentArr.length()) { - throw new JSONPointerException(format("index %s is out of bounds - the array has %d elements", indexToken, - Integer.valueOf(currentArr.length()))); - } - try { - return currentArr.get(index); - } catch (JSONException e) { - throw new JSONPointerException("Error reading value at index position " + index, e); - } - } catch (NumberFormatException e) { - throw new JSONPointerException(format("%s is not an array index", indexToken), e); - } - } - - @Override - public String toString() { - StringBuilder rval = new StringBuilder(""); - for (String token: this.refTokens) { - rval.append('/').append(escape(token)); - } - return rval.toString(); - } - - private static String escape(String token) { - return token.replace("~", "~0") - .replace("/", "~1") - .replace("\\", "\\\\") - .replace("\"", "\\\""); - } - - public String toURIFragment() { - try { - StringBuilder rval = new StringBuilder("#"); - for (String token : this.refTokens) { - rval.append('/').append(URLEncoder.encode(token, ENCODING)); - } - return rval.toString(); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - -} diff --git a/src/ARSCLib/com/reandroid/json/JSONPointerException.java b/src/ARSCLib/com/reandroid/json/JSONPointerException.java deleted file mode 100644 index 218e6611..00000000 --- a/src/ARSCLib/com/reandroid/json/JSONPointerException.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -public class JSONPointerException extends JSONException { - private static final long serialVersionUID = 8872944667561856751L; - - public JSONPointerException(String message) { - super(message); - } - - public JSONPointerException(String message, Throwable cause) { - super(message, cause); - } - -} diff --git a/src/ARSCLib/com/reandroid/json/JSONPropertyIgnore.java b/src/ARSCLib/com/reandroid/json/JSONPropertyIgnore.java deleted file mode 100644 index 160f14a6..00000000 --- a/src/ARSCLib/com/reandroid/json/JSONPropertyIgnore.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -@Documented -@Retention(RUNTIME) -@Target({METHOD}) - -public @interface JSONPropertyIgnore { } diff --git a/src/ARSCLib/com/reandroid/json/JSONPropertyName.java b/src/ARSCLib/com/reandroid/json/JSONPropertyName.java deleted file mode 100644 index 5268dc45..00000000 --- a/src/ARSCLib/com/reandroid/json/JSONPropertyName.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -@Documented -@Retention(RUNTIME) -@Target({METHOD}) - -public @interface JSONPropertyName { - - String value(); -} diff --git a/src/ARSCLib/com/reandroid/json/JSONString.java b/src/ARSCLib/com/reandroid/json/JSONString.java deleted file mode 100644 index a78be929..00000000 --- a/src/ARSCLib/com/reandroid/json/JSONString.java +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -public interface JSONString { - - public String toJSONString(); -} diff --git a/src/ARSCLib/com/reandroid/json/JSONStringer.java b/src/ARSCLib/com/reandroid/json/JSONStringer.java deleted file mode 100644 index a511ff7f..00000000 --- a/src/ARSCLib/com/reandroid/json/JSONStringer.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -import java.io.StringWriter; - -public class JSONStringer extends JSONWriter { - - public JSONStringer() { - super(new StringWriter()); - } - - @Override - public String toString() { - return this.mode == 'd' ? this.writer.toString() : null; - } -} diff --git a/src/ARSCLib/com/reandroid/json/JSONTokener.java b/src/ARSCLib/com/reandroid/json/JSONTokener.java deleted file mode 100644 index 6ea5f398..00000000 --- a/src/ARSCLib/com/reandroid/json/JSONTokener.java +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.StringReader; - -public class JSONTokener { - /** current read character position on the current line. */ - private long character; - /** flag to indicate if the end of the input has been found. */ - private boolean eof; - /** current read index of the input. */ - private long index; - /** current line of the input. */ - private long line; - /** previous character read from the input. */ - private char previous; - /** Reader for the input. */ - private final Reader reader; - /** flag to indicate that a previous character was requested. */ - private boolean usePrevious; - /** the number of characters read in the previous line. */ - private long characterPreviousLine; - public JSONTokener(Reader reader) { - this.reader = reader.markSupported() - ? reader - : new BufferedReader(reader); - this.eof = false; - this.usePrevious = false; - this.previous = 0; - this.index = 0; - this.character = 1; - this.characterPreviousLine = 0; - this.line = 1; - } - public JSONTokener(InputStream inputStream) { - this(new InputStreamReader(inputStream)); - } - public JSONTokener(String s) { - this(new StringReader(s)); - } - public void back() throws JSONException { - if (this.usePrevious || this.index <= 0) { - throw new JSONException("Stepping back two steps is not supported"); - } - this.decrementIndexes(); - this.usePrevious = true; - this.eof = false; - } - - private void decrementIndexes() { - this.index--; - if(this.previous=='\r' || this.previous == '\n') { - this.line--; - this.character=this.characterPreviousLine ; - } else if(this.character > 0){ - this.character--; - } - } - - public static int dehexchar(char c) { - if (c >= '0' && c <= '9') { - return c - '0'; - } - if (c >= 'A' && c <= 'F') { - return c - ('A' - 10); - } - if (c >= 'a' && c <= 'f') { - return c - ('a' - 10); - } - return -1; - } - - public boolean end() { - return this.eof && !this.usePrevious; - } - public boolean more() throws JSONException { - if(this.usePrevious) { - return true; - } - try { - this.reader.mark(1); - } catch (IOException e) { - throw new JSONException("Unable to preserve stream position", e); - } - try { - // -1 is EOF, but next() can not consume the null character '\0' - if(this.reader.read() <= 0) { - this.eof = true; - return false; - } - this.reader.reset(); - } catch (IOException e) { - throw new JSONException("Unable to read the next character from the stream", e); - } - return true; - } - public char next() throws JSONException { - int c; - if (this.usePrevious) { - this.usePrevious = false; - c = this.previous; - } else { - try { - c = this.reader.read(); - } catch (IOException exception) { - throw new JSONException(exception); - } - } - if (c <= 0) { // End of stream - this.eof = true; - return 0; - } - this.incrementIndexes(c); - this.previous = (char) c; - return this.previous; - } - - private void incrementIndexes(int c) { - if(c > 0) { - this.index++; - if(c=='\r') { - this.line++; - this.characterPreviousLine = this.character; - this.character=0; - }else if (c=='\n') { - if(this.previous != '\r') { - this.line++; - this.characterPreviousLine = this.character; - } - this.character=0; - } else { - this.character++; - } - } - } - - public char next(char c) throws JSONException { - char n = this.next(); - if (n != c) { - if(n > 0) { - throw this.syntaxError("Expected '" + c + "' and instead saw '" + - n + "'"); - } - throw this.syntaxError("Expected '" + c + "' and instead saw ''"); - } - return n; - } - public String next(int n) throws JSONException { - if (n == 0) { - return ""; - } - - char[] chars = new char[n]; - int pos = 0; - - while (pos < n) { - chars[pos] = this.next(); - if (this.end()) { - throw this.syntaxError("Substring bounds error"); - } - pos += 1; - } - return new String(chars); - } - public char nextClean() throws JSONException { - for (;;) { - char c = this.next(); - if (c == 0 || c > ' ') { - return c; - } - } - } - public String nextString(char quote) throws JSONException { - char c; - StringBuilder sb = new StringBuilder(); - for (;;) { - c = this.next(); - switch (c) { - case 0: - case '\n': - case '\r': - throw this.syntaxError("Unterminated string"); - case '\\': - c = this.next(); - switch (c) { - case 'b': - sb.append('\b'); - break; - case 't': - sb.append('\t'); - break; - case 'n': - sb.append('\n'); - break; - case 'f': - sb.append('\f'); - break; - case 'r': - sb.append('\r'); - break; - case 'u': - try { - sb.append((char)Integer.parseInt(this.next(4), 16)); - } catch (NumberFormatException e) { - throw this.syntaxError("Illegal escape.", e); - } - break; - case '"': - case '\'': - case '\\': - case '/': - sb.append(c); - break; - default: - throw this.syntaxError("Illegal escape."); - } - break; - default: - if (c == quote) { - return sb.toString(); - } - sb.append(c); - } - } - } - public String nextTo(char delimiter) throws JSONException { - StringBuilder sb = new StringBuilder(); - for (;;) { - char c = this.next(); - if (c == delimiter || c == 0 || c == '\n' || c == '\r') { - if (c != 0) { - this.back(); - } - return sb.toString().trim(); - } - sb.append(c); - } - } - public String nextTo(String delimiters) throws JSONException { - char c; - StringBuilder sb = new StringBuilder(); - for (;;) { - c = this.next(); - if (delimiters.indexOf(c) >= 0 || c == 0 || - c == '\n' || c == '\r') { - if (c != 0) { - this.back(); - } - return sb.toString().trim(); - } - sb.append(c); - } - } - public Object nextValue() throws JSONException { - char c = this.nextClean(); - String string; - - switch (c) { - case '"': - case '\'': - return this.nextString(c); - case '{': - this.back(); - return new JSONObject(this); - case '[': - this.back(); - return new JSONArray(this); - } - - /* - * Handle unquoted text. This could be the values true, false, or - * null, or it can be a number. An implementation (such as this one) - * is allowed to also accept non-standard forms. - * - * Accumulate characters until we reach the end of the text or a - * formatting character. - */ - - StringBuilder sb = new StringBuilder(); - while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) { - sb.append(c); - c = this.next(); - } - if (!this.eof) { - this.back(); - } - - string = sb.toString().trim(); - if ("".equals(string)) { - throw this.syntaxError("Missing value"); - } - return JSONObject.stringToValue(string); - } - public char skipTo(char to) throws JSONException { - char c; - try { - long startIndex = this.index; - long startCharacter = this.character; - long startLine = this.line; - this.reader.mark(1000000); - do { - c = this.next(); - if (c == 0) { - // in some readers, reset() may throw an exception if - // the remaining portion of the input is greater than - // the mark size (1,000,000 above). - this.reader.reset(); - this.index = startIndex; - this.character = startCharacter; - this.line = startLine; - return 0; - } - } while (c != to); - this.reader.mark(1); - } catch (IOException exception) { - throw new JSONException(exception); - } - this.back(); - return c; - } - - public JSONException syntaxError(String message) { - return new JSONException(message + this.toString()); - } - - public JSONException syntaxError(String message, Throwable causedBy) { - return new JSONException(message + this.toString(), causedBy); - } - - @Override - public String toString() { - return " at " + this.index + " [character " + this.character + " line " + - this.line + "]"; - } -} diff --git a/src/ARSCLib/com/reandroid/json/JSONWriter.java b/src/ARSCLib/com/reandroid/json/JSONWriter.java deleted file mode 100644 index 794de4dc..00000000 --- a/src/ARSCLib/com/reandroid/json/JSONWriter.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -import java.io.IOException; -import java.util.Collection; -import java.util.Map; - -public class JSONWriter { - private static final int maxdepth = 200; - - private boolean comma; - - protected char mode; - - private final JSONObject stack[]; - - private int top; - - protected Appendable writer; - - public JSONWriter(Appendable w) { - this.comma = false; - this.mode = 'i'; - this.stack = new JSONObject[maxdepth]; - this.top = 0; - this.writer = w; - } - - private JSONWriter append(String string) throws JSONException { - if (string == null) { - throw new JSONException("Null pointer"); - } - if (this.mode == 'o' || this.mode == 'a') { - try { - if (this.comma && this.mode == 'a') { - this.writer.append(','); - } - this.writer.append(string); - } catch (IOException e) { - // Android as of API 25 does not support this exception constructor - // however we won't worry about it. If an exception is happening here - // it will just throw a "Method not found" exception instead. - throw new JSONException(e); - } - if (this.mode == 'o') { - this.mode = 'k'; - } - this.comma = true; - return this; - } - throw new JSONException("Value out of sequence."); - } - - public JSONWriter array() throws JSONException { - if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') { - this.push(null); - this.append("["); - this.comma = false; - return this; - } - throw new JSONException("Misplaced array."); - } - - private JSONWriter end(char m, char c) throws JSONException { - if (this.mode != m) { - throw new JSONException(m == 'a' - ? "Misplaced endArray." - : "Misplaced endObject."); - } - this.pop(m); - try { - this.writer.append(c); - } catch (IOException e) { - // Android as of API 25 does not support this exception constructor - // however we won't worry about it. If an exception is happening here - // it will just throw a "Method not found" exception instead. - throw new JSONException(e); - } - this.comma = true; - return this; - } - - public JSONWriter endArray() throws JSONException { - return this.end('a', ']'); - } - - public JSONWriter endObject() throws JSONException { - return this.end('k', '}'); - } - - public JSONWriter key(String string) throws JSONException { - if (string == null) { - throw new JSONException("Null key."); - } - if (this.mode == 'k') { - try { - JSONObject topObject = this.stack[this.top - 1]; - // don't use the built in putOnce method to maintain Android support - if(topObject.has(string)) { - throw new JSONException("Duplicate key \"" + string + "\""); - } - topObject.put(string, true); - if (this.comma) { - this.writer.append(','); - } - this.writer.append(JSONObject.quote(string)); - this.writer.append(':'); - this.comma = false; - this.mode = 'o'; - return this; - } catch (IOException e) { - // Android as of API 25 does not support this exception constructor - // however we won't worry about it. If an exception is happening here - // it will just throw a "Method not found" exception instead. - throw new JSONException(e); - } - } - throw new JSONException("Misplaced key."); - } - public JSONWriter object() throws JSONException { - if (this.mode == 'i') { - this.mode = 'o'; - } - if (this.mode == 'o' || this.mode == 'a') { - this.append("{"); - this.push(new JSONObject()); - this.comma = false; - return this; - } - throw new JSONException("Misplaced object."); - - } - private void pop(char c) throws JSONException { - if (this.top <= 0) { - throw new JSONException("Nesting error."); - } - char m = this.stack[this.top - 1] == null ? 'a' : 'k'; - if (m != c) { - throw new JSONException("Nesting error."); - } - this.top -= 1; - this.mode = this.top == 0 - ? 'd' - : this.stack[this.top - 1] == null - ? 'a' - : 'k'; - } - - private void push(JSONObject jo) throws JSONException { - if (this.top >= maxdepth) { - throw new JSONException("Nesting too deep."); - } - this.stack[this.top] = jo; - this.mode = jo == null ? 'a' : 'k'; - this.top += 1; - } - - public static String valueToString(Object value) throws JSONException { - if (value == null || value.equals(null)) { - return "null"; - } - if (value instanceof JSONString) { - String object; - try { - object = ((JSONString) value).toJSONString(); - } catch (Exception e) { - throw new JSONException(e); - } - if (object != null) { - return object; - } - throw new JSONException("Bad value from toJSONString: " + object); - } - if (value instanceof Number) { - // not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex - final String numberAsString = JSONObject.numberToString((Number) value); - if(JSONObject.NUMBER_PATTERN.matcher(numberAsString).matches()) { - // Close enough to a JSON number that we will return it unquoted - return numberAsString; - } - // The Number value is not a valid JSON number. - // Instead we will quote it as a string - return JSONObject.quote(numberAsString); - } - if (value instanceof Boolean || value instanceof JSONObject - || value instanceof JSONArray) { - return value.toString(); - } - if (value instanceof Map) { - Map map = (Map) value; - return new JSONObject(map).toString(); - } - if (value instanceof Collection) { - Collection coll = (Collection) value; - return new JSONArray(coll).toString(); - } - if (value.getClass().isArray()) { - return new JSONArray(value).toString(); - } - if(value instanceof Enum){ - return JSONObject.quote(((Enum)value).name()); - } - return JSONObject.quote(value.toString()); - } - - public JSONWriter value(boolean b) throws JSONException { - return this.append(b ? "true" : "false"); - } - - public JSONWriter value(double d) throws JSONException { - return this.value(Double.valueOf(d)); - } - - public JSONWriter value(long l) throws JSONException { - return this.append(Long.toString(l)); - } - public JSONWriter value(Object object) throws JSONException { - return this.append(valueToString(object)); - } -} diff --git a/src/ARSCLib/com/reandroid/json/JsonUtil.java b/src/ARSCLib/com/reandroid/json/JsonUtil.java deleted file mode 100644 index 91bf1563..00000000 --- a/src/ARSCLib/com/reandroid/json/JsonUtil.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -import java.io.*; -import java.nio.charset.StandardCharsets; - -public class JsonUtil { - - public static void readJSONObject(File file, JSONConvert jsonConvert) throws IOException { - FileInputStream inputStream=new FileInputStream(file); - readJSONObject(inputStream, jsonConvert); - inputStream.close(); - } - public static void readJSONObject(InputStream inputStream, JSONConvert jsonConvert){ - InputStreamReader reader=new InputStreamReader(inputStream, StandardCharsets.UTF_8); - readJSONObject(reader, jsonConvert); - } - public static void readJSONObject(Reader reader, JSONConvert jsonConvert){ - JSONObject jsonObject=new JSONObject(new JSONTokener(reader)); - jsonConvert.fromJson(jsonObject); - } - - public static void readJSONArray(File file, JSONConvert jsonConvert) throws IOException { - FileInputStream inputStream=new FileInputStream(file); - readJSONArray(inputStream, jsonConvert); - inputStream.close(); - } - public static void readJSONArray(InputStream inputStream, JSONConvert jsonConvert){ - InputStreamReader reader=new InputStreamReader(inputStream, StandardCharsets.UTF_8); - readJSONArray(reader, jsonConvert); - } - public static void readJSONArray(Reader reader, JSONConvert jsonConvert){ - JSONArray jsonObject=new JSONArray(new JSONTokener(reader)); - jsonConvert.fromJson(jsonObject); - } - -} diff --git a/src/ARSCLib/com/reandroid/json/Property.java b/src/ARSCLib/com/reandroid/json/Property.java deleted file mode 100644 index c6c2d4d1..00000000 --- a/src/ARSCLib/com/reandroid/json/Property.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -import java.util.Enumeration; -import java.util.Properties; - -public class Property { - - public static JSONObject toJSONObject(java.util.Properties properties) throws JSONException { - // can't use the new constructor for Android support - // JSONObject jo = new JSONObject(properties == null ? 0 : properties.size()); - JSONObject jo = new JSONObject(); - if (properties != null && !properties.isEmpty()) { - Enumeration enumProperties = properties.propertyNames(); - while(enumProperties.hasMoreElements()) { - String name = (String)enumProperties.nextElement(); - jo.put(name, properties.getProperty(name)); - } - } - return jo; - } - - public static Properties toProperties(JSONObject jo) throws JSONException { - Properties properties = new Properties(); - if (jo != null) { - // Don't use the new entrySet API to maintain Android support - for (final String key : jo.keySet()) { - Object value = jo.opt(key); - if (!JSONObject.NULL.equals(value)) { - properties.put(key, value.toString()); - } - } - } - return properties; - } -} diff --git a/src/ARSCLib/com/reandroid/json/XML.java b/src/ARSCLib/com/reandroid/json/XML.java deleted file mode 100644 index a22114ae..00000000 --- a/src/ARSCLib/com/reandroid/json/XML.java +++ /dev/null @@ -1,605 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -import java.io.Reader; -import java.io.StringReader; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.Iterator; -@SuppressWarnings("boxing") -public class XML { - - /** The Character '&'. */ - public static final Character AMP = '&'; - - /** The Character '''. */ - public static final Character APOS = '\''; - - /** The Character '!'. */ - public static final Character BANG = '!'; - - /** The Character '='. */ - public static final Character EQ = '='; - - /** The Character
{@code '>'. }
*/ - public static final Character GT = '>'; - - /** The Character '<'. */ - public static final Character LT = '<'; - - /** The Character '?'. */ - public static final Character QUEST = '?'; - - /** The Character '"'. */ - public static final Character QUOT = '"'; - - /** The Character '/'. */ - public static final Character SLASH = '/'; - - public static final String NULL_ATTR = "xsi:nil"; - - public static final String TYPE_ATTR = "xsi:type"; - - private static Iterable codePointIterator(final String string) { - return new Iterable() { - @Override - public Iterator iterator() { - return new Iterator() { - private int nextIndex = 0; - private int length = string.length(); - - @Override - public boolean hasNext() { - return this.nextIndex < this.length; - } - - @Override - public Integer next() { - int result = string.codePointAt(this.nextIndex); - this.nextIndex += Character.charCount(result); - return result; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - }; - } - - public static String escape(String string) { - StringBuilder sb = new StringBuilder(string.length()); - for (final int cp : codePointIterator(string)) { - switch (cp) { - case '&': - sb.append("&"); - break; - case '<': - sb.append("<"); - break; - case '>': - sb.append(">"); - break; - case '"': - sb.append("""); - break; - case '\'': - sb.append("'"); - break; - default: - if (mustEscape(cp)) { - sb.append("&#x"); - sb.append(Integer.toHexString(cp)); - sb.append(';'); - } else { - sb.appendCodePoint(cp); - } - } - } - return sb.toString(); - } - - private static boolean mustEscape(int cp) { - /* Valid range from https://www.w3.org/TR/REC-xml/#charsets - * - * #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] - * - * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. - */ - // isISOControl is true when (cp >= 0 && cp <= 0x1F) || (cp >= 0x7F && cp <= 0x9F) - // all ISO control characters are out of range except tabs and new lines - return (Character.isISOControl(cp) - && cp != 0x9 - && cp != 0xA - && cp != 0xD - ) || !( - // valid the range of acceptable characters that aren't control - (cp >= 0x20 && cp <= 0xD7FF) - || (cp >= 0xE000 && cp <= 0xFFFD) - || (cp >= 0x10000 && cp <= 0x10FFFF) - ) - ; - } - - public static String unescape(String string) { - StringBuilder sb = new StringBuilder(string.length()); - for (int i = 0, length = string.length(); i < length; i++) { - char c = string.charAt(i); - if (c == '&') { - final int semic = string.indexOf(';', i); - if (semic > i) { - final String entity = string.substring(i + 1, semic); - sb.append(XMLTokener.unescapeEntity(entity)); - // skip past the entity we just parsed. - i += entity.length() + 1; - } else { - // this shouldn't happen in most cases since the parser - // errors on unclosed entries. - sb.append(c); - } - } else { - // not part of an entity - sb.append(c); - } - } - return sb.toString(); - } - - public static void noSpace(String string) throws JSONException { - int i, length = string.length(); - if (length == 0) { - throw new JSONException("Empty string."); - } - for (i = 0; i < length; i += 1) { - if (Character.isWhitespace(string.charAt(i))) { - throw new JSONException("'" + string - + "' contains a space character."); - } - } - } - - private static boolean parse(XMLTokener x, JSONObject context, String name, XMLParserConfiguration config) - throws JSONException { - char c; - int i; - JSONObject jsonObject = null; - String string; - String tagName; - Object token; - XMLXsiTypeConverter xmlXsiTypeConverter; - - // Test for and skip past these forms: - // - // - // - // - // Report errors for these forms: - // <> - // <= - // << - - token = x.nextToken(); - - // "); - return false; - } - x.back(); - } else if (c == '[') { - token = x.nextToken(); - if ("CDATA".equals(token)) { - if (x.next() == '[') { - string = x.nextCDATA(); - if (string.length() > 0) { - context.accumulate(config.getcDataTagName(), string); - } - return false; - } - } - throw x.syntaxError("Expected 'CDATA['"); - } - i = 1; - do { - token = x.nextMeta(); - if (token == null) { - throw x.syntaxError("Missing '>' after ' 0); - return false; - } else if (token == QUEST) { - - // "); - return false; - } else if (token == SLASH) { - - // Close tag - if (x.nextToken() != GT) { - throw x.syntaxError("Misshaped tag"); - } - if (nilAttributeFound) { - context.accumulate(tagName, JSONObject.NULL); - } else if (jsonObject.length() > 0) { - context.accumulate(tagName, jsonObject); - } else { - context.accumulate(tagName, ""); - } - return false; - - } else if (token == GT) { - // Content, between <...> and - for (;;) { - token = x.nextContent(); - if (token == null) { - if (tagName != null) { - throw x.syntaxError("Unclosed tag " + tagName); - } - return false; - } else if (token instanceof String) { - string = (String) token; - if (string.length() > 0) { - if(xmlXsiTypeConverter != null) { - jsonObject.accumulate(config.getcDataTagName(), - stringToValue(string, xmlXsiTypeConverter)); - } else { - jsonObject.accumulate(config.getcDataTagName(), - config.isKeepStrings() ? string : stringToValue(string)); - } - } - - } else if (token == LT) { - // Nested element - if (parse(x, jsonObject, tagName, config)) { - if (jsonObject.length() == 0) { - context.accumulate(tagName, ""); - } else if (jsonObject.length() == 1 - && jsonObject.opt(config.getcDataTagName()) != null) { - context.accumulate(tagName, jsonObject.opt(config.getcDataTagName())); - } else { - context.accumulate(tagName, jsonObject); - } - return false; - } - } - } - } else { - throw x.syntaxError("Misshaped tag"); - } - } - } - } - - public static Object stringToValue(String string, XMLXsiTypeConverter typeConverter) { - if(typeConverter != null) { - return typeConverter.convert(string); - } - return stringToValue(string); - } - - // To maintain compatibility with the Android API, this method is a direct copy of - // the one in JSONObject. Changes made here should be reflected there. - // This method should not make calls out of the XML object. - public static Object stringToValue(String string) { - if ("".equals(string)) { - return string; - } - - // check JSON key words true/false/null - if ("true".equalsIgnoreCase(string)) { - return Boolean.TRUE; - } - if ("false".equalsIgnoreCase(string)) { - return Boolean.FALSE; - } - if ("null".equalsIgnoreCase(string)) { - return JSONObject.NULL; - } - - /* - * If it might be a number, try converting it. If a number cannot be - * produced, then the value will just be a string. - */ - - char initial = string.charAt(0); - if ((initial >= '0' && initial <= '9') || initial == '-') { - try { - return stringToNumber(string); - } catch (Exception ignore) { - } - } - return string; - } - - - private static Number stringToNumber(final String val) throws NumberFormatException { - char initial = val.charAt(0); - if ((initial >= '0' && initial <= '9') || initial == '-') { - // decimal representation - if (isDecimalNotation(val)) { - // Use a BigDecimal all the time so we keep the original - // representation. BigDecimal doesn't support -0.0, ensure we - // keep that by forcing a decimal. - try { - BigDecimal bd = new BigDecimal(val); - if(initial == '-' && BigDecimal.ZERO.compareTo(bd)==0) { - return Double.valueOf(-0.0); - } - return bd; - } catch (NumberFormatException retryAsDouble) { - // this is to support "Hex Floats" like this: 0x1.0P-1074 - try { - Double d = Double.valueOf(val); - if(d.isNaN() || d.isInfinite()) { - throw new NumberFormatException("val ["+val+"] is not a valid number."); - } - return d; - } catch (NumberFormatException ignore) { - throw new NumberFormatException("val ["+val+"] is not a valid number."); - } - } - } - // block items like 00 01 etc. Java number parsers treat these as Octal. - if(initial == '0' && val.length() > 1) { - char at1 = val.charAt(1); - if(at1 >= '0' && at1 <= '9') { - throw new NumberFormatException("val ["+val+"] is not a valid number."); - } - } else if (initial == '-' && val.length() > 2) { - char at1 = val.charAt(1); - char at2 = val.charAt(2); - if(at1 == '0' && at2 >= '0' && at2 <= '9') { - throw new NumberFormatException("val ["+val+"] is not a valid number."); - } - } - // integer representation. - // This will narrow any values to the smallest reasonable Object representation - // (Integer, Long, or BigInteger) - - // BigInteger down conversion: We use a similar bitLenth compare as - // BigInteger#intValueExact uses. Increases GC, but objects hold - // only what they need. i.e. Less runtime overhead if the value is - // long lived. - BigInteger bi = new BigInteger(val); - if(bi.bitLength() <= 31){ - return Integer.valueOf(bi.intValue()); - } - if(bi.bitLength() <= 63){ - return Long.valueOf(bi.longValue()); - } - return bi; - } - throw new NumberFormatException("val ["+val+"] is not a valid number."); - } - - - private static boolean isDecimalNotation(final String val) { - return val.indexOf('.') > -1 || val.indexOf('e') > -1 - || val.indexOf('E') > -1 || "-0".equals(val); - } - public static JSONObject toJSONObject(String string) throws JSONException { - return toJSONObject(string, XMLParserConfiguration.ORIGINAL); - } - - public static JSONObject toJSONObject(Reader reader) throws JSONException { - return toJSONObject(reader, XMLParserConfiguration.ORIGINAL); - } - - public static JSONObject toJSONObject(Reader reader, boolean keepStrings) throws JSONException { - if(keepStrings) { - return toJSONObject(reader, XMLParserConfiguration.KEEP_STRINGS); - } - return toJSONObject(reader, XMLParserConfiguration.ORIGINAL); - } - - public static JSONObject toJSONObject(Reader reader, XMLParserConfiguration config) throws JSONException { - JSONObject jo = new JSONObject(); - XMLTokener x = new XMLTokener(reader); - while (x.more()) { - x.skipPast("<"); - if(x.more()) { - parse(x, jo, null, config); - } - } - return jo; - } - - public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { - return toJSONObject(new StringReader(string), keepStrings); - } - - public static JSONObject toJSONObject(String string, XMLParserConfiguration config) throws JSONException { - return toJSONObject(new StringReader(string), config); - } - - public static String toString(Object object) throws JSONException { - return toString(object, null, XMLParserConfiguration.ORIGINAL); - } - - public static String toString(final Object object, final String tagName) { - return toString(object, tagName, XMLParserConfiguration.ORIGINAL); - } - - public static String toString(final Object object, final String tagName, final XMLParserConfiguration config) - throws JSONException { - StringBuilder sb = new StringBuilder(); - JSONArray ja; - JSONObject jo; - String string; - - if (object instanceof JSONObject) { - - // Emit - if (tagName != null) { - sb.append('<'); - sb.append(tagName); - sb.append('>'); - } - - // Loop thru the keys. - // don't use the new entrySet accessor to maintain Android Support - jo = (JSONObject) object; - for (final String key : jo.keySet()) { - Object value = jo.opt(key); - if (value == null) { - value = ""; - } else if (value.getClass().isArray()) { - value = new JSONArray(value); - } - - // Emit content in body - if (key.equals(config.getcDataTagName())) { - if (value instanceof JSONArray) { - ja = (JSONArray) value; - int jaLength = ja.length(); - // don't use the new iterator API to maintain support for Android - for (int i = 0; i < jaLength; i++) { - if (i > 0) { - sb.append('\n'); - } - Object val = ja.opt(i); - sb.append(escape(val.toString())); - } - } else { - sb.append(escape(value.toString())); - } - - // Emit an array of similar keys - - } else if (value instanceof JSONArray) { - ja = (JSONArray) value; - int jaLength = ja.length(); - // don't use the new iterator API to maintain support for Android - for (int i = 0; i < jaLength; i++) { - Object val = ja.opt(i); - if (val instanceof JSONArray) { - sb.append('<'); - sb.append(key); - sb.append('>'); - sb.append(toString(val, null, config)); - sb.append("'); - } else { - sb.append(toString(val, key, config)); - } - } - } else if ("".equals(value)) { - sb.append('<'); - sb.append(key); - sb.append("/>"); - - // Emit a new tag - - } else { - sb.append(toString(value, key, config)); - } - } - if (tagName != null) { - - // Emit the close tag - sb.append("'); - } - return sb.toString(); - - } - - if (object != null && (object instanceof JSONArray || object.getClass().isArray())) { - if(object.getClass().isArray()) { - ja = new JSONArray(object); - } else { - ja = (JSONArray) object; - } - int jaLength = ja.length(); - // don't use the new iterator API to maintain support for Android - for (int i = 0; i < jaLength; i++) { - Object val = ja.opt(i); - // XML does not have good support for arrays. If an array - // appears in a place where XML is lacking, synthesize an - // element. - sb.append(toString(val, tagName == null ? "array" : tagName, config)); - } - return sb.toString(); - } - - string = (object == null) ? "null" : escape(object.toString()); - return (tagName == null) ? "\"" + string + "\"" - : (string.length() == 0) ? "<" + tagName + "/>" : "<" + tagName - + ">" + string + ""; - - } -} diff --git a/src/ARSCLib/com/reandroid/json/XMLParserConfiguration.java b/src/ARSCLib/com/reandroid/json/XMLParserConfiguration.java deleted file mode 100644 index a1da111b..00000000 --- a/src/ARSCLib/com/reandroid/json/XMLParserConfiguration.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -@SuppressWarnings({""}) -public class XMLParserConfiguration { - /** Original Configuration of the XML Parser. */ - public static final XMLParserConfiguration ORIGINAL - = new XMLParserConfiguration(); - /** Original configuration of the XML Parser except that values are kept as strings. */ - public static final XMLParserConfiguration KEEP_STRINGS - = new XMLParserConfiguration().withKeepStrings(true); - - private boolean keepStrings; - - - private String cDataTagName; - - - private boolean convertNilAttributeToNull; - - private Map> xsiTypeMap; - - public XMLParserConfiguration() { - this.keepStrings = false; - this.cDataTagName = "content"; - this.convertNilAttributeToNull = false; - this.xsiTypeMap = Collections.emptyMap(); - } - - @Deprecated - public XMLParserConfiguration(final boolean keepStrings) { - this(keepStrings, "content", false); - } - - @Deprecated - public XMLParserConfiguration(final String cDataTagName) { - this(false, cDataTagName, false); - } - - @Deprecated - public XMLParserConfiguration(final boolean keepStrings, final String cDataTagName) { - this.keepStrings = keepStrings; - this.cDataTagName = cDataTagName; - this.convertNilAttributeToNull = false; - } - - @Deprecated - public XMLParserConfiguration(final boolean keepStrings, final String cDataTagName, final boolean convertNilAttributeToNull) { - this.keepStrings = keepStrings; - this.cDataTagName = cDataTagName; - this.convertNilAttributeToNull = convertNilAttributeToNull; - } - - private XMLParserConfiguration(final boolean keepStrings, final String cDataTagName, - final boolean convertNilAttributeToNull, final Map> xsiTypeMap ) { - this.keepStrings = keepStrings; - this.cDataTagName = cDataTagName; - this.convertNilAttributeToNull = convertNilAttributeToNull; - this.xsiTypeMap = Collections.unmodifiableMap(xsiTypeMap); - } - - @Override - protected XMLParserConfiguration clone() { - // future modifications to this method should always ensure a "deep" - // clone in the case of collections. i.e. if a Map is added as a configuration - // item, a new map instance should be created and if possible each value in the - // map should be cloned as well. If the values of the map are known to also - // be immutable, then a shallow clone of the map is acceptable. - return new XMLParserConfiguration( - this.keepStrings, - this.cDataTagName, - this.convertNilAttributeToNull, - this.xsiTypeMap - ); - } - - - public boolean isKeepStrings() { - return this.keepStrings; - } - - public XMLParserConfiguration withKeepStrings(final boolean newVal) { - XMLParserConfiguration newConfig = this.clone(); - newConfig.keepStrings = newVal; - return newConfig; - } - - public String getcDataTagName() { - return this.cDataTagName; - } - - public XMLParserConfiguration withcDataTagName(final String newVal) { - XMLParserConfiguration newConfig = this.clone(); - newConfig.cDataTagName = newVal; - return newConfig; - } - - public boolean isConvertNilAttributeToNull() { - return this.convertNilAttributeToNull; - } - - public XMLParserConfiguration withConvertNilAttributeToNull(final boolean newVal) { - XMLParserConfiguration newConfig = this.clone(); - newConfig.convertNilAttributeToNull = newVal; - return newConfig; - } - - public Map> getXsiTypeMap() { - return this.xsiTypeMap; - } - - public XMLParserConfiguration withXsiTypeMap(final Map> xsiTypeMap) { - XMLParserConfiguration newConfig = this.clone(); - Map> cloneXsiTypeMap = new HashMap>(xsiTypeMap); - newConfig.xsiTypeMap = Collections.unmodifiableMap(cloneXsiTypeMap); - return newConfig; - } -} diff --git a/src/ARSCLib/com/reandroid/json/XMLTokener.java b/src/ARSCLib/com/reandroid/json/XMLTokener.java deleted file mode 100644 index f0c45749..00000000 --- a/src/ARSCLib/com/reandroid/json/XMLTokener.java +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -import java.io.Reader; - -public class XMLTokener extends JSONTokener { - - /** The table of entity values. It initially contains Character values for - * amp, apos, gt, lt, quot. - */ - public static final java.util.HashMap entity; - - static { - entity = new java.util.HashMap(8); - entity.put("amp", XML.AMP); - entity.put("apos", XML.APOS); - entity.put("gt", XML.GT); - entity.put("lt", XML.LT); - entity.put("quot", XML.QUOT); - } - - public XMLTokener(Reader r) { - super(r); - } - - public XMLTokener(String s) { - super(s); - } - - public String nextCDATA() throws JSONException { - char c; - int i; - StringBuilder sb = new StringBuilder(); - while (more()) { - c = next(); - sb.append(c); - i = sb.length() - 3; - if (i >= 0 && sb.charAt(i) == ']' && - sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>') { - sb.setLength(i); - return sb.toString(); - } - } - throw syntaxError("Unclosed CDATA"); - } - public Object nextContent() throws JSONException { - char c; - StringBuilder sb; - do { - c = next(); - } while (Character.isWhitespace(c)); - if (c == 0) { - return null; - } - if (c == '<') { - return XML.LT; - } - sb = new StringBuilder(); - for (;;) { - if (c == 0) { - return sb.toString().trim(); - } - if (c == '<') { - back(); - return sb.toString().trim(); - } - if (c == '&') { - sb.append(nextEntity(c)); - } else { - sb.append(c); - } - c = next(); - } - } - public Object nextEntity(@SuppressWarnings("unused") char ampersand) throws JSONException { - StringBuilder sb = new StringBuilder(); - for (;;) { - char c = next(); - if (Character.isLetterOrDigit(c) || c == '#') { - sb.append(Character.toLowerCase(c)); - } else if (c == ';') { - break; - } else { - throw syntaxError("Missing ';' in XML entity: &" + sb); - } - } - String string = sb.toString(); - return unescapeEntity(string); - } - - - static String unescapeEntity(String e) { - // validate - if (e == null || e.isEmpty()) { - return ""; - } - // if our entity is an encoded unicode point, parse it. - if (e.charAt(0) == '#') { - int cp; - if (e.charAt(1) == 'x' || e.charAt(1) == 'X') { - // hex encoded unicode - cp = Integer.parseInt(e.substring(2), 16); - } else { - // decimal encoded unicode - cp = Integer.parseInt(e.substring(1)); - } - return new String(new int[] {cp},0,1); - } - Character knownEntity = entity.get(e); - if(knownEntity==null) { - // we don't know the entity so keep it encoded - return '&' + e + ';'; - } - return knownEntity.toString(); - } - public Object nextMeta() throws JSONException { - char c; - char q; - do { - c = next(); - } while (Character.isWhitespace(c)); - switch (c) { - case 0: - throw syntaxError("Misshaped meta tag"); - case '<': - return XML.LT; - case '>': - return XML.GT; - case '/': - return XML.SLASH; - case '=': - return XML.EQ; - case '!': - return XML.BANG; - case '?': - return XML.QUEST; - case '"': - case '\'': - q = c; - for (;;) { - c = next(); - if (c == 0) { - throw syntaxError("Unterminated string"); - } - if (c == q) { - return Boolean.TRUE; - } - } - default: - for (;;) { - c = next(); - if (Character.isWhitespace(c)) { - return Boolean.TRUE; - } - switch (c) { - case 0: - throw syntaxError("Unterminated string"); - case '<': - case '>': - case '/': - case '=': - case '!': - case '?': - case '"': - case '\'': - back(); - return Boolean.TRUE; - } - } - } - } - public Object nextToken() throws JSONException { - char c; - char q; - StringBuilder sb; - do { - c = next(); - } while (Character.isWhitespace(c)); - switch (c) { - case 0: - throw syntaxError("Misshaped element"); - case '<': - throw syntaxError("Misplaced '<'"); - case '>': - return XML.GT; - case '/': - return XML.SLASH; - case '=': - return XML.EQ; - case '!': - return XML.BANG; - case '?': - return XML.QUEST; - -// Quoted string - - case '"': - case '\'': - q = c; - sb = new StringBuilder(); - for (;;) { - c = next(); - if (c == 0) { - throw syntaxError("Unterminated string"); - } - if (c == q) { - return sb.toString(); - } - if (c == '&') { - sb.append(nextEntity(c)); - } else { - sb.append(c); - } - } - default: - -// Name - - sb = new StringBuilder(); - for (;;) { - sb.append(c); - c = next(); - if (Character.isWhitespace(c)) { - return sb.toString(); - } - switch (c) { - case 0: - return sb.toString(); - case '>': - case '/': - case '=': - case '!': - case '?': - case '[': - case ']': - back(); - return sb.toString(); - case '<': - case '"': - case '\'': - throw syntaxError("Bad character in a name"); - } - } - } - } - // The Android implementation of JSONTokener has a public method of public void skipPast(String to) - // even though ours does not have that method, to have API compatibility, our method in the subclass - // should match. - public void skipPast(String to) { - boolean b; - char c; - int i; - int j; - int offset = 0; - int length = to.length(); - char[] circle = new char[length]; - - /* - * First fill the circle buffer with as many characters as are in the - * to string. If we reach an early end, bail. - */ - - for (i = 0; i < length; i += 1) { - c = next(); - if (c == 0) { - return; - } - circle[i] = c; - } - - /* We will loop, possibly for all of the remaining characters. */ - - for (;;) { - j = offset; - b = true; - - /* Compare the circle buffer with the to string. */ - - for (i = 0; i < length; i += 1) { - if (circle[j] != to.charAt(i)) { - b = false; - break; - } - j += 1; - if (j >= length) { - j -= length; - } - } - - /* If we exit the loop with b intact, then victory is ours. */ - - if (b) { - return; - } - - /* Get the next character. If there isn't one, then defeat is ours. */ - - c = next(); - if (c == 0) { - return; - } - /* - * Shove the character in the circle buffer and advance the - * circle offset. The offset is mod n. - */ - circle[offset] = c; - offset += 1; - if (offset >= length) { - offset -= length; - } - } - } -} diff --git a/src/ARSCLib/com/reandroid/json/XMLXsiTypeConverter.java b/src/ARSCLib/com/reandroid/json/XMLXsiTypeConverter.java deleted file mode 100644 index af9ef099..00000000 --- a/src/ARSCLib/com/reandroid/json/XMLXsiTypeConverter.java +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright (c) 2002 JSON.org (now "Public Domain") - * This is NOT property of REAndroid - * This package is renamed from org.json.* to avoid class conflict when used on anroid platforms -*/ -package com.reandroid.json; - -public interface XMLXsiTypeConverter { - T convert(String value); -} diff --git a/src/ARSCLib/com/reandroid/xml/ElementWriter.java b/src/ARSCLib/com/reandroid/xml/ElementWriter.java deleted file mode 100755 index 8676f9b2..00000000 --- a/src/ARSCLib/com/reandroid/xml/ElementWriter.java +++ /dev/null @@ -1,79 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml; - -import java.io.IOException; -import java.io.Writer; - -class ElementWriter extends Writer { - private final Writer mWriter; - private final long mMaxLen; - private final boolean mUnlimitedLength; - private long mCurrentLength; - private boolean mLengthFinished; - ElementWriter(Writer writer, long maxLen){ - mWriter=writer; - this.mMaxLen=maxLen; - this.mUnlimitedLength=maxLen<0; - } - ElementWriter(Writer writer){ - this(writer, -1); - } - boolean isFinished(){ - return mLengthFinished; - } - private boolean mInterruptedWritten; - void writeInterrupted(){ - if(!mLengthFinished){ - return; - } - if(mInterruptedWritten){ - return; - } - mInterruptedWritten=true; - String txt="\n .\n .\n .\n more items ...\n"; - try { - mWriter.write(txt); - } catch (IOException e) { - } - } - @Override - public void write(char[] chars, int i, int i1) throws IOException { - updateCurrentLength(i1); - mWriter.write(chars, i, i1); - } - - @Override - public void flush() throws IOException { - mWriter.flush(); - } - @Override - public void close() throws IOException { - mWriter.close(); - } - private boolean updateCurrentLength(int len){ - if(mUnlimitedLength){ - return false; - } - if(mLengthFinished){ - mLengthFinished=true; - //return true; - } - mCurrentLength+=len; - mLengthFinished=mCurrentLength>=mMaxLen; - return mLengthFinished; - } -} diff --git a/src/ARSCLib/com/reandroid/xml/NameSpaceItem.java b/src/ARSCLib/com/reandroid/xml/NameSpaceItem.java deleted file mode 100755 index 392dd8f2..00000000 --- a/src/ARSCLib/com/reandroid/xml/NameSpaceItem.java +++ /dev/null @@ -1,156 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class NameSpaceItem { - private String prefix; - private String namespaceUri; - public NameSpaceItem(String prefix, String nsUri){ - this.prefix=prefix; - this.namespaceUri=nsUri; - validate(); - } - public String toAttributeName(){ - return ATTR_PREFIX+":"+prefix; - } - public SchemaAttr toSchemaAttribute(){ - return new SchemaAttr(getPrefix(), getNamespaceUri()); - } - public boolean isPrefixEqual(String p){ - if(XMLUtil.isEmpty(prefix)){ - return false; - } - return prefix.equals(p); - } - public boolean isUriEqual(String nsUri){ - if(XMLUtil.isEmpty(namespaceUri)){ - return false; - } - return namespaceUri.equals(nsUri); - } - public boolean isValid(){ - return isPrefixValid() && isUriValid(); - } - private boolean validate(){ - boolean preOk=isPrefixValid(); - boolean uriOk=isUriValid(); - if(preOk && uriOk){ - if(!NAME_ANDROID.equals(prefix) && URI_ANDROID.equals(namespaceUri)){ - namespaceUri= URI_APP; - } - return true; - } - if(!preOk && !uriOk){ - return false; - } - if(!preOk){ - if(URI_ANDROID.equals(namespaceUri)){ - prefix= NAME_ANDROID; - }else { - prefix= NAME_APP; - } - } - if(!uriOk){ - if(NAME_ANDROID.equals(prefix)){ - namespaceUri= URI_ANDROID; - }else { - namespaceUri= URI_APP; - } - } - return true; - } - private boolean isPrefixValid(){ - return !XMLUtil.isEmpty(prefix); - } - private boolean isUriValid(){ - if(XMLUtil.isEmpty(namespaceUri)){ - return false; - } - Matcher matcher=PATTERN_URI.matcher(namespaceUri); - return matcher.find(); - } - public String getNamespaceUri() { - return namespaceUri; - } - public String getPrefix() { - return prefix; - } - public void setNamespaceUri(String namespaceUri) { - this.namespaceUri = namespaceUri; - validate(); - } - public void setPrefix(String prefix) { - this.prefix = prefix; - validate(); - } - @Override - public boolean equals(Object o){ - if(o instanceof NameSpaceItem){ - return isUriEqual(((NameSpaceItem)o).namespaceUri); - } - return false; - } - @Override - public int hashCode(){ - String u=namespaceUri; - if(u==null){ - u=""; - } - return u.hashCode(); - } - @Override - public String toString(){ - StringBuilder builder=new StringBuilder(); - boolean appendOnce=false; - if(namespaceUri!=null){ - builder.append(namespaceUri); - appendOnce=true; - } - if(prefix!=null){ - if(appendOnce){ - builder.append(':'); - } - builder.append(prefix); - } - return builder.toString(); - } - private static NameSpaceItem ns_android; - private static NameSpaceItem ns_app; - public static NameSpaceItem getAndroid(){ - if(ns_android==null){ - ns_android=new NameSpaceItem(NAME_ANDROID, URI_ANDROID); - } - return ns_android; - } - public static NameSpaceItem getApp(){ - if(ns_app==null){ - ns_app=new NameSpaceItem(NAME_APP, URI_APP); - } - return ns_app; - } - private static final Pattern PATTERN_URI=Pattern.compile("^https?://[^\\s/]+/[^\\s]+$"); - - - private static final String ATTR_PREFIX = "xmlns"; - private static final String URI_ANDROID = "http://schemas.android.com/apk/res/android"; - private static final String URI_APP = "http://schemas.android.com/apk/res-auto"; - private static final String NAME_ANDROID = "android"; - private static final String NAME_APP = "app"; - -} diff --git a/src/ARSCLib/com/reandroid/xml/SchemaAttr.java b/src/ARSCLib/com/reandroid/xml/SchemaAttr.java deleted file mode 100755 index 74933a79..00000000 --- a/src/ARSCLib/com/reandroid/xml/SchemaAttr.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class SchemaAttr extends XMLAttribute { - private static final String DEFAULT_XMLNS="xmlns"; - private String mXmlns; - private String mPrefix; - public SchemaAttr(String prefix, String uri) { - this(DEFAULT_XMLNS, prefix, uri); - } - public SchemaAttr(String xmlns, String prefix, String uri) { - super(prefix, uri); - this.set(xmlns, prefix, uri); - } - private void set(String xmlns, String prefix, String uri){ - setXmlns(xmlns); - if(XMLUtil.isEmpty(prefix)){ - prefix=null; - } - setName(prefix); - setUri(uri); - } - @Override - public void setName(String fullName){ - if(fullName==null){ - setPrefix(null); - return; - } - int i=fullName.indexOf(':'); - if(i>0 && i0){ - return mName.substring(0,i); - } - return null; - } - public String getNameWoPrefix(){ - int i=mName.indexOf(":"); - if(i>0){ - return mName.substring(i+1); - } - return mName; - } - public String getValue(){ - if(mValue==null){ - mValue=""; - } - return mValue; - } - public int getValueInt(){ - long l=Long.decode(getValue()); - return (int)l; - } - public boolean getValueBool(){ - String str=getValue().toLowerCase(); - if("true".equals(str)){ - return true; - } - return false; - } - public boolean isValueBool(){ - String str=getValue().toLowerCase(); - if("true".equals(str)){ - return true; - } - return "false".equals(str); - } - public void setName(String name){ - mName=name; - } - public void setValue(String val){ - mValue= XMLUtil.escapeXmlChars(val); - } - - @Override - public boolean write(Writer writer, boolean newLineAttributes) throws IOException { - writer.write(getName()); - writer.write("=\""); - String val= XMLUtil.trimQuote(getValue()); - val= XMLUtil.escapeXmlChars(val); - val= XMLUtil.escapeQuote(val); - writer.write(val); - writer.write('"'); - return true; - } - @Override - public String toText(int indent, boolean newLineAttributes) { - StringWriter writer=new StringWriter(); - try { - write(writer); - } catch (IOException ignored) { - } - writer.flush(); - return writer.toString(); - } - @Override - public int hashCode(){ - String name=getName(); - if(name==null){ - name=""; - } - return name.hashCode(); - } - @Override - public boolean equals(Object obj){ - if(obj instanceof XMLAttribute){ - XMLAttribute attr=(XMLAttribute)obj; - return getName().equals(attr.getName()); - } - return false; - } - @Override - public String toString(){ - return toText(); - } -} diff --git a/src/ARSCLib/com/reandroid/xml/XMLComment.java b/src/ARSCLib/com/reandroid/xml/XMLComment.java deleted file mode 100755 index ebddc585..00000000 --- a/src/ARSCLib/com/reandroid/xml/XMLComment.java +++ /dev/null @@ -1,86 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml; - - -import java.io.IOException; -import java.io.Writer; - -public class XMLComment extends XMLElement { - private String mStart; - private String mEnd; - private boolean mIsHidden; - public XMLComment(String commentText){ - this(); - setCommentText(commentText); - } - public XMLComment(){ - super(); - initializeStartEnd(); - } - - public void setHidden(boolean hide){ - mIsHidden=hide; - } - public boolean isHidden(){ - return mIsHidden; - } - public void setCommentText(String text){ - setTextContent(text); - } - public String getCommentText(){ - return getTextContent(); - } - private void initializeStartEnd(){ - setTagName(""); - mStart=""; - setStart(mStart); - setEnd(mEnd); - setStartPrefix(""); - setEndPrefix(""); - } - @Override - int getChildIndent(){ - return getIndent(); - } - @Override - boolean isEmpty(){ - return XMLUtil.isEmpty(getTextContent()); - } - - - void buildTextContent(Writer writer) throws IOException{ - } - @Override - public boolean write(Writer writer, boolean newLineAttributes) throws IOException { - if(isHidden()){ - return false; - } - if(isEmpty()){ - return false; - } - boolean appendOnce=appendComments(writer); - if(appendOnce){ - writer.write(XMLUtil.NEW_LINE); - } - appendIndentText(writer); - writer.write(mStart); - writer.write(getCommentText()); - writer.write(mEnd); - return true; - } -} diff --git a/src/ARSCLib/com/reandroid/xml/XMLDocument.java b/src/ARSCLib/com/reandroid/xml/XMLDocument.java deleted file mode 100755 index 128b1646..00000000 --- a/src/ARSCLib/com/reandroid/xml/XMLDocument.java +++ /dev/null @@ -1,254 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml; - -import com.reandroid.xml.parser.XMLDocumentParser; -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.util.Comparator; - -public class XMLDocument extends XMLNode{ - private XMLElement mDocumentElement; - private Object mTag; - private String mName; - private String mConfigName; - private float mIndentScale; - private XmlHeaderElement mHeaderElement; - private Object mLastElementSorter; - public XMLDocument(String elementName){ - this(); - XMLElement docElem=new XMLElement(elementName); - setDocumentElement(docElem); - } - public XMLDocument(){ - mIndentScale=0.5f; - mHeaderElement = new XmlHeaderElement(); - } - public void setHeaderElement(XmlHeaderElement headerElement){ - this.mHeaderElement=headerElement; - } - public void hideComments(boolean hide){ - hideComments(true, hide); - } - public void hideComments(boolean recursive, boolean hide){ - if(mDocumentElement==null){ - return; - } - mDocumentElement.hideComments(recursive, hide); - } - public XmlHeaderElement getHeaderElement(){ - return mHeaderElement; - } - - public void sortDocumentElement(Comparator comparator){ - if(mDocumentElement==null||comparator==null){ - return; - } - if(mLastElementSorter !=null){ - if(mLastElementSorter.getClass().equals(comparator.getClass())){ - return; - } - } - mLastElementSorter=comparator; - mDocumentElement.sortChildes(comparator); - } - public void setIndentScalePercent(int val){ - int percent; - if(val>100){ - percent=100; - }else if(val<0){ - percent=0; - }else { - percent=val; - } - mIndentScale=percent/100.0f; - XMLElement docElem=getDocumentElement(); - if(docElem!=null){ - docElem.setIndentScale(mIndentScale); - } - } - public String getName(){ - return mName; - } - public String getConfigName(){ - return mConfigName; - } - public void setName(String name){ - mName=name; - } - public void setConfigName(String configName){ - mConfigName=configName; - } - public Object getTag(){ - return mTag; - } - public void setTag(Object obj){ - mTag=obj; - } - public XMLElement createElement(String tag) { - XMLElement docEl=getDocumentElement(); - if(docEl==null){ - docEl=new XMLElement(tag); - setDocumentElement(docEl); - return docEl; - } - XMLElement baseElement=docEl.createElement(tag); - return baseElement; - } - public XMLElement getDocumentElement(){ - return mDocumentElement; - } - public void setDocumentElement(XMLElement baseElement){ - mDocumentElement=baseElement; - if(baseElement!=null){ - baseElement.setIndentScale(mIndentScale); - } - } - private String getElementString(boolean newLineAttributes){ - XMLElement baseElement=getDocumentElement(); - if(baseElement==null){ - return null; - } - return baseElement.toString(); - } - private boolean appendDocumentElement(Writer writer, boolean newLineAttributes) throws IOException { - if(mDocumentElement==null){ - return false; - } - return mDocumentElement.write(writer, newLineAttributes); - } - private boolean appendDocumentAttribute(Writer writer) throws IOException { - XmlHeaderElement headerElement=getHeaderElement(); - if(headerElement==null){ - return false; - } - return headerElement.write(writer, false); - } - public boolean saveAndroidResource(File file) throws IOException{ - if(file==null){ - throw new IOException("File is null"); - } - File dir=file.getParentFile(); - if(!dir.exists()){ - dir.mkdirs(); - } - FileOutputStream out=new FileOutputStream(file,false); - return saveAndroidResource(out); - } - public boolean saveAndroidValuesResource(File file) throws IOException{ - if(file==null){ - throw new IOException("File is null"); - } - File dir=file.getParentFile(); - if(!dir.exists()){ - dir.mkdirs(); - } - FileOutputStream out=new FileOutputStream(file,false); - return saveAndroidValuesResource(out); - } - public boolean saveAndroidResource(OutputStream out) throws IOException{ - setIndent(1); - hideComments(true); - return save(out, true); - } - public boolean saveAndroidValuesResource(OutputStream out) throws IOException{ - setIndent(1); - //hideComments(true); - return save(out, false); - } - - public boolean save(OutputStream out, boolean newLineAttributes) throws IOException{ - OutputStreamWriter writer=new OutputStreamWriter(out, StandardCharsets.UTF_8); - boolean result= write(writer, newLineAttributes); - writer.flush(); - writer.close(); - return result; - } - public boolean save(File file, boolean newLineAttributes) throws IOException{ - File dir=file.getParentFile(); - if(dir!=null&&!dir.exists()){ - dir.mkdirs(); - } - setIndent(1); - FileWriter writer=new FileWriter(file,false); - boolean result= write(writer, newLineAttributes); - writer.flush(); - writer.close(); - return result; - } - @Override - public boolean write(Writer writer, boolean newLineAttributes) throws IOException{ - boolean has_header=appendDocumentAttribute(writer); - if(has_header){ - writer.write(XMLUtil.NEW_LINE); - } - return appendDocumentElement(writer, newLineAttributes); - } - @Override - public String toText(int indent, boolean newLineAttributes){ - StringWriter writer=new StringWriter(); - setIndent(indent); - try { - write(writer, newLineAttributes); - writer.flush(); - writer.close(); - } catch (IOException ignored) { - } - return writer.toString(); - } - - @Override - public String toString(){ - StringWriter strWriter=new StringWriter(); - ElementWriter writer=new ElementWriter(strWriter, XMLElement.DEBUG_TO_STRING); - try { - write(writer, false); - } catch (IOException e) { - } - strWriter.flush(); - return strWriter.toString(); - } - public static XMLDocument load(String text) throws XMLException { - XMLDocumentParser parser=new XMLDocumentParser(text); - return parser.parse(); - } - public static XMLDocument load(InputStream in) throws XMLException { - if(in==null){ - throw new XMLException("InputStream=null"); - } - XMLDocumentParser parser=new XMLDocumentParser(in); - return parser.parse(); - } - public static XMLDocument load(File file) throws XMLException { - XMLDocumentParser parser=new XMLDocumentParser(file); - XMLDocument resDocument=parser.parse(); - if(resDocument!=null){ - if(resDocument.getTag()==null){ - resDocument.setTag(file); - } - } - return resDocument; - } - - public void setIndent(int indent){ - XMLElement docEle=getDocumentElement(); - if(docEle==null){ - return; - } - docEle.setIndent(indent); - } - -} diff --git a/src/ARSCLib/com/reandroid/xml/XMLElement.java b/src/ARSCLib/com/reandroid/xml/XMLElement.java deleted file mode 100755 index 0477f2b2..00000000 --- a/src/ARSCLib/com/reandroid/xml/XMLElement.java +++ /dev/null @@ -1,789 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml; - - -import com.reandroid.xml.parser.XMLSpanParser; - -import java.io.IOException; -import java.io.StringWriter; -import java.io.Writer; -import java.util.*; - -public class XMLElement extends XMLNode{ - static final long DEBUG_TO_STRING=500; - private String mTagName; - private final LinkedHashMap mAttributes = new LinkedHashMap<>(); - private final List mChildElements = new ArrayList<>(); - private final List mComments = new ArrayList<>(); - private final List mTexts = new ArrayList<>(); - private XMLElement mParent; - private int mIndent; - private float mAttributeIndentScale = 1.0f; - private Object mTag; - private int mResId; - private float mIndentScale; - private String mStart; - private String mStartPrefix; - private String mEnd; - private String mEndPrefix; - private Set nameSpaceItems; - public XMLElement(String tagName){ - this(); - setTagName(tagName); - } - public XMLElement(){ - setDefaultStartEnd(); - } - - public void addText(XMLText text){ - addTextInternal(text, true); - } - private void addTextInternal(XMLText text, boolean addSupper){ - if(text==null){ - return; - } - mTexts.add(text); - if(addSupper){ - super.addChildNodeInternal(text); - } - } - private void appendText(String text){ - if(text==null || text.length()==0){ - return; - } - addText(new XMLText(text)); - } - public String getTagNamePrefix(){ - int i=mTagName.indexOf(":"); - if(i>0){ - return mTagName.substring(0,i); - } - return null; - } - public String getTagNameWoPrefix(){ - int i=mTagName.indexOf(":"); - if(i>0){ - return mTagName.substring(i+1); - } - return mTagName; - } - private void setDefaultStartEnd(){ - this.mStart="<"; - this.mEnd=">"; - this.mStartPrefix="/"; - this.mEndPrefix="/"; - } - public void applyNameSpaceItems(){ - if(nameSpaceItems!=null){ - for(NameSpaceItem nsItem:nameSpaceItems){ - SchemaAttr schemaAttr=nsItem.toSchemaAttribute(); - XMLAttribute exist=getAttribute(schemaAttr.getName()); - if(exist!=null){ - exist.setValue(schemaAttr.getValue()); - }else { - addAttribute(schemaAttr); - } - } - } - if(mParent!=null){ - mParent.applyNameSpaceItems(); - } - } - public void addNameSpace(NameSpaceItem nsItem){ - if(nsItem==null){ - return; - } - if(mParent!=null){ - mParent.addNameSpace(nsItem); - return; - } - if(nameSpaceItems==null){ - nameSpaceItems=new HashSet<>(); - } - nameSpaceItems.add(nsItem); - } - public NameSpaceItem getNameSpaceItemForUri(String uri){ - if(nameSpaceItems!=null){ - for(NameSpaceItem ns:nameSpaceItems){ - if(ns.isUriEqual(uri)){ - return ns; - } - } - } - if(mParent!=null){ - return mParent.getNameSpaceItemForUri(uri); - } - return null; - } - public NameSpaceItem getNameSpaceItemForPrefix(String prefix){ - if(nameSpaceItems!=null){ - for(NameSpaceItem ns:nameSpaceItems){ - if(ns.isPrefixEqual(prefix)){ - return ns; - } - } - } - if(mParent!=null){ - return mParent.getNameSpaceItemForPrefix(prefix); - } - return null; - } - void setStart(String start) { - this.mStart = start; - } - void setEnd(String end) { - this.mEnd = end; - } - void setStartPrefix(String pfx) { - if(pfx==null){ - pfx=""; - } - this.mStartPrefix = pfx; - } - void setEndPrefix(String pfx) { - if(pfx==null){ - pfx=""; - } - this.mEndPrefix = pfx; - } - public void setIndentScale(float scale){ - mIndentScale=scale; - } - private float getIndentScale(){ - XMLElement parent=getParent(); - if(parent==null){ - return mIndentScale; - } - return parent.getIndentScale(); - } - public int getResourceId(){ - return mResId; - } - public void setResourceId(int id){ - mResId=id; - } - public XMLElement createElement(String tag) { - XMLElement baseElement=new XMLElement(tag); - addChildNoCheck(baseElement, true); - return baseElement; - } - public void addChild(Collection elements) { - if(elements==null){ - return; - } - for(XMLElement element:elements){ - addChild(element); - } - } - public void addChild(XMLElement child) { - addChildNoCheck(child, true); - } - private void clearChildElements(){ - mChildElements.clear(); - } - private void clearTexts(){ - mTexts.clear(); - } - public XMLComment getCommentAt(int index){ - if(index<0){ - return null; - } - if(index>=mComments.size()){ - return null; - } - return mComments.get(index); - } - public void hideComments(boolean recursive, boolean hide){ - hideComments(hide); - if(recursive){ - for(XMLElement child: mChildElements){ - child.hideComments(recursive, hide); - } - } - } - private void hideComments(boolean hide){ - for(XMLComment ce:mComments){ - ce.setHidden(hide); - } - } - public int getCommentsCount(){ - return mComments.size(); - } - public void addComments(Collection commentElements){ - if(commentElements==null){ - return; - } - for(XMLComment ce:commentElements){ - addComment(ce); - } - } - public void clearComments(){ - mComments.clear(); - } - public void addComment(XMLComment commentElement) { - addCommentInternal(commentElement, true); - } - void addCommentInternal(XMLComment commentElement, boolean addSuper) { - if(commentElement==null){ - return; - } - mComments.add(commentElement); - commentElement.setIndent(getIndent()); - commentElement.setParent(this); - if(addSuper){ - super.addChildNodeInternal(commentElement); - } - } - @Override - void clearChildNodesInternal(){ - super.clearChildNodesInternal(); - mChildElements.clear(); - mComments.clear(); - mTexts.clear(); - } - public Collection listAttributes(){ - return mAttributes.values(); - } - public int getChildesCount(){ - return mChildElements.size(); - } - public List listChildElements(){ - return mChildElements; - } - public XMLElement getChildAt(int index){ - if(index<0 || index>= mChildElements.size()){ - return null; - } - return mChildElements.get(index); - } - public int getAttributeCount(){ - return mAttributes.size(); - } - public String getAttributeValue(String name){ - XMLAttribute attr=getAttribute(name); - if (attr==null){ - return null; - } - return attr.getValue(); - } - public int getAttributeValueInt(String name, int def){ - XMLAttribute attr=getAttribute(name); - if (attr==null){ - return def; - } - return attr.getValueInt(); - } - public int getAttributeValueInt(String name) throws XMLException { - XMLAttribute attr=getAttribute(name); - if (attr==null){ - throw new XMLException("Expecting integer for attr <"+name+ "> at '"+toString()+"'"); - } - try{ - return attr.getValueInt(); - }catch (NumberFormatException ex){ - throw new XMLException(ex.getMessage()+": "+" '"+toString()+"'"); - } - } - public XMLAttribute getAttribute(String name){ - return mAttributes.get(name); - } - public XMLAttribute removeAttribute(String name){ - XMLAttribute attribute = mAttributes.remove(name); - if(attribute!=null){ - attribute.setParent(null); - } - return attribute; - } - public XMLAttribute setAttribute(String name, int value){ - return setAttribute(name, String.valueOf(value)); - } - public XMLAttribute setAttribute(String name, boolean value){ - String v=value?"true":"false"; - return setAttribute(name, v); - } - public XMLAttribute setAttribute(String name, String value){ - if(XMLUtil.isEmpty(name)){ - return null; - } - XMLAttribute attr=getAttribute(name); - if(attr==null){ - if(SchemaAttr.looksSchema(name, value)){ - attr=new SchemaAttr(name, value); - }else{ - attr=new XMLAttribute(name,value); - } - addAttribute(attr); - }else { - attr.setValue(value); - } - return attr; - } - public void addAttributes(Collection attrs){ - if(attrs==null){ - return; - } - for(XMLAttribute a:attrs){ - addAttribute(a); - } - } - public void addAttribute(XMLAttribute attr){ - if(attr==null){ - return; - } - String name = attr.getName(); - if(XMLUtil.isEmpty(name)){ - return; - } - XMLAttribute exist = mAttributes.get(name); - if(exist!=null){ - return; - } - mAttributes.put(name, attr); - attr.setParent(this); - } - public void sortChildes(Comparator comparator){ - if(comparator==null){ - return; - } - mChildElements.sort(comparator); - } - public XMLElement getParent(){ - return mParent; - } - void setParent(XMLElement baseElement){ - mParent=baseElement; - } - @Override - void onChildAdded(XMLNode xmlNode){ - if(xmlNode instanceof XMLComment){ - addCommentInternal((XMLComment) xmlNode, false); - }else if(xmlNode instanceof XMLElement){ - addChildNoCheck((XMLElement) xmlNode, false); - }else if(xmlNode instanceof XMLText){ - addTextInternal((XMLText) xmlNode, false); - } - } - private void addChildNoCheck(XMLElement child, boolean addSupper){ - if(child==null || child == this){ - return; - } - child.setParent(this); - child.setIndent(getChildIndent()); - mChildElements.add(child); - if(addSupper){ - super.addChildNodeInternal(child); - } - } - public int getLevel(){ - int rs=0; - XMLElement parent=getParent(); - if(parent!=null){ - rs=rs+1; - rs+=parent.getLevel(); - } - return rs; - } - int getIndent(){ - XMLElement parent = getParent(); - if(parent!=null && parent.hasTextContent()){ - return 0; - } - return mIndent; - } - int getChildIndent(){ - if(mIndent<=0 || hasTextContent()){ - return 0; - } - int rs=mIndent+1; - String tag= getTagName(); - if(tag!=null){ - int i=tag.length(); - if(i>10){ - i=10; - } - rs+=i; - } - return rs; - } - public void setIndent(int indent){ - mIndent=indent; - int chIndent=getChildIndent(); - for(XMLElement child: mChildElements){ - child.setIndent(chIndent); - } - if(mComments!=null){ - for(XMLComment ce:mComments){ - ce.setIndent(indent); - } - } - } - - /** - * @param indentScale scale of attributes indent relative to element tag start - */ - public void setAttributesIndentScale(float indentScale){ - setAttributesIndentScale(indentScale, true); - } - public void setAttributesIndentScale(float indentScale, boolean setToChildes){ - this.mAttributeIndentScale = indentScale; - if(!setToChildes){ - return; - } - for(XMLElement child:listChildElements()){ - child.setAttributesIndentScale(indentScale, true); - } - } - private float getAttributeIndentScale(){ - return mAttributeIndentScale; - } - private int calculateAttributesIndent(){ - float scale = getAttributeIndentScale(); - int indent = 0; - String tagName = getTagName(); - if(tagName!=null){ - indent += tagName.length(); - } - indent += 2; - if(indent>MAX_ATTRIBUTE_INDENT){ - indent = MAX_ATTRIBUTE_INDENT; - } - int baseIndent = getIndentWidth(); - indent = (int) (scale * indent); - indent = baseIndent + indent; - if(indent<0){ - indent = 0; - } - return indent; - } - private boolean appendAttributesIndentText(Writer writer, boolean appendOnce, int indent) throws IOException { - if(indent<=0){ - return false; - } - if(appendOnce){ - writer.write(XMLUtil.NEW_LINE); - for(int i=0;i40){ - i=40; - } - return i; - } - public String getTagName(){ - return mTagName; - } - public void setTagName(String tag){ - mTagName =tag; - } - public Object getTag(){ - return mTag; - } - public void setTag(Object tag){ - mTag =tag; - } - public String getTextContent(){ - if(!hasTextContent()){ - return null; - } - return buildTextContent(true); - } - public String buildTextContent(boolean unEscape){ - StringWriter writer=new StringWriter(); - try { - for(XMLNode node:getChildNodes()){ - node.buildTextContent(writer, unEscape); - } - writer.flush(); - writer.close(); - } catch (IOException ignored) { - } - return writer.toString(); - } - void buildTextContent(Writer writer, boolean unEscape) throws IOException { - writer.write("<"); - writer.write(getTagName()); - appendAttributes(writer, false); - if(!hasChildNodes()){ - writer.write("/>"); - return; - } - writer.write('>'); - for(XMLNode node:getChildNodes()){ - node.buildTextContent(writer, unEscape); - } - if(hasChildNodes()){ - writer.write("'); - } - } - private void appendTextContent(Writer writer) throws IOException { - for(XMLNode child:getChildNodes()){ - if(child instanceof XMLElement){ - ((XMLElement)child).setIndent(0); - } - child.write(writer, false); - } - } - public boolean hasChildElements(){ - return mChildElements.size()>0; - } - public boolean hasTextContent() { - return mTexts.size()>0; - } - public String getText(){ - if(mTexts.size()==0){ - return null; - } - return mTexts.get(0).getText(); - } - public void setSpannableText(String text){ - clearChildNodes(); - XMLElement element = parseSpanSafe(text); - if(element==null){ - addText( new XMLText(text)); - return; - } - for(XMLNode xmlNode:element.getChildNodes()){ - super.addChildNode(xmlNode); - } - } - public void setTextContent(String text){ - setTextContent(text, true); - } - public void setTextContent(String text, boolean escape){ - clearChildElements(); - clearTexts(); - super.getChildNodes().clear(); - if(escape){ - text=XMLUtil.escapeXmlChars(text); - } - appendText(text); - } - private boolean appendAttributes(Writer writer, boolean newLineAttributes) throws IOException { - boolean addedOnce=false; - int attributesIndent = calculateAttributesIndent(); - boolean indentAppend = false; - for(XMLAttribute attr:listAttributes()){ - if(newLineAttributes){ - indentAppend = appendAttributesIndentText(writer, indentAppend, attributesIndent); - } - if(addedOnce){ - if(!indentAppend){ - writer.write(' '); - } - }else { - writer.write(' '); - } - attr.write(writer); - addedOnce=true; - } - return addedOnce; - } - boolean isEmpty(){ - if(mTagName!=null){ - return false; - } - if(mAttributes.size()>0){ - return false; - } - if(mComments!=null && mComments.size()>0){ - return false; - } - if(mTexts.size()>0){ - return false; - } - return true; - } - private boolean canAppendChildes(){ - for(XMLElement child: mChildElements){ - if (!child.isEmpty()){ - return true; - } - } - return false; - } - boolean appendComments(Writer writer) throws IOException { - if(mComments==null){ - return false; - } - boolean appendPrevious=false; - boolean addedOnce=false; - for(XMLComment ce:mComments){ - if(ce.isEmpty()){ - continue; - } - if(appendPrevious){ - writer.write(XMLUtil.NEW_LINE); - } - appendPrevious=ce.write(writer, false); - if(appendPrevious){ - addedOnce=true; - } - } - return addedOnce; - } - private boolean appendChildes(Writer writer, boolean newLineAttributes) throws IOException { - boolean appendPrevious=true; - boolean addedOnce=false; - for(XMLElement child: mChildElements){ - if(stopWriting(writer)){ - break; - } - if(child.isEmpty()){ - continue; - } - if(appendPrevious){ - writer.write(XMLUtil.NEW_LINE); - } - appendPrevious=child.write(writer, newLineAttributes); - if(!addedOnce && appendPrevious){ - addedOnce=true; - } - } - return addedOnce; - } - private boolean stopWriting(Writer writer){ - if(!(writer instanceof ElementWriter)){ - return false; - } - ElementWriter elementWriter=(ElementWriter)writer; - if(elementWriter.isFinished()){ - elementWriter.writeInterrupted(); - return true; - } - return false; - } - @Override - public boolean write(Writer writer, boolean newLineAttributes) throws IOException { - if(isEmpty()){ - return false; - } - if(stopWriting(writer)){ - return false; - } - boolean appendOnce=appendComments(writer); - if(appendOnce){ - writer.write(XMLUtil.NEW_LINE); - } - appendIndentText(writer); - writer.write(mStart); - String tagName=getTagName(); - if(tagName!=null){ - writer.write(tagName); - } - appendAttributes(writer, newLineAttributes); - boolean useEndTag=false; - boolean hasTextCon=hasTextContent(); - if(hasTextCon){ - writer.write(mEnd); - appendTextContent(writer); - useEndTag=true; - }else if(canAppendChildes()){ - writer.write(mEnd); - appendChildes(writer, newLineAttributes); - useEndTag=true; - } - if(useEndTag){ - if(!hasTextCon){ - writer.write(XMLUtil.NEW_LINE); - appendIndentText(writer); - } - writer.write(mStart); - writer.write(mStartPrefix); - writer.write(getTagName()); - }else { - writer.write(mEndPrefix); - } - writer.write(mEnd); - return true; - } - @Override - public String toText(int indent, boolean newLineAttributes){ - StringWriter writer=new StringWriter(); - setIndent(indent); - try { - write(writer, newLineAttributes); - writer.flush(); - writer.close(); - } catch (IOException ignored) { - } - return writer.toString(); - } - protected List listSpannable(){ - List results = new ArrayList<>(); - for(XMLNode child:getChildNodes()){ - if((child instanceof XMLElement) || (child instanceof XMLText)){ - results.add(child); - } - } - return results; - } - protected String getSpannableText() { - StringBuilder builder = new StringBuilder(); - builder.append(getTagName()); - for(XMLAttribute attribute:listAttributes()){ - builder.append(' '); - builder.append(attribute.toText(0, false)); - } - return builder.toString(); - } - @Override - public String toString(){ - StringWriter strWriter=new StringWriter(); - ElementWriter writer=new ElementWriter(strWriter, DEBUG_TO_STRING); - try { - write(writer, false); - } catch (IOException ignored) { - } - strWriter.flush(); - return strWriter.toString(); - } - - private static XMLElement parseSpanSafe(String spanText){ - if(spanText==null){ - return null; - } - try { - XMLSpanParser spanParser = new XMLSpanParser(); - return spanParser.parse(spanText); - } catch (XMLException ignored) { - return null; - } - } - - private static final int MAX_ATTRIBUTE_INDENT = 20; -} diff --git a/src/ARSCLib/com/reandroid/xml/XMLException.java b/src/ARSCLib/com/reandroid/xml/XMLException.java deleted file mode 100755 index 51683fa0..00000000 --- a/src/ARSCLib/com/reandroid/xml/XMLException.java +++ /dev/null @@ -1,22 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml; - -public class XMLException extends Exception { - public XMLException(String msg){ - super(msg); - } -} diff --git a/src/ARSCLib/com/reandroid/xml/XMLNode.java b/src/ARSCLib/com/reandroid/xml/XMLNode.java deleted file mode 100644 index a4ad863f..00000000 --- a/src/ARSCLib/com/reandroid/xml/XMLNode.java +++ /dev/null @@ -1,95 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml; - -import java.io.IOException; -import java.io.Writer; -import java.util.ArrayList; -import java.util.List; - -public abstract class XMLNode { - private int mLineNumber; - private int mColumnNumber; - private final List mChildNodes = new ArrayList<>(); - - public int getColumnNumber() { - return mColumnNumber; - } - public void setColumnNumber(int columnNumber) { - this.mColumnNumber = columnNumber; - } - public int getLineNumber() { - return mLineNumber; - } - public void setLineNumber(int lineNumber) { - this.mLineNumber = lineNumber; - } - - public void addChildNode(XMLNode xmlNode){ - boolean addOk=addChildNodeInternal(xmlNode); - if(addOk){ - onChildAdded(xmlNode); - } - } - boolean addChildNodeInternal(XMLNode xmlNode){ - if(xmlNode!=null && canAdd(xmlNode)){ - return mChildNodes.add(xmlNode); - } - return false; - } - void onChildAdded(XMLNode xmlNode){ - - } - boolean canAdd(XMLNode xmlNode){ - return xmlNode!=null; - } - boolean contains(XMLNode xmlNode){ - return mChildNodes.contains(xmlNode); - } - void removeChildNode(XMLNode xmlNode){ - int i = mChildNodes.indexOf(xmlNode); - while (i>=0){ - i = mChildNodes.indexOf(xmlNode); - } - mChildNodes.remove(xmlNode); - } - public void clearChildNodes(){ - clearChildNodesInternal(); - } - void clearChildNodesInternal(){ - mChildNodes.clear(); - } - public List getChildNodes() { - return mChildNodes; - } - boolean hasChildNodes(){ - return mChildNodes.size()>0; - } - void buildTextContent(Writer writer, boolean unEscape) throws IOException{ - - } - public boolean write(Writer writer) throws IOException { - return write(writer, false); - } - public String toText(){ - return toText(1, false); - } - public String toText(boolean newLineAttributes){ - return toText(1, newLineAttributes); - } - public abstract boolean write(Writer writer, boolean newLineAttributes) throws IOException; - public abstract String toText(int indent, boolean newLineAttributes); -} diff --git a/src/ARSCLib/com/reandroid/xml/XMLParserFactory.java b/src/ARSCLib/com/reandroid/xml/XMLParserFactory.java deleted file mode 100644 index ca339e2f..00000000 --- a/src/ARSCLib/com/reandroid/xml/XMLParserFactory.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml; - -import com.android.org.kxml2.io.KXmlParser; -import com.reandroid.common.FileChannelInputStream; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.*; -import java.nio.charset.StandardCharsets; - -public class XMLParserFactory { - - public static XmlPullParser newPullParser(File file) throws XmlPullParserException { - XmlPullParser parser = newPullParser(); - try { - parser.setInput(new FileChannelInputStream(file), StandardCharsets.UTF_8.name()); - } catch (IOException ex) { - throw new XmlPullParserException(ex.getMessage() + ", file = " + file); - } - return parser; - } - public static XmlPullParser newPullParser(InputStream inputStream) throws XmlPullParserException { - XmlPullParser parser = newPullParser(); - parser.setInput(inputStream, StandardCharsets.UTF_8.name()); - return parser; - } - public static XmlPullParser newPullParser(){ - return new KXmlParser(); - } -} diff --git a/src/ARSCLib/com/reandroid/xml/XMLSpanInfo.java b/src/ARSCLib/com/reandroid/xml/XMLSpanInfo.java deleted file mode 100644 index 17e082bc..00000000 --- a/src/ARSCLib/com/reandroid/xml/XMLSpanInfo.java +++ /dev/null @@ -1,27 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml; - -public class XMLSpanInfo { - public final String tag; - public final int start; - public int end; - public XMLSpanInfo(String tag, int start, int end){ - this.tag=tag; - this.start=start; - this.end=end; - } -} diff --git a/src/ARSCLib/com/reandroid/xml/XMLSpannable.java b/src/ARSCLib/com/reandroid/xml/XMLSpannable.java deleted file mode 100644 index 859e91bc..00000000 --- a/src/ARSCLib/com/reandroid/xml/XMLSpannable.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml; - -import com.reandroid.xml.parser.XMLSpanParser; - -import java.util.*; - -public class XMLSpannable implements Comparable{ - private XMLElement mElement; - private String mText; - private List mSpanInfoList; - public XMLSpannable(XMLElement element){ - this.mElement=element; - } - public boolean isValid(){ - List spanInfoList = getSpanInfoList(); - if(spanInfoList.size()==0){ - return false; - } - for(XMLSpanInfo spanInfo:spanInfoList){ - if(spanInfo.end'); - for(XMLNode xmlNode: element.getChildNodes()){ - if(xmlNode instanceof XMLElement){ - appendXml(builder, (XMLElement) xmlNode); - }else if(xmlNode instanceof XMLText){ - appendXml(builder, (XMLText) xmlNode); - } - } - builder.append('<'); - builder.append('/'); - builder.append(element.getTagName()); - builder.append('>'); - } - private void appendXmlAttributes(StringBuilder builder, XMLElement element){ - for(XMLAttribute xmlAttribute : element.listAttributes()){ - builder.append(' '); - builder.append(xmlAttribute.getName()); - builder.append('='); - builder.append('"'); - builder.append(xmlAttribute.getValue()); - builder.append('"'); - } - } - private void appendXml(StringBuilder builder, XMLText xmlText){ - builder.append(xmlText.getText(true)); - } - public String getText(){ - if(mText==null){ - buildSpanInfo(); - } - return mText; - } - public List getSpanInfoList(){ - if(mSpanInfoList==null){ - buildSpanInfo(); - } - return mSpanInfoList; - } - private void buildSpanInfo(){ - mSpanInfoList=new ArrayList<>(); - StringBuilder builder=new StringBuilder(); - buildSpanInfo(mElement, builder); - mText=builder.toString(); - mElement=null; - } - private void buildSpanInfo(XMLElement element, StringBuilder builder){ - XMLSpanInfo info = null; - for(XMLNode node:element.listSpannable()){ - if(info != null){ - int pos = builder.length(); - if(pos > 0){ - pos = pos - 1; - } - info.end = pos; - info = null; - } - if(node instanceof XMLText){ - builder.append(((XMLText)node).getText()); - continue; - } - XMLElement child = (XMLElement) node; - info=new XMLSpanInfo( - child.getSpannableText(), - builder.length(), 0); - mSpanInfoList.add(info); - buildSpanInfo(child, builder); - } - if(info!=null){ - int pos = builder.length(); - if(pos > 0){ - pos = pos - 1; - } - info.end = pos; - } - } - @Override - public int compareTo(XMLSpannable xmlSpannable) { - return getText().compareTo(xmlSpannable.getText()); - } - - public static XMLSpannable parse(String text){ - if(!hasStyle(text)){ - return null; - } - try { - XMLSpannable spannable=new XMLSpannable(PARSER.parse(text)); - if(spannable.isValid()){ - return spannable; - } - } catch (Exception ignored) { - } - return null; - } - public static Set tagList(Collection spannableList){ - Set results=new HashSet<>(); - for(XMLSpannable xmlSpannable:spannableList){ - for(XMLSpanInfo spanInfo: xmlSpannable.getSpanInfoList()){ - results.add(spanInfo.tag); - } - } - return results; - } - public static List toTextList(Collection spannableList){ - List results=new ArrayList<>(spannableList.size()); - for(XMLSpannable xmlSpannable:spannableList){ - results.add(xmlSpannable.getText()); - } - return results; - } - public static void sort(List spannableList){ - Comparator cmp=new Comparator() { - @Override - public int compare(XMLSpannable s1, XMLSpannable s2) { - return s1.compareTo(s2); - } - }; - spannableList.sort(cmp); - } - private static boolean hasStyle(String text){ - if(text==null){ - return false; - } - int i=text.indexOf('<'); - if(i<0){ - return false; - } - i=text.indexOf('>'); - return i>1; - } - - private static final XMLSpanParser PARSER=new XMLSpanParser(); - -} diff --git a/src/ARSCLib/com/reandroid/xml/XMLText.java b/src/ARSCLib/com/reandroid/xml/XMLText.java deleted file mode 100644 index fed511bd..00000000 --- a/src/ARSCLib/com/reandroid/xml/XMLText.java +++ /dev/null @@ -1,66 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml; - -import java.io.IOException; -import java.io.Writer; - -public class XMLText extends XMLNode{ - private String text; - public XMLText(String text){ - this.text=XMLUtil.escapeXmlChars(text); - } - public XMLText(){ - this(null); - } - - @Override - public void addChildNode(XMLNode xmlNode){ - throw new IllegalArgumentException("Can not add xml node on text: "+xmlNode); - } - public String getText(){ - return getText(true); - } - public String getText(boolean unEscape){ - if(unEscape){ - return XMLUtil.unEscapeXmlChars(text); - } - return text; - } - public void setText(String text){ - this.text=XMLUtil.escapeXmlChars(text); - } - @Override - void buildTextContent(Writer writer, boolean unEscape) throws IOException{ - writer.write(getText(unEscape)); - } - @Override - public boolean write(Writer writer, boolean newLineAttributes) throws IOException { - if(!XMLUtil.isEmpty(this.text)){ - writer.write(this.text); - return true; - } - return false; - } - @Override - public String toText(int indent, boolean newLineAttributes) { - return getText(false); - } - @Override - public String toString(){ - return getText(); - } -} diff --git a/src/ARSCLib/com/reandroid/xml/XMLUtil.java b/src/ARSCLib/com/reandroid/xml/XMLUtil.java deleted file mode 100755 index 5c403f05..00000000 --- a/src/ARSCLib/com/reandroid/xml/XMLUtil.java +++ /dev/null @@ -1,94 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml; - -import java.util.regex.Pattern; - -public class XMLUtil { - public static String NEW_LINE="\n"; - public static boolean isEmpty(String s){ - if(s==null){ - return true; - } - return s.length()==0; - } - public static String escapeXmlChars(String str){ - if(str==null){ - return null; - } - if(str.indexOf('&')<0 && str.indexOf('<')<0 && str.indexOf('>')<0){ - return str; - } - str=str.replaceAll("&", "&"); - str=str.replaceAll("<", "<"); - str=str.replaceAll(">", ">"); - str=str.replaceAll("&", "&"); - str=str.replaceAll("<", "<"); - str=str.replaceAll(">", ">"); - return str; - } - public static String escapeQuote(String str){ - if(str==null){ - return null; - } - int i = str.indexOf('"'); - if(i<0){ - return str; - } - str=str.replaceAll("\"", """); - return str; - } - public static String unEscapeXmlChars(String str){ - if(str==null){ - return null; - } - int i=str.indexOf('&'); - if(i<0){ - return str; - } - str=str.replaceAll("&", "&"); - str=str.replaceAll("<", "<"); - str=str.replaceAll(">", ">"); - str=str.replaceAll(""", "\""); - return str; - } - public static String trimQuote(String txt){ - if(txt==null){ - return null; - } - String tmp=txt.trim(); - if(tmp.length()==0){ - return txt; - } - char c1=tmp.charAt(0); - if(c1!='"'){ - return txt; - } - int end=tmp.length()-1; - c1=tmp.charAt(end); - if(c1!='"'){ - return txt; - } - if(end<=1){ - return ""; - } - return tmp.substring(1,end); - } - - - private static final Pattern PATTERN_ESCAPE = Pattern.compile("^.*[><&].*$"); - -} diff --git a/src/ARSCLib/com/reandroid/xml/XmlHeaderElement.java b/src/ARSCLib/com/reandroid/xml/XmlHeaderElement.java deleted file mode 100755 index 357f224d..00000000 --- a/src/ARSCLib/com/reandroid/xml/XmlHeaderElement.java +++ /dev/null @@ -1,108 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml; - - import java.io.IOException; - import java.io.Writer; - - public class XmlHeaderElement extends XMLElement { - private static final String ATTR_VERSION="version"; - private static final String ATTR_ENCODING="encoding"; - private static final String ATTR_STANDALONE="standalone"; - public XmlHeaderElement(XmlHeaderElement element){ - this(); - copyAll(element); - } - public XmlHeaderElement(){ - super(); - initializeStartEnd(); - setDefaultAttr(); - } - private void copyAll(XmlHeaderElement element){ - if(element==null){ - return; - } - for(XMLAttribute exist : element.listAttributes()){ - setAttribute(exist.getName(), exist.getValue()); - } - } - private void initializeStartEnd(){ - setTagName("xml"); - setStart(""); - setStartPrefix(""); - setEndPrefix(""); - } - private void setDefaultAttr(){ - setVersion("1.0"); - setEncoding("utf-8"); - setStandalone(null); - } - public Object getProperty(String name){ - XMLAttribute attr=getAttribute(name); - if(attr==null){ - return null; - } - String val=attr.getValue(); - if(ATTR_STANDALONE.equalsIgnoreCase(name)){ - boolean res=false; - if("true".equals(val)){ - res=true; - } - return res; - } - return val; - } - public void setProperty(String name, Object o){ - if(ATTR_STANDALONE.equalsIgnoreCase(name)){ - if(o instanceof Boolean){ - setStandalone((Boolean)o); - return; - } - } - String val=null; - if(o!=null){ - val=o.toString(); - } - setAttribute(name, val); - } - public void setVersion(String version){ - setAttribute(ATTR_VERSION, version); - } - public void setEncoding(String encoding){ - setAttribute(ATTR_ENCODING, encoding); - } - public void setStandalone(Boolean flag){ - if(flag==null){ - removeAttribute(ATTR_STANDALONE); - return; - } - String str=flag?"yes":"no"; - setAttribute(ATTR_STANDALONE, str); - } - @Override - int getChildIndent(){ - return 0; - } - @Override - int getIndent(){ - return 0; - } - @Override - void buildTextContent(Writer writer, boolean unEscape) throws IOException { - - } -} diff --git a/src/ARSCLib/com/reandroid/xml/XmlParserToSerializer.java b/src/ARSCLib/com/reandroid/xml/XmlParserToSerializer.java deleted file mode 100644 index 0e324adb..00000000 --- a/src/ARSCLib/com/reandroid/xml/XmlParserToSerializer.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml; - -import android.content.res.XmlResourceParser; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - -import java.io.Closeable; -import java.io.IOException; - -public class XmlParserToSerializer { - private final XmlSerializer serializer; - private final XmlPullParser parser; - private boolean enableIndent; - boolean processNamespace; - boolean reportNamespaceAttrs; - - public XmlParserToSerializer(XmlPullParser parser, XmlSerializer serializer){ - this.parser = parser; - this.serializer = serializer; - this.enableIndent = true; - setFeatureSafe(parser, XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); - setFeatureSafe(parser, XmlPullParser.FEATURE_REPORT_NAMESPACE_ATTRIBUTES, true); - } - - public void setEnableIndent(boolean enableIndent) { - this.enableIndent = enableIndent; - } - - public void write() throws IOException, XmlPullParserException { - XmlPullParser parser = this.parser; - - this.processNamespace = getFeatureSafe(parser, - XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); - - this.reportNamespaceAttrs = getFeatureSafe(parser, - XmlPullParser.FEATURE_REPORT_NAMESPACE_ATTRIBUTES, false); - - int event = parser.next(); - while (nextEvent(event)){ - event = parser.next(); - } - close(); - } - private void close() throws IOException { - XmlPullParser parser = this.parser; - if(parser instanceof Closeable){ - ((Closeable)parser).close(); - } - XmlSerializer serializer = this.serializer; - if(serializer instanceof Closeable){ - ((Closeable)serializer).close(); - } - } - private boolean nextEvent(int event) throws IOException, XmlPullParserException { - boolean hasNext = true; - switch (event){ - case XmlResourceParser.START_DOCUMENT: - onStartDocument(); - break; - case XmlResourceParser.START_TAG: - onStartTag(); - break; - case XmlResourceParser.TEXT: - onText(); - break; - case XmlResourceParser.COMMENT: - onComment(); - break; - case XmlResourceParser.END_TAG: - onEndTag(); - break; - case XmlResourceParser.END_DOCUMENT: - onEndDocument(); - hasNext = false; - break; - } - return hasNext; - } - - private void onStartDocument() throws IOException{ - serializer.startDocument("utf-8", null); - } - private void onStartTag() throws IOException, XmlPullParserException { - XmlPullParser parser = this.parser; - XmlSerializer serializer = this.serializer; - - boolean processNamespace = this.processNamespace; - boolean countNamespaceAsAttribute = processNamespace && reportNamespaceAttrs; - - if(enableIndent){ - setFeatureSafe(serializer, FEATURE_INDENT_OUTPUT, true); - } - - if(!countNamespaceAsAttribute){ - int nsCount = parser.getNamespaceCount(parser.getDepth()); - for(int i=0; i= elStackSize) { - // we add at least one extra slot ... - final int newSize = (depth >= 7 ? 2 * depth : 8) + 2; // = lucky 7 + 1 //25 - final boolean needsCopying = elStackSize > 0; - String[] arr = null; - arr = new String[newSize]; - if(needsCopying) System.arraycopy(elName, 0, arr, 0, elStackSize); - elName = arr; - arr = new String[newSize]; - if(needsCopying) System.arraycopy(elPrefix, 0, arr, 0, elStackSize); - elPrefix = arr; - arr = new String[newSize]; - if(needsCopying) System.arraycopy(elUri, 0, arr, 0, elStackSize); - elUri = arr; - - int[] iarr = new int[newSize]; - if(needsCopying) { - System.arraycopy(elNamespaceCount, 0, iarr, 0, elStackSize); - } else { - iarr[0] = 0; - } - elNamespaceCount = iarr; - iarr = new int[newSize]; - if(needsCopying) { - System.arraycopy(elRawNameEnd, 0, iarr, 0, elStackSize); - } - elRawNameEnd = iarr; - - iarr = new int[newSize]; - if(needsCopying) { - System.arraycopy(elRawNameLine, 0, iarr, 0, elStackSize); - } - elRawNameLine = iarr; - - final char[][] carr = new char[newSize][]; - if(needsCopying) { - System.arraycopy(elRawName, 0, carr, 0, elStackSize); - } - elRawName = carr; - } - } - protected int attributeCount; - protected String[] attributeName; - protected int[] attributeNameHash; - protected String[] attributePrefix; - protected String[] attributeUri; - protected String[] attributeValue; - - /** - * Make sure that in attributes temporary array is enough space. - */ - protected void ensureAttributesCapacity(int size) { - final int attrPosSize = attributeName != null ? attributeName.length : 0; - if(size >= attrPosSize) { - final int newSize = size > 7 ? 2 * size : 8; // = lucky 7 + 1 //25 - - final boolean needsCopying = attrPosSize > 0; - String[] arr = null; - - arr = new String[newSize]; - if(needsCopying) System.arraycopy(attributeName, 0, arr, 0, attrPosSize); - attributeName = arr; - - arr = new String[newSize]; - if(needsCopying) System.arraycopy(attributePrefix, 0, arr, 0, attrPosSize); - attributePrefix = arr; - - arr = new String[newSize]; - if(needsCopying) System.arraycopy(attributeUri, 0, arr, 0, attrPosSize); - attributeUri = arr; - - arr = new String[newSize]; - if(needsCopying) System.arraycopy(attributeValue, 0, arr, 0, attrPosSize); - attributeValue = arr; - - if( ! allStringsInterned ) { - final int[] iarr = new int[newSize]; - if(needsCopying) System.arraycopy(attributeNameHash, 0, iarr, 0, attrPosSize); - attributeNameHash = iarr; - } - - arr = null; - } - } - protected int namespaceEnd; - protected String namespacePrefix[]; - protected int namespacePrefixHash[]; - protected String namespaceUri[]; - - protected void ensureNamespacesCapacity(int size) { - final int namespaceSize = namespacePrefix != null ? namespacePrefix.length : 0; - if(size >= namespaceSize) { - final int newSize = size > 7 ? 2 * size : 8; // = lucky 7 + 1 //25 - - final String[] newNamespacePrefix = new String[newSize]; - final String[] newNamespaceUri = new String[newSize]; - if(namespacePrefix != null) { - System.arraycopy( - namespacePrefix, 0, newNamespacePrefix, 0, namespaceEnd); - System.arraycopy( - namespaceUri, 0, newNamespaceUri, 0, namespaceEnd); - } - namespacePrefix = newNamespacePrefix; - namespaceUri = newNamespaceUri; - - - if( ! allStringsInterned ) { - final int[] newNamespacePrefixHash = new int[newSize]; - if(namespacePrefixHash != null) { - System.arraycopy( - namespacePrefixHash, 0, newNamespacePrefixHash, 0, namespaceEnd); - } - namespacePrefixHash = newNamespacePrefixHash; - } - } - } - protected static int fastHash(char ch[], int off, int len ) { - if(len == 0) { - return 0; - } - int hash = ch[off]; - hash = (hash << 7) + ch[ off + len - 1 ]; - if(len > 16) { - hash = (hash << 7) + ch[ off + (len / 4)]; - } - if(len > 8) { - hash = (hash << 7) + ch[ off + (len / 2)]; - } - return hash; - } - protected int entityEnd; - - protected String entityName[]; - protected char[] entityNameBuf[]; - protected String entityReplacement[]; - protected char[] entityReplacementBuf[]; - - protected int entityNameHash[]; - - protected void ensureEntityCapacity() { - final int entitySize = entityReplacementBuf != null ? entityReplacementBuf.length : 0; - if(entityEnd >= entitySize) { - final int newSize = entityEnd > 7 ? 2 * entityEnd : 8; // = lucky 7 + 1 //25 - final String[] newEntityName = new String[newSize]; - final char[][] newEntityNameBuf = new char[newSize][]; - final String[] newEntityReplacement = new String[newSize]; - final char[][] newEntityReplacementBuf = new char[newSize][]; - if(entityName != null) { - System.arraycopy(entityName, 0, newEntityName, 0, entityEnd); - System.arraycopy(entityNameBuf, 0, newEntityNameBuf, 0, entityEnd); - System.arraycopy(entityReplacement, 0, newEntityReplacement, 0, entityEnd); - System.arraycopy(entityReplacementBuf, 0, newEntityReplacementBuf, 0, entityEnd); - } - entityName = newEntityName; - entityNameBuf = newEntityNameBuf; - entityReplacement = newEntityReplacement; - entityReplacementBuf = newEntityReplacementBuf; - - if( ! allStringsInterned ) { - final int[] newEntityNameHash = new int[newSize]; - if(entityNameHash != null) { - System.arraycopy(entityNameHash, 0, newEntityNameHash, 0, entityEnd); - } - entityNameHash = newEntityNameHash; - } - } - } - protected static final int READ_CHUNK_SIZE = 8*1024; - protected Reader reader; - protected String inputEncoding; - protected InputStream inputStream; - - - protected int bufLoadFactor = 95; - - protected char buf[] = new char[READ_CHUNK_SIZE]; - protected int bufSoftLimit = ( bufLoadFactor * buf.length ) /100; - protected boolean preventBufferCompaction; - - protected int bufAbsoluteStart; // this is buf - protected int bufStart; - protected int bufEnd; - protected int pos; - protected int posStart; - protected int posEnd; - - protected char[] pc = new char[ - Runtime.getRuntime().freeMemory() > 1000000L ? READ_CHUNK_SIZE : 64 ]; - protected int pcStart; - protected int pcEnd; - - protected boolean usePC; - - - protected boolean seenStartTag; - protected boolean seenEndTag; - protected boolean pastEndTag; - protected boolean seenAmpersand; - protected boolean seenMarkup; - protected boolean seenDocdecl; - - protected boolean tokenize; - protected String text; - protected String entityRefName; - - protected String xmlDeclVersion; - protected Boolean xmlDeclStandalone; - protected String xmlDeclContent; - - protected void reset() { - location = null; - lineNumber = 1; - columnNumber = 0; - seenRoot = false; - reachedEnd = false; - eventType = START_DOCUMENT; - emptyElementTag = false; - - depth = 0; - - attributeCount = 0; - - namespaceEnd = 0; - - entityEnd = 0; - - reader = null; - inputEncoding = null; - - preventBufferCompaction = false; - bufAbsoluteStart = 0; - bufEnd = bufStart = 0; - pos = posStart = posEnd = 0; - - pcEnd = pcStart = 0; - - usePC = false; - - seenStartTag = false; - seenEndTag = false; - pastEndTag = false; - seenAmpersand = false; - seenMarkup = false; - seenDocdecl = false; - - xmlDeclVersion = null; - xmlDeclStandalone = null; - xmlDeclContent = null; - - resetStringCache(); - } - - public MXParser() { - } - public void setFeature(String name, boolean state) throws XmlPullParserException - { - if(name == null) throw new IllegalArgumentException("feature name should not be null"); - if(FEATURE_PROCESS_NAMESPACES.equals(name)) { - if(eventType != START_DOCUMENT) throw new XmlPullParserException( - "namespace processing feature can only be changed before parsing", this, null); - processNamespaces = state; - } else if(FEATURE_NAMES_INTERNED.equals(name)) { - if(state != false) { - throw new XmlPullParserException( - "interning names in this implementation is not supported"); - } - } else if(FEATURE_PROCESS_DOCDECL.equals(name)) { - if(state != false) { - throw new XmlPullParserException( - "processing DOCDECL is not supported"); - } - } else if(FEATURE_XML_ROUNDTRIP.equals(name)) { - roundtripSupported = state; - } else { - throw new XmlPullParserException("unsupported feature "+name); - } - } - - public boolean getFeature(String name) - { - if(name == null) throw new IllegalArgumentException("feature name should not be null"); - if(FEATURE_PROCESS_NAMESPACES.equals(name)) { - return processNamespaces; - } else if(FEATURE_NAMES_INTERNED.equals(name)) { - return false; - } else if(FEATURE_PROCESS_DOCDECL.equals(name)) { - return false; - } else if(FEATURE_XML_ROUNDTRIP.equals(name)) { - return roundtripSupported; - } - return false; - } - - public void setProperty(String name, - Object value) - throws XmlPullParserException - { - if(PROPERTY_LOCATION.equals(name)) { - location = (String) value; - } else { - throw new XmlPullParserException("unsupported property: '"+name+"'"); - } - } - - - public Object getProperty(String name) - { - if(name == null) throw new IllegalArgumentException("property name should not be null"); - if(PROPERTY_XMLDECL_VERSION.equals(name)) { - return xmlDeclVersion; - } else if(PROPERTY_XMLDECL_STANDALONE.equals(name)) { - return xmlDeclStandalone; - } else if(PROPERTY_XMLDECL_CONTENT.equals(name)) { - return xmlDeclContent; - } else if(PROPERTY_LOCATION.equals(name)) { - return location; - } - return null; - } - - - public void setInput(Reader in) throws XmlPullParserException - { - reset(); - reader = in; - } - - public void setInput(java.io.InputStream inputStream, String inputEncoding) - throws XmlPullParserException - { - if(inputStream == null) { - throw new IllegalArgumentException("input stream can not be null"); - } - this.inputStream = inputStream; - Reader reader; - try { - if(inputEncoding != null) { - reader = new InputStreamReader(inputStream, inputEncoding); - } else { - reader = new InputStreamReader(inputStream, "UTF-8"); - } - } catch (UnsupportedEncodingException une) { - throw new XmlPullParserException( - "could not create reader for encoding "+inputEncoding+" : "+une, this, une); - } - setInput(reader); - this.inputEncoding = inputEncoding; - } - public InputStream getInputStream(){ - return inputStream; - } - public Reader getReader(){ - reset(); - return reader; - } - - public String getInputEncoding() { - return inputEncoding; - } - - public void defineEntityReplacementText(String entityName, - String replacementText) - throws XmlPullParserException - { - ensureEntityCapacity(); - - // this is to make sure that if interning works we will take advantage of it ... - this.entityName[entityEnd] = newString(entityName.toCharArray(), 0, entityName.length()); - entityNameBuf[entityEnd] = entityName.toCharArray(); - - entityReplacement[entityEnd] = replacementText; - entityReplacementBuf[entityEnd] = replacementText.toCharArray(); - if(!allStringsInterned) { - entityNameHash[ entityEnd ] = - fastHash(entityNameBuf[entityEnd], 0, entityNameBuf[entityEnd].length); - } - ++entityEnd; - } - - public int getNamespaceCount(int depth) throws XmlPullParserException - { - if(!processNamespaces || depth == 0) { - return 0; - } - if(depth < 0 || depth > this.depth) { - throw new IllegalArgumentException( - "allowed namespace depth 0.."+this.depth+" not "+depth); - } - return elNamespaceCount[ depth ]; - } - - public String getNamespacePrefix(int pos) - throws XmlPullParserException - { - if(pos < namespaceEnd) { - return namespacePrefix[ pos ]; - } else { - throw new XmlPullParserException( - "position "+pos+" exceeded number of available namespaces "+namespaceEnd); - } - } - - public String getNamespaceUri(int pos) throws XmlPullParserException - { - if(pos < namespaceEnd) { - return namespaceUri[ pos ]; - } else { - throw new XmlPullParserException( - "position "+pos+" exceeded number of available namespaces "+namespaceEnd); - } - } - - public String getNamespace( String prefix ) - { - if(prefix != null) { - for( int i = namespaceEnd -1; i >= 0; i--) { - if( prefix.equals( namespacePrefix[ i ] ) ) { - return namespaceUri[ i ]; - } - } - if("xml".equals( prefix )) { - return XML_URI; - } else if("xmlns".equals( prefix )) { - return XMLNS_URI; - } - } else { - for( int i = namespaceEnd -1; i >= 0; i--) { - if( namespacePrefix[ i ] == null) { //"") { //null ) { //TODO check FIXME Alek - return namespaceUri[ i ]; - } - } - - } - return null; - } - - - public int getDepth() - { - return depth; - } - - - private static int findFragment(int bufMinPos, char[] b, int start, int end) { - if(start < bufMinPos) { - start = bufMinPos; - if(start > end) start = end; - return start; - } - if(end - start > 65) { - start = end - 10; // try to find good location - } - int i = start + 1; - while(--i > bufMinPos) { - if((end - i) > 65) break; - final char c = b[i]; - if(c == '<' && (start - i) > 10) break; - } - return i; - } - @Override - public String getPositionDescription() - { - return "line="+getLineNumber()+", col="+getColumnNumber(); - } - @Override - public int getLineNumber() - { - return lineNumber; - } - @Override - public int getColumnNumber() - { - return columnNumber; - } - - - public boolean isWhitespace() throws XmlPullParserException - { - if(eventType == TEXT || eventType == CDSECT) { - if(usePC) { - for (int i = pcStart; i = attributeCount) throw new IndexOutOfBoundsException( - "attribute position must be 0.."+(attributeCount-1)+" and not "+index); - return attributeUri[ index ]; - } - - public String getAttributeName(int index) - { - if(eventType != START_TAG) throw new IndexOutOfBoundsException( - "only START_TAG can have attributes"); - if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException( - "attribute position must be 0.."+(attributeCount-1)+" and not "+index); - return attributeName[ index ]; - } - - public String getAttributePrefix(int index) - { - if(eventType != START_TAG) throw new IndexOutOfBoundsException( - "only START_TAG can have attributes"); - if(processNamespaces == false) return null; - if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException( - "attribute position must be 0.."+(attributeCount-1)+" and not "+index); - return attributePrefix[ index ]; - } - - public String getAttributeType(int index) { - if(eventType != START_TAG) throw new IndexOutOfBoundsException( - "only START_TAG can have attributes"); - if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException( - "attribute position must be 0.."+(attributeCount-1)+" and not "+index); - return "CDATA"; - } - - public boolean isAttributeDefault(int index) { - if(eventType != START_TAG) throw new IndexOutOfBoundsException( - "only START_TAG can have attributes"); - if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException( - "attribute position must be 0.."+(attributeCount-1)+" and not "+index); - return false; - } - - public String getAttributeValue(int index) - { - if(eventType != START_TAG) throw new IndexOutOfBoundsException( - "only START_TAG can have attributes"); - if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException( - "attribute position must be 0.."+(attributeCount-1)+" and not "+index); - return attributeValue[ index ]; - } - - @Override - public String getAttributeValue(String namespace, String name) - { - if(eventType != START_TAG) { - throw new IndexOutOfBoundsException("only START_TAG can have attributes " - +getPositionDescription()); - } - if(name == null) { - throw new IllegalArgumentException("attribute name can not be null"); - } - // TODO make check if namespace is interned!!! etc. for names!!! - if(processNamespaces) { - if(namespace == null) { - namespace = ""; - } - - for(int i = 0; i < attributeCount; ++i) { - if((namespace == attributeUri[ i ] || - namespace.equals(attributeUri[ i ]) ) - //(namespace != null && namespace.equals(attributeUri[ i ])) - // taking advantage of String.intern() - && name.equals(attributeName[ i ]) ) - { - return attributeValue[i]; - } - } - } else { - if(namespace != null && namespace.length() == 0) { - namespace = null; - } - if(namespace != null) throw new IllegalArgumentException( - "when namespaces processing is disabled attribute namespace must be null"); - for(int i = 0; i < attributeCount; ++i) { - if(name.equals(attributeName[i])) - { - return attributeValue[i]; - } - } - } - return null; - } - - - public int getEventType() - throws XmlPullParserException - { - return eventType; - } - - public void require(int type, String namespace, String name) - throws XmlPullParserException, IOException - { - if(processNamespaces == false && namespace != null) { - throw new XmlPullParserException( - "processing namespaces must be enabled on parser (or factory)"+ - " to have possible namespaces declared on elements" - +(" (position:"+ getPositionDescription())+")"); - } - if (type != getEventType() - || (namespace != null && !namespace.equals (getNamespace())) - || (name != null && !name.equals (getName ())) ) - { - throw new XmlPullParserException ( - "expected event "+TYPES[ type ] - +(name != null ? " with name '"+name+"'" : "") - +(namespace != null && name != null ? " and" : "") - +(namespace != null ? " with namespace '"+namespace+"'" : "") - +" but got" - +(type != getEventType() ? " "+TYPES[ getEventType() ] : "") - +(name != null && getName() != null && !name.equals (getName ()) - ? " name '"+getName()+"'" : "") - +(namespace != null && name != null - && getName() != null && !name.equals (getName ()) - && getNamespace() != null && !namespace.equals (getNamespace()) - ? " and" : "") - +(namespace != null && getNamespace() != null && !namespace.equals (getNamespace()) - ? " namespace '"+getNamespace()+"'" : "") - +(" (position:"+ getPositionDescription())+")"); - } - } - - public void skipSubTree() - throws XmlPullParserException, IOException - { - require(START_TAG, null, null); - int level = 1; - while(level > 0) { - int eventType = next(); - if(eventType == END_TAG) { - --level; - } else if(eventType == START_TAG) { - ++level; - } - } - } - - public String nextText() throws XmlPullParserException, IOException - { - if(getEventType() != START_TAG) { - throw new XmlPullParserException( - "parser must be on START_TAG to read next text", this, null); - } - int eventType = next(); - if(eventType == TEXT) { - final String result = getText(); - eventType = next(); - if(eventType != END_TAG) { - throw new XmlPullParserException( - "TEXT must be immediately followed by END_TAG and not " - +TYPES[ getEventType() ], this, null); - } - return result; - } else if(eventType == END_TAG) { - return ""; - } else { - throw new XmlPullParserException( - "parser must be on START_TAG or TEXT to read text", this, null); - } - } - - public int nextTag() throws XmlPullParserException, IOException - { - next(); - if(eventType == TEXT && isWhitespace()) { // skip whitespace - next(); - } - if (eventType != START_TAG && eventType != END_TAG) { - throw new XmlPullParserException("expected START_TAG or END_TAG not " - +TYPES[ getEventType() ], this, null); - } - return eventType; - } - - public int next() - throws XmlPullParserException, IOException - { - tokenize = false; - return nextImpl(); - } - - public int nextToken() - throws XmlPullParserException, IOException - { - tokenize = true; - return nextImpl(); - } - - - protected int nextImpl() - throws XmlPullParserException, IOException - { - text = null; - pcEnd = pcStart = 0; - usePC = false; - bufStart = posEnd; - if(pastEndTag) { - pastEndTag = false; - --depth; - namespaceEnd = elNamespaceCount[ depth ]; // less namespaces available - } - if(emptyElementTag) { - emptyElementTag = false; - pastEndTag = true; - return eventType = END_TAG; - } - if(depth > 0) { - - if(seenStartTag) { - seenStartTag = false; - return eventType = parseStartTag(); - } - if(seenEndTag) { - seenEndTag = false; - return eventType = parseEndTag(); - } - - char ch; - if(seenMarkup) { // we have read ahead ... - seenMarkup = false; - ch = '<'; - } else if(seenAmpersand) { - seenAmpersand = false; - ch = '&'; - } else { - ch = more(); - } - posStart = pos - 1; // VERY IMPORTANT: this is correct start of event!!! - - // when true there is some potential event TEXT to return - keep gathering - boolean hadCharData = false; - - // when true TEXT data is not continual (like ) and requires PC merging - boolean needsMerging = false; - - MAIN_LOOP: - while(true) { - // work on MARKUP - if(ch == '<') { - if(hadCharData) { - //posEnd = pos - 1; - if(tokenize) { - seenMarkup = true; - return eventType = TEXT; - } - } - ch = more(); - if(ch == '/') { - if(!tokenize && hadCharData) { - seenEndTag = true; - //posEnd = pos - 2; - return eventType = TEXT; - } - return eventType = parseEndTag(); - } else if(ch == '!') { - ch = more(); - if(ch == '-') { - // note: if(tokenize == false) posStart/End is NOT changed!!!! - parseComment(); - if(tokenize) return eventType = COMMENT; - if( !usePC && hadCharData ) { - needsMerging = true; - } else { - posStart = pos; //completely ignore comment - } - } else if(ch == '[') { - parseCDSect(hadCharData); - if(tokenize) return eventType = CDSECT; - final int cdStart = posStart; - final int cdEnd = posEnd; - final int cdLen = cdEnd - cdStart; - - - if(cdLen > 0) { // was there anything inside CDATA section? - hadCharData = true; - if(!usePC) { - needsMerging = true; - } - } - } else { - throw new XmlPullParserException( - "unexpected character in markup "+printable(ch), this, null); - } - } else if(ch == '?') { - parsePI(); - if(tokenize) return eventType = PROCESSING_INSTRUCTION; - if( !usePC && hadCharData ) { - needsMerging = true; - } else { - posStart = pos; //completely ignore PI - } - - } else if( isNameStartChar(ch) ) { - if(!tokenize && hadCharData) { - seenStartTag = true; - //posEnd = pos - 2; - return eventType = TEXT; - } - return eventType = parseStartTag(); - } else { - throw new XmlPullParserException( - "unexpected character in markup "+printable(ch), this, null); - } - - } else if(ch == '&') { - // work on ENTITTY - //posEnd = pos - 1; - if(tokenize && hadCharData) { - seenAmpersand = true; - return eventType = TEXT; - } - final int oldStart = posStart + bufAbsoluteStart; - final int oldEnd = posEnd + bufAbsoluteStart; - final char[] resolvedEntity = parseEntityRef(); - if(tokenize) return eventType = ENTITY_REF; - // check if replacement text can be resolved !!! - if(resolvedEntity == null) { - if(entityRefName == null) { - entityRefName = newString(buf, posStart, posEnd - posStart); - } - throw new XmlPullParserException( - "could not resolve entity named '"+printable(entityRefName)+"'", - this, null); - } - //int entStart = posStart; - //int entEnd = posEnd; - posStart = oldStart - bufAbsoluteStart; - posEnd = oldEnd - bufAbsoluteStart; - if(!usePC) { - if(hadCharData) { - joinPC(); // posEnd is already set correctly!!! - needsMerging = false; - } else { - usePC = true; - pcStart = pcEnd = 0; - } - } - for (int i = 0; i < resolvedEntity.length; i++) - { - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = resolvedEntity[ i ]; - - } - hadCharData = true; - } else { - - if(needsMerging) { - joinPC(); - needsMerging = false; - } - - hadCharData = true; - - boolean normalizedCR = false; - final boolean normalizeInput = tokenize == false || roundtripSupported == false; - - boolean seenBracket = false; - boolean seenBracketBracket = false; - do { - if(ch == ']') { - if(seenBracket) { - seenBracketBracket = true; - } else { - seenBracket = true; - } - } else if(seenBracketBracket && ch == '>') { - throw new XmlPullParserException( - "characters ]]> are not allowed in content", this, null); - } else { - if(seenBracket) { - seenBracketBracket = seenBracket = false; - } - // assert seenTwoBrackets == seenBracket == false; - } - if(normalizeInput) { - // deal with normalization issues ... - if(ch == '\r') { - normalizedCR = true; - posEnd = pos -1; - // posEnd is already is set - if(!usePC) { - if(posEnd > posStart) { - joinPC(); - } else { - usePC = true; - pcStart = pcEnd = 0; - } - } - //assert usePC == true; - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = '\n'; - } else if(ch == '\n') { - // if(!usePC) { joinPC(); } else { if(pcEnd >= pc.length) ensurePC(); } - if(!normalizedCR && usePC) { - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = '\n'; - } - normalizedCR = false; - } else { - if(usePC) { - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = ch; - } - normalizedCR = false; - } - } - - ch = more(); - } while(ch != '<' && ch != '&'); - posEnd = pos - 1; - continue MAIN_LOOP; - } - ch = more(); - } // endless while(true) - } else { - if(seenRoot) { - return parseEpilog(); - } else { - return parseProlog(); - } - } - } - - - protected int parseProlog() - throws XmlPullParserException, IOException - { - char ch; - if(seenMarkup) { - ch = buf[ pos - 1 ]; - } else { - ch = more(); - } - - if(eventType == START_DOCUMENT) { - if(ch == '\uFFFE') { - throw new XmlPullParserException( - "first character in input was UNICODE noncharacter (0xFFFE)"+ - "- input requires int swapping", this, null); - } - if(ch == '\uFEFF') { - ch = more(); - } - } - seenMarkup = false; - boolean gotS = false; - posStart = pos - 1; - final boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false; - boolean normalizedCR = false; - while(true) { - if(ch == '<') { - if(gotS && tokenize) { - posEnd = pos - 1; - seenMarkup = true; - return eventType = IGNORABLE_WHITESPACE; - } - ch = more(); - if(ch == '?') { - if(parsePI()) { // make sure to skip XMLDecl - if(tokenize) { - return eventType = PROCESSING_INSTRUCTION; - } - } else { - // skip over - continue tokenizing - posStart = pos; - gotS = false; - } - - } else if(ch == '!') { - ch = more(); - if(ch == 'D') { - if(seenDocdecl) { - throw new XmlPullParserException( - "only one docdecl allowed in XML document", this, null); - } - seenDocdecl = true; - parseDocdecl(); - if(tokenize) return eventType = DOCDECL; - } else if(ch == '-') { - parseComment(); - if(tokenize) return eventType = COMMENT; - } else { - throw new XmlPullParserException( - "unexpected markup posStart) { - joinPC(); - } else { - usePC = true; - pcStart = pcEnd = 0; - } - } - //assert usePC == true; - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = '\n'; - } else if(ch == '\n') { - if(!normalizedCR && usePC) { - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = '\n'; - } - normalizedCR = false; - } else { - if(usePC) { - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = ch; - } - normalizedCR = false; - } - } - } else { - throw new XmlPullParserException( - "only whitespace content allowed before start tag and not "+printable(ch), - this, null); - } - ch = more(); - } - } - - protected int parseEpilog() - throws XmlPullParserException, IOException - { - if(eventType == END_DOCUMENT) { - throw new XmlPullParserException("already reached end of XML input", this, null); - } - if(reachedEnd) { - return eventType = END_DOCUMENT; - } - boolean gotS = false; - final boolean normalizeIgnorableWS = tokenize && !roundtripSupported; - boolean normalizedCR = false; - try { - char ch; - if(seenMarkup) { - ch = buf[ pos - 1 ]; - } else { - ch = more(); - } - seenMarkup = false; - posStart = pos - 1; - if(!reachedEnd) { - while(true) { - if(ch == '<') { - if(gotS && tokenize) { - posEnd = pos - 1; - seenMarkup = true; - return eventType = IGNORABLE_WHITESPACE; - } - ch = more(); - if(reachedEnd) { - break; - } - if(ch == '?') { - parsePI(); - if(tokenize) return eventType = PROCESSING_INSTRUCTION; - - } else if(ch == '!') { - ch = more(); - if(reachedEnd) { - break; - } - if(ch == 'D') { - parseDocdecl(); - if(tokenize) { - return eventType = DOCDECL; - } - } else if(ch == '-') { - parseComment(); - if(tokenize) return eventType = COMMENT; - } else { - throw new XmlPullParserException( - "unexpected markup posStart) { - joinPC(); - } else { - usePC = true; - pcStart = pcEnd = 0; - } - } - //assert usePC == true; - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = '\n'; - } else if(ch == '\n') { - if(!normalizedCR && usePC) { - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = '\n'; - } - normalizedCR = false; - } else { - if(usePC) { - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = ch; - } - normalizedCR = false; - } - } - } else { - throw new XmlPullParserException( - "in epilog non whitespace content is not allowed but got "+printable(ch), - this, null); - } - ch = more(); - if(reachedEnd) { - break; - } - - } - } - } catch(EOFException ex) { - reachedEnd = true; - } - if(reachedEnd) { - if(tokenize && gotS) { - posEnd = pos; // well - this is LAST available character pos - return eventType = IGNORABLE_WHITESPACE; - } - return eventType = END_DOCUMENT; - } else { - throw new XmlPullParserException("internal error in parseEpilog"); - } - } - - - public int parseEndTag() throws XmlPullParserException, IOException { - char ch = more(); - if(!isNameStartChar(ch)) { - throw new XmlPullParserException( - "expected name start and not "+printable(ch), this, null); - } - posStart = pos - 3; - final int nameStart = pos - 1 + bufAbsoluteStart; - do { - ch = more(); - } while(isNameChar(ch)); - - int off = nameStart - bufAbsoluteStart; - final int len = (pos - 1) - off; - final char[] cbuf = elRawName[depth]; - if(elRawNameEnd[depth] != len) { - // construct strings for exception - final String startname = new String(cbuf, 0, elRawNameEnd[depth]); - final String endname = new String(buf, off, len); - throw new XmlPullParserException( - "end tag name must match start tag name <"+startname+">" - +" from line "+elRawNameLine[depth], this, null); - } - for (int i = 0; i < len; i++) - { - if(buf[off++] != cbuf[i]) { - // construct strings for exception - final String startname = new String(cbuf, 0, len); - final String endname = new String(buf, off - i - 1, len); - throw new XmlPullParserException( - "end tag name must be the same as start tag <"+startname+">" - +" from line "+elRawNameLine[depth], this, null); - } - } - - while(isS(ch)) { - ch = more(); - } // skip additional white spaces - if(ch != '>') { - throw new XmlPullParserException( - "expected > to finish end tag not "+printable(ch) - +" from line "+elRawNameLine[depth], this, null); - } - posEnd = pos; - pastEndTag = true; - return eventType = END_TAG; - } - - public int parseStartTag() throws XmlPullParserException, IOException { - ++depth; - posStart = pos - 2; - emptyElementTag = false; - attributeCount = 0; - final int nameStart = pos - 1 + bufAbsoluteStart; - int colonPos = -1; - char ch = buf[ pos - 1]; - if(ch == ':' && processNamespaces) throw new XmlPullParserException( - "when namespaces processing enabled colon can not be at element name start", - this, null); - while(true) { - ch = more(); - if(!isNameChar(ch)) break; - if(ch == ':' && processNamespaces) { - if(colonPos != -1) throw new XmlPullParserException( - "only one colon is allowed in name of element when namespaces are enabled", - this, null); - colonPos = pos - 1 + bufAbsoluteStart; - } - } - ensureElementsCapacity(); - int elLen = (pos - 1) - (nameStart - bufAbsoluteStart); - if(elRawName[ depth ] == null || elRawName[ depth ].length < elLen) { - elRawName[ depth ] = new char[ 2 * elLen ]; - } - System.arraycopy(buf, nameStart - bufAbsoluteStart, elRawName[ depth ], 0, elLen); - elRawNameEnd[ depth ] = elLen; - elRawNameLine[ depth ] = lineNumber; - - String name = null; - - // work on prefixes and namespace URI - String prefix = null; - if(processNamespaces) { - if(colonPos != -1) { - prefix = elPrefix[ depth ] = newString(buf, nameStart - bufAbsoluteStart, - colonPos - nameStart); - name = elName[ depth ] = newString(buf, colonPos + 1 - bufAbsoluteStart, - //(pos -1) - (colonPos + 1)); - pos - 2 - (colonPos - bufAbsoluteStart)); - } else { - prefix = elPrefix[ depth ] = null; - name = elName[ depth ] = newString(buf, nameStart - bufAbsoluteStart, elLen); - } - } else { - name = elName[ depth ] = newString(buf, nameStart - bufAbsoluteStart, elLen); - } - - - while(true) { - while(isS(ch)) { - ch = more(); - } - - if(ch == '>') { - break; - } else if(ch == '/') { - if(emptyElementTag) throw new XmlPullParserException( - "repeated / in tag declaration", this, null); - emptyElementTag = true; - ch = more(); - if(ch != '>') throw new XmlPullParserException( - "expected > to end empty tag not "+printable(ch), this, null); - break; - } else if(isNameStartChar(ch)) { - ch = parseAttribute(); - ch = more(); - continue; - } else { - throw new XmlPullParserException( - "start tag unexpected character "+printable(ch), this, null); - } - } - - // now when namespaces were declared we can resolve them - if(processNamespaces) { - String uri = getNamespace(prefix); - if(uri == null) { - if(prefix == null) { // no prefix and no uri => use default namespace - uri = NO_NAMESPACE; - } else { - throw new XmlPullParserException( - "could not determine namespace bound to element prefix "+prefix, - this, null); - } - - } - elUri[ depth ] = uri; - - for (int i = 0; i < attributeCount; i++) - { - final String attrPrefix = attributePrefix[ i ]; - if(attrPrefix != null) { - final String attrUri = getNamespace(attrPrefix); - if(attrUri == null) { - throw new XmlPullParserException( - "could not determine namespace bound to attribute prefix "+attrPrefix, - this, null); - - } - attributeUri[ i ] = attrUri; - } else { - attributeUri[ i ] = NO_NAMESPACE; - } - } - - for (int i = 1; i < attributeCount; i++) - { - for (int j = 0; j < i; j++) - { - if( attributeUri[j] == attributeUri[i] - && (allStringsInterned && attributeName[j].equals(attributeName[i]) - || (!allStringsInterned - && attributeNameHash[ j ] == attributeNameHash[ i ] - && attributeName[j].equals(attributeName[i])) ) - - ) { - // prepare data for nice error message? - String attr1 = attributeName[j]; - if(attributeUri[j] != null) attr1 = attributeUri[j]+":"+attr1; - String attr2 = attributeName[i]; - if(attributeUri[i] != null) attr2 = attributeUri[i]+":"+attr2; - throw new XmlPullParserException( - "duplicated attributes "+attr1+" and "+attr2, this, null); - } - } - } - - - } else { - for (int i = 1; i < attributeCount; i++) - { - for (int j = 0; j < i; j++) - { - if((allStringsInterned && attributeName[j].equals(attributeName[i]) - || (!allStringsInterned - && attributeNameHash[ j ] == attributeNameHash[ i ] - && attributeName[j].equals(attributeName[i])) ) - - ) { - // prepare data for nice error message? - final String attr1 = attributeName[j]; - final String attr2 = attributeName[i]; - throw new XmlPullParserException( - "duplicated attributes "+attr1+" and "+attr2, this, null); - } - } - } - } - - elNamespaceCount[ depth ] = namespaceEnd; - posEnd = pos; - return eventType = START_TAG; - } - - protected char parseAttribute() throws XmlPullParserException, IOException - { - final int prevPosStart = posStart + bufAbsoluteStart; - final int nameStart = pos - 1 + bufAbsoluteStart; - int colonPos = -1; - char ch = buf[ pos - 1 ]; - if(ch == ':' && processNamespaces) throw new XmlPullParserException( - "when namespaces processing enabled colon can not be at attribute name start", - this, null); - - - boolean startsWithXmlns = processNamespaces && ch == 'x'; - int xmlnsPos = 0; - - ch = more(); - while(isNameChar(ch)) { - if(processNamespaces) { - if(startsWithXmlns && xmlnsPos < 5) { - ++xmlnsPos; - if(xmlnsPos == 1) { if(ch != 'm') startsWithXmlns = false; } - else if(xmlnsPos == 2) { if(ch != 'l') startsWithXmlns = false; } - else if(xmlnsPos == 3) { if(ch != 'n') startsWithXmlns = false; } - else if(xmlnsPos == 4) { if(ch != 's') startsWithXmlns = false; } - else if(xmlnsPos == 5) { - if(ch != ':') throw new XmlPullParserException( - "after xmlns in attribute name must be colon" - +"when namespaces are enabled", this, null); - //colonPos = pos - 1 + bufAbsoluteStart; - } - } - if(ch == ':') { - if(colonPos != -1) throw new XmlPullParserException( - "only one colon is allowed in attribute name" - +" when namespaces are enabled", this, null); - colonPos = pos - 1 + bufAbsoluteStart; - } - } - ch = more(); - } - - ensureAttributesCapacity(attributeCount); - - String name = null; - String prefix = null; - if(processNamespaces) { - if(xmlnsPos < 4) startsWithXmlns = false; - if(startsWithXmlns) { - if(colonPos != -1) { - //prefix = attributePrefix[ attributeCount ] = null; - final int nameLen = pos - 2 - (colonPos - bufAbsoluteStart); - if(nameLen == 0) { - throw new XmlPullParserException( - "namespace prefix is required after xmlns: " - +" when namespaces are enabled", this, null); - } - name = //attributeName[ attributeCount ] = - newString(buf, colonPos - bufAbsoluteStart + 1, nameLen); - } - } else { - if(colonPos != -1) { - int prefixLen = colonPos - nameStart; - prefix = attributePrefix[ attributeCount ] = - newString(buf, nameStart - bufAbsoluteStart,prefixLen); - //colonPos - (nameStart - bufAbsoluteStart)); - int nameLen = pos - 2 - (colonPos - bufAbsoluteStart); - name = attributeName[ attributeCount ] = - newString(buf, colonPos - bufAbsoluteStart + 1, nameLen); - } else { - prefix = attributePrefix[ attributeCount ] = null; - name = attributeName[ attributeCount ] = - newString(buf, nameStart - bufAbsoluteStart, - pos - 1 - (nameStart - bufAbsoluteStart)); - } - if(!allStringsInterned) { - attributeNameHash[ attributeCount ] = name.hashCode(); - } - } - - } else { - name = attributeName[ attributeCount ] = - newString(buf, nameStart - bufAbsoluteStart, - pos - 1 - (nameStart - bufAbsoluteStart)); - if(!allStringsInterned) { - attributeNameHash[ attributeCount ] = name.hashCode(); - } - } - - while(isS(ch)) { - ch = more(); - } // skip additional spaces - if(ch != '=') { - throw new XmlPullParserException( - "expected = after attribute name '"+name+processNamespaces+"'", this, null); - } - ch = more(); - while(isS(ch)) { - ch = more(); - } // skip additional spaces - - final char delimit = ch; - if(delimit != '"' && delimit != '\'') throw new XmlPullParserException( - "attribute value must start with quotation or apostrophe not " - +printable(delimit), this, null); - boolean normalizedCR = false; - usePC = false; - pcStart = pcEnd; - posStart = pos; - - while(true) { - ch = more(); - if(ch == delimit) { - break; - } if(ch == '<') { - throw new XmlPullParserException( - "markup not allowed inside attribute value - illegal < ", this, null); - } if(ch == '&') { - posEnd = pos - 1; - if(!usePC) { - final boolean hadCharData = posEnd > posStart; - if(hadCharData) { - // posEnd is already set correctly!!! - joinPC(); - } else { - usePC = true; - pcStart = pcEnd = 0; - } - } - final char[] resolvedEntity = parseEntityRef(); - if(resolvedEntity == null) { - if(entityRefName == null) { - entityRefName = newString(buf, posStart, posEnd - posStart); - } - throw new XmlPullParserException( - "could not resolve entity named '"+printable(entityRefName)+"'", - this, null); - } - for (int i = 0; i < resolvedEntity.length; i++) - { - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = resolvedEntity[ i ]; - } - } else if(ch == '\t' || ch == '\n' || ch == '\r') { - if(!usePC) { - posEnd = pos - 1; - if(posEnd > posStart) { - joinPC(); - } else { - usePC = true; - pcEnd = pcStart = 0; - } - } - //assert usePC == true; - if(pcEnd >= pc.length) ensurePC(pcEnd); - if(ch != '\n' || !normalizedCR) { - pc[pcEnd++] = ' '; //'\n'; - } - - } else { - if(usePC) { - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = ch; - } - } - normalizedCR = ch == '\r'; - } - - - if(processNamespaces && startsWithXmlns) { - String ns = null; - if(!usePC) { - ns = newStringIntern(buf, posStart, pos - 1 - posStart); - } else { - ns = newStringIntern(pc, pcStart, pcEnd - pcStart); - } - ensureNamespacesCapacity(namespaceEnd); - int prefixHash = -1; - if(colonPos != -1) { - if(ns.length() == 0) { - throw new XmlPullParserException( - "non-default namespace can not be declared to be empty string", this, null); - } - // declare new namespace - namespacePrefix[ namespaceEnd ] = name; - if(!allStringsInterned) { - prefixHash = namespacePrefixHash[ namespaceEnd ] = name.hashCode(); - } - } else { - // declare new default namespace ... - namespacePrefix[ namespaceEnd ] = null; - if(!allStringsInterned) { - prefixHash = namespacePrefixHash[ namespaceEnd ] = -1; - } - } - namespaceUri[ namespaceEnd ] = ns; - final int startNs = elNamespaceCount[ depth - 1 ]; - for (int i = namespaceEnd - 1; i >= startNs; --i) - { - if(((allStringsInterned || name == null) && namespacePrefix[ i ] == name) - || (!allStringsInterned && name != null && - namespacePrefixHash[ i ] == prefixHash - && name.equals(namespacePrefix[ i ]) - )) - { - final String s = name == null ? "default" : "'"+name+"'"; - throw new XmlPullParserException( - "duplicated namespace declaration for "+s+" prefix", this, null); - } - } - - ++namespaceEnd; - - } else { - if(!usePC) { - attributeValue[ attributeCount ] = - new String(buf, posStart, pos - 1 - posStart); - } else { - attributeValue[ attributeCount ] = - new String(pc, pcStart, pcEnd - pcStart); - } - ++attributeCount; - } - posStart = prevPosStart - bufAbsoluteStart; - return ch; - } - - protected char[] charRefOneCharBuf = new char[1]; - - protected char[] parseEntityRef() - throws XmlPullParserException, IOException - { - entityRefName = null; - posStart = pos; - char ch = more(); - if(ch == '#') { - // parse character reference - char charRef = 0; - ch = more(); - if(ch == 'x') { - //encoded in hex - while(true) { - ch = more(); - if(ch >= '0' && ch <= '9') { - charRef = (char)(charRef * 16 + (ch - '0')); - } else if(ch >= 'a' && ch <= 'f') { - charRef = (char)(charRef * 16 + (ch - ('a' - 10))); - } else if(ch >= 'A' && ch <= 'F') { - charRef = (char)(charRef * 16 + (ch - ('A' - 10))); - } else if(ch == ';') { - break; - } else { - throw new XmlPullParserException( - "character reference (with hex value) may not contain " - +printable(ch), this, null); - } - } - } else { - // encoded in decimal - while(true) { - if(ch >= '0' && ch <= '9') { - charRef = (char)(charRef * 10 + (ch - '0')); - } else if(ch == ';') { - break; - } else { - throw new XmlPullParserException( - "character reference (with decimal value) may not contain " - +printable(ch), this, null); - } - ch = more(); - } - } - posEnd = pos - 1; - charRefOneCharBuf[0] = charRef; - if(tokenize) { - text = newString(charRefOneCharBuf, 0, 1); - } - return charRefOneCharBuf; - } else { - // [68] EntityRef ::= '&' Name ';' - // scan name until ; - if(!isNameStartChar(ch)) { - throw new XmlPullParserException( - "entity reference names can not start with character '" - +printable(ch)+"'", this, null); - } - while(true) { - ch = more(); - if(ch == ';') { - break; - } - if(!isNameChar(ch)) { - throw new XmlPullParserException( - "entity reference name can not contain character " - +printable(ch)+"'", this, null); - } - } - posEnd = pos - 1; - // determine what name maps to - final int len = posEnd - posStart; - if(len == 2 && buf[posStart] == 'l' && buf[posStart+1] == 't') { - if(tokenize) { - text = "<"; - } - charRefOneCharBuf[0] = '<'; - return charRefOneCharBuf; - } else if(len == 3 && buf[posStart] == 'a' - && buf[posStart+1] == 'm' && buf[posStart+2] == 'p') { - if(tokenize) { - text = "&"; - } - charRefOneCharBuf[0] = '&'; - return charRefOneCharBuf; - } else if(len == 2 && buf[posStart] == 'g' && buf[posStart+1] == 't') { - if(tokenize) { - text = ">"; - } - charRefOneCharBuf[0] = '>'; - return charRefOneCharBuf; - } else if(len == 4 && buf[posStart] == 'a' && buf[posStart+1] == 'p' - && buf[posStart+2] == 'o' && buf[posStart+3] == 's') - { - if(tokenize) { - text = "'"; - } - charRefOneCharBuf[0] = '\''; - return charRefOneCharBuf; - } else if(len == 4 && buf[posStart] == 'q' && buf[posStart+1] == 'u' - && buf[posStart+2] == 'o' && buf[posStart+3] == 't') - { - if(tokenize) { - text = "\""; - } - charRefOneCharBuf[0] = '"'; - return charRefOneCharBuf; - } else { - final char[] result = lookuEntityReplacement(len); - if(result != null) { - return result; - } - } - if(tokenize) text = null; - return null; - } - } - - protected char[] lookuEntityReplacement(int entitNameLen) - throws XmlPullParserException, IOException - - { - if(!allStringsInterned) { - final int hash = fastHash(buf, posStart, posEnd - posStart); - LOOP: - for (int i = entityEnd - 1; i >= 0; --i) - { - if(hash == entityNameHash[ i ] && entitNameLen == entityNameBuf[ i ].length) { - final char[] entityBuf = entityNameBuf[ i ]; - for (int j = 0; j < entitNameLen; j++) - { - if(buf[posStart + j] != entityBuf[j]) continue LOOP; - } - if(tokenize) text = entityReplacement[ i ]; - return entityReplacementBuf[ i ]; - } - } - } else { - entityRefName = newString(buf, posStart, posEnd - posStart); - for (int i = entityEnd - 1; i >= 0; --i) - { - // take advantage that interning for newStirng is enforced - if(entityRefName == entityName[ i ]) { - if(tokenize) text = entityReplacement[ i ]; - return entityReplacementBuf[ i ]; - } - } - } - return null; - } - - - protected void parseComment() - throws XmlPullParserException, IOException - { - // implements XML 1.0 Section 2.5 Comments - - //ASSUMPTION: seen - ch = more(); - if(seenDashDash && ch != '>') { - throw new XmlPullParserException( - "in comment after two dashes (--) next character must be >" - +" not "+printable(ch), this, null); - } - if(ch == '-') { - if(!seenDash) { - seenDash = true; - } else { - seenDashDash = true; - seenDash = false; - } - } else if(ch == '>') { - if(seenDashDash) { - break; // found end sequence!!!! - } else { - seenDashDash = false; - } - seenDash = false; - } else { - seenDash = false; - } - if(normalizeIgnorableWS) { - if(ch == '\r') { - normalizedCR = true; - //posEnd = pos -1; - //joinPC(); - // posEnd is already set - if(!usePC) { - posEnd = pos -1; - if(posEnd > posStart) { - joinPC(); - } else { - usePC = true; - pcStart = pcEnd = 0; - } - } - //assert usePC == true; - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = '\n'; - } else if(ch == '\n') { - if(!normalizedCR && usePC) { - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = '\n'; - } - normalizedCR = false; - } else { - if(usePC) { - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = ch; - } - normalizedCR = false; - } - } - } - - } catch(EOFException ex) { - throw new XmlPullParserException( - "comment started on line "+curLine+" and column "+curColumn+" was not closed", - this, ex); - } - if(tokenize) { - posEnd = pos - 3; - if(usePC) { - pcEnd -= 2; - } - } - } - - protected boolean parsePI() - throws XmlPullParserException, IOException - { - if(tokenize) posStart = pos; - final int curLine = lineNumber; - final int curColumn = columnNumber; - int piTargetStart = pos + bufAbsoluteStart; - int piTargetEnd = -1; - final boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false; - boolean normalizedCR = false; - - try { - boolean seenQ = false; - char ch = more(); - if(isS(ch)) { - throw new XmlPullParserException( - "processing instruction PITarget must be exactly after - //ch = more(); - - if(ch == '?') { - seenQ = true; - } else if(ch == '>') { - if(seenQ) { - break; // found end sequence!!!! - } - seenQ = false; - } else { - if(piTargetEnd == -1 && isS(ch)) { - piTargetEnd = pos - 1 + bufAbsoluteStart; - - // [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l')) - if((piTargetEnd - piTargetStart) == 3) { - if((buf[piTargetStart] == 'x' || buf[piTargetStart] == 'X') - && (buf[piTargetStart+1] == 'm' || buf[piTargetStart+1] == 'M') - && (buf[piTargetStart+2] == 'l' || buf[piTargetStart+2] == 'L') - ) - { - if(piTargetStart > 3) { // posStart) { - joinPC(); - } else { - usePC = true; - pcStart = pcEnd = 0; - } - } - //assert usePC == true; - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = '\n'; - } else if(ch == '\n') { - if(!normalizedCR && usePC) { - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = '\n'; - } - normalizedCR = false; - } else { - if(usePC) { - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = ch; - } - normalizedCR = false; - } - } - ch = more(); - } - } catch(EOFException ex) { - throw new XmlPullParserException( - "processing instruction started on line "+curLine+" and column "+curColumn - +" was not closed", - this, ex); - } - if(piTargetEnd == -1) { - piTargetEnd = pos - 2 + bufAbsoluteStart; - } - piTargetStart -= bufAbsoluteStart; - piTargetEnd -= bufAbsoluteStart; - if(tokenize) { - posEnd = pos - 2; - if(normalizeIgnorableWS) { - --pcEnd; - } - } - return true; - } - - protected final static char[] VERSION = "version".toCharArray(); - protected final static char[] NCODING = "ncoding".toCharArray(); - protected final static char[] TANDALONE = "tandalone".toCharArray(); - protected final static char[] YES = "yes".toCharArray(); - protected final static char[] NO = "no".toCharArray(); - - - - protected void parseXmlDecl(char ch) - throws XmlPullParserException, IOException - { - preventBufferCompaction = true; - bufStart = 0; // necessary to keep pos unchanged during expansion! - - ch = skipS(ch); - ch = requireInput(ch, VERSION); - ch = skipS(ch); - if(ch != '=') { - throw new XmlPullParserException( - "expected equals sign (=) after version and not "+printable(ch), this, null); - } - ch = more(); - ch = skipS(ch); - if(ch != '\'' && ch != '"') { - throw new XmlPullParserException( - "expected apostrophe (') or quotation mark (\") after version and not " - +printable(ch), this, null); - } - final char quotChar = ch; - final int versionStart = pos; - ch = more(); - while(ch != quotChar) { - if((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z') && (ch < '0' || ch > '9') - && ch != '_' && ch != '.' && ch != ':' && ch != '-') - { - throw new XmlPullParserException( - " 'z') && (ch < 'A' || ch > 'Z')) - { - throw new XmlPullParserException( - " 'z') && (ch < 'A' || ch > 'Z') && (ch < '0' || ch > '9') - && ch != '.' && ch != '_' && ch != '-') - { - throw new XmlPullParserException( - " as last part of ') { - throw new XmlPullParserException( - "expected ?> as last part of ' && bracketLevel == 0) break; - if(normalizeIgnorableWS) { - if(ch == '\r') { - normalizedCR = true; - //posEnd = pos -1; - //joinPC(); - // posEnd is alreadys set - if(!usePC) { - posEnd = pos -1; - if(posEnd > posStart) { - joinPC(); - } else { - usePC = true; - pcStart = pcEnd = 0; - } - } - //assert usePC == true; - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = '\n'; - } else if(ch == '\n') { - if(!normalizedCR && usePC) { - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = '\n'; - } - normalizedCR = false; - } else { - if(usePC) { - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = ch; - } - normalizedCR = false; - } - } - - } - posEnd = pos - 1; - } - - protected void parseCDSect(boolean hadCharData) - throws XmlPullParserException, IOException - { - char ch = more(); - if(ch != 'C') throw new XmlPullParserException( - "expected <[CDATA[ for comment start", this, null); - ch = more(); - if(ch != 'D') throw new XmlPullParserException( - "expected <[CDATA[ for comment start", this, null); - ch = more(); - if(ch != 'A') throw new XmlPullParserException( - "expected <[CDATA[ for comment start", this, null); - ch = more(); - if(ch != 'T') throw new XmlPullParserException( - "expected <[CDATA[ for comment start", this, null); - ch = more(); - if(ch != 'A') throw new XmlPullParserException( - "expected <[CDATA[ for comment start", this, null); - ch = more(); - if(ch != '[') throw new XmlPullParserException( - "expected posStart) { - joinPC(); - } else { - usePC = true; - pcStart = pcEnd = 0; - } - } - } - } - boolean seenBracket = false; - boolean seenBracketBracket = false; - boolean normalizedCR = false; - while(true) { - // scan until it hits "]]>" - ch = more(); - if(ch == ']') { - if(!seenBracket) { - seenBracket = true; - } else { - seenBracketBracket = true; - //seenBracket = false; - } - } else if(ch == '>') { - if(seenBracket && seenBracketBracket) { - break; // found end sequence!!!! - } else { - seenBracketBracket = false; - } - seenBracket = false; - } else { - if(seenBracket) { - seenBracket = false; - } - } - if(normalizeInput) { - // deal with normalization issues ... - if(ch == '\r') { - normalizedCR = true; - posStart = cdStart - bufAbsoluteStart; - posEnd = pos - 1; // posEnd is alreadys set - if(!usePC) { - if(posEnd > posStart) { - joinPC(); - } else { - usePC = true; - pcStart = pcEnd = 0; - } - } - //assert usePC == true; - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = '\n'; - } else if(ch == '\n') { - if(!normalizedCR && usePC) { - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = '\n'; - } - normalizedCR = false; - } else { - if(usePC) { - if(pcEnd >= pc.length) ensurePC(pcEnd); - pc[pcEnd++] = ch; - } - normalizedCR = false; - } - } - } - } catch(EOFException ex) { - throw new XmlPullParserException( - "CDATA section started on line "+curLine+" and column "+curColumn+" was not closed", - this, ex); - } - if(normalizeInput) { - if(usePC) { - pcEnd = pcEnd - 2; - } - } - posStart = cdStart - bufAbsoluteStart; - posEnd = pos - 3; - } - - protected void fillBuf() throws IOException, XmlPullParserException { - if(reader == null) throw new XmlPullParserException( - "reader must be set before parsing is started"); - - if(bufEnd > bufSoftLimit) { - boolean compact = bufStart > bufSoftLimit; - boolean expand = false; - if(preventBufferCompaction) { - compact = false; - expand = true; - } else if(!compact) { - //freeSpace - if(bufStart < buf.length / 2) { - expand = true; - } else { - // at least half of buffer can be reclaimed --> worthwhile effort!!! - compact = true; - } - } - - // if buffer almost full then compact it - if(compact) { - System.arraycopy(buf, bufStart, buf, 0, bufEnd - bufStart); - } else if(expand) { - final int newSize = 2 * buf.length; - final char[] newBuf = new char[ newSize ]; - System.arraycopy(buf, bufStart, newBuf, 0, bufEnd - bufStart); - buf = newBuf; - if(bufLoadFactor > 0) { - bufSoftLimit = (int) (( ((long) bufLoadFactor) * buf.length ) /100); - } - - } else { - throw new XmlPullParserException("internal error in fillBuffer()"); - } - bufEnd -= bufStart; - pos -= bufStart; - posStart -= bufStart; - posEnd -= bufStart; - bufAbsoluteStart += bufStart; - bufStart = 0; - } - final int len = buf.length - bufEnd > READ_CHUNK_SIZE ? READ_CHUNK_SIZE : buf.length - bufEnd; - final int ret = reader.read(buf, bufEnd, len); - if(ret > 0) { - bufEnd += ret; - return; - } - if(ret == -1) { - if(bufAbsoluteStart == 0 && pos == 0) { - throw new EOFException("input contained no data"); - } else { - if(seenRoot && depth == 0) { - reachedEnd = true; - return; - } else { - StringBuffer expectedTagStack = new StringBuffer(); - if(depth > 0) { - expectedTagStack.append(" - expected end tag"); - if(depth > 1) { - expectedTagStack.append("s"); //more than one end tag - } - expectedTagStack.append(" "); - for (int i = depth; i > 0; i--) - { - String tagName = new String(elRawName[i], 0, elRawNameEnd[i]); - expectedTagStack.append("'); - } - expectedTagStack.append(" to close"); - for (int i = depth; i > 0; i--) - { - if(i != depth) { - expectedTagStack.append(" and"); //more than one end tag - } - String tagName = new String(elRawName[i], 0, elRawNameEnd[i]); - expectedTagStack.append(" start tag <"+tagName+">"); - expectedTagStack.append(" from line "+elRawNameLine[i]); - } - expectedTagStack.append(", parser stopped on"); - } - throw new EOFException("no more data available" - +expectedTagStack.toString()+getPositionDescription()); - } - } - } else { - throw new IOException("error reading input, returned "+ret); - } - } - - protected char more() throws IOException, XmlPullParserException { - if(pos >= bufEnd) { - fillBuf(); - if(reachedEnd) { - return (char)-1; - } - } - final char ch = buf[pos++]; - if(ch == '\n') { - ++lineNumber; columnNumber = 1; - } - else { - ++columnNumber; - } - return ch; - } - - protected void ensurePC(int end) { - final int newSize = end > READ_CHUNK_SIZE ? 2 * end : 2 * READ_CHUNK_SIZE; - final char[] newPC = new char[ newSize ]; - System.arraycopy(pc, 0, newPC, 0, pcEnd); - pc = newPC; - } - - protected void joinPC() { - final int len = posEnd - posStart; - final int newEnd = pcEnd + len + 1; - if(newEnd >= pc.length) { - ensurePC(newEnd); - } - System.arraycopy(buf, posStart, pc, pcEnd, len); - pcEnd += len; - usePC = true; - - } - - protected char requireInput(char ch, char[] input) - throws XmlPullParserException, IOException - { - for (int i = 0; i < input.length; i++) - { - if(ch != input[i]) { - throw new XmlPullParserException( - "expected "+printable(input[i])+" in "+new String(input) - +" and not "+printable(ch), this, null); - } - ch = more(); - } - return ch; - } - - protected char requireNextS() - throws XmlPullParserException, IOException - { - final char ch = more(); - if(!isS(ch)) { - throw new XmlPullParserException( - "white space is required and not "+printable(ch), this, null); - } - return skipS(ch); - } - - protected char skipS(char ch) - throws XmlPullParserException, IOException - { - while(isS(ch)) { ch = more(); } // skip additional spaces - return ch; - } - - protected static final int LOOKUP_MAX = 0x400; - protected static final char LOOKUP_MAX_CHAR = (char)LOOKUP_MAX; - protected static boolean[] lookupNameStartChar = new boolean[ LOOKUP_MAX ]; - protected static boolean[] lookupNameChar = new boolean[ LOOKUP_MAX ]; - - private static void setName(char ch) - { - lookupNameChar[ ch ] = true; - } - private static void setNameStart(char ch) - { - lookupNameStartChar[ ch ] = true; setName(ch); - } - - static { - setNameStart(':'); - for (char ch = 'A'; ch <= 'Z'; ++ch) setNameStart(ch); - setNameStart('_'); - for (char ch = 'a'; ch <= 'z'; ++ch) setNameStart(ch); - for (char ch = '\u00c0'; ch <= '\u02FF'; ++ch) setNameStart(ch); - for (char ch = '\u0370'; ch <= '\u037d'; ++ch) setNameStart(ch); - for (char ch = '\u037f'; ch < '\u0400'; ++ch) setNameStart(ch); - - setName('-'); - setName('.'); - for (char ch = '0'; ch <= '9'; ++ch) setName(ch); - setName('\u00b7'); - for (char ch = '\u0300'; ch <= '\u036f'; ++ch) setName(ch); - } - - //private final static boolean isNameStartChar(char ch) { - protected boolean isNameStartChar(char ch) { - return (ch < LOOKUP_MAX_CHAR && lookupNameStartChar[ ch ]) - || (ch >= LOOKUP_MAX_CHAR && ch <= '\u2027') - || (ch >= '\u202A' && ch <= '\u218F') - || (ch >= '\u2800' && ch <= '\uFFEF') ; - - } - - protected boolean isNameChar(char ch) { - return (ch < LOOKUP_MAX_CHAR && lookupNameChar[ ch ]) - || (ch >= LOOKUP_MAX_CHAR && ch <= '\u2027') - || (ch >= '\u202A' && ch <= '\u218F') - || (ch >= '\u2800' && ch <= '\uFFEF') - || ch=='@' || ch=='$'; - } - - protected boolean isS(char ch) { - return (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'); - } - - protected String printable(char ch) { - if(ch == '\n') { - return "\\n"; - } else if(ch == '\r') { - return "\\r"; - } else if(ch == '\t') { - return "\\t"; - } else if(ch == '\'') { - return "\\'"; - } if(ch > 127 || ch < 32) { - return "\\u"+Integer.toHexString((int)ch); - } - return ""+ch; - } - - protected String printable(String s) { - if(s == null) return null; - final int sLen = s.length(); - StringBuffer buf = new StringBuffer(sLen + 10); - for(int i = 0; i < sLen; ++i) { - buf.append(printable(s.charAt(i))); - } - s = buf.toString(); - return s; - } -} - - diff --git a/src/ARSCLib/com/reandroid/xml/parser/MXParserCachingStrings.java b/src/ARSCLib/com/reandroid/xml/parser/MXParserCachingStrings.java deleted file mode 100644 index 4be5a9d4..00000000 --- a/src/ARSCLib/com/reandroid/xml/parser/MXParserCachingStrings.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * This class is taken from org.xmlpull.* - * - * Check license: http://xmlpull.org - * - */ - -/*This package is renamed from org.xmlpull.* to avoid conflicts*/ -package com.reandroid.xml.parser; - -public class MXParserCachingStrings extends MXParser implements Cloneable -{ - protected final static boolean CACHE_STATISTICS = false; - protected final static boolean TRACE_SIZING = false; - protected final static int INITIAL_CAPACITY = 13; - protected int cacheStatCalls; - protected int cacheStatWalks; - protected int cacheStatResets; - protected int cacheStatRehash; - - protected static final int CACHE_LOAD = 77; - protected int cacheEntriesCount; - protected int cacheEntriesThreshold; - - protected char[][] keys; - protected String[] values; - - public MXParserCachingStrings() { - super(); - allStringsInterned = true; - initStringCache(); - } - - @Override - public void setFeature(String name, boolean state) throws XmlPullParserException - { - if(FEATURE_NAMES_INTERNED.equals(name)) { - if(eventType != START_DOCUMENT) throw new XmlPullParserException( - "interning names feature can only be changed before parsing", this, null); - allStringsInterned = state; - if(!state && keys != null) { - resetStringCache(); - } - } else { - super.setFeature(name, state); - } - } - - public boolean getFeature(String name) - { - if(FEATURE_NAMES_INTERNED.equals(name)) { - return allStringsInterned; - } else { - return super.getFeature(name); - } - } - - - protected String newString(char[] cbuf, int off, int len) { - if(allStringsInterned) { - return newStringIntern(cbuf, off, len); - } else { - return super.newString(cbuf, off, len); - } - } - - protected String newStringIntern(char[] cbuf, int off, int len) { - if(CACHE_STATISTICS) { - ++cacheStatCalls; - } - if (cacheEntriesCount >= cacheEntriesThreshold) { - rehash(); - } - int offset = fastHash(cbuf, off, len) % keys.length; - char[] k = null; - while( (k = keys[offset]) != null - && !keysAreEqual(k, 0, k.length, - cbuf, off, len)) - { - offset = (offset + 1) % keys.length; - if(CACHE_STATISTICS) ++cacheStatWalks; - } - if (k != null) { - return values[offset]; - } else { - k = new char[len]; - System.arraycopy(cbuf, off, k, 0, len); - final String v = new String(k).intern(); - keys[offset] = k; - values[offset] = v; - ++cacheEntriesCount; - return v; - } - - } - - protected void initStringCache() { - if(keys == null) { - if(INITIAL_CAPACITY < 0) { - throw new IllegalArgumentException("Illegal initial capacity: " + INITIAL_CAPACITY); - } - if(CACHE_LOAD < 0 || CACHE_LOAD > 99) { - throw new IllegalArgumentException("Illegal load factor: " + CACHE_LOAD); - } - cacheEntriesThreshold = (int)((INITIAL_CAPACITY * CACHE_LOAD)/100); - if(cacheEntriesThreshold >= INITIAL_CAPACITY) { - throw new RuntimeException( - "internal error: threshold must be less than capacity: "+INITIAL_CAPACITY); - } - keys = new char[INITIAL_CAPACITY][]; - values = new String[INITIAL_CAPACITY]; - cacheEntriesCount = 0; - } - } - - protected void resetStringCache() { - if(CACHE_STATISTICS) { - ++cacheStatResets; - } - initStringCache(); - } - - private void rehash() { - if(CACHE_STATISTICS) ++cacheStatRehash; - final int newSize = 2 * keys.length + 1; - cacheEntriesThreshold = (int)((newSize * CACHE_LOAD)/100); - if(cacheEntriesThreshold >= newSize) throw new RuntimeException( - "internal error: threshold must be less than capacity: "+newSize); - - final char[][] newKeys = new char[newSize][]; - final String[] newValues = new String[newSize]; - for(int i = 0; i < keys.length; i++) { - final char[] k = keys[i]; - keys[i] = null; - final String v = values[i]; - values[i] = null; - if(k != null) { - int newOffset = fastHash(k, 0, k.length) % newSize; - char[] newk = null; - while((newk = newKeys[newOffset]) != null) { - if(keysAreEqual(newk, 0, newk.length, - k, 0, k.length)) { - throw new RuntimeException("internal cache error: duplicated keys: "+ - new String(newk)+" and "+new String(k)); - } - newOffset = (newOffset + 1) % newSize; - } - - newKeys[newOffset] = k; - newValues[newOffset] = v; - } - } - keys = newKeys; - values = newValues; - } - - private static boolean keysAreEqual (char[] a, int astart, int alength, - char[] b, int bstart, int blength) { - if(alength != blength) { - return false; - } else { - for(int i = 0; i < alength; i++) { - if(a[astart + i] != b[bstart + i]) { - return false; - } - } - return true; - } - } - -} diff --git a/src/ARSCLib/com/reandroid/xml/parser/MXParserNonValidating.java b/src/ARSCLib/com/reandroid/xml/parser/MXParserNonValidating.java deleted file mode 100644 index 2141bd34..00000000 --- a/src/ARSCLib/com/reandroid/xml/parser/MXParserNonValidating.java +++ /dev/null @@ -1,309 +0,0 @@ -/* - * This class is taken from org.xmlpull.* - * - * Check license: http://xmlpull.org - * - */ - -/*This package is renamed from org.xmlpull.* to avoid conflicts*/ -package com.reandroid.xml.parser; - -import java.io.IOException; - -public class MXParserNonValidating extends MXParserCachingStrings -{ - private boolean processDocDecl; - - public MXParserNonValidating() { - super(); - } - - @Override - public void setFeature(String name, - boolean state) throws XmlPullParserException - { - if(FEATURE_PROCESS_DOCDECL.equals(name)) { - if(eventType != START_DOCUMENT) throw new XmlPullParserException( - "process DOCDECL feature can only be changed before parsing", this, null); - processDocDecl = state; - } else { - super.setFeature(name, state); - } - } - - @Override - public boolean getFeature(String name) - { - if(FEATURE_PROCESS_DOCDECL.equals(name)) { - return processDocDecl; - } else { - return super.getFeature(name); - } - } - - - @Override - protected char more() throws IOException, XmlPullParserException { - return super.more(); - } - - @Override - protected char[] lookuEntityReplacement(int entitNameLen) throws XmlPullParserException, IOException - - { - if(!allStringsInterned) { - final int hash = fastHash(buf, posStart, posEnd - posStart); - LOOP: - for (int i = entityEnd - 1; i >= 0; --i) - { - if(hash == entityNameHash[ i ] && entitNameLen == entityNameBuf[ i ].length) { - final char[] entityBuf = entityNameBuf[ i ]; - for (int j = 0; j < entitNameLen; j++) - { - if(buf[posStart + j] != entityBuf[j]) continue LOOP; - } - if(tokenize) text = entityReplacement[ i ]; - return entityReplacementBuf[ i ]; - } - } - } else { - entityRefName = newString(buf, posStart, posEnd - posStart); - for (int i = entityEnd - 1; i >= 0; --i) - { - // take advantage that interning for newStirng is enforced - if(entityRefName == entityName[ i ]) { - if(tokenize) { - text = entityReplacement[ i ]; - } - return entityReplacementBuf[ i ]; - } - } - } - return null; - } - - - @Override - protected void parseDocdecl() - throws XmlPullParserException, IOException - { - //make sure that tokenize flag is disabled temporarily!!!! - final boolean oldTokenize = tokenize; - try { - //ASSUMPTION: seen ' - ch = requireNextS(); - int nameStart = pos; - ch = readName(ch); - int nameEnd = pos; - ch = skipS(ch); - // [75] ExternalID ::= 'SYSTEM' S SystemLiteral | 'PUBLIC' S PubidLiteral S SystemLiteral - if(ch == 'S' || ch == 'P') { - ch = processExternalId(ch); - ch = skipS(ch); - } - if(ch == '[') { - processInternalSubset(); - } - ch = skipS(ch); - if(ch != '>') { - throw new XmlPullParserException( - "expected > to finish <[DOCTYPE but got "+printable(ch), this, null); - } - posEnd = pos - 1; - } finally { - tokenize = oldTokenize; - } - } - protected char processExternalId(char ch) - throws XmlPullParserException, IOException - { - // [75] ExternalID ::= 'SYSTEM' S SystemLiteral | 'PUBLIC' S PubidLiteral S SystemLiteral - // [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'") - // [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'" - // [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] - - //TODO - - return ch; - } - - protected void processInternalSubset() - throws XmlPullParserException, IOException - { - // [28] ... (markupdecl | DeclSep)* ']' // [WFC: External Subset] - // [28a] DeclSep ::= PEReference | S // [WFC: PE Between Declarations] - - // [69] PEReference ::= '%' Name ';' //[WFC: No Recursion] [WFC: In DTD] - while(true) { - char ch = more(); // firs ttime called it will skip initial "[" - if(ch == ']') break; - if(ch == '%') { - processPEReference(); - } else if(isS(ch)) { - ch = skipS(ch); - } else { - processMarkupDecl(ch); - } - } - } - - protected void processPEReference() - throws XmlPullParserException, IOException - { - //TODO - } - protected void processMarkupDecl(char ch) - throws XmlPullParserException, IOException - { - // [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl | NotationDecl | PI | Comment - // [WFC: PEs in Internal Subset] - - - //BIG SWITCH statement - if(ch != '<') { - throw new XmlPullParserException("expected < for markupdecl in DTD not "+printable(ch), - this, null); - } - ch = more(); - if(ch == '?') { - parsePI(); - } else if(ch == '!') { - ch = more(); - if(ch == '-') { - // note: if(tokenize == false) posStart/End is NOT changed!!!! - parseComment(); - } else { - ch = more(); - if(ch == 'A') { - processAttlistDecl(ch); //A-TTLIST - } else if(ch == 'E') { - ch = more(); - if(ch == 'L') { - processElementDecl(ch); //EL-EMENT - } else if(ch == 'N') { - processEntityDecl(ch); // EN-TITY - } else { - throw new XmlPullParserException( - "expected ELEMENT or ENTITY after ' - //???? [VC: Unique Element Type Declaration] - // [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children - // [47] children ::= (choice | seq) ('?' | '*' | '+')? - // [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')? - // [49] choice ::= '(' S? cp ( S? '|' S? cp )+ S? ')' - // [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')' - // [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' - // | '(' S? '#PCDATA' S? ')' - - //assert ch == 'L' - ch = requireNextS(); - readName(ch); - ch = requireNextS(); - // readContentSpec(ch); - } - - protected void processAttlistDecl(char ch) - throws XmlPullParserException, IOException - { - // [52] AttlistDecl ::= '' - // [53] AttDef ::= S Name S AttType S DefaultDecl - // [54] AttType ::= StringType | TokenizedType | EnumeratedType - // [55] StringType ::= 'CDATA' - // [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY' | 'ENTITIES' | 'NMTOKEN' - // | 'NMTOKENS' - // [57] EnumeratedType ::= NotationType | Enumeration - // [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')' - // [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')' - // [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue) - // [WFC: No < in Attribute Values] - - //assert ch == 'A' - - } - - - protected void processEntityDecl(char ch) - throws XmlPullParserException, IOException - { - - // [70] EntityDecl ::= GEDecl | PEDecl - // [71] GEDecl ::= '' - // [72] PEDecl ::= '' - // [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?) - // [74] PEDef ::= EntityValue | ExternalID - // [75] ExternalID ::= 'SYSTEM' S SystemLiteral | 'PUBLIC' S PubidLiteral S SystemLiteral - - //[9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' - // | "'" ([^%&'] | PEReference | Reference)* "'" - - //assert ch == 'N' - - } - - protected void processNotationDecl(char ch) - throws XmlPullParserException, IOException - { - - // [82] NotationDecl ::= '' - // [83] PublicID ::= 'PUBLIC' S PubidLiteral - - //assert ch == 'N' - } - - - - protected char readName(char ch) - throws XmlPullParserException, IOException - { - if(isNameStartChar(ch)) { - throw new XmlPullParserException( - "XML name must start with name start character not "+printable(ch), this, null); - } - while(isNameChar(ch)) { - ch = more(); - } - return ch; - } -} \ No newline at end of file diff --git a/src/ARSCLib/com/reandroid/xml/parser/XMLDocumentParser.java b/src/ARSCLib/com/reandroid/xml/parser/XMLDocumentParser.java deleted file mode 100755 index 5457df93..00000000 --- a/src/ARSCLib/com/reandroid/xml/parser/XMLDocumentParser.java +++ /dev/null @@ -1,384 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml.parser; - -import com.android.org.kxml2.io.KXmlParser; -import com.reandroid.common.FileChannelInputStream; -import com.reandroid.xml.*; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.*; -import java.util.ArrayList; -import java.util.List; - -public class XMLDocumentParser { - private final XmlPullParser mParser; - private XMLDocument mResDocument; - private XMLElement mCurrentElement; - private boolean mNameSpaceCreated; - private StringBuilder mCurrentText; - private List mComments; - private int mIndent; - public XMLDocumentParser(XmlPullParser parser){ - this.mParser=parser; - } - public XMLDocumentParser(InputStream in) throws XMLParseException { - this(createParser(in)); - } - public XMLDocumentParser(File file) throws XMLParseException { - this(createParser(file)); - } - public XMLDocumentParser(String text) throws XMLParseException { - this(createParser(text)); - } - - public XMLDocument parse() throws XMLParseException { - try { - XMLDocument document= parseDocument(); - close(); - return document; - } catch (XmlPullParserException | IOException e) { - XMLParseException ex=new XMLParseException(e.getMessage()); - ex.setStackTrace(e.getStackTrace()); - throw ex; - } - } - private void close(){ - closeParser(); - closeReader(); - closeFileInputStream(); - mResDocument=null; - mCurrentElement=null; - mCurrentText=null; - mComments=null; - } - private void closeFileInputStream(){ - if(!(mParser instanceof MXParser)){ - return; - } - MXParser parser=(MXParser) mParser; - InputStream inputStream = parser.getInputStream(); - if(!(inputStream instanceof FileInputStream)){ - return; - } - try { - inputStream.close(); - } catch (IOException ignored) { - } - } - private void closeReader(){ - if(!(mParser instanceof MXParser)){ - return; - } - MXParser parser=(MXParser) mParser; - Reader reader = parser.getReader(); - if(reader!=null){ - try { - reader.close(); - } catch (IOException ignored) { - } - } - } - private void closeParser(){ - if(!(mParser instanceof Closeable)){ - return; - } - Closeable closeable = (Closeable) mParser; - try { - closeable.close(); - } catch (IOException ignored) { - } - } - - private XMLDocument parseDocument() throws XmlPullParserException, IOException { - mResDocument=null; - int type; - while ((type=mParser.nextToken()) !=XmlPullParser.END_DOCUMENT){ - event(type); - } - event(XmlPullParser.END_DOCUMENT); - if(mResDocument==null){ - throw new XmlPullParserException("Failed to parse/empty document"); - } - return mResDocument; - } - private void event(int type) { - if (type == XmlPullParser.START_DOCUMENT){ - onStartDocument(); - }else if (type == XmlPullParser.END_DOCUMENT){ - onEndDocument(); - }else if (type == XmlPullParser.START_TAG){ - onStartTag(); - }else if (type == XmlPullParser.END_TAG){ - onEndTag(); - }else if (type == XmlPullParser.TEXT){ - onText(); - }else if (type == XmlPullParser.ENTITY_REF){ - onEntityRef(); - }else if (type == XmlPullParser.COMMENT){ - onComment(); - }else if (type == XmlPullParser.IGNORABLE_WHITESPACE){ - onIgnorableWhiteSpace(); - }else { - onUnknownType(type); - } - } - private void onStartDocument(){ - mResDocument=new XMLDocument(); - mIndent=-1; - } - private void onEndDocument(){ - flushComments(null); - applyIndent(mResDocument); - } - private void onStartTag(){ - String name=mParser.getName(); - flushTextContent(); - if(mCurrentElement==null){ - if(mResDocument==null){ - onStartDocument(); - } - mCurrentElement=new XMLElement(name); - mResDocument.setDocumentElement(mCurrentElement); - }else { - mCurrentElement=mCurrentElement.createElement(name); - } - mCurrentElement.setColumnNumber(mParser.getColumnNumber()); - mCurrentElement.setLineNumber(mParser.getLineNumber()); - checkIndent(); - flushComments(mCurrentElement); - String ns=mParser.getNamespace(); - if(!XMLUtil.isEmpty(ns)){ - String prefix=mParser.getPrefix(); - if(!XMLUtil.isEmpty(prefix)){ - String tagName=appendPrefix(prefix,name); - mCurrentElement.setTagName(tagName); - checkNamespace(prefix, ns); - } - } - loadAttributes(); - } - private void loadAttributes(){ - int max=mParser.getAttributeCount(); - for(int i=0; i(); - } - mComments.add(ce); - } - private void flushComments(XMLElement element){ - if(mComments==null){ - return; - } - if(element!=null){ - element.addComments(mComments); - } - mComments.clear(); - mComments=null; - } - private void onIgnorableWhiteSpace(){ - } - private void onIgnore(int type){ - - } - private void onUnknownType(int type){ - String typeName=toTypeName(type); - //System.err.println("Unknown TYPE = "+typeName+" "+type); - } - private String toTypeName(int type){ - String[] allTypes=XmlPullParser.TYPES; - if(type<0 || type>=allTypes.length){ - return "type:"+type; - } - return allTypes[type]; - } - - private void checkIndent(){ - if(mIndent>=0){ - return; - } - String txt=mParser.getText(); - if(txt==null){ - return; - } - int len=txt.length(); - int col=mParser.getColumnNumber(); - mIndent=col-len; - if(mIndent<0){ - mIndent=0; - } - } - private void applyIndent(XMLDocument resDocument){ - if(mIndent<=0 || mIndent>5 || resDocument==null){ - mIndent=-1; - return; - } - resDocument.setIndent(mIndent); - mIndent=-1; - } - - private static XmlPullParser createParser(String text) throws XMLParseException { - if(text == null){ - throw new XMLParseException("Text is null, failed to create XmlPullParser"); - } - InputStream in = new ByteArrayInputStream(text.getBytes()); - return createParser(in); - } - private static XmlPullParser createParser(File file) throws XMLParseException { - if(file == null){ - throw new XMLParseException("File is null, failed to create XmlPullParser"); - } - if(!file.isFile()){ - throw new XMLParseException("No such file : "+file.getAbsolutePath()); - } - InputStream in; - try { - in=new FileChannelInputStream(file); - return createParser(in); - } catch (IOException e) { - throw new XMLParseException(e.getMessage()); - } - } - private static XmlPullParser createParser(InputStream in) throws XMLParseException { - try { - XmlPullParser parser = new KXmlParser(); - parser.setInput(in, null); - return parser; - } catch (XmlPullParserException e) { - throw new XMLParseException(e.getMessage()); - } - } - - private static boolean isAndroid(int id){ - int pkgId=toPackageId(id); - return pkgId>0 && pkgId<=ANDROID_PACKAGE_MAX; - } - private static boolean isResourceId(int id){ - int pkgId=toPackageId(id); - return pkgId>0 && pkgId<128; - } - private static int toPackageId(int id){ - if(id<=0xff){ - return id; - } - return ((id >> 24) & 0xff); - } - private static final int ANDROID_PACKAGE_MAX=3; -} diff --git a/src/ARSCLib/com/reandroid/xml/parser/XMLParseException.java b/src/ARSCLib/com/reandroid/xml/parser/XMLParseException.java deleted file mode 100755 index bb8cbbfc..00000000 --- a/src/ARSCLib/com/reandroid/xml/parser/XMLParseException.java +++ /dev/null @@ -1,24 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml.parser; - -import com.reandroid.xml.XMLException; - -public class XMLParseException extends XMLException { - public XMLParseException(String msg) { - super(msg); - } -} diff --git a/src/ARSCLib/com/reandroid/xml/parser/XMLSpanParser.java b/src/ARSCLib/com/reandroid/xml/parser/XMLSpanParser.java deleted file mode 100644 index 9e8e08fc..00000000 --- a/src/ARSCLib/com/reandroid/xml/parser/XMLSpanParser.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml.parser; - -import com.reandroid.xml.*; - -import java.io.IOException; -import java.io.StringReader; - -public class XMLSpanParser { - private final Object mLock = new Object(); - private final XmlPullParser mParser; - private XMLElement mCurrentElement; - public XMLSpanParser(){ - this.mParser = new MXParserNonValidating(); - } - public XMLElement parse(String text) throws XMLException { - synchronized (mLock){ - try { - text=""+text+""; - parseString(text); - } catch (XmlPullParserException|IOException ex) { - throw new XMLException(ex.getMessage()); - } - XMLElement element=mCurrentElement; - mCurrentElement=null; - return element; - } - } - private void parseString(String text) throws XmlPullParserException, IOException { - mCurrentElement=null; - StringReader reader=new StringReader(text); - this.mParser.setInput(reader); - int type; - while ((type=mParser.next()) !=XmlPullParser.END_DOCUMENT){ - event(type); - } - } - private void event(int type) { - if (type == XmlPullParser.START_DOCUMENT){ - onStartDocument(); - }else if (type == XmlPullParser.START_TAG){ - onStartTag(); - }else if (type == XmlPullParser.END_TAG){ - onEndTag(); - }else if (type == XmlPullParser.TEXT){ - onText(); - }else if (type == XmlPullParser.ENTITY_REF){ - onEntityRef(); - }else if (type == XmlPullParser.IGNORABLE_WHITESPACE){ - onText(); - } - } - - - private void loadAttributes(){ - int max=mParser.getAttributeCount(); - for(int i=0; i0){ - mCurrentElement.addText(new XMLText(text)); - } - } - private void onEntityRef() { - String text = getEntity(mParser.getName()); - mCurrentElement.addText(new XMLText(text)); - } - private String getEntity(String name){ - if("amp".equals(name)){ - return "&"; - } - if("lt".equals(name)){ - return "<"; - } - if("gt".equals(name)){ - return ">"; - } - return name; - } - private void onStartDocument() { - this.mCurrentElement=null; - } -} diff --git a/src/ARSCLib/com/reandroid/xml/parser/XmlPullParser.java b/src/ARSCLib/com/reandroid/xml/parser/XmlPullParser.java deleted file mode 100644 index fe2c9ea8..00000000 --- a/src/ARSCLib/com/reandroid/xml/parser/XmlPullParser.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * This class is taken from org.xmlpull.* - * - * Check license: http://xmlpull.org - * - */ - -/*This package is renamed from org.xmlpull.* to avoid conflicts*/ -package com.reandroid.xml.parser; - -import java.io.InputStream; -import java.io.IOException; -import java.io.Reader; - -@Deprecated -public interface XmlPullParser { - - String NO_NAMESPACE = ""; - int START_DOCUMENT = 0; - int END_DOCUMENT = 1; - int START_TAG = 2; - int END_TAG = 3; - int TEXT = 4; - int CDSECT = 5; - int ENTITY_REF = 6; - int IGNORABLE_WHITESPACE = 7; - int PROCESSING_INSTRUCTION = 8; - int COMMENT = 9; - int DOCDECL = 10; - String [] TYPES = { - "START_DOCUMENT", - "END_DOCUMENT", - "START_TAG", - "END_TAG", - "TEXT", - "CDSECT", - "ENTITY_REF", - "IGNORABLE_WHITESPACE", - "PROCESSING_INSTRUCTION", - "COMMENT", - "DOCDECL" - }; - - String FEATURE_PROCESS_NAMESPACES = "http://xmlpull.org/v1/doc/features.html#process-namespaces"; - - String FEATURE_REPORT_NAMESPACE_ATTRIBUTES = "http://xmlpull.org/v1/doc/features.html#report-namespace-prefixes"; - String FEATURE_PROCESS_DOCDECL = "http://xmlpull.org/v1/doc/features.html#process-docdecl"; - - String FEATURE_VALIDATION = "http://xmlpull.org/v1/doc/features.html#validation"; - - void setFeature(String name, boolean state) throws XmlPullParserException; - boolean getFeature(String name); - void setProperty(String name, Object value) throws XmlPullParserException; - Object getProperty(String name); - void setInput(Reader in) throws XmlPullParserException; - void setInput(InputStream inputStream, String inputEncoding) throws XmlPullParserException; - String getInputEncoding(); - void defineEntityReplacementText( String entityName, String replacementText ) throws XmlPullParserException; - int getNamespaceCount(int depth) throws XmlPullParserException; - String getNamespacePrefix(int pos) throws XmlPullParserException; - String getNamespaceUri(int pos) throws XmlPullParserException; - String getNamespace (String prefix); - int getDepth(); - String getPositionDescription(); - int getLineNumber(); - int getColumnNumber(); - boolean isWhitespace() throws XmlPullParserException; - String getText (); - char[] getTextCharacters(int [] holderForStartAndLength); - String getNamespace (); - String getName(); - String getPrefix(); - boolean isEmptyElementTag() throws XmlPullParserException; - int getAttributeCount(); - String getAttributeNamespace (int index); - String getAttributeName (int index); - String getAttributePrefix(int index); - String getAttributeType(int index); - boolean isAttributeDefault(int index); - String getAttributeValue(int index); - String getAttributeValue(String namespace, String name); - int getEventType() throws XmlPullParserException; - int next() throws XmlPullParserException, IOException; - int nextToken() throws XmlPullParserException, IOException; - void require(int type, String namespace, String name) throws XmlPullParserException, IOException; - String nextText() throws XmlPullParserException, IOException; - int nextTag() throws XmlPullParserException, IOException; -// public void skipSubTree() throws XmlPullParserException, IOException; -} - diff --git a/src/ARSCLib/com/reandroid/xml/parser/XmlPullParserException.java b/src/ARSCLib/com/reandroid/xml/parser/XmlPullParserException.java deleted file mode 100644 index 50915cc7..00000000 --- a/src/ARSCLib/com/reandroid/xml/parser/XmlPullParserException.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This class is taken from org.xmlpull.* - * - * Check license: http://xmlpull.org - * - */ - -/*This package is renamed from org.xmlpull.* to avoid conflicts*/ -package com.reandroid.xml.parser; - -@Deprecated -public class XmlPullParserException extends Exception { - protected Throwable detail; - protected int row = -1; - protected int column = -1; - - public XmlPullParserException(String s) { - super(s); - } - public XmlPullParserException(String msg, XmlPullParser parser, Throwable chain) { - super(buildMessage(msg, parser)); - if (parser != null) { - this.row = parser.getLineNumber(); - this.column = parser.getColumnNumber(); - } - this.detail = chain; - } - public Throwable getDetail() { return detail; } - public int getLineNumber() { return row; } - public int getColumnNumber() { return column; } - private static String buildMessage(String msg, XmlPullParser parser){ - StringBuilder builder=new StringBuilder(); - if(parser!=null){ - builder.append("[line="); - builder.append(parser.getLineNumber()); - builder.append(", col="); - builder.append(parser.getColumnNumber()); - builder.append("] "); - } - if(msg!=null){ - builder.append(msg); - } - return builder.toString(); - } -} - diff --git a/src/ARSCLib/com/reandroid/xml/source/XMLDocumentSource.java b/src/ARSCLib/com/reandroid/xml/source/XMLDocumentSource.java deleted file mode 100644 index 20ede1ab..00000000 --- a/src/ARSCLib/com/reandroid/xml/source/XMLDocumentSource.java +++ /dev/null @@ -1,39 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml.source; - -import com.reandroid.xml.XMLDocument; - -public class XMLDocumentSource implements XMLSource{ - private final String path; - private XMLDocument xmlDocument; - public XMLDocumentSource(String path, XMLDocument xmlDocument){ - this.path=path; - this.xmlDocument=xmlDocument; - } - @Override - public String getPath() { - return path; - } - @Override - public XMLDocument getXMLDocument(){ - return xmlDocument; - } - @Override - public void disposeXml() { - xmlDocument=null; - } -} diff --git a/src/ARSCLib/com/reandroid/xml/source/XMLFileSource.java b/src/ARSCLib/com/reandroid/xml/source/XMLFileSource.java deleted file mode 100644 index 5eac4f6b..00000000 --- a/src/ARSCLib/com/reandroid/xml/source/XMLFileSource.java +++ /dev/null @@ -1,46 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml.source; - -import com.reandroid.xml.XMLDocument; -import com.reandroid.xml.XMLException; - -import java.io.File; - -public class XMLFileSource implements XMLSource{ - private final String path; - private final File file; - public XMLFileSource(String path, File file){ - this.path=path; - this.file=file; - } - public File getFile(){ - return this.file; - } - @Override - public String getPath() { - return path; - } - @Override - public XMLDocument getXMLDocument() throws XMLException { - return XMLDocument.load(getFile()); - } - @Override - public void disposeXml() { - } - - -} diff --git a/src/ARSCLib/com/reandroid/xml/source/XMLSource.java b/src/ARSCLib/com/reandroid/xml/source/XMLSource.java deleted file mode 100644 index 687dc146..00000000 --- a/src/ARSCLib/com/reandroid/xml/source/XMLSource.java +++ /dev/null @@ -1,25 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml.source; - -import com.reandroid.xml.XMLDocument; -import com.reandroid.xml.XMLException; - -public interface XMLSource { - public void disposeXml(); - public String getPath(); - public XMLDocument getXMLDocument() throws XMLException; -} diff --git a/src/ARSCLib/com/reandroid/xml/source/XMLStringSource.java b/src/ARSCLib/com/reandroid/xml/source/XMLStringSource.java deleted file mode 100644 index baee62ec..00000000 --- a/src/ARSCLib/com/reandroid/xml/source/XMLStringSource.java +++ /dev/null @@ -1,43 +0,0 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * 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. - */ -package com.reandroid.xml.source; - -import com.reandroid.xml.XMLDocument; -import com.reandroid.xml.XMLException; - -public class XMLStringSource implements XMLSource{ - private final String path; - private String xmlString; - public XMLStringSource(String path, String xmlString){ - this.path=path; - this.xmlString=xmlString; - } - public String getXmlString() { - return xmlString; - } - @Override - public String getPath() { - return path; - } - @Override - public XMLDocument getXMLDocument() throws XMLException { - return XMLDocument.load(xmlString); - } - @Override - public void disposeXml() { - this.xmlString=null; - } -} diff --git a/src/ARSCLib/meson.build b/src/ARSCLib/meson.build deleted file mode 100644 index 17b15bec..00000000 --- a/src/ARSCLib/meson.build +++ /dev/null @@ -1,372 +0,0 @@ -hax_arsc_lib_jar = jar('hax_arsc_lib', [ - 'com/android/org/kxml2/io/KXmlSerializer.java', - 'com/android/org/kxml2/io/LibCoreStringPool.java', - 'com/android/org/kxml2/io/KXmlParser.java', - 'com/reandroid/common/EntryStore.java', - 'com/reandroid/common/FileChannelInputStream.java', - 'com/reandroid/common/TableEntryStore.java', - 'com/reandroid/common/ReferenceResolver.java', - 'com/reandroid/common/Frameworks.java', - 'com/reandroid/apk/APKLogger.java', - 'com/reandroid/apk/ApkModuleXmlEncoder.java', - 'com/reandroid/apk/FrameworkApk.java', - 'com/reandroid/apk/JsonManifestInputSource.java', - 'com/reandroid/apk/ApkJsonDecoder.java', - 'com/reandroid/apk/ApkUtil.java', - 'com/reandroid/apk/BlockInputSource.java', - 'com/reandroid/apk/FrameworkOptimizer.java', - 'com/reandroid/apk/PathSanitizer.java', - 'com/reandroid/apk/UncompressedFiles.java', - 'com/reandroid/apk/XmlHelper.java', - 'com/reandroid/apk/ResFile.java', - 'com/reandroid/apk/TableBlockJsonBuilder.java', - 'com/reandroid/apk/StringPoolBuilder.java', - 'com/reandroid/apk/CrcOutputStream.java', - 'com/reandroid/apk/RenamedInputSource.java', - 'com/reandroid/apk/PathMap.java', - 'com/reandroid/apk/ApkJsonEncoder.java', - 'com/reandroid/apk/ApkModuleXmlDecoder.java', - 'com/reandroid/apk/SplitJsonTableInputSource.java', - 'com/reandroid/apk/AndroidFrameworks.java', - 'com/reandroid/apk/ApkDecoder.java', - 'com/reandroid/apk/ResourceIds.java', - 'com/reandroid/apk/JsonXmlInputSource.java', - 'com/reandroid/apk/ApkBundle.java', - 'com/reandroid/apk/TableBlockJson.java', - 'com/reandroid/apk/SingleJsonTableInputSource.java', - 'com/reandroid/apk/DexFileInputSource.java', - 'com/reandroid/apk/ApkModule.java', - 'com/reandroid/apk/FileMagic.java', - 'com/reandroid/apk/xmlencoder/XMLEncodeSource.java', - 'com/reandroid/apk/xmlencoder/XMLValuesEncoderBag.java', - 'com/reandroid/apk/xmlencoder/XMLValuesEncoder.java', - 'com/reandroid/apk/xmlencoder/XMLFileEncoder.java', - 'com/reandroid/apk/xmlencoder/EncodeUtil.java', - 'com/reandroid/apk/xmlencoder/EncodeException.java', - 'com/reandroid/apk/xmlencoder/EncodeMaterials.java', - 'com/reandroid/apk/xmlencoder/XMLValuesEncoderColor.java', - 'com/reandroid/apk/xmlencoder/ValuesEncoder.java', - 'com/reandroid/apk/xmlencoder/XMLValuesEncoderInteger.java', - 'com/reandroid/apk/xmlencoder/XMLValuesEncoderStyle.java', - 'com/reandroid/apk/xmlencoder/XMLValuesEncoderDimen.java', - 'com/reandroid/apk/xmlencoder/XMLValuesEncoderAttr.java', - 'com/reandroid/apk/xmlencoder/XMLValuesEncoderString.java', - 'com/reandroid/apk/xmlencoder/XMLValuesEncoderPlurals.java', - 'com/reandroid/apk/xmlencoder/ValuesStringPoolBuilder.java', - 'com/reandroid/apk/xmlencoder/XMLValuesEncoderArray.java', - 'com/reandroid/apk/xmlencoder/RESEncoder.java', - 'com/reandroid/apk/xmlencoder/FilePathEncoder.java', - 'com/reandroid/apk/xmlencoder/XMLValuesEncoderId.java', - 'com/reandroid/apk/xmlencoder/XMLValuesEncoderCommon.java', - 'com/reandroid/apk/xmldecoder/XMLEntryDecoder.java', - 'com/reandroid/apk/xmldecoder/BagDecoder.java', - 'com/reandroid/apk/xmldecoder/BagDecoderAttr.java', - 'com/reandroid/apk/xmldecoder/EntryWriter.java', - 'com/reandroid/apk/xmldecoder/XMLEntryDecoderSerializer.java', - 'com/reandroid/apk/xmldecoder/EntryWriterElement.java', - 'com/reandroid/apk/xmldecoder/ResXmlDocumentSerializer.java', - 'com/reandroid/apk/xmldecoder/DecoderTableEntry.java', - 'com/reandroid/apk/xmldecoder/XMLDecodeHelper.java', - 'com/reandroid/apk/xmldecoder/DecoderResTableEntry.java', - 'com/reandroid/apk/xmldecoder/BagDecoderArray.java', - 'com/reandroid/apk/xmldecoder/DecoderResTableEntryMap.java', - 'com/reandroid/apk/xmldecoder/BagDecoderPlural.java', - 'com/reandroid/apk/xmldecoder/XMLEntryDecoderDocument.java', - 'com/reandroid/apk/xmldecoder/XMLNamespaceValidator.java', - 'com/reandroid/apk/xmldecoder/BagDecoderCommon.java', - 'com/reandroid/apk/xmldecoder/EntryWriterSerializer.java', - 'com/reandroid/apk/xmldecoder/XMLBagDecoder.java', - 'com/reandroid/arsc/item/SpecFlagsArray.java', - 'com/reandroid/arsc/item/StyleItem.java', - 'com/reandroid/arsc/item/BlockItem.java', - 'com/reandroid/arsc/item/ShortItem.java', - 'com/reandroid/arsc/item/ReferenceItem.java', - 'com/reandroid/arsc/item/ResXmlString.java', - 'com/reandroid/arsc/item/ReferenceBlock.java', - 'com/reandroid/arsc/item/IntegerArray.java', - 'com/reandroid/arsc/item/ByteItem.java', - 'com/reandroid/arsc/item/StyleItemReference.java', - 'com/reandroid/arsc/item/TypeString.java', - 'com/reandroid/arsc/item/LongItem.java', - 'com/reandroid/arsc/item/SpecString.java', - 'com/reandroid/arsc/item/TableString.java', - 'com/reandroid/arsc/item/FixedLengthString.java', - 'com/reandroid/arsc/item/ByteArray.java', - 'com/reandroid/arsc/item/SpecFlag.java', - 'com/reandroid/arsc/item/IntegerItem.java', - 'com/reandroid/arsc/item/ResXmlID.java', - 'com/reandroid/arsc/item/StringItem.java', - 'com/reandroid/arsc/item/IndirectItem.java', - 'com/reandroid/arsc/header/TableHeader.java', - 'com/reandroid/arsc/header/OverlayableHeader.java', - 'com/reandroid/arsc/header/OverlayablePolicyHeader.java', - 'com/reandroid/arsc/header/StringPoolHeader.java', - 'com/reandroid/arsc/header/InfoHeader.java', - 'com/reandroid/arsc/header/HeaderBlock.java', - 'com/reandroid/arsc/header/PackageHeader.java', - 'com/reandroid/arsc/header/XmlNodeHeader.java', - 'com/reandroid/arsc/header/StagedAliasHeader.java', - 'com/reandroid/arsc/header/LibraryHeader.java', - 'com/reandroid/arsc/header/TypeHeader.java', - 'com/reandroid/arsc/header/SpecHeader.java', - 'com/reandroid/arsc/container/BlockList.java', - 'com/reandroid/arsc/container/ResValueContainer.java', - 'com/reandroid/arsc/container/PackageBody.java', - 'com/reandroid/arsc/container/SpecTypePair.java', - 'com/reandroid/arsc/container/FixedBlockContainer.java', - 'com/reandroid/arsc/container/SingleBlockContainer.java', - 'com/reandroid/arsc/container/ExpandableBlockContainer.java', - 'com/reandroid/arsc/base/BlockArray.java', - 'com/reandroid/arsc/base/Block.java', - 'com/reandroid/arsc/base/BlockCounter.java', - 'com/reandroid/arsc/base/BlockCreator.java', - 'com/reandroid/arsc/base/BlockArrayCreator.java', - 'com/reandroid/arsc/base/BlockContainer.java', - 'com/reandroid/arsc/BuildInfo.java', - 'com/reandroid/arsc/list/OverlayableList.java', - 'com/reandroid/arsc/list/StagedAliasList.java', - 'com/reandroid/arsc/decoder/ComplexUtil.java', - 'com/reandroid/arsc/decoder/Decoder.java', - 'com/reandroid/arsc/decoder/ColorUtil.java', - 'com/reandroid/arsc/decoder/ValueDecoder.java', - 'com/reandroid/arsc/decoder/ThreeByteCharsetDecoder.java', - 'com/reandroid/arsc/io/BlockLoad.java', - 'com/reandroid/arsc/io/BlockReader.java', - 'com/reandroid/arsc/pool/ResXmlStringPool.java', - 'com/reandroid/arsc/pool/builder/StringPoolMerger.java', - 'com/reandroid/arsc/pool/builder/StyleBuilder.java', - 'com/reandroid/arsc/pool/StringPool.java', - 'com/reandroid/arsc/pool/SpecStringPool.java', - 'com/reandroid/arsc/pool/TypeStringPool.java', - 'com/reandroid/arsc/pool/TableStringPool.java', - 'com/reandroid/arsc/pool/JsonStringPoolHelper.java', - 'com/reandroid/arsc/chunk/LibraryBlock.java', - 'com/reandroid/arsc/chunk/TableBlock.java', - 'com/reandroid/arsc/chunk/UnknownChunk.java', - 'com/reandroid/arsc/chunk/MainChunk.java', - 'com/reandroid/arsc/chunk/TypeBlock.java', - 'com/reandroid/arsc/chunk/ChunkType.java', - 'com/reandroid/arsc/chunk/PackageBlock.java', - 'com/reandroid/arsc/chunk/xml/ResIdBuilder.java', - 'com/reandroid/arsc/chunk/xml/ResXmlNode.java', - 'com/reandroid/arsc/chunk/xml/ResXmlPullParser.java', - 'com/reandroid/arsc/chunk/xml/ResXmlText.java', - 'com/reandroid/arsc/chunk/xml/ResXmlIDMap.java', - 'com/reandroid/arsc/chunk/xml/ResXmlAttribute.java', - 'com/reandroid/arsc/chunk/xml/ResXmlEndElement.java', - 'com/reandroid/arsc/chunk/xml/ResXmlElement.java', - 'com/reandroid/arsc/chunk/xml/BaseXmlChunk.java', - 'com/reandroid/arsc/chunk/xml/ResXmlDocument.java', - 'com/reandroid/arsc/chunk/xml/ResXmlStartNamespace.java', - 'com/reandroid/arsc/chunk/xml/ResXmlStartElement.java', - 'com/reandroid/arsc/chunk/xml/ParserEventList.java', - 'com/reandroid/arsc/chunk/xml/ResXmlTextNode.java', - 'com/reandroid/arsc/chunk/xml/ParserEvent.java', - 'com/reandroid/arsc/chunk/xml/ResXmlNamespace.java', - 'com/reandroid/arsc/chunk/xml/AndroidManifestBlock.java', - 'com/reandroid/arsc/chunk/xml/ResXmlEndNamespace.java', - 'com/reandroid/arsc/chunk/SpecBlock.java', - 'com/reandroid/arsc/chunk/StagedAlias.java', - 'com/reandroid/arsc/chunk/ParentChunk.java', - 'com/reandroid/arsc/chunk/Overlayable.java', - 'com/reandroid/arsc/chunk/OverlayablePolicy.java', - 'com/reandroid/arsc/chunk/Chunk.java', - 'com/reandroid/arsc/ApkFile.java', - 'com/reandroid/arsc/array/EntryArray.java', - 'com/reandroid/arsc/array/SparseOffsetsArray.java', - 'com/reandroid/arsc/array/StyleArray.java', - 'com/reandroid/arsc/array/SpecTypePairArray.java', - 'com/reandroid/arsc/array/ResXmlIDArray.java', - 'com/reandroid/arsc/array/ResXmlAttributeArray.java', - 'com/reandroid/arsc/array/TypeBlockArray.java', - 'com/reandroid/arsc/array/TypeStringArray.java', - 'com/reandroid/arsc/array/SpecBlockArray.java', - 'com/reandroid/arsc/array/ResValueMapArray.java', - 'com/reandroid/arsc/array/StringArray.java', - 'com/reandroid/arsc/array/StagedAliasEntryArray.java', - 'com/reandroid/arsc/array/TableStringArray.java', - 'com/reandroid/arsc/array/SpecStringArray.java', - 'com/reandroid/arsc/array/OffsetArray.java', - 'com/reandroid/arsc/array/LibraryInfoArray.java', - 'com/reandroid/arsc/array/OffsetBlockArray.java', - 'com/reandroid/arsc/array/CompoundItemArray.java', - 'com/reandroid/arsc/array/ResXmlStringArray.java', - 'com/reandroid/arsc/array/PackageArray.java', - 'com/reandroid/arsc/model/StyleSpanInfo.java', - 'com/reandroid/arsc/model/StyledStringBuilder.java', - 'com/reandroid/arsc/value/AttributeType.java', - 'com/reandroid/arsc/value/Entry.java', - 'com/reandroid/arsc/value/StagedAliasEntry.java', - 'com/reandroid/arsc/value/CompoundEntry.java', - 'com/reandroid/arsc/value/ValueItem.java', - 'com/reandroid/arsc/value/EntryHeader.java', - 'com/reandroid/arsc/value/ResTableMapEntry.java', - 'com/reandroid/arsc/value/ResTableEntry.java', - 'com/reandroid/arsc/value/plurals/PluralsQuantity.java', - 'com/reandroid/arsc/value/plurals/PluralsBag.java', - 'com/reandroid/arsc/value/plurals/PluralsBagItem.java', - 'com/reandroid/arsc/value/Value.java', - 'com/reandroid/arsc/value/AttributeDataFormat.java', - 'com/reandroid/arsc/value/ResValueMap.java', - 'com/reandroid/arsc/value/ResConfig.java', - 'com/reandroid/arsc/value/attribute/AttributeBagItem.java', - 'com/reandroid/arsc/value/attribute/AttributeBag.java', - 'com/reandroid/arsc/value/AttributeValue.java', - 'com/reandroid/arsc/value/EntryHeaderMap.java', - 'com/reandroid/arsc/value/style/StyleBag.java', - 'com/reandroid/arsc/value/style/StyleBagItem.java', - 'com/reandroid/arsc/value/ValueType.java', - 'com/reandroid/arsc/value/TableEntry.java', - 'com/reandroid/arsc/value/ValueHeader.java', - 'com/reandroid/arsc/value/array/ArrayBagItem.java', - 'com/reandroid/arsc/value/array/ArrayBag.java', - 'com/reandroid/arsc/value/bag/BagItem.java', - 'com/reandroid/arsc/value/bag/Bag.java', - 'com/reandroid/arsc/value/bag/MapBag.java', - 'com/reandroid/arsc/value/LibraryInfo.java', - 'com/reandroid/arsc/value/ResValue.java', - 'com/reandroid/arsc/util/FrameworkTable.java', - 'com/reandroid/arsc/util/HexBytesWriter.java', - 'com/reandroid/arsc/util/ResNameMap.java', - 'com/reandroid/arsc/util/HexUtil.java', - 'com/reandroid/arsc/group/EntryGroup.java', - 'com/reandroid/arsc/group/StringGroup.java', - 'com/reandroid/arsc/group/ItemGroup.java', - 'com/reandroid/archive/ZipEntrySource.java', - 'com/reandroid/archive/ByteInputSource.java', - 'com/reandroid/archive/APKArchive.java', - 'com/reandroid/archive/WriteInterceptor.java', - 'com/reandroid/archive/FileInputSource.java', - 'com/reandroid/archive/ZipAlign.java', - 'com/reandroid/archive/InputSource.java', - 'com/reandroid/archive/ZipSerializer.java', - 'com/reandroid/archive/ZipArchive.java', - 'com/reandroid/archive/WriteProgress.java', - 'com/reandroid/archive/InputSourceUtil.java', - 'com/reandroid/xml/XMLDocument.java', - 'com/reandroid/xml/XMLElement.java', - 'com/reandroid/xml/NameSpaceItem.java', - 'com/reandroid/xml/XmlHeaderElement.java', - 'com/reandroid/xml/source/XMLDocumentSource.java', - 'com/reandroid/xml/source/XMLSource.java', - 'com/reandroid/xml/source/XMLStringSource.java', - 'com/reandroid/xml/source/XMLFileSource.java', - 'com/reandroid/xml/XmlParserToSerializer.java', - 'com/reandroid/xml/XMLNode.java', - 'com/reandroid/xml/parser/MXParser.java', - 'com/reandroid/xml/parser/XmlPullParser.java', - 'com/reandroid/xml/parser/XMLParseException.java', - 'com/reandroid/xml/parser/XmlPullParserException.java', - 'com/reandroid/xml/parser/MXParserNonValidating.java', - 'com/reandroid/xml/parser/XMLDocumentParser.java', - 'com/reandroid/xml/parser/MXParserCachingStrings.java', - 'com/reandroid/xml/parser/XMLSpanParser.java', - 'com/reandroid/xml/XMLParserFactory.java', - 'com/reandroid/xml/XMLSpannable.java', - 'com/reandroid/xml/XMLComment.java', - 'com/reandroid/xml/XMLUtil.java', - 'com/reandroid/xml/XMLSpanInfo.java', - 'com/reandroid/xml/ElementWriter.java', - 'com/reandroid/xml/XMLAttribute.java', - 'com/reandroid/xml/SchemaAttr.java', - 'com/reandroid/xml/XMLException.java', - 'com/reandroid/xml/XMLText.java', - 'com/reandroid/archive2/io/CountingOutputStream.java', - 'com/reandroid/archive2/io/ReadOnlyStream.java', - 'com/reandroid/archive2/io/CountingInputStream.java', - 'com/reandroid/archive2/io/SlicedInputStream.java', - 'com/reandroid/archive2/io/FileChannelOutputStream.java', - 'com/reandroid/archive2/io/ZipInput.java', - 'com/reandroid/archive2/io/ArchiveUtil.java', - 'com/reandroid/archive2/io/ZipFileInput.java', - 'com/reandroid/archive2/io/ZipFileOutput.java', - 'com/reandroid/archive2/io/ZipOutput.java', - 'com/reandroid/archive2/io/RandomStream.java', - 'com/reandroid/archive2/io/WriteOnlyStream.java', - 'com/reandroid/archive2/io/ArchiveEntrySource.java', - 'com/reandroid/archive2/ZipSignature.java', - 'com/reandroid/archive2/ArchiveEntry.java', - 'com/reandroid/archive2/block/CertificateBlock.java', - 'com/reandroid/archive2/block/v3/SchemeV31.java', - 'com/reandroid/archive2/block/v3/SchemeV3.java', - 'com/reandroid/archive2/block/LengthPrefixedBlock.java', - 'com/reandroid/archive2/block/LengthPrefixedBytes.java', - 'com/reandroid/archive2/block/CertificateBlockList.java', - 'com/reandroid/archive2/block/BottomBlock.java', - 'com/reandroid/archive2/block/UnknownScheme.java', - 'com/reandroid/archive2/block/DataDescriptor.java', - 'com/reandroid/archive2/block/LocalFileHeader.java', - 'com/reandroid/archive2/block/CentralEntryHeader.java', - 'com/reandroid/archive2/block/ApkSignatureBlock.java', - 'com/reandroid/archive2/block/ZipStringEncoding.java', - 'com/reandroid/archive2/block/SignatureScheme.java', - 'com/reandroid/archive2/block/LengthPrefixedList.java', - 'com/reandroid/archive2/block/stamp/SchemeStampV2.java', - 'com/reandroid/archive2/block/stamp/SchemeStampV1.java', - 'com/reandroid/archive2/block/ZipHeader.java', - 'com/reandroid/archive2/block/SignatureInfo.java', - 'com/reandroid/archive2/block/ZipBlock.java', - 'com/reandroid/archive2/block/EndRecord.java', - 'com/reandroid/archive2/block/v2/SchemeV2.java', - 'com/reandroid/archive2/block/v2/V2SignedDataList.java', - 'com/reandroid/archive2/block/v2/V2Signer.java', - 'com/reandroid/archive2/block/v2/V2Signature.java', - 'com/reandroid/archive2/block/v2/V2SignedData.java', - 'com/reandroid/archive2/block/SignatureId.java', - 'com/reandroid/archive2/block/SignatureFooter.java', - 'com/reandroid/archive2/block/CommonHeader.java', - 'com/reandroid/archive2/block/pad/SchemePadding.java', - 'com/reandroid/archive2/writer/RenamedArchiveSource.java', - 'com/reandroid/archive2/writer/ArchiveOutputSource.java', - 'com/reandroid/archive2/writer/BufferFileOutput.java', - 'com/reandroid/archive2/writer/ZipAligner.java', - 'com/reandroid/archive2/writer/ApkWriter.java', - 'com/reandroid/archive2/writer/OutputSource.java', - 'com/reandroid/archive2/writer/BufferFileInput.java', - 'com/reandroid/archive2/writer/EntryBuffer.java', - 'com/reandroid/archive2/model/CentralFileDirectory.java', - 'com/reandroid/archive2/model/LocalFileDirectory.java', - 'com/reandroid/archive2/Archive.java', - 'com/reandroid/identifiers/PackageIdentifier.java', - 'com/reandroid/identifiers/ResourceIdentifier.java', - 'com/reandroid/identifiers/TypeIdentifier.java', - 'com/reandroid/identifiers/IdentifierMap.java', - 'com/reandroid/identifiers/Identifier.java', - 'com/reandroid/identifiers/TableIdentifier.java', - 'com/reandroid/json/JSONStringer.java', - 'com/reandroid/json/JSONPointer.java', - 'com/reandroid/json/JSONPropertyIgnore.java', - 'com/reandroid/json/CookieList.java', - 'com/reandroid/json/JsonUtil.java', - 'com/reandroid/json/JSONWriter.java', - 'com/reandroid/json/HTTP.java', - 'com/reandroid/json/JSONML.java', - 'com/reandroid/json/CDL.java', - 'com/reandroid/json/XMLParserConfiguration.java', - 'com/reandroid/json/XMLTokener.java', - 'com/reandroid/json/HTTPTokener.java', - 'com/reandroid/json/JSONString.java', - 'com/reandroid/json/JSONTokener.java', - 'com/reandroid/json/JSONException.java', - 'com/reandroid/json/XMLXsiTypeConverter.java', - 'com/reandroid/json/XML.java', - 'com/reandroid/json/Cookie.java', - 'com/reandroid/json/JSONItem.java', - 'com/reandroid/json/Property.java', - 'com/reandroid/json/JSONConvert.java', - 'com/reandroid/json/JSONObject.java', - 'com/reandroid/json/JSONPropertyName.java', - 'com/reandroid/json/JSONArray.java', - 'com/reandroid/json/JSONPointerException.java', - 'android/content/res/XmlResourceParser.java', - 'android/util/AttributeSet.java', - 'org/xmlpull/v1/XmlPullParser.java', - 'org/xmlpull/v1/XmlPullParserException.java', - 'org/xmlpull/v1/XmlPullParserFactory.java', - 'org/xmlpull/v1/XmlSerializer.java', - ], - java_args: [ - '-bootclasspath', bootclasspath, - '-source', '1.8', '-target', '1.8' - ]) - diff --git a/src/ARSCLib/org/xmlpull/v1/XmlPullParser.java b/src/ARSCLib/org/xmlpull/v1/XmlPullParser.java deleted file mode 100644 index 675e3576..00000000 --- a/src/ARSCLib/org/xmlpull/v1/XmlPullParser.java +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- //------100-columns-wide------>|*/ -// for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/) -package org.xmlpull.v1; - -import java.io.InputStream; -import java.io.IOException; -import java.io.Reader; - -public interface XmlPullParser{ - String NO_NAMESPACE = ""; - int START_DOCUMENT = 0; - int END_DOCUMENT = 1; - int START_TAG = 2; - int END_TAG = 3; - int TEXT = 4; - int CDSECT = 5; - int ENTITY_REF = 6; - int IGNORABLE_WHITESPACE = 7; - int PROCESSING_INSTRUCTION = 8; - int COMMENT = 9; - int DOCDECL = 10; - String [] TYPES = { - "START_DOCUMENT", - "END_DOCUMENT", - "START_TAG", - "END_TAG", - "TEXT", - "CDSECT", - "ENTITY_REF", - "IGNORABLE_WHITESPACE", - "PROCESSING_INSTRUCTION", - "COMMENT", - "DOCDECL" - }; - String FEATURE_PROCESS_NAMESPACES = "http://xmlpull.org/v1/doc/features.html#process-namespaces"; - String FEATURE_REPORT_NAMESPACE_ATTRIBUTES = "http://xmlpull.org/v1/doc/features.html#report-namespace-prefixes"; - String FEATURE_PROCESS_DOCDECL = "http://xmlpull.org/v1/doc/features.html#process-docdecl"; - String FEATURE_VALIDATION = "http://xmlpull.org/v1/doc/features.html#validation"; - - void setFeature(String name, boolean state) throws XmlPullParserException; - boolean getFeature(String name); - void setProperty(String name, Object value) throws XmlPullParserException; - Object getProperty(String name); - void setInput(Reader in) throws XmlPullParserException; - void setInput(InputStream inputStream, String inputEncoding) throws XmlPullParserException; - String getInputEncoding(); - void defineEntityReplacementText( String entityName, String replacementText ) throws XmlPullParserException; - int getNamespaceCount(int depth) throws XmlPullParserException; - String getNamespacePrefix(int pos) throws XmlPullParserException; - String getNamespaceUri(int pos) throws XmlPullParserException; - String getNamespace (String prefix); - int getDepth(); - String getPositionDescription (); - int getLineNumber(); - int getColumnNumber(); - boolean isWhitespace() throws XmlPullParserException; - String getText (); - char[] getTextCharacters(int [] holderForStartAndLength); - String getNamespace (); - String getName(); - String getPrefix(); - boolean isEmptyElementTag() throws XmlPullParserException; - int getAttributeCount(); - String getAttributeNamespace (int index); - String getAttributeName (int index); - String getAttributePrefix(int index); - String getAttributeType(int index); - boolean isAttributeDefault(int index); - String getAttributeValue(int index); - String getAttributeValue(String namespace, String name); - int getEventType() throws XmlPullParserException; - int next() throws XmlPullParserException, IOException; - int nextToken() throws XmlPullParserException, IOException; - void require(int type, String namespace, String name) throws XmlPullParserException, IOException; - String nextText() throws XmlPullParserException, IOException; - int nextTag() throws XmlPullParserException, IOException; - -} diff --git a/src/ARSCLib/org/xmlpull/v1/XmlPullParserException.java b/src/ARSCLib/org/xmlpull/v1/XmlPullParserException.java deleted file mode 100644 index c62a21b4..00000000 --- a/src/ARSCLib/org/xmlpull/v1/XmlPullParserException.java +++ /dev/null @@ -1,76 +0,0 @@ -/* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- //------100-columns-wide------>|*/ -// for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/) - -package org.xmlpull.v1; - -/** - * This exception is thrown to signal XML Pull Parser related faults. - * - * @author
Aleksander Slominski - */ -public class XmlPullParserException extends Exception{ - protected Throwable detail; - protected int row = -1; - protected int column = -1; - - /* public XmlPullParserException() { - }*/ - - public XmlPullParserException(String s) { - super(s); - } - - /* - public XmlPullParserException(String s, Throwable thrwble) { - super(s); - this.detail = thrwble; - } - - public XmlPullParserException(String s, int row, int column) { - super(s); - this.row = row; - this.column = column; - } - */ - - public XmlPullParserException(String msg, XmlPullParser parser, Throwable chain) { - super ((msg == null ? "" : msg+" ") - + (parser == null ? "" : "(position:"+parser.getPositionDescription()+") ") - + (chain == null ? "" : "caused by: "+chain)); - - if (parser != null) { - this.row = parser.getLineNumber(); - this.column = parser.getColumnNumber(); - } - this.detail = chain; - } - - public Throwable getDetail() { return detail; } - // public void setDetail(Throwable cause) { this.detail = cause; } - public int getLineNumber() { return row; } - public int getColumnNumber() { return column; } - - /* - public String getMessage() { - if(detail == null) - return super.getMessage(); - else - return super.getMessage() + "; nested exception is: \n\t" - + detail.getMessage(); - } - */ - - //NOTE: code that prints this and detail is difficult in J2ME - public void printStackTrace() { - if (detail == null) { - super.printStackTrace(); - } else { - synchronized(System.err) { - System.err.println(super.getMessage() + "; nested exception is:"); - detail.printStackTrace(); - } - } - } - -} - diff --git a/src/ARSCLib/org/xmlpull/v1/XmlPullParserFactory.java b/src/ARSCLib/org/xmlpull/v1/XmlPullParserFactory.java deleted file mode 100644 index 46bff9bd..00000000 --- a/src/ARSCLib/org/xmlpull/v1/XmlPullParserFactory.java +++ /dev/null @@ -1,119 +0,0 @@ -/* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- //------100-columns-wide------>|*/ -// for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/) -package org.xmlpull.v1; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -public class XmlPullParserFactory { - public static final String PROPERTY_NAME = "org.xmlpull.v1.XmlPullParserFactory"; - protected ArrayList parserClasses; - protected ArrayList serializerClasses; - protected String classNamesLocation = null; - protected HashMap features = new HashMap(); - protected XmlPullParserFactory() { - parserClasses = new ArrayList(); - serializerClasses = new ArrayList(); - try { - parserClasses.add(Class.forName("com.android.org.kxml2.io.KXmlParser")); - serializerClasses.add(Class.forName("com.android.org.kxml2.io.KXmlSerializer")); - } catch (ClassNotFoundException e) { - throw new AssertionError(); - } - } - public void setFeature(String name, boolean state) throws XmlPullParserException { - features.put(name, state); - } - public boolean getFeature(String name) { - Boolean value = features.get(name); - return value != null ? value.booleanValue() : false; - } - public void setNamespaceAware(boolean awareness) { - features.put (XmlPullParser.FEATURE_PROCESS_NAMESPACES, awareness); - } - public boolean isNamespaceAware() { - return getFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES); - } - public void setValidating(boolean validating) { - features.put(XmlPullParser.FEATURE_VALIDATION, validating); - } - - public boolean isValidating() { - return getFeature(XmlPullParser.FEATURE_VALIDATION); - } - public XmlPullParser newPullParser() throws XmlPullParserException { - final XmlPullParser pp = getParserInstance(); - for (Map.Entry entry : features.entrySet()) { - if (entry.getValue()) { - pp.setFeature(entry.getKey(), entry.getValue()); - } - } - return pp; - } - private XmlPullParser getParserInstance() throws XmlPullParserException { - ArrayList exceptions = null; - if (parserClasses != null && !parserClasses.isEmpty()) { - exceptions = new ArrayList(); - for (Object o : parserClasses) { - try { - if (o != null) { - Class parserClass = (Class) o; - return (XmlPullParser) parserClass.newInstance(); - } - } catch (InstantiationException e) { - exceptions.add(e); - } catch (IllegalAccessException e) { - exceptions.add(e); - } catch (ClassCastException e) { - exceptions.add(e); - } - } - } - throw newInstantiationException("Invalid parser class list", exceptions); - } - private XmlSerializer getSerializerInstance() throws XmlPullParserException { - ArrayList exceptions = null; - if (serializerClasses != null && !serializerClasses.isEmpty()) { - exceptions = new ArrayList(); - for (Object o : serializerClasses) { - try { - if (o != null) { - Class serializerClass = (Class) o; - return (XmlSerializer) serializerClass.newInstance(); - } - } catch (InstantiationException e) { - exceptions.add(e); - } catch (IllegalAccessException e) { - exceptions.add(e); - } catch (ClassCastException e) { - exceptions.add(e); - } - } - } - throw newInstantiationException("Invalid serializer class list", exceptions); - } - private static XmlPullParserException newInstantiationException(String message, - ArrayList exceptions) { - if (exceptions == null || exceptions.isEmpty()) { - return new XmlPullParserException(message); - } else { - XmlPullParserException exception = new XmlPullParserException(message); - for (Exception ex : exceptions) { - exception.addSuppressed(ex); - } - return exception; - } - } - - public XmlSerializer newSerializer() throws XmlPullParserException { - return getSerializerInstance(); - } - public static XmlPullParserFactory newInstance () throws XmlPullParserException { - return new XmlPullParserFactory(); - } - public static XmlPullParserFactory newInstance (String unused, Class unused2) - throws XmlPullParserException { - return newInstance(); - } -} diff --git a/src/ARSCLib/org/xmlpull/v1/XmlSerializer.java b/src/ARSCLib/org/xmlpull/v1/XmlSerializer.java deleted file mode 100644 index 2cfeec49..00000000 --- a/src/ARSCLib/org/xmlpull/v1/XmlSerializer.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.xmlpull.v1; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.Writer; - -public interface XmlSerializer { - void setFeature(String name, boolean state) - throws IllegalArgumentException, IllegalStateException; - boolean getFeature(String name); - void setProperty(String name, Object value) - throws IllegalArgumentException, IllegalStateException; - Object getProperty(String name); - void setOutput(OutputStream os, String encoding) - throws IOException, IllegalArgumentException, IllegalStateException; - void setOutput(Writer writer) - throws IOException, IllegalArgumentException, IllegalStateException; - void startDocument(String encoding, Boolean standalone) - throws IOException, IllegalArgumentException, IllegalStateException; - void endDocument() - throws IOException, IllegalArgumentException, IllegalStateException; - void setPrefix(String prefix, String namespace) - throws IOException, IllegalArgumentException, IllegalStateException; - String getPrefix(String namespace, boolean generatePrefix) - throws IllegalArgumentException; - int getDepth(); - String getNamespace(); - String getName(); - XmlSerializer startTag(String namespace, String name) - throws IOException, IllegalArgumentException, IllegalStateException; - XmlSerializer attribute(String namespace, String name, String value) - throws IOException, IllegalArgumentException, IllegalStateException; - XmlSerializer endTag(String namespace, String name) - throws IOException, IllegalArgumentException, IllegalStateException; - XmlSerializer text(String text) - throws IOException, IllegalArgumentException, IllegalStateException; - XmlSerializer text(char [] buf, int start, int len) - throws IOException, IllegalArgumentException, IllegalStateException; - void cdsect(String text) - throws IOException, IllegalArgumentException, IllegalStateException; - void entityRef(String text) throws IOException, - IllegalArgumentException, IllegalStateException; - void processingInstruction(String text) - throws IOException, IllegalArgumentException, IllegalStateException; - void comment(String text) - throws IOException, IllegalArgumentException, IllegalStateException; - void docdecl(String text) - throws IOException, IllegalArgumentException, IllegalStateException; - void ignorableWhitespace(String text) - throws IOException, IllegalArgumentException, IllegalStateException; - void flush() throws IOException; -}