mirror of
https://github.com/revanced/Apktool.git
synced 2025-05-01 22:54:24 +02:00
Code cleanup of 2013
Signed-off-by: Connor Tumbleson <connor.tumbleson@gmail.com>
This commit is contained in:
parent
f504ceca43
commit
e82c0754de
@ -36,8 +36,8 @@ import java.util.logging.*;
|
|||||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||||
*/
|
*/
|
||||||
public class Main {
|
public class Main {
|
||||||
public static void main(String[] args)
|
public static void main(String[] args) throws IOException,
|
||||||
throws IOException, InterruptedException, BrutException {
|
InterruptedException, BrutException {
|
||||||
try {
|
try {
|
||||||
Verbosity verbosity = Verbosity.NORMAL;
|
Verbosity verbosity = Verbosity.NORMAL;
|
||||||
int i;
|
int i;
|
||||||
@ -48,7 +48,7 @@ public class Main {
|
|||||||
version_print();
|
version_print();
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
if (! opt.startsWith("-")) {
|
if (!opt.startsWith("-")) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ("-v".equals(opt) || "--verbose".equals(opt)) {
|
if ("-v".equals(opt) || "--verbose".equals(opt)) {
|
||||||
@ -97,7 +97,7 @@ public class Main {
|
|||||||
int i;
|
int i;
|
||||||
for (i = 0; i < args.length; i++) {
|
for (i = 0; i < args.length; i++) {
|
||||||
String opt = args[i];
|
String opt = args[i];
|
||||||
if (! opt.startsWith("-")) {
|
if (!opt.startsWith("-")) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ("-s".equals(opt) || "--no-src".equals(opt)) {
|
if ("-s".equals(opt) || "--no-src".equals(opt)) {
|
||||||
@ -132,8 +132,8 @@ public class Main {
|
|||||||
outName = args[i + 1];
|
outName = args[i + 1];
|
||||||
} else if (args.length == i + 1) {
|
} else if (args.length == i + 1) {
|
||||||
outName = args[i];
|
outName = args[i];
|
||||||
outName = outName.endsWith(".apk") ?
|
outName = outName.endsWith(".apk") ? outName.substring(0,
|
||||||
outName.substring(0, outName.length() - 4) : outName + ".out";
|
outName.length() - 4) : outName + ".out";
|
||||||
outName = new File(outName).getName();
|
outName = new File(outName).getName();
|
||||||
} else {
|
} else {
|
||||||
throw new InvalidArgsError();
|
throw new InvalidArgsError();
|
||||||
@ -145,24 +145,26 @@ public class Main {
|
|||||||
try {
|
try {
|
||||||
decoder.decode();
|
decoder.decode();
|
||||||
} catch (OutDirExistsException ex) {
|
} catch (OutDirExistsException ex) {
|
||||||
System.out.println(
|
System.out
|
||||||
"Destination directory (" + outDir.getAbsolutePath() + ") " +
|
.println("Destination directory ("
|
||||||
"already exists. Use -f switch if you want to overwrite it.");
|
+ outDir.getAbsolutePath()
|
||||||
|
+ ") "
|
||||||
|
+ "already exists. Use -f switch if you want to overwrite it.");
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
} catch (InFileNotFoundException ex) {
|
} catch (InFileNotFoundException ex) {
|
||||||
System.out.println(
|
System.out.println("Input file (" + args[i] + ") "
|
||||||
"Input file (" + args[i] + ") " +
|
+ "was not found or was not readable.");
|
||||||
"was not found or was not readable.");
|
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
} catch (CantFindFrameworkResException ex) {
|
} catch (CantFindFrameworkResException ex) {
|
||||||
System.out.println(
|
System.out
|
||||||
"Can't find framework resources for package of id: " +
|
.println("Can't find framework resources for package of id: "
|
||||||
String.valueOf(ex.getPkgId()) + ". You must install proper " +
|
+ String.valueOf(ex.getPkgId())
|
||||||
"framework files, see project website for more info.");
|
+ ". You must install proper "
|
||||||
|
+ "framework files, see project website for more info.");
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
System.out.println(
|
System.out
|
||||||
"Could not modify file. Please ensure you have permission.");
|
.println("Could not modify file. Please ensure you have permission.");
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +187,7 @@ public class Main {
|
|||||||
String mAaptPath = "";
|
String mAaptPath = "";
|
||||||
for (i = 0; i < args.length; i++) {
|
for (i = 0; i < args.length; i++) {
|
||||||
String opt = args[i];
|
String opt = args[i];
|
||||||
if (! opt.startsWith("-")) {
|
if (!opt.startsWith("-")) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ("-f".equals(opt) || "--force-all".equals(opt)) {
|
if ("-f".equals(opt) || "--force-all".equals(opt)) {
|
||||||
@ -225,7 +227,8 @@ public class Main {
|
|||||||
throw new InvalidArgsError();
|
throw new InvalidArgsError();
|
||||||
}
|
}
|
||||||
|
|
||||||
new Androlib().build(new File(appDirName), outFile, flags, mOrigApk, mAaptPath);
|
new Androlib().build(new File(appDirName), outFile, flags, mOrigApk,
|
||||||
|
mAaptPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void cmdInstallFramework(String[] args)
|
private static void cmdInstallFramework(String[] args)
|
||||||
@ -264,74 +267,77 @@ public class Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void version_print() {
|
private static void version_print() {
|
||||||
System.out.println(
|
System.out.println(Androlib.getVersion());
|
||||||
Androlib.getVersion());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void usage() {
|
private static void usage() {
|
||||||
System.out.println(
|
System.out
|
||||||
"Apktool v" + Androlib.getVersion() + " - a tool for reengineering Android apk files\n" +
|
.println("Apktool v"
|
||||||
"Copyright 2010 Ryszard Wiśniewski <brut.alll@gmail.com>\n" +
|
+ Androlib.getVersion()
|
||||||
"with smali v" + ApktoolProperties.get("smaliVersion") +
|
+ " - a tool for reengineering Android apk files\n"
|
||||||
", and baksmali v" + ApktoolProperties.get("baksmaliVersion") + "\n" +
|
+ "Copyright 2010 Ryszard Wiśniewski <brut.alll@gmail.com>\n"
|
||||||
"Updated by @iBotPeaches <connor.tumbleson@gmail.com> \n" +
|
+ "with smali v"
|
||||||
"Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)\n" +
|
+ ApktoolProperties.get("smaliVersion")
|
||||||
"\n" +
|
+ ", and baksmali v"
|
||||||
"Usage: apktool [-q|--quiet OR -v|--verbose] COMMAND [...]\n" +
|
+ ApktoolProperties.get("baksmaliVersion")
|
||||||
"\n" +
|
+ "\n"
|
||||||
"COMMANDs are:\n" +
|
+ "Updated by @iBotPeaches <connor.tumbleson@gmail.com> \n"
|
||||||
"\n" +
|
+ "Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)\n"
|
||||||
" d[ecode] [OPTS] <file.apk> [<dir>]\n" +
|
+ "\n"
|
||||||
" Decode <file.apk> to <dir>.\n" +
|
+ "Usage: apktool [-q|--quiet OR -v|--verbose] COMMAND [...]\n"
|
||||||
"\n" +
|
+ "\n"
|
||||||
" OPTS:\n" +
|
+ "COMMANDs are:\n"
|
||||||
"\n" +
|
+ "\n"
|
||||||
" -s, --no-src\n" +
|
+ " d[ecode] [OPTS] <file.apk> [<dir>]\n"
|
||||||
" Do not decode sources.\n" +
|
+ " Decode <file.apk> to <dir>.\n"
|
||||||
" -r, --no-res\n" +
|
+ "\n"
|
||||||
" Do not decode resources.\n" +
|
+ " OPTS:\n"
|
||||||
" -d, --debug\n" +
|
+ "\n"
|
||||||
" Decode in debug mode. Check project page for more info.\n" +
|
+ " -s, --no-src\n"
|
||||||
" -b, --no-debug-info\n" +
|
+ " Do not decode sources.\n"
|
||||||
" Baksmali -- don't write out debug info (.local, .param, .line, etc.)\n" +
|
+ " -r, --no-res\n"
|
||||||
" -f, --force\n" +
|
+ " Do not decode resources.\n"
|
||||||
" Force delete destination directory.\n" +
|
+ " -d, --debug\n"
|
||||||
" -t <tag>, --frame-tag <tag>\n" +
|
+ " Decode in debug mode. Check project page for more info.\n"
|
||||||
" Try to use framework files tagged by <tag>.\n" +
|
+ " -b, --no-debug-info\n"
|
||||||
" --frame-path <dir>\n" +
|
+ " Baksmali -- don't write out debug info (.local, .param, .line, etc.)\n"
|
||||||
" Use the specified directory for framework files\n" +
|
+ " -f, --force\n"
|
||||||
" --keep-broken-res\n" +
|
+ " Force delete destination directory.\n"
|
||||||
" Use if there was an error and some resources were dropped, e.g.:\n" +
|
+ " -t <tag>, --frame-tag <tag>\n"
|
||||||
" \"Invalid config flags detected. Dropping resources\", but you\n" +
|
+ " Try to use framework files tagged by <tag>.\n"
|
||||||
" want to decode them anyway, even with errors. You will have to\n" +
|
+ " --frame-path <dir>\n"
|
||||||
" fix them manually before building." +
|
+ " Use the specified directory for framework files\n"
|
||||||
"\n\n" +
|
+ " --keep-broken-res\n"
|
||||||
" b[uild] [OPTS] [<app_path>] [<out_file>]\n" +
|
+ " Use if there was an error and some resources were dropped, e.g.:\n"
|
||||||
" Build an apk from already decoded application located in <app_path>.\n" +
|
+ " \"Invalid config flags detected. Dropping resources\", but you\n"
|
||||||
"\n" +
|
+ " want to decode them anyway, even with errors. You will have to\n"
|
||||||
" It will automatically detect, whether files was changed and perform\n" +
|
+ " fix them manually before building."
|
||||||
" needed steps only.\n" +
|
+ "\n\n"
|
||||||
"\n" +
|
+ " b[uild] [OPTS] [<app_path>] [<out_file>]\n"
|
||||||
" If you omit <app_path> then current directory will be used.\n" +
|
+ " Build an apk from already decoded application located in <app_path>.\n"
|
||||||
" If you omit <out_file> then <app_path>/dist/<name_of_original.apk>\n" +
|
+ "\n"
|
||||||
" will be used.\n" +
|
+ " It will automatically detect, whether files was changed and perform\n"
|
||||||
"\n" +
|
+ " needed steps only.\n"
|
||||||
" OPTS:\n" +
|
+ "\n"
|
||||||
"\n" +
|
+ " If you omit <app_path> then current directory will be used.\n"
|
||||||
" -f, --force-all\n" +
|
+ " If you omit <out_file> then <app_path>/dist/<name_of_original.apk>\n"
|
||||||
" Skip changes detection and build all files.\n" +
|
+ " will be used.\n"
|
||||||
" -d, --debug\n" +
|
+ "\n"
|
||||||
" Build in debug mode. Check project page for more info.\n" +
|
+ " OPTS:\n"
|
||||||
" -a, --aapt\n" +
|
+ "\n"
|
||||||
" Loads aapt from specified location.\n" +
|
+ " -f, --force-all\n"
|
||||||
"\n" +
|
+ " Skip changes detection and build all files.\n"
|
||||||
" if|install-framework <framework.apk> [<tag>] --frame-path [<location>] \n" +
|
+ " -d, --debug\n"
|
||||||
" Install framework file to your system.\n" +
|
+ " Build in debug mode. Check project page for more info.\n"
|
||||||
"\n" +
|
+ " -a, --aapt\n"
|
||||||
"For additional info, see: http://code.google.com/p/android-apktool/" +
|
+ " Loads aapt from specified location.\n"
|
||||||
"\n" +
|
+ "\n"
|
||||||
"For smali/baksmali info, see: http://code.google.com/p/smali/"
|
+ " if|install-framework <framework.apk> [<tag>] --frame-path [<location>] \n"
|
||||||
);
|
+ " Install framework file to your system.\n"
|
||||||
|
+ "\n"
|
||||||
|
+ "For additional info, see: http://code.google.com/p/android-apktool/"
|
||||||
|
+ "\n"
|
||||||
|
+ "For smali/baksmali info, see: http://code.google.com/p/smali/");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setupLogging(Verbosity verbosity) {
|
private static void setupLogging(Verbosity verbosity) {
|
||||||
|
@ -22,9 +22,9 @@ import android.util.AttributeSet;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The XML parsing interface returned for an XML resource. This is a standard
|
* The XML parsing interface returned for an XML resource. This is a standard
|
||||||
* XmlPullParser interface, as well as an extended AttributeSet interface and
|
* XmlPullParser interface, as well as an extended AttributeSet interface and an
|
||||||
* an additional close() method on this interface for the client to indicate
|
* additional close() method on this interface for the client to indicate when
|
||||||
* when it is done reading the resource.
|
* it is done reading the resource.
|
||||||
*/
|
*/
|
||||||
public interface XmlResourceParser extends XmlPullParser, AttributeSet {
|
public interface XmlResourceParser extends XmlPullParser, AttributeSet {
|
||||||
/**
|
/**
|
||||||
@ -33,4 +33,3 @@ public interface XmlResourceParser extends XmlPullParser, AttributeSet {
|
|||||||
*/
|
*/
|
||||||
public void close();
|
public void close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,29 +21,57 @@ package android.util;
|
|||||||
*/
|
*/
|
||||||
public interface AttributeSet {
|
public interface AttributeSet {
|
||||||
int getAttributeCount();
|
int getAttributeCount();
|
||||||
String getAttributeName(int index);
|
|
||||||
String getAttributeValue(int index);
|
|
||||||
String getPositionDescription();
|
|
||||||
int getAttributeNameResource(int index);
|
|
||||||
int getAttributeListValue(int index,String options[],int defaultValue);
|
|
||||||
boolean getAttributeBooleanValue(int index,boolean defaultValue);
|
|
||||||
int getAttributeResourceValue(int index,int defaultValue);
|
|
||||||
int getAttributeIntValue(int index,int defaultValue);
|
|
||||||
int getAttributeUnsignedIntValue(int index,int defaultValue);
|
|
||||||
float getAttributeFloatValue(int index,float defaultValue);
|
|
||||||
String getIdAttribute();
|
|
||||||
String getClassAttribute();
|
|
||||||
int getIdAttributeResourceValue(int index);
|
|
||||||
int getStyleAttribute();
|
|
||||||
String getAttributeValue(String namespace, String attribute);
|
|
||||||
int getAttributeListValue(String namespace,String attribute,String options[],int defaultValue);
|
|
||||||
boolean getAttributeBooleanValue(String namespace,String attribute,boolean defaultValue);
|
|
||||||
int getAttributeResourceValue(String namespace,String attribute,int defaultValue);
|
|
||||||
int getAttributeIntValue(String namespace,String attribute,int defaultValue);
|
|
||||||
int getAttributeUnsignedIntValue(String namespace,String attribute,int defaultValue);
|
|
||||||
float getAttributeFloatValue(String namespace,String attribute,float defaultValue);
|
|
||||||
|
|
||||||
//TODO: remove
|
String getAttributeName(int index);
|
||||||
|
|
||||||
|
String getAttributeValue(int index);
|
||||||
|
|
||||||
|
String getPositionDescription();
|
||||||
|
|
||||||
|
int getAttributeNameResource(int index);
|
||||||
|
|
||||||
|
int getAttributeListValue(int index, String options[], int defaultValue);
|
||||||
|
|
||||||
|
boolean getAttributeBooleanValue(int index, boolean defaultValue);
|
||||||
|
|
||||||
|
int getAttributeResourceValue(int index, int defaultValue);
|
||||||
|
|
||||||
|
int getAttributeIntValue(int index, int defaultValue);
|
||||||
|
|
||||||
|
int getAttributeUnsignedIntValue(int index, int defaultValue);
|
||||||
|
|
||||||
|
float getAttributeFloatValue(int index, float defaultValue);
|
||||||
|
|
||||||
|
String getIdAttribute();
|
||||||
|
|
||||||
|
String getClassAttribute();
|
||||||
|
|
||||||
|
int getIdAttributeResourceValue(int index);
|
||||||
|
|
||||||
|
int getStyleAttribute();
|
||||||
|
|
||||||
|
String getAttributeValue(String namespace, String attribute);
|
||||||
|
|
||||||
|
int getAttributeListValue(String namespace, String attribute,
|
||||||
|
String options[], int defaultValue);
|
||||||
|
|
||||||
|
boolean getAttributeBooleanValue(String namespace, String attribute,
|
||||||
|
boolean defaultValue);
|
||||||
|
|
||||||
|
int getAttributeResourceValue(String namespace, String attribute,
|
||||||
|
int defaultValue);
|
||||||
|
|
||||||
|
int getAttributeIntValue(String namespace, String attribute,
|
||||||
|
int defaultValue);
|
||||||
|
|
||||||
|
int getAttributeUnsignedIntValue(String namespace, String attribute,
|
||||||
|
int defaultValue);
|
||||||
|
|
||||||
|
float getAttributeFloatValue(String namespace, String attribute,
|
||||||
|
float defaultValue);
|
||||||
|
|
||||||
|
// TODO: remove
|
||||||
int getAttributeValueType(int index);
|
int getAttributeValueType(int index);
|
||||||
|
|
||||||
int getAttributeValueData(int index);
|
int getAttributeValueData(int index);
|
||||||
}
|
}
|
@ -26,58 +26,86 @@ public class TypedValue {
|
|||||||
|
|
||||||
/** The <var>data</var> field holds a resource identifier. */
|
/** The <var>data</var> field holds a resource identifier. */
|
||||||
public static final int TYPE_REFERENCE = 0x01;
|
public static final int TYPE_REFERENCE = 0x01;
|
||||||
/** The <var>data</var> field holds an attribute resource
|
/**
|
||||||
* identifier (referencing an attribute in the current theme
|
* The <var>data</var> field holds an attribute resource identifier
|
||||||
* style, not a resource entry). */
|
* (referencing an attribute in the current theme style, not a resource
|
||||||
|
* entry).
|
||||||
|
*/
|
||||||
public static final int TYPE_ATTRIBUTE = 0x02;
|
public static final int TYPE_ATTRIBUTE = 0x02;
|
||||||
/** The <var>string</var> field holds string data. In addition, if
|
/**
|
||||||
* <var>data</var> is non-zero then it is the string block
|
* The <var>string</var> field holds string data. In addition, if
|
||||||
* index of the string and <var>assetCookie</var> is the set of
|
* <var>data</var> is non-zero then it is the string block index of the
|
||||||
* assets the string came from. */
|
* string and <var>assetCookie</var> is the set of assets the string came
|
||||||
|
* from.
|
||||||
|
*/
|
||||||
public static final int TYPE_STRING = 0x03;
|
public static final int TYPE_STRING = 0x03;
|
||||||
/** The <var>data</var> field holds an IEEE 754 floating point number. */
|
/** The <var>data</var> field holds an IEEE 754 floating point number. */
|
||||||
public static final int TYPE_FLOAT = 0x04;
|
public static final int TYPE_FLOAT = 0x04;
|
||||||
/** The <var>data</var> field holds a complex number encoding a
|
/**
|
||||||
* dimension value. */
|
* The <var>data</var> field holds a complex number encoding a dimension
|
||||||
|
* value.
|
||||||
|
*/
|
||||||
public static final int TYPE_DIMENSION = 0x05;
|
public static final int TYPE_DIMENSION = 0x05;
|
||||||
/** The <var>data</var> field holds a complex number encoding a fraction
|
/**
|
||||||
* of a container. */
|
* The <var>data</var> field holds a complex number encoding a fraction of a
|
||||||
|
* container.
|
||||||
|
*/
|
||||||
public static final int TYPE_FRACTION = 0x06;
|
public static final int TYPE_FRACTION = 0x06;
|
||||||
|
|
||||||
/** Identifies the start of plain integer values. Any type value
|
/**
|
||||||
* from this to {@link #TYPE_LAST_INT} means the
|
* Identifies the start of plain integer values. Any type value from this to
|
||||||
* <var>data</var> field holds a generic integer value. */
|
* {@link #TYPE_LAST_INT} means the <var>data</var> field holds a generic
|
||||||
|
* integer value.
|
||||||
|
*/
|
||||||
public static final int TYPE_FIRST_INT = 0x10;
|
public static final int TYPE_FIRST_INT = 0x10;
|
||||||
|
|
||||||
/** The <var>data</var> field holds a number that was
|
/**
|
||||||
* originally specified in decimal. */
|
* The <var>data</var> field holds a number that was originally specified in
|
||||||
|
* decimal.
|
||||||
|
*/
|
||||||
public static final int TYPE_INT_DEC = 0x10;
|
public static final int TYPE_INT_DEC = 0x10;
|
||||||
/** The <var>data</var> field holds a number that was
|
/**
|
||||||
* originally specified in hexadecimal (0xn). */
|
* The <var>data</var> field holds a number that was originally specified in
|
||||||
|
* hexadecimal (0xn).
|
||||||
|
*/
|
||||||
public static final int TYPE_INT_HEX = 0x11;
|
public static final int TYPE_INT_HEX = 0x11;
|
||||||
/** The <var>data</var> field holds 0 or 1 that was originally
|
/**
|
||||||
* specified as "false" or "true". */
|
* The <var>data</var> field holds 0 or 1 that was originally specified as
|
||||||
|
* "false" or "true".
|
||||||
|
*/
|
||||||
public static final int TYPE_INT_BOOLEAN = 0x12;
|
public static final int TYPE_INT_BOOLEAN = 0x12;
|
||||||
|
|
||||||
/** Identifies the start of integer values that were specified as
|
/**
|
||||||
* color constants (starting with '#'). */
|
* Identifies the start of integer values that were specified as color
|
||||||
|
* constants (starting with '#').
|
||||||
|
*/
|
||||||
public static final int TYPE_FIRST_COLOR_INT = 0x1c;
|
public static final int TYPE_FIRST_COLOR_INT = 0x1c;
|
||||||
|
|
||||||
/** The <var>data</var> field holds a color that was originally
|
/**
|
||||||
* specified as #aarrggbb. */
|
* The <var>data</var> field holds a color that was originally specified as
|
||||||
|
* #aarrggbb.
|
||||||
|
*/
|
||||||
public static final int TYPE_INT_COLOR_ARGB8 = 0x1c;
|
public static final int TYPE_INT_COLOR_ARGB8 = 0x1c;
|
||||||
/** The <var>data</var> field holds a color that was originally
|
/**
|
||||||
* specified as #rrggbb. */
|
* The <var>data</var> field holds a color that was originally specified as
|
||||||
|
* #rrggbb.
|
||||||
|
*/
|
||||||
public static final int TYPE_INT_COLOR_RGB8 = 0x1d;
|
public static final int TYPE_INT_COLOR_RGB8 = 0x1d;
|
||||||
/** The <var>data</var> field holds a color that was originally
|
/**
|
||||||
* specified as #argb. */
|
* The <var>data</var> field holds a color that was originally specified as
|
||||||
|
* #argb.
|
||||||
|
*/
|
||||||
public static final int TYPE_INT_COLOR_ARGB4 = 0x1e;
|
public static final int TYPE_INT_COLOR_ARGB4 = 0x1e;
|
||||||
/** The <var>data</var> field holds a color that was originally
|
/**
|
||||||
* specified as #rgb. */
|
* The <var>data</var> field holds a color that was originally specified as
|
||||||
|
* #rgb.
|
||||||
|
*/
|
||||||
public static final int TYPE_INT_COLOR_RGB4 = 0x1f;
|
public static final int TYPE_INT_COLOR_RGB4 = 0x1f;
|
||||||
|
|
||||||
/** Identifies the end of integer values that were specified as color
|
/**
|
||||||
* constants. */
|
* Identifies the end of integer values that were specified as color
|
||||||
|
* constants.
|
||||||
|
*/
|
||||||
public static final int TYPE_LAST_COLOR_INT = 0x1f;
|
public static final int TYPE_LAST_COLOR_INT = 0x1f;
|
||||||
|
|
||||||
/** Identifies the end of plain integer values. */
|
/** Identifies the end of plain integer values. */
|
||||||
@ -87,15 +115,18 @@ public class TypedValue {
|
|||||||
|
|
||||||
/** Complex data: bit location of unit information. */
|
/** Complex data: bit location of unit information. */
|
||||||
public static final int COMPLEX_UNIT_SHIFT = 0;
|
public static final int COMPLEX_UNIT_SHIFT = 0;
|
||||||
/** Complex data: mask to extract unit information (after shifting by
|
/**
|
||||||
* {@link #COMPLEX_UNIT_SHIFT}). This gives us 16 possible types, as
|
* Complex data: mask to extract unit information (after shifting by
|
||||||
* defined below. */
|
* {@link #COMPLEX_UNIT_SHIFT}). This gives us 16 possible types, as defined
|
||||||
|
* below.
|
||||||
|
*/
|
||||||
public static final int COMPLEX_UNIT_MASK = 0xf;
|
public static final int COMPLEX_UNIT_MASK = 0xf;
|
||||||
|
|
||||||
/** {@link #TYPE_DIMENSION} complex unit: Value is raw pixels. */
|
/** {@link #TYPE_DIMENSION} complex unit: Value is raw pixels. */
|
||||||
public static final int COMPLEX_UNIT_PX = 0;
|
public static final int COMPLEX_UNIT_PX = 0;
|
||||||
/** {@link #TYPE_DIMENSION} complex unit: Value is Device Independent
|
/**
|
||||||
* Pixels. */
|
* {@link #TYPE_DIMENSION} complex unit: Value is Device Independent Pixels.
|
||||||
|
*/
|
||||||
public static final int COMPLEX_UNIT_DIP = 1;
|
public static final int COMPLEX_UNIT_DIP = 1;
|
||||||
/** {@link #TYPE_DIMENSION} complex unit: Value is a scaled pixel. */
|
/** {@link #TYPE_DIMENSION} complex unit: Value is a scaled pixel. */
|
||||||
public static final int COMPLEX_UNIT_SP = 2;
|
public static final int COMPLEX_UNIT_SP = 2;
|
||||||
@ -106,18 +137,23 @@ public class TypedValue {
|
|||||||
/** {@link #TYPE_DIMENSION} complex unit: Value is in millimeters. */
|
/** {@link #TYPE_DIMENSION} complex unit: Value is in millimeters. */
|
||||||
public static final int COMPLEX_UNIT_MM = 5;
|
public static final int COMPLEX_UNIT_MM = 5;
|
||||||
|
|
||||||
/** {@link #TYPE_FRACTION} complex unit: A basic fraction of the overall
|
/**
|
||||||
* size. */
|
* {@link #TYPE_FRACTION} complex unit: A basic fraction of the overall size.
|
||||||
|
*/
|
||||||
public static final int COMPLEX_UNIT_FRACTION = 0;
|
public static final int COMPLEX_UNIT_FRACTION = 0;
|
||||||
/** {@link #TYPE_FRACTION} complex unit: A fraction of the parent size. */
|
/** {@link #TYPE_FRACTION} complex unit: A fraction of the parent size. */
|
||||||
public static final int COMPLEX_UNIT_FRACTION_PARENT = 1;
|
public static final int COMPLEX_UNIT_FRACTION_PARENT = 1;
|
||||||
|
|
||||||
/** Complex data: where the radix information is, telling where the decimal
|
/**
|
||||||
* place appears in the mantissa. */
|
* Complex data: where the radix information is, telling where the decimal
|
||||||
|
* place appears in the mantissa.
|
||||||
|
*/
|
||||||
public static final int COMPLEX_RADIX_SHIFT = 4;
|
public static final int COMPLEX_RADIX_SHIFT = 4;
|
||||||
/** Complex data: mask to extract radix information (after shifting by
|
/**
|
||||||
|
* Complex data: mask to extract radix information (after shifting by
|
||||||
* {@link #COMPLEX_RADIX_SHIFT}). This give us 4 possible fixed point
|
* {@link #COMPLEX_RADIX_SHIFT}). This give us 4 possible fixed point
|
||||||
* representations as defined below. */
|
* representations as defined below.
|
||||||
|
*/
|
||||||
public static final int COMPLEX_RADIX_MASK = 0x3;
|
public static final int COMPLEX_RADIX_MASK = 0x3;
|
||||||
|
|
||||||
/** Complex data: the mantissa is an integral number -- i.e., 0xnnnnnn.0 */
|
/** Complex data: the mantissa is an integral number -- i.e., 0xnnnnnn.0 */
|
||||||
@ -131,16 +167,19 @@ public class TypedValue {
|
|||||||
|
|
||||||
/** Complex data: bit location of mantissa information. */
|
/** Complex data: bit location of mantissa information. */
|
||||||
public static final int COMPLEX_MANTISSA_SHIFT = 8;
|
public static final int COMPLEX_MANTISSA_SHIFT = 8;
|
||||||
/** Complex data: mask to extract mantissa information (after shifting by
|
/**
|
||||||
* {@link #COMPLEX_MANTISSA_SHIFT}). This gives us 23 bits of precision;
|
* Complex data: mask to extract mantissa information (after shifting by
|
||||||
* the top bit is the sign. */
|
* {@link #COMPLEX_MANTISSA_SHIFT}). This gives us 23 bits of precision; the
|
||||||
|
* top bit is the sign.
|
||||||
|
*/
|
||||||
public static final int COMPLEX_MANTISSA_MASK = 0xffffff;
|
public static final int COMPLEX_MANTISSA_MASK = 0xffffff;
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If {@link #density} is equal to this value, then the density should be
|
* If {@link #density} is equal to this value, then the density should be
|
||||||
* treated as the system's default density value: {@link DisplayMetrics#DENSITY_DEFAULT}.
|
* treated as the system's default density value:
|
||||||
|
* {@link DisplayMetrics#DENSITY_DEFAULT}.
|
||||||
*/
|
*/
|
||||||
public static final int DENSITY_DEFAULT = 0;
|
public static final int DENSITY_DEFAULT = 0;
|
||||||
|
|
||||||
@ -152,16 +191,16 @@ public class TypedValue {
|
|||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
|
||||||
/** The type held by this value, as defined by the constants here.
|
/**
|
||||||
* This tells you how to interpret the other fields in the object. */
|
* The type held by this value, as defined by the constants here. This tells
|
||||||
|
* you how to interpret the other fields in the object.
|
||||||
|
*/
|
||||||
public int type;
|
public int type;
|
||||||
|
|
||||||
private static final float MANTISSA_MULT =
|
private static final float MANTISSA_MULT = 1.0f / (1 << TypedValue.COMPLEX_MANTISSA_SHIFT);
|
||||||
1.0f / (1<<TypedValue.COMPLEX_MANTISSA_SHIFT);
|
|
||||||
private static final float[] RADIX_MULTS = new float[] {
|
private static final float[] RADIX_MULTS = new float[] {
|
||||||
1.0f*MANTISSA_MULT, 1.0f/(1<<7)*MANTISSA_MULT,
|
1.0f * MANTISSA_MULT, 1.0f / (1 << 7) * MANTISSA_MULT,
|
||||||
1.0f/(1<<15)*MANTISSA_MULT, 1.0f/(1<<23)*MANTISSA_MULT
|
1.0f / (1 << 15) * MANTISSA_MULT, 1.0f / (1 << 23) * MANTISSA_MULT };
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the base value from a complex data integer. This uses the
|
* Retrieve the base value from a complex data integer. This uses the
|
||||||
@ -169,37 +208,34 @@ public class TypedValue {
|
|||||||
* the data to compute a floating point representation of the number they
|
* the data to compute a floating point representation of the number they
|
||||||
* describe. The units are ignored.
|
* describe. The units are ignored.
|
||||||
*
|
*
|
||||||
* @param complex A complex data value.
|
* @param complex
|
||||||
|
* A complex data value.
|
||||||
*
|
*
|
||||||
* @return A floating point value corresponding to the complex data.
|
* @return A floating point value corresponding to the complex data.
|
||||||
*/
|
*/
|
||||||
public static float complexToFloat(int complex)
|
public static float complexToFloat(int complex) {
|
||||||
{
|
return (complex & (TypedValue.COMPLEX_MANTISSA_MASK << TypedValue.COMPLEX_MANTISSA_SHIFT))
|
||||||
return (complex&(TypedValue.COMPLEX_MANTISSA_MASK
|
* RADIX_MULTS[(complex >> TypedValue.COMPLEX_RADIX_SHIFT)
|
||||||
<<TypedValue.COMPLEX_MANTISSA_SHIFT))
|
|
||||||
* RADIX_MULTS[(complex>>TypedValue.COMPLEX_RADIX_SHIFT)
|
|
||||||
& TypedValue.COMPLEX_RADIX_MASK];
|
& TypedValue.COMPLEX_RADIX_MASK];
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String[] DIMENSION_UNIT_STRS = new String[] {
|
private static final String[] DIMENSION_UNIT_STRS = new String[] { "px",
|
||||||
"px", "dip", "sp", "pt", "in", "mm"
|
"dip", "sp", "pt", "in", "mm" };
|
||||||
};
|
private static final String[] FRACTION_UNIT_STRS = new String[] { "%", "%p" };
|
||||||
private static final String[] FRACTION_UNIT_STRS = new String[] {
|
|
||||||
"%", "%p"
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform type conversion as per {@link #coerceToString()} on an
|
* Perform type conversion as per {@link #coerceToString()} on an explicitly
|
||||||
* explicitly supplied type and data.
|
* supplied type and data.
|
||||||
*
|
*
|
||||||
* @param type The data type identifier.
|
* @param type
|
||||||
* @param data The data value.
|
* The data type identifier.
|
||||||
|
* @param data
|
||||||
|
* The data value.
|
||||||
*
|
*
|
||||||
* @return String The coerced string value. If the value is
|
* @return String The coerced string value. If the value is null or the type
|
||||||
* null or the type is not known, null is returned.
|
* is not known, null is returned.
|
||||||
*/
|
*/
|
||||||
public static final String coerceToString(int type, int data)
|
public static final String coerceToString(int type, int data) {
|
||||||
{
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TYPE_NULL:
|
case TYPE_NULL:
|
||||||
return null;
|
return null;
|
||||||
@ -210,11 +246,13 @@ public class TypedValue {
|
|||||||
case TYPE_FLOAT:
|
case TYPE_FLOAT:
|
||||||
return Float.toString(Float.intBitsToFloat(data));
|
return Float.toString(Float.intBitsToFloat(data));
|
||||||
case TYPE_DIMENSION:
|
case TYPE_DIMENSION:
|
||||||
return Float.toString(complexToFloat(data)) + DIMENSION_UNIT_STRS[
|
return Float.toString(complexToFloat(data))
|
||||||
(data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK];
|
+ DIMENSION_UNIT_STRS[(data >> COMPLEX_UNIT_SHIFT)
|
||||||
|
& COMPLEX_UNIT_MASK];
|
||||||
case TYPE_FRACTION:
|
case TYPE_FRACTION:
|
||||||
return Float.toString(complexToFloat(data)*100) + FRACTION_UNIT_STRS[
|
return Float.toString(complexToFloat(data) * 100)
|
||||||
(data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK];
|
+ FRACTION_UNIT_STRS[(data >> COMPLEX_UNIT_SHIFT)
|
||||||
|
& COMPLEX_UNIT_MASK];
|
||||||
case TYPE_INT_HEX:
|
case TYPE_INT_HEX:
|
||||||
return "0x" + Integer.toHexString(data);
|
return "0x" + Integer.toHexString(data);
|
||||||
case TYPE_INT_BOOLEAN:
|
case TYPE_INT_BOOLEAN:
|
||||||
@ -222,20 +260,22 @@ public class TypedValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type >= TYPE_FIRST_COLOR_INT && type <= TYPE_LAST_COLOR_INT) {
|
if (type >= TYPE_FIRST_COLOR_INT && type <= TYPE_LAST_COLOR_INT) {
|
||||||
String res =String.format("%08x", data);
|
String res = String.format("%08x", data);
|
||||||
char[] vals = res.toCharArray();
|
char[] vals = res.toCharArray();
|
||||||
switch (type) {
|
switch (type) {
|
||||||
default:
|
default:
|
||||||
case TYPE_INT_COLOR_ARGB8://#AaRrGgBb
|
case TYPE_INT_COLOR_ARGB8:// #AaRrGgBb
|
||||||
break;
|
break;
|
||||||
case TYPE_INT_COLOR_RGB8://#FFRrGgBb->#RrGgBb
|
case TYPE_INT_COLOR_RGB8:// #FFRrGgBb->#RrGgBb
|
||||||
res = res.substring(2);
|
res = res.substring(2);
|
||||||
break;
|
break;
|
||||||
case TYPE_INT_COLOR_ARGB4://#AARRGGBB->#ARGB
|
case TYPE_INT_COLOR_ARGB4:// #AARRGGBB->#ARGB
|
||||||
res = new StringBuffer().append(vals[0]).append(vals[2]).append(vals[4]).append(vals[6]).toString();
|
res = new StringBuffer().append(vals[0]).append(vals[2])
|
||||||
|
.append(vals[4]).append(vals[6]).toString();
|
||||||
break;
|
break;
|
||||||
case TYPE_INT_COLOR_RGB4://#FFRRGGBB->#RGB
|
case TYPE_INT_COLOR_RGB4:// #FFRRGGBB->#RGB
|
||||||
res = new StringBuffer().append(vals[2]).append(vals[4]).append(vals[6]).toString();
|
res = new StringBuffer().append(vals[2]).append(vals[4])
|
||||||
|
.append(vals[6]).toString();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return "#" + res;
|
return "#" + res;
|
||||||
@ -246,13 +286,11 @@ public class TypedValue {
|
|||||||
case TYPE_INT_DEC:
|
case TYPE_INT_DEC:
|
||||||
res = Integer.toString(data);
|
res = Integer.toString(data);
|
||||||
break;
|
break;
|
||||||
//defined before
|
// defined before
|
||||||
/*case TYPE_INT_HEX:
|
/*
|
||||||
res = "0x" + Integer.toHexString(data);
|
* case TYPE_INT_HEX: res = "0x" + Integer.toHexString(data); break;
|
||||||
break;
|
* case TYPE_INT_BOOLEAN: res = (data != 0) ? "true":"false"; break;
|
||||||
case TYPE_INT_BOOLEAN:
|
*/
|
||||||
res = (data != 0) ? "true":"false";
|
|
||||||
break;*/
|
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,8 @@ public class Androlib {
|
|||||||
return mAndRes.getResTable(apkFile, true);
|
return mAndRes.getResTable(apkFile, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResTable getResTable(ExtFile apkFile, boolean loadMainPkg) throws AndrolibException {
|
public ResTable getResTable(ExtFile apkFile, boolean loadMainPkg)
|
||||||
|
throws AndrolibException {
|
||||||
return mAndRes.getResTable(apkFile, loadMainPkg);
|
return mAndRes.getResTable(apkFile, loadMainPkg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,8 +65,8 @@ public class Androlib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void decodeSourcesSmali(File apkFile, File outDir, boolean debug, boolean bakdeb)
|
public void decodeSourcesSmali(File apkFile, File outDir, boolean debug,
|
||||||
throws AndrolibException {
|
boolean bakdeb) throws AndrolibException {
|
||||||
try {
|
try {
|
||||||
File smaliDir = new File(outDir, SMALI_DIRNAME);
|
File smaliDir = new File(outDir, SMALI_DIRNAME);
|
||||||
OS.rmdir(smaliDir);
|
OS.rmdir(smaliDir);
|
||||||
@ -102,7 +103,7 @@ public class Androlib {
|
|||||||
public void decodeResourcesRaw(ExtFile apkFile, File outDir)
|
public void decodeResourcesRaw(ExtFile apkFile, File outDir)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
try {
|
try {
|
||||||
//Directory apk = apkFile.getDirectory();
|
// Directory apk = apkFile.getDirectory();
|
||||||
LOGGER.info("Copying raw resources...");
|
LOGGER.info("Copying raw resources...");
|
||||||
apkFile.getDirectory().copyToDir(outDir, APK_RESOURCES_FILENAMES);
|
apkFile.getDirectory().copyToDir(outDir, APK_RESOURCES_FILENAMES);
|
||||||
} catch (DirectoryException ex) {
|
} catch (DirectoryException ex) {
|
||||||
@ -135,7 +136,7 @@ public class Androlib {
|
|||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
DumperOptions options = new DumperOptions();
|
DumperOptions options = new DumperOptions();
|
||||||
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||||
// options.setIndent(4);
|
// options.setIndent(4);
|
||||||
Yaml yaml = new Yaml(options);
|
Yaml yaml = new Yaml(options);
|
||||||
|
|
||||||
FileWriter writer = null;
|
FileWriter writer = null;
|
||||||
@ -148,7 +149,8 @@ public class Androlib {
|
|||||||
if (writer != null) {
|
if (writer != null) {
|
||||||
try {
|
try {
|
||||||
writer.close();
|
writer.close();
|
||||||
} catch (IOException ex) {}
|
} catch (IOException ex) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,24 +168,28 @@ public class Androlib {
|
|||||||
if (in != null) {
|
if (in != null) {
|
||||||
try {
|
try {
|
||||||
in.close();
|
in.close();
|
||||||
} catch (IOException ex) {}
|
} catch (IOException ex) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void build(File appDir, File outFile,
|
public void build(File appDir, File outFile,
|
||||||
HashMap<String, Boolean> flags, ExtFile origApk, String aaptPath) throws BrutException {
|
HashMap<String, Boolean> flags, ExtFile origApk, String aaptPath)
|
||||||
|
throws BrutException {
|
||||||
build(new ExtFile(appDir), outFile, flags, origApk, aaptPath);
|
build(new ExtFile(appDir), outFile, flags, origApk, aaptPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void build(ExtFile appDir, File outFile,
|
public void build(ExtFile appDir, File outFile,
|
||||||
HashMap<String, Boolean> flags, ExtFile origApk, String aaptPath) throws BrutException {
|
HashMap<String, Boolean> flags, ExtFile origApk, String aaptPath)
|
||||||
|
throws BrutException {
|
||||||
|
|
||||||
mAaptPath = aaptPath;
|
mAaptPath = aaptPath;
|
||||||
Map<String, Object> meta = readMetaFile(appDir);
|
Map<String, Object> meta = readMetaFile(appDir);
|
||||||
Object t1 = meta.get("isFrameworkApk");
|
Object t1 = meta.get("isFrameworkApk");
|
||||||
flags.put("framework", t1 == null ? false : (Boolean) t1);
|
flags.put("framework", t1 == null ? false : (Boolean) t1);
|
||||||
flags.put("compression", meta.get("compressionType") == null ? false : (Boolean) meta.get("compressionType"));
|
flags.put("compression", meta.get("compressionType") == null ? false
|
||||||
|
: (Boolean) meta.get("compressionType"));
|
||||||
mAndRes.setSdkInfo((Map<String, String>) meta.get("sdkInfo"));
|
mAndRes.setSdkInfo((Map<String, String>) meta.get("sdkInfo"));
|
||||||
|
|
||||||
// check the orig apk
|
// check the orig apk
|
||||||
@ -197,8 +203,8 @@ public class Androlib {
|
|||||||
|
|
||||||
if (outFile == null) {
|
if (outFile == null) {
|
||||||
String outFileName = (String) meta.get("apkFileName");
|
String outFileName = (String) meta.get("apkFileName");
|
||||||
outFile = new File(appDir, "dist" + File.separator +
|
outFile = new File(appDir, "dist" + File.separator
|
||||||
(outFileName == null ? "out.apk" : outFileName));
|
+ (outFileName == null ? "out.apk" : outFileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
new File(appDir, APK_DIRNAME).mkdirs();
|
new File(appDir, APK_DIRNAME).mkdirs();
|
||||||
@ -206,24 +212,23 @@ public class Androlib {
|
|||||||
buildResources(appDir, flags,
|
buildResources(appDir, flags,
|
||||||
(Map<String, Object>) meta.get("usesFramework"));
|
(Map<String, Object>) meta.get("usesFramework"));
|
||||||
buildLib(appDir, flags);
|
buildLib(appDir, flags);
|
||||||
buildApk(appDir, outFile,flags);
|
buildApk(appDir, outFile, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void buildSources(File appDir, HashMap<String, Boolean> flags)
|
public void buildSources(File appDir, HashMap<String, Boolean> flags)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
if (! buildSourcesRaw(appDir, flags)
|
if (!buildSourcesRaw(appDir, flags)
|
||||||
&& ! buildSourcesSmali(appDir, flags)
|
&& !buildSourcesSmali(appDir, flags)
|
||||||
&& ! buildSourcesJava(appDir, flags)
|
&& !buildSourcesJava(appDir, flags)) {
|
||||||
) {
|
|
||||||
LOGGER.warning("Could not find sources");
|
LOGGER.warning("Could not find sources");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean buildSourcesRaw(File appDir,
|
public boolean buildSourcesRaw(File appDir, HashMap<String, Boolean> flags)
|
||||||
HashMap<String, Boolean> flags) throws AndrolibException {
|
throws AndrolibException {
|
||||||
try {
|
try {
|
||||||
File working = new File(appDir, "classes.dex");
|
File working = new File(appDir, "classes.dex");
|
||||||
if (! working.exists()) {
|
if (!working.exists()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (flags.get("debug")) {
|
if (flags.get("debug")) {
|
||||||
@ -241,14 +246,14 @@ public class Androlib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean buildSourcesSmali(File appDir,
|
public boolean buildSourcesSmali(File appDir, HashMap<String, Boolean> flags)
|
||||||
HashMap<String, Boolean> flags) throws AndrolibException {
|
throws AndrolibException {
|
||||||
ExtFile smaliDir = new ExtFile(appDir, "smali");
|
ExtFile smaliDir = new ExtFile(appDir, "smali");
|
||||||
if (! smaliDir.exists()) {
|
if (!smaliDir.exists()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
File dex = new File(appDir, APK_DIRNAME + "/classes.dex");
|
File dex = new File(appDir, APK_DIRNAME + "/classes.dex");
|
||||||
if (! flags.get("forceBuildAll")) {
|
if (!flags.get("forceBuildAll")) {
|
||||||
LOGGER.info("Checking whether sources has changed...");
|
LOGGER.info("Checking whether sources has changed...");
|
||||||
}
|
}
|
||||||
if (flags.get("forceBuildAll") || isModified(smaliDir, dex)) {
|
if (flags.get("forceBuildAll") || isModified(smaliDir, dex)) {
|
||||||
@ -259,14 +264,14 @@ public class Androlib {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean buildSourcesJava(File appDir,
|
public boolean buildSourcesJava(File appDir, HashMap<String, Boolean> flags)
|
||||||
HashMap<String, Boolean> flags) throws AndrolibException {
|
throws AndrolibException {
|
||||||
File javaDir = new File(appDir, "src");
|
File javaDir = new File(appDir, "src");
|
||||||
if (! javaDir.exists()) {
|
if (!javaDir.exists()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
File dex = new File(appDir, APK_DIRNAME + "/classes.dex");
|
File dex = new File(appDir, APK_DIRNAME + "/classes.dex");
|
||||||
if (! flags.get("forceBuildAll")) {
|
if (!flags.get("forceBuildAll")) {
|
||||||
LOGGER.info("Checking whether sources has changed...");
|
LOGGER.info("Checking whether sources has changed...");
|
||||||
}
|
}
|
||||||
if (flags.get("forceBuildAll") || isModified(javaDir, dex)) {
|
if (flags.get("forceBuildAll") || isModified(javaDir, dex)) {
|
||||||
@ -278,27 +283,26 @@ public class Androlib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void buildResources(ExtFile appDir, HashMap<String, Boolean> flags,
|
public void buildResources(ExtFile appDir, HashMap<String, Boolean> flags,
|
||||||
Map<String, Object> usesFramework)
|
Map<String, Object> usesFramework) throws BrutException {
|
||||||
throws BrutException {
|
if (!buildResourcesRaw(appDir, flags)
|
||||||
if (! buildResourcesRaw(appDir, flags)
|
&& !buildResourcesFull(appDir, flags, usesFramework)
|
||||||
&& ! buildResourcesFull(appDir, flags, usesFramework)
|
&& !buildManifest(appDir, flags, usesFramework)) {
|
||||||
&& ! buildManifest(appDir, flags, usesFramework)) {
|
|
||||||
LOGGER.warning("Could not find resources");
|
LOGGER.warning("Could not find resources");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean buildResourcesRaw(ExtFile appDir, HashMap<String, Boolean> flags)
|
public boolean buildResourcesRaw(ExtFile appDir,
|
||||||
throws AndrolibException {
|
HashMap<String, Boolean> flags) throws AndrolibException {
|
||||||
try {
|
try {
|
||||||
if (! new File(appDir, "resources.arsc").exists()) {
|
if (!new File(appDir, "resources.arsc").exists()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
File apkDir = new File(appDir, APK_DIRNAME);
|
File apkDir = new File(appDir, APK_DIRNAME);
|
||||||
if (! flags.get("forceBuildAll")) {
|
if (!flags.get("forceBuildAll")) {
|
||||||
LOGGER.info("Checking whether resources has changed...");
|
LOGGER.info("Checking whether resources has changed...");
|
||||||
}
|
}
|
||||||
if (flags.get("forceBuildAll") || isModified(
|
if (flags.get("forceBuildAll")
|
||||||
newFiles(APK_RESOURCES_FILENAMES, appDir),
|
|| isModified(newFiles(APK_RESOURCES_FILENAMES, appDir),
|
||||||
newFiles(APK_RESOURCES_FILENAMES, apkDir))) {
|
newFiles(APK_RESOURCES_FILENAMES, apkDir))) {
|
||||||
LOGGER.info("Copying raw resources...");
|
LOGGER.info("Copying raw resources...");
|
||||||
appDir.getDirectory()
|
appDir.getDirectory()
|
||||||
@ -310,19 +314,19 @@ public class Androlib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean buildResourcesFull(File appDir, HashMap<String, Boolean> flags,
|
public boolean buildResourcesFull(File appDir,
|
||||||
Map<String, Object> usesFramework)
|
HashMap<String, Boolean> flags, Map<String, Object> usesFramework)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
try {
|
try {
|
||||||
if (! new File(appDir, "res").exists()) {
|
if (!new File(appDir, "res").exists()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (! flags.get("forceBuildAll")) {
|
if (!flags.get("forceBuildAll")) {
|
||||||
LOGGER.info("Checking whether resources has changed...");
|
LOGGER.info("Checking whether resources has changed...");
|
||||||
}
|
}
|
||||||
File apkDir = new File(appDir, APK_DIRNAME);
|
File apkDir = new File(appDir, APK_DIRNAME);
|
||||||
if (flags.get("forceBuildAll") || isModified(
|
if (flags.get("forceBuildAll")
|
||||||
newFiles(APP_RESOURCES_FILENAMES, appDir),
|
|| isModified(newFiles(APP_RESOURCES_FILENAMES, appDir),
|
||||||
newFiles(APK_RESOURCES_FILENAMES, apkDir))) {
|
newFiles(APK_RESOURCES_FILENAMES, apkDir))) {
|
||||||
LOGGER.info("Building resources...");
|
LOGGER.info("Building resources...");
|
||||||
|
|
||||||
@ -330,21 +334,18 @@ public class Androlib {
|
|||||||
apkFile.delete();
|
apkFile.delete();
|
||||||
|
|
||||||
File ninePatch = new File(appDir, "9patch");
|
File ninePatch = new File(appDir, "9patch");
|
||||||
if (! ninePatch.exists()) {
|
if (!ninePatch.exists()) {
|
||||||
ninePatch = null;
|
ninePatch = null;
|
||||||
}
|
}
|
||||||
mAndRes.aaptPackage(
|
mAndRes.aaptPackage(apkFile, new File(appDir,
|
||||||
apkFile,
|
"AndroidManifest.xml"), new File(appDir, "res"),
|
||||||
new File(appDir, "AndroidManifest.xml"),
|
|
||||||
new File(appDir, "res"),
|
|
||||||
ninePatch, null, parseUsesFramework(usesFramework),
|
ninePatch, null, parseUsesFramework(usesFramework),
|
||||||
flags, mAaptPath
|
flags, mAaptPath);
|
||||||
);
|
|
||||||
|
|
||||||
Directory tmpDir = new ExtFile(apkFile).getDirectory();
|
Directory tmpDir = new ExtFile(apkFile).getDirectory();
|
||||||
tmpDir.copyToDir(apkDir,
|
tmpDir.copyToDir(apkDir,
|
||||||
tmpDir.containsDir("res") ? APK_RESOURCES_FILENAMES :
|
tmpDir.containsDir("res") ? APK_RESOURCES_FILENAMES
|
||||||
APK_RESOURCES_WITHOUT_RES_FILENAMES);
|
: APK_RESOURCES_WITHOUT_RES_FILENAMES);
|
||||||
|
|
||||||
// delete tmpDir
|
// delete tmpDir
|
||||||
apkFile.delete();
|
apkFile.delete();
|
||||||
@ -359,32 +360,31 @@ public class Androlib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean buildManifestRaw(ExtFile appDir, HashMap<String, Boolean> flags)
|
public boolean buildManifestRaw(ExtFile appDir,
|
||||||
throws AndrolibException {
|
HashMap<String, Boolean> flags) throws AndrolibException {
|
||||||
try {
|
try {
|
||||||
File apkDir = new File(appDir, APK_DIRNAME);
|
File apkDir = new File(appDir, APK_DIRNAME);
|
||||||
LOGGER.info("Copying raw AndroidManifest.xml...");
|
LOGGER.info("Copying raw AndroidManifest.xml...");
|
||||||
appDir.getDirectory()
|
appDir.getDirectory().copyToDir(apkDir, APK_MANIFEST_FILENAMES);
|
||||||
.copyToDir(apkDir, APK_MANIFEST_FILENAMES);
|
|
||||||
return true;
|
return true;
|
||||||
} catch (DirectoryException ex) {
|
} catch (DirectoryException ex) {
|
||||||
throw new AndrolibException(ex);
|
throw new AndrolibException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean buildManifest(ExtFile appDir, HashMap<String, Boolean> flags,
|
public boolean buildManifest(ExtFile appDir,
|
||||||
Map<String, Object> usesFramework)
|
HashMap<String, Boolean> flags, Map<String, Object> usesFramework)
|
||||||
throws BrutException {
|
throws BrutException {
|
||||||
try {
|
try {
|
||||||
if (! new File(appDir, "AndroidManifest.xml").exists()) {
|
if (!new File(appDir, "AndroidManifest.xml").exists()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (! flags.get("forceBuildAll")) {
|
if (!flags.get("forceBuildAll")) {
|
||||||
LOGGER.info("Checking whether resources has changed...");
|
LOGGER.info("Checking whether resources has changed...");
|
||||||
}
|
}
|
||||||
File apkDir = new File(appDir, APK_DIRNAME);
|
File apkDir = new File(appDir, APK_DIRNAME);
|
||||||
if (flags.get("forceBuildAll") || isModified(
|
if (flags.get("forceBuildAll")
|
||||||
newFiles(APK_MANIFEST_FILENAMES, appDir),
|
|| isModified(newFiles(APK_MANIFEST_FILENAMES, appDir),
|
||||||
newFiles(APK_MANIFEST_FILENAMES, apkDir))) {
|
newFiles(APK_MANIFEST_FILENAMES, apkDir))) {
|
||||||
LOGGER.info("Building AndroidManifest.xml...");
|
LOGGER.info("Building AndroidManifest.xml...");
|
||||||
|
|
||||||
@ -392,17 +392,13 @@ public class Androlib {
|
|||||||
apkFile.delete();
|
apkFile.delete();
|
||||||
|
|
||||||
File ninePatch = new File(appDir, "9patch");
|
File ninePatch = new File(appDir, "9patch");
|
||||||
if (! ninePatch.exists()) {
|
if (!ninePatch.exists()) {
|
||||||
ninePatch = null;
|
ninePatch = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
mAndRes.aaptPackage(
|
mAndRes.aaptPackage(apkFile, new File(appDir,
|
||||||
apkFile,
|
"AndroidManifest.xml"), null, ninePatch, null,
|
||||||
new File(appDir, "AndroidManifest.xml"),
|
parseUsesFramework(usesFramework), flags, mAaptPath);
|
||||||
null,
|
|
||||||
ninePatch, null, parseUsesFramework(usesFramework),
|
|
||||||
flags, mAaptPath
|
|
||||||
);
|
|
||||||
|
|
||||||
Directory tmpDir = new ExtFile(apkFile).getDirectory();
|
Directory tmpDir = new ExtFile(apkFile).getDirectory();
|
||||||
tmpDir.copyToDir(apkDir, APK_MANIFEST_FILENAMES);
|
tmpDir.copyToDir(apkDir, APK_MANIFEST_FILENAMES);
|
||||||
@ -422,7 +418,7 @@ public class Androlib {
|
|||||||
public void buildLib(File appDir, HashMap<String, Boolean> flags)
|
public void buildLib(File appDir, HashMap<String, Boolean> flags)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
File working = new File(appDir, "lib");
|
File working = new File(appDir, "lib");
|
||||||
if (! working.exists()) {
|
if (!working.exists()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
File stored = new File(appDir, APK_DIRNAME + "/lib");
|
File stored = new File(appDir, APK_DIRNAME + "/lib");
|
||||||
@ -437,23 +433,23 @@ public class Androlib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void buildApk(File appDir, File outApk, HashMap<String, Boolean> flags)
|
public void buildApk(File appDir, File outApk,
|
||||||
throws AndrolibException {
|
HashMap<String, Boolean> flags) throws AndrolibException {
|
||||||
LOGGER.info("Building apk file...");
|
LOGGER.info("Building apk file...");
|
||||||
if (outApk.exists()) {
|
if (outApk.exists()) {
|
||||||
outApk.delete();
|
outApk.delete();
|
||||||
} else {
|
} else {
|
||||||
File outDir = outApk.getParentFile();
|
File outDir = outApk.getParentFile();
|
||||||
if (outDir != null && ! outDir.exists()) {
|
if (outDir != null && !outDir.exists()) {
|
||||||
outDir.mkdirs();
|
outDir.mkdirs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File assetDir = new File(appDir, "assets");
|
File assetDir = new File(appDir, "assets");
|
||||||
if (! assetDir.exists()) {
|
if (!assetDir.exists()) {
|
||||||
assetDir = null;
|
assetDir = null;
|
||||||
}
|
}
|
||||||
mAndRes.aaptPackage(outApk, null, null,
|
mAndRes.aaptPackage(outApk, null, null, new File(appDir, APK_DIRNAME),
|
||||||
new File(appDir, APK_DIRNAME), assetDir, null, flags, mAaptPath);
|
assetDir, null, flags, mAaptPath);
|
||||||
|
|
||||||
// retain signature
|
// retain signature
|
||||||
// aapt r (remove)
|
// aapt r (remove)
|
||||||
@ -484,10 +480,9 @@ public class Androlib {
|
|||||||
|
|
||||||
public static String getVersion() {
|
public static String getVersion() {
|
||||||
String version = ApktoolProperties.get("application.version");
|
String version = ApktoolProperties.get("application.version");
|
||||||
return version.endsWith("-SNAPSHOT") ?
|
return version.endsWith("-SNAPSHOT") ? version.substring(0,
|
||||||
version.substring(0, version.length() - 9) + '.' +
|
version.length() - 9)
|
||||||
ApktoolProperties.get("git.commit.id.abbrev")
|
+ '.' + ApktoolProperties.get("git.commit.id.abbrev") : version;
|
||||||
: version;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private File[] parseUsesFramework(Map<String, Object> usesFramework)
|
private File[] parseUsesFramework(Map<String, Object> usesFramework)
|
||||||
@ -511,21 +506,21 @@ public class Androlib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isModified(File working, File stored) {
|
private boolean isModified(File working, File stored) {
|
||||||
if (! stored.exists()) {
|
if (!stored.exists()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return BrutIO.recursiveModifiedTime(working) >
|
return BrutIO.recursiveModifiedTime(working) > BrutIO
|
||||||
BrutIO.recursiveModifiedTime(stored);
|
.recursiveModifiedTime(stored);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isModified(File[] working, File[] stored) {
|
private boolean isModified(File[] working, File[] stored) {
|
||||||
for (int i = 0; i < stored.length; i++) {
|
for (int i = 0; i < stored.length; i++) {
|
||||||
if (! stored[i].exists()) {
|
if (!stored[i].exists()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return BrutIO.recursiveModifiedTime(working) >
|
return BrutIO.recursiveModifiedTime(working) > BrutIO
|
||||||
BrutIO.recursiveModifiedTime(stored);
|
.recursiveModifiedTime(stored);
|
||||||
}
|
}
|
||||||
|
|
||||||
private File[] newFiles(String[] names, File dir) {
|
private File[] newFiles(String[] names, File dir) {
|
||||||
@ -540,21 +535,19 @@ public class Androlib {
|
|||||||
mOrigApkFile = new ExtFile(apkFile);
|
mOrigApkFile = new ExtFile(apkFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private ExtFile mOrigApkFile = null;
|
private ExtFile mOrigApkFile = null;
|
||||||
private String mAaptPath = null;
|
private String mAaptPath = null;
|
||||||
|
|
||||||
private final static Logger LOGGER =
|
private final static Logger LOGGER = Logger.getLogger(Androlib.class
|
||||||
Logger.getLogger(Androlib.class.getName());
|
.getName());
|
||||||
|
|
||||||
private final static String SMALI_DIRNAME = "smali";
|
private final static String SMALI_DIRNAME = "smali";
|
||||||
private final static String APK_DIRNAME = "build/apk";
|
private final static String APK_DIRNAME = "build/apk";
|
||||||
private final static String[] APK_RESOURCES_FILENAMES =
|
private final static String[] APK_RESOURCES_FILENAMES = new String[] {
|
||||||
new String[]{"resources.arsc", "AndroidManifest.xml", "res"};
|
"resources.arsc", "AndroidManifest.xml", "res" };
|
||||||
private final static String[] APK_RESOURCES_WITHOUT_RES_FILENAMES =
|
private final static String[] APK_RESOURCES_WITHOUT_RES_FILENAMES = new String[] {
|
||||||
new String[]{"resources.arsc", "AndroidManifest.xml"};
|
"resources.arsc", "AndroidManifest.xml" };
|
||||||
private final static String[] APP_RESOURCES_FILENAMES =
|
private final static String[] APP_RESOURCES_FILENAMES = new String[] {
|
||||||
new String[]{"AndroidManifest.xml", "res"};
|
"AndroidManifest.xml", "res" };
|
||||||
private final static String[] APK_MANIFEST_FILENAMES =
|
private final static String[] APK_MANIFEST_FILENAMES = new String[] { "AndroidManifest.xml" };
|
||||||
new String[]{"AndroidManifest.xml"};
|
|
||||||
}
|
}
|
||||||
|
@ -96,13 +96,15 @@ public class ApkDecoder {
|
|||||||
|
|
||||||
if (hasResources()) {
|
if (hasResources()) {
|
||||||
|
|
||||||
// read the resources.arsc checking for STORED vs DEFLATE compression
|
// read the resources.arsc checking for STORED vs DEFLATE
|
||||||
|
// compression
|
||||||
// this will determine whether we compress on rebuild or not.
|
// this will determine whether we compress on rebuild or not.
|
||||||
JarFile jf = new JarFile(mApkFile.getAbsoluteFile());
|
JarFile jf = new JarFile(mApkFile.getAbsoluteFile());
|
||||||
JarEntry je = jf.getJarEntry("resources.arsc");
|
JarEntry je = jf.getJarEntry("resources.arsc");
|
||||||
if (je != null) {
|
if (je != null) {
|
||||||
int compression = je.getMethod();
|
int compression = je.getMethod();
|
||||||
mCompressResources = (compression != ZipEntry.STORED) && (compression == ZipEntry.DEFLATED);
|
mCompressResources = (compression != ZipEntry.STORED)
|
||||||
|
&& (compression == ZipEntry.DEFLATED);
|
||||||
}
|
}
|
||||||
jf.close();
|
jf.close();
|
||||||
|
|
||||||
|
@ -20,8 +20,6 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import org.jf.baksmali.baksmali;
|
|
||||||
import org.jf.smali.main;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||||
@ -39,7 +37,8 @@ public class ApktoolProperties {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void loadProps() {
|
private static void loadProps() {
|
||||||
InputStream in = ApktoolProperties.class.getResourceAsStream("/properties/apktool.properties");
|
InputStream in = ApktoolProperties.class
|
||||||
|
.getResourceAsStream("/properties/apktool.properties");
|
||||||
sProps = new Properties();
|
sProps = new Properties();
|
||||||
try {
|
try {
|
||||||
sProps.load(in);
|
sProps.load(in);
|
||||||
@ -48,7 +47,8 @@ public class ApktoolProperties {
|
|||||||
LOGGER.warning("Can't load properties.");
|
LOGGER.warning("Can't load properties.");
|
||||||
}
|
}
|
||||||
|
|
||||||
InputStream templateStream = ApktoolProperties.class.getResourceAsStream("/properties/baksmali.properties");
|
InputStream templateStream = ApktoolProperties.class
|
||||||
|
.getResourceAsStream("/properties/baksmali.properties");
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
String version = "(unknown)";
|
String version = "(unknown)";
|
||||||
try {
|
try {
|
||||||
@ -57,7 +57,8 @@ public class ApktoolProperties {
|
|||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
}
|
}
|
||||||
sProps.put("baksmaliVersion", version);
|
sProps.put("baksmaliVersion", version);
|
||||||
templateStream = ApktoolProperties.class.getResourceAsStream("/properties/smali.properties");
|
templateStream = ApktoolProperties.class
|
||||||
|
.getResourceAsStream("/properties/smali.properties");
|
||||||
properties = new Properties();
|
properties = new Properties();
|
||||||
version = "(unknown)";
|
version = "(unknown)";
|
||||||
try {
|
try {
|
||||||
@ -70,6 +71,6 @@ public class ApktoolProperties {
|
|||||||
|
|
||||||
private static Properties sProps;
|
private static Properties sProps;
|
||||||
|
|
||||||
private static final Logger LOGGER =
|
private static final Logger LOGGER = Logger
|
||||||
Logger.getLogger(ApktoolProperties.class.getName());
|
.getLogger(ApktoolProperties.class.getName());
|
||||||
}
|
}
|
@ -30,29 +30,29 @@ public class SmaliMod {
|
|||||||
|
|
||||||
public static boolean assembleSmaliFile(InputStream smaliStream,
|
public static boolean assembleSmaliFile(InputStream smaliStream,
|
||||||
String name, DexFile dexFile, boolean verboseErrors,
|
String name, DexFile dexFile, boolean verboseErrors,
|
||||||
boolean oldLexer, boolean printTokens)
|
boolean oldLexer, boolean printTokens) throws IOException,
|
||||||
throws IOException, RecognitionException {
|
RecognitionException {
|
||||||
CommonTokenStream tokens;
|
CommonTokenStream tokens;
|
||||||
|
|
||||||
|
|
||||||
boolean lexerErrors = false;
|
boolean lexerErrors = false;
|
||||||
LexerErrorInterface lexer;
|
LexerErrorInterface lexer;
|
||||||
|
|
||||||
InputStreamReader reader = new InputStreamReader(smaliStream, "UTF-8");
|
InputStreamReader reader = new InputStreamReader(smaliStream, "UTF-8");
|
||||||
|
|
||||||
lexer = new smaliFlexLexer(reader);
|
lexer = new smaliFlexLexer(reader);
|
||||||
tokens = new CommonTokenStream((TokenSource)lexer);
|
tokens = new CommonTokenStream((TokenSource) lexer);
|
||||||
|
|
||||||
if (printTokens) {
|
if (printTokens) {
|
||||||
tokens.getTokens();
|
tokens.getTokens();
|
||||||
|
|
||||||
for (int i=0; i<tokens.size(); i++) {
|
for (int i = 0; i < tokens.size(); i++) {
|
||||||
Token token = tokens.get(i);
|
Token token = tokens.get(i);
|
||||||
if (token.getChannel() == smaliParser.HIDDEN) {
|
if (token.getChannel() == BaseRecognizer.HIDDEN) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println(smaliParser.tokenNames[token.getType()] + ": " + token.getText());
|
System.out.println(smaliParser.tokenNames[token.getType()]
|
||||||
|
+ ": " + token.getText());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +61,8 @@ public class SmaliMod {
|
|||||||
|
|
||||||
smaliParser.smali_file_return result = parser.smali_file();
|
smaliParser.smali_file_return result = parser.smali_file();
|
||||||
|
|
||||||
if (parser.getNumberOfSyntaxErrors() > 0 || lexer.getNumberOfSyntaxErrors() > 0) {
|
if (parser.getNumberOfSyntaxErrors() > 0
|
||||||
|
|| lexer.getNumberOfSyntaxErrors() > 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,11 +154,13 @@ final public class AndrolibResources {
|
|||||||
public void adjust_package_manifest(ResTable resTable, String filePath)
|
public void adjust_package_manifest(ResTable resTable, String filePath)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
|
|
||||||
// check if packages different, and that package is not equal to "android"
|
// check if packages different, and that package is not equal to
|
||||||
|
// "android"
|
||||||
Map<String, String> packageInfo = resTable.getPackageInfo();
|
Map<String, String> packageInfo = resTable.getPackageInfo();
|
||||||
if ((packageInfo.get("cur_package").equalsIgnoreCase(packageInfo.get("orig_package"))
|
if ((packageInfo.get("cur_package").equalsIgnoreCase(
|
||||||
|| ("android".equalsIgnoreCase(packageInfo.get("cur_package"))
|
packageInfo.get("orig_package")) || ("android"
|
||||||
|| ("com.htc".equalsIgnoreCase(packageInfo.get("cur_package")))))) {
|
.equalsIgnoreCase(packageInfo.get("cur_package")) || ("com.htc"
|
||||||
|
.equalsIgnoreCase(packageInfo.get("cur_package")))))) {
|
||||||
|
|
||||||
LOGGER.info("Regular manifest package...");
|
LOGGER.info("Regular manifest package...");
|
||||||
} else {
|
} else {
|
||||||
@ -181,7 +183,8 @@ final public class AndrolibResources {
|
|||||||
|
|
||||||
// re-save manifest.
|
// re-save manifest.
|
||||||
// fancy an auto-sort :p
|
// fancy an auto-sort :p
|
||||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
TransformerFactory transformerFactory = TransformerFactory
|
||||||
|
.newInstance();
|
||||||
Transformer transformer = transformerFactory.newTransformer();
|
Transformer transformer = transformerFactory.newTransformer();
|
||||||
DOMSource source = new DOMSource(doc);
|
DOMSource source = new DOMSource(doc);
|
||||||
StreamResult result = new StreamResult(new File(filePath));
|
StreamResult result = new StreamResult(new File(filePath));
|
||||||
@ -219,7 +222,8 @@ final public class AndrolibResources {
|
|||||||
"AndroidManifest.xml");
|
"AndroidManifest.xml");
|
||||||
|
|
||||||
// fix package if needed
|
// fix package if needed
|
||||||
adjust_package_manifest(resTable, outDir.getAbsolutePath() + "/AndroidManifest.xml");
|
adjust_package_manifest(resTable, outDir.getAbsolutePath()
|
||||||
|
+ "/AndroidManifest.xml");
|
||||||
|
|
||||||
if (inApk.containsDir("res")) {
|
if (inApk.containsDir("res")) {
|
||||||
in = inApk.getDir("res");
|
in = inApk.getDir("res");
|
||||||
@ -268,7 +272,8 @@ final public class AndrolibResources {
|
|||||||
|
|
||||||
public void aaptPackage(File apkFile, File manifest, File resDir,
|
public void aaptPackage(File apkFile, File manifest, File resDir,
|
||||||
File rawDir, File assetDir, File[] include,
|
File rawDir, File assetDir, File[] include,
|
||||||
HashMap<String, Boolean> flags, String aaptPath) throws AndrolibException {
|
HashMap<String, Boolean> flags, String aaptPath)
|
||||||
|
throws AndrolibException {
|
||||||
|
|
||||||
List<String> cmd = new ArrayList<String>();
|
List<String> cmd = new ArrayList<String>();
|
||||||
|
|
||||||
@ -280,7 +285,8 @@ final public class AndrolibResources {
|
|||||||
cmd.add(aaptFile.getPath());
|
cmd.add(aaptFile.getPath());
|
||||||
|
|
||||||
if (flags.get("verbose")) {
|
if (flags.get("verbose")) {
|
||||||
LOGGER.info(aaptFile.getPath() + " being used as aapt location.");
|
LOGGER.info(aaptFile.getPath()
|
||||||
|
+ " being used as aapt location.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOGGER.warning("aapt location could not be found. Defaulting back to default");
|
LOGGER.warning("aapt location could not be found. Defaulting back to default");
|
||||||
@ -420,7 +426,7 @@ final public class AndrolibResources {
|
|||||||
" ");
|
" ");
|
||||||
serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_LINE_SEPARATOR,
|
serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_LINE_SEPARATOR,
|
||||||
System.getProperty("line.separator"));
|
System.getProperty("line.separator"));
|
||||||
serial.setProperty(ExtMXSerializer.PROPERTY_DEFAULT_ENCODING, "utf-8");
|
serial.setProperty(ExtXmlSerializer.PROPERTY_DEFAULT_ENCODING, "utf-8");
|
||||||
serial.setDisabledAttrEscape(true);
|
serial.setDisabledAttrEscape(true);
|
||||||
return serial;
|
return serial;
|
||||||
}
|
}
|
||||||
@ -665,7 +671,8 @@ final public class AndrolibResources {
|
|||||||
if (!dir.exists()) {
|
if (!dir.exists()) {
|
||||||
if (!dir.mkdirs()) {
|
if (!dir.mkdirs()) {
|
||||||
if (sFrameworkFolder != null) {
|
if (sFrameworkFolder != null) {
|
||||||
System.out.println("Can't create Framework directory: " + dir);
|
System.out.println("Can't create Framework directory: "
|
||||||
|
+ dir);
|
||||||
}
|
}
|
||||||
throw new AndrolibException("Can't create directory: " + dir);
|
throw new AndrolibException("Can't create directory: " + dir);
|
||||||
}
|
}
|
||||||
|
@ -42,21 +42,20 @@ public class ResSmaliUpdater {
|
|||||||
try {
|
try {
|
||||||
dir = new FileDirectory(smaliDir);
|
dir = new FileDirectory(smaliDir);
|
||||||
} catch (DirectoryException ex) {
|
} catch (DirectoryException ex) {
|
||||||
throw new AndrolibException(
|
throw new AndrolibException("Could not tag res IDs", ex);
|
||||||
"Could not tag res IDs", ex);
|
|
||||||
}
|
}
|
||||||
for (String fileName : dir.getFiles(true)) {
|
for (String fileName : dir.getFiles(true)) {
|
||||||
try {
|
try {
|
||||||
tagResIdsForFile(resTable, dir, fileName);
|
tagResIdsForFile(resTable, dir, fileName);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new AndrolibException(
|
throw new AndrolibException("Could not tag resIDs for file: "
|
||||||
"Could not tag resIDs for file: " + fileName, ex);
|
+ fileName, ex);
|
||||||
} catch (DirectoryException ex) {
|
} catch (DirectoryException ex) {
|
||||||
throw new AndrolibException(
|
throw new AndrolibException("Could not tag resIDs for file: "
|
||||||
"Could not tag resIDs for file: " + fileName, ex);
|
+ fileName, ex);
|
||||||
} catch (AndrolibException ex) {
|
} catch (AndrolibException ex) {
|
||||||
throw new AndrolibException(
|
throw new AndrolibException("Could not tag resIDs for file: "
|
||||||
"Could not tag resIDs for file: " + fileName, ex);
|
+ fileName, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,47 +65,47 @@ public class ResSmaliUpdater {
|
|||||||
try {
|
try {
|
||||||
Directory dir = new FileDirectory(smaliDir);
|
Directory dir = new FileDirectory(smaliDir);
|
||||||
for (String fileName : dir.getFiles(true)) {
|
for (String fileName : dir.getFiles(true)) {
|
||||||
Iterator<String> it =
|
Iterator<String> it = IOUtils.readLines(
|
||||||
IOUtils.readLines(dir.getFileInput(fileName)).iterator();
|
dir.getFileInput(fileName)).iterator();
|
||||||
PrintWriter out = new PrintWriter(dir.getFileOutput(fileName));
|
PrintWriter out = new PrintWriter(dir.getFileOutput(fileName));
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
String line = it.next();
|
String line = it.next();
|
||||||
out.println(line);
|
out.println(line);
|
||||||
Matcher m1 = RES_NAME_PATTERN.matcher(line);
|
Matcher m1 = RES_NAME_PATTERN.matcher(line);
|
||||||
if (! m1.matches()) {
|
if (!m1.matches()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Matcher m2 = RES_ID_PATTERN.matcher(it.next());
|
Matcher m2 = RES_ID_PATTERN.matcher(it.next());
|
||||||
if (! m2.matches()) {
|
if (!m2.matches()) {
|
||||||
throw new AndrolibException();
|
throw new AndrolibException();
|
||||||
}
|
}
|
||||||
int resID = resTable.getPackage(m1.group(1))
|
int resID = resTable.getPackage(m1.group(1))
|
||||||
.getType(m1.group(2)).getResSpec(m1.group(3))
|
.getType(m1.group(2)).getResSpec(m1.group(3))
|
||||||
.getId().id;
|
.getId().id;
|
||||||
if (m2.group(1) != null) {
|
if (m2.group(1) != null) {
|
||||||
out.println(String.format(
|
out.println(String.format(RES_ID_FORMAT_FIELD,
|
||||||
RES_ID_FORMAT_FIELD, m2.group(1), resID));
|
m2.group(1), resID));
|
||||||
} else {
|
} else {
|
||||||
out.println(String.format(
|
out.println(String.format(RES_ID_FORMAT_CONST,
|
||||||
RES_ID_FORMAT_CONST, m2.group(2), resID));
|
m2.group(2), resID));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.close();
|
out.close();
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new AndrolibException(
|
throw new AndrolibException("Could not tag res IDs for: "
|
||||||
"Could not tag res IDs for: " + smaliDir.getAbsolutePath(), ex);
|
+ smaliDir.getAbsolutePath(), ex);
|
||||||
} catch (DirectoryException ex) {
|
} catch (DirectoryException ex) {
|
||||||
throw new AndrolibException(
|
throw new AndrolibException("Could not tag res IDs for: "
|
||||||
"Could not tag res IDs for: " + smaliDir.getAbsolutePath(), ex);
|
+ smaliDir.getAbsolutePath(), ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tagResIdsForFile(ResTable resTable, Directory dir,
|
private void tagResIdsForFile(ResTable resTable, Directory dir,
|
||||||
String fileName) throws IOException, DirectoryException,
|
String fileName) throws IOException, DirectoryException,
|
||||||
AndrolibException {
|
AndrolibException {
|
||||||
Iterator<String> it =
|
Iterator<String> it = IOUtils.readLines(dir.getFileInput(fileName))
|
||||||
IOUtils.readLines(dir.getFileInput(fileName)).iterator();
|
.iterator();
|
||||||
PrintWriter out = new PrintWriter(dir.getFileOutput(fileName));
|
PrintWriter out = new PrintWriter(dir.getFileOutput(fileName));
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
String line = it.next();
|
String line = it.next();
|
||||||
@ -121,13 +120,13 @@ public class ResSmaliUpdater {
|
|||||||
if (resID != -1) {
|
if (resID != -1) {
|
||||||
try {
|
try {
|
||||||
ResResSpec spec = resTable.getResSpec(resID);
|
ResResSpec spec = resTable.getResSpec(resID);
|
||||||
out.println(String.format(
|
out.println(String.format(RES_NAME_FORMAT,
|
||||||
RES_NAME_FORMAT, spec.getFullName()));
|
spec.getFullName()));
|
||||||
} catch (UndefinedResObject ex) {
|
} catch (UndefinedResObject ex) {
|
||||||
if (! R_FILE_PATTERN.matcher(fileName).matches()) {
|
if (!R_FILE_PATTERN.matcher(fileName).matches()) {
|
||||||
LOGGER.warning(String.format(
|
LOGGER.warning(String.format(
|
||||||
"Undefined resource spec in %s: 0x%08x"
|
"Undefined resource spec in %s: 0x%08x",
|
||||||
, fileName, resID));
|
fileName, resID));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,20 +147,17 @@ public class ResSmaliUpdater {
|
|||||||
return resID;
|
return resID;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static String RES_ID_FORMAT_FIELD =
|
private final static String RES_ID_FORMAT_FIELD = ".field %s:I = 0x%08x";
|
||||||
".field %s:I = 0x%08x";
|
private final static String RES_ID_FORMAT_CONST = " const %s, 0x%08x";
|
||||||
private final static String RES_ID_FORMAT_CONST =
|
private final static Pattern RES_ID_PATTERN = Pattern
|
||||||
" const %s, 0x%08x";
|
.compile("^(?:\\.field (.+?):I =| const(?:|/(?:|high)16) ([pv]\\d+?),) 0x(7[a-f]0[1-9a-f](?:|[0-9a-f]{4}))$");
|
||||||
private final static Pattern RES_ID_PATTERN = Pattern.compile(
|
private final static String RES_NAME_FORMAT = "# APKTOOL/RES_NAME: %s";
|
||||||
"^(?:\\.field (.+?):I =| const(?:|/(?:|high)16) ([pv]\\d+?),) 0x(7[a-f]0[1-9a-f](?:|[0-9a-f]{4}))$");
|
private final static Pattern RES_NAME_PATTERN = Pattern
|
||||||
private final static String RES_NAME_FORMAT =
|
.compile("^# APKTOOL/RES_NAME: ([a-zA-Z0-9.]+):([a-z]+)/([a-zA-Z0-9._]+)$");
|
||||||
"# APKTOOL/RES_NAME: %s";
|
|
||||||
private final static Pattern RES_NAME_PATTERN = Pattern.compile(
|
|
||||||
"^# APKTOOL/RES_NAME: ([a-zA-Z0-9.]+):([a-z]+)/([a-zA-Z0-9._]+)$");
|
|
||||||
|
|
||||||
private final static Pattern R_FILE_PATTERN = Pattern.compile(
|
private final static Pattern R_FILE_PATTERN = Pattern
|
||||||
".*R\\$[a-z]+\\.smali$");
|
.compile(".*R\\$[a-z]+\\.smali$");
|
||||||
|
|
||||||
private final static Logger LOGGER =
|
private final static Logger LOGGER = Logger.getLogger(ResSmaliUpdater.class
|
||||||
Logger.getLogger(ResSmaliUpdater.class.getName());
|
.getName());
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,7 @@ import java.util.*;
|
|||||||
*/
|
*/
|
||||||
public class ResConfig {
|
public class ResConfig {
|
||||||
private final ResConfigFlags mFlags;
|
private final ResConfigFlags mFlags;
|
||||||
private final Map<ResResSpec, ResResource> mResources =
|
private final Map<ResResSpec, ResResource> mResources = new LinkedHashMap<ResResSpec, ResResource>();
|
||||||
new LinkedHashMap<ResResSpec, ResResource>();
|
|
||||||
|
|
||||||
public ResConfig(ResConfigFlags flags) {
|
public ResConfig(ResConfigFlags flags) {
|
||||||
this.mFlags = flags;
|
this.mFlags = flags;
|
||||||
@ -53,15 +52,14 @@ public class ResConfig {
|
|||||||
return mFlags;
|
return mFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addResource(ResResource res)
|
public void addResource(ResResource res) throws AndrolibException {
|
||||||
throws AndrolibException {
|
|
||||||
addResource(res, false);
|
addResource(res, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addResource(ResResource res, boolean overwrite)
|
public void addResource(ResResource res, boolean overwrite)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
ResResSpec spec = res.getResSpec();
|
ResResSpec spec = res.getResSpec();
|
||||||
if (mResources.put(spec, res) != null && ! overwrite) {
|
if (mResources.put(spec, res) != null && !overwrite) {
|
||||||
throw new AndrolibException(String.format(
|
throw new AndrolibException(String.format(
|
||||||
"Multiple resources: spec=%s, config=%s", spec, this));
|
"Multiple resources: spec=%s, config=%s", spec, this));
|
||||||
}
|
}
|
||||||
|
@ -57,8 +57,8 @@ public class ResConfigFlags {
|
|||||||
public ResConfigFlags() {
|
public ResConfigFlags() {
|
||||||
mcc = 0;
|
mcc = 0;
|
||||||
mnc = 0;
|
mnc = 0;
|
||||||
language = new char[]{'\00', '\00'};
|
language = new char[] { '\00', '\00' };
|
||||||
country = new char[]{'\00', '\00'};
|
country = new char[] { '\00', '\00' };
|
||||||
layoutDirection = SCREENLAYOUT_LAYOUTDIR_ANY;
|
layoutDirection = SCREENLAYOUT_LAYOUTDIR_ANY;
|
||||||
orientation = ORIENTATION_ANY;
|
orientation = ORIENTATION_ANY;
|
||||||
touchscreen = TOUCHSCREEN_ANY;
|
touchscreen = TOUCHSCREEN_ANY;
|
||||||
@ -78,11 +78,12 @@ public class ResConfigFlags {
|
|||||||
mQualifiers = "";
|
mQualifiers = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResConfigFlags(short mcc, short mnc, char[] language, char[] country,
|
public ResConfigFlags(short mcc, short mnc, char[] language,
|
||||||
short layoutDirection, byte orientation, byte touchscreen,
|
char[] country, short layoutDirection, byte orientation,
|
||||||
short density, byte keyboard, byte navigation, byte inputFlags,
|
byte touchscreen, short density, byte keyboard, byte navigation,
|
||||||
short screenWidth, short screenHeight, short sdkVersion, byte screenLayout,
|
byte inputFlags, short screenWidth, short screenHeight,
|
||||||
byte uiMode, short smallestScreenWidthDp, short screenWidthDp,
|
short sdkVersion, byte screenLayout, byte uiMode,
|
||||||
|
short smallestScreenWidthDp, short screenWidthDp,
|
||||||
short screenHeightDp, boolean isInvalid) {
|
short screenHeightDp, boolean isInvalid) {
|
||||||
if (orientation < 0 || orientation > 3) {
|
if (orientation < 0 || orientation > 3) {
|
||||||
LOGGER.warning("Invalid orientation value: " + orientation);
|
LOGGER.warning("Invalid orientation value: " + orientation);
|
||||||
@ -351,7 +352,7 @@ public class ResConfigFlags {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return ! getQualifiers().equals("") ? getQualifiers() : "[DEFAULT]";
|
return !getQualifiers().equals("") ? getQualifiers() : "[DEFAULT]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -373,7 +374,6 @@ public class ResConfigFlags {
|
|||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: Dirty static hack. This counter should be a part of ResPackage,
|
// TODO: Dirty static hack. This counter should be a part of ResPackage,
|
||||||
// but it would be hard right now and this feature is very rarely used.
|
// but it would be hard right now and this feature is very rarely used.
|
||||||
private static int sErrCounter = 0;
|
private static int sErrCounter = 0;
|
||||||
@ -472,7 +472,6 @@ public class ResConfigFlags {
|
|||||||
public final static byte UI_MODE_NIGHT_NO = 0x10;
|
public final static byte UI_MODE_NIGHT_NO = 0x10;
|
||||||
public final static byte UI_MODE_NIGHT_YES = 0x20;
|
public final static byte UI_MODE_NIGHT_YES = 0x20;
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ResConfigFlags.class
|
||||||
private static final Logger LOGGER =
|
.getName());
|
||||||
Logger.getLogger(ResConfigFlags.class.getName());
|
|
||||||
}
|
}
|
@ -31,12 +31,9 @@ public class ResPackage {
|
|||||||
private final ResTable mResTable;
|
private final ResTable mResTable;
|
||||||
private final int mId;
|
private final int mId;
|
||||||
private final String mName;
|
private final String mName;
|
||||||
private final Map<ResID, ResResSpec> mResSpecs =
|
private final Map<ResID, ResResSpec> mResSpecs = new LinkedHashMap<ResID, ResResSpec>();
|
||||||
new LinkedHashMap<ResID, ResResSpec>();
|
private final Map<ResConfigFlags, ResConfig> mConfigs = new LinkedHashMap<ResConfigFlags, ResConfig>();
|
||||||
private final Map<ResConfigFlags, ResConfig> mConfigs =
|
private final Map<String, ResType> mTypes = new LinkedHashMap<String, ResType>();
|
||||||
new LinkedHashMap<ResConfigFlags, ResConfig>();
|
|
||||||
private final Map<String, ResType> mTypes =
|
|
||||||
new LinkedHashMap<String, ResType>();
|
|
||||||
private final Set<ResID> mSynthesizedRes = new HashSet<ResID>();
|
private final Set<ResID> mSynthesizedRes = new HashSet<ResID>();
|
||||||
|
|
||||||
private ResValueFactory mValueFactory;
|
private ResValueFactory mValueFactory;
|
||||||
@ -118,15 +115,14 @@ public class ResPackage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Collection<ResValuesFile> listValuesFiles() {
|
public Collection<ResValuesFile> listValuesFiles() {
|
||||||
Map<Duo<ResType, ResConfig>, ResValuesFile> ret =
|
Map<Duo<ResType, ResConfig>, ResValuesFile> ret = new HashMap<Duo<ResType, ResConfig>, ResValuesFile>();
|
||||||
new HashMap<Duo<ResType, ResConfig>, ResValuesFile>();
|
|
||||||
for (ResResSpec spec : mResSpecs.values()) {
|
for (ResResSpec spec : mResSpecs.values()) {
|
||||||
for (ResResource res : spec.listResources()) {
|
for (ResResource res : spec.listResources()) {
|
||||||
if (res.getValue() instanceof ResValuesXmlSerializable) {
|
if (res.getValue() instanceof ResValuesXmlSerializable) {
|
||||||
ResType type = res.getResSpec().getType();
|
ResType type = res.getResSpec().getType();
|
||||||
ResConfig config = res.getConfig();
|
ResConfig config = res.getConfig();
|
||||||
Duo<ResType, ResConfig> key =
|
Duo<ResType, ResConfig> key = new Duo<ResType, ResConfig>(
|
||||||
new Duo<ResType, ResConfig>(type, config);
|
type, config);
|
||||||
ResValuesFile values = ret.get(key);
|
ResValuesFile values = ret.get(key);
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
values = new ResValuesFile(this, type, config);
|
values = new ResValuesFile(this, type, config);
|
||||||
@ -194,7 +190,9 @@ public class ResPackage {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final ResPackage other = (ResPackage) obj;
|
final ResPackage other = (ResPackage) obj;
|
||||||
if (this.mResTable != other.mResTable && (this.mResTable == null || !this.mResTable.equals(other.mResTable))) {
|
if (this.mResTable != other.mResTable
|
||||||
|
&& (this.mResTable == null || !this.mResTable
|
||||||
|
.equals(other.mResTable))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.mId != other.mId) {
|
if (this.mId != other.mId) {
|
||||||
@ -206,7 +204,8 @@ public class ResPackage {
|
|||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int hash = 17;
|
int hash = 17;
|
||||||
hash = 31 * hash + (this.mResTable != null ? this.mResTable.hashCode() : 0);
|
hash = 31 * hash
|
||||||
|
+ (this.mResTable != null ? this.mResTable.hashCode() : 0);
|
||||||
hash = 31 * hash + this.mId;
|
hash = 31 * hash + this.mId;
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,7 @@ public class ResResSpec {
|
|||||||
private final String mName;
|
private final String mName;
|
||||||
private final ResPackage mPackage;
|
private final ResPackage mPackage;
|
||||||
private final ResType mType;
|
private final ResType mType;
|
||||||
private final Map<ResConfigFlags, ResResource> mResources =
|
private final Map<ResConfigFlags, ResResource> mResources = new LinkedHashMap<ResConfigFlags, ResResource>();
|
||||||
new LinkedHashMap<ResConfigFlags, ResResource>();
|
|
||||||
|
|
||||||
public ResResSpec(ResID id, String name, ResPackage pkg, ResType type) {
|
public ResResSpec(ResID id, String name, ResPackage pkg, ResType type) {
|
||||||
this.mId = id;
|
this.mId = id;
|
||||||
@ -77,16 +76,13 @@ public class ResResSpec {
|
|||||||
return getFullName(false, false);
|
return getFullName(false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFullName(ResPackage relativeToPackage,
|
public String getFullName(ResPackage relativeToPackage, boolean excludeType) {
|
||||||
boolean excludeType) {
|
return getFullName(getPackage().equals(relativeToPackage), excludeType);
|
||||||
return getFullName(
|
|
||||||
getPackage().equals(relativeToPackage), excludeType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFullName(boolean excludePackage, boolean excludeType) {
|
public String getFullName(boolean excludePackage, boolean excludeType) {
|
||||||
return
|
return (excludePackage ? "" : getPackage().getName() + ":")
|
||||||
(excludePackage ? "" : getPackage().getName() + ":") +
|
+ (excludeType ? "" : getType().getName() + "/") + getName();
|
||||||
(excludeType ? "" : getType().getName() + "/") + getName();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResID getId() {
|
public ResID getId() {
|
||||||
@ -105,16 +101,16 @@ public class ResResSpec {
|
|||||||
return mType;
|
return mType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addResource(ResResource res)
|
public void addResource(ResResource res) throws AndrolibException {
|
||||||
throws AndrolibException {
|
|
||||||
addResource(res, false);
|
addResource(res, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addResource(ResResource res, boolean overwrite)
|
public void addResource(ResResource res, boolean overwrite)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
ResConfigFlags flags = res.getConfig().getFlags();
|
ResConfigFlags flags = res.getConfig().getFlags();
|
||||||
if (mResources.put(flags, res) != null && ! overwrite) {
|
if (mResources.put(flags, res) != null && !overwrite) {
|
||||||
throw new AndrolibException(String.format("Multiple resources: spec=%s, config=%s", this, flags));
|
throw new AndrolibException(String.format(
|
||||||
|
"Multiple resources: spec=%s, config=%s", this, flags));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,16 +27,15 @@ public class ResResource {
|
|||||||
private final ResResSpec mResSpec;
|
private final ResResSpec mResSpec;
|
||||||
private final ResValue mValue;
|
private final ResValue mValue;
|
||||||
|
|
||||||
public ResResource(ResConfig config, ResResSpec spec,
|
public ResResource(ResConfig config, ResResSpec spec, ResValue value) {
|
||||||
ResValue value) {
|
|
||||||
this.mConfig = config;
|
this.mConfig = config;
|
||||||
this.mResSpec = spec;
|
this.mResSpec = spec;
|
||||||
this.mValue = value;
|
this.mValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFilePath() {
|
public String getFilePath() {
|
||||||
return mResSpec.getType().getName() +
|
return mResSpec.getType().getName()
|
||||||
mConfig.getFlags().getQualifiers() + "/" + mResSpec.getName();
|
+ mConfig.getFlags().getQualifiers() + "/" + mResSpec.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResConfig getConfig() {
|
public ResConfig getConfig() {
|
||||||
|
@ -28,14 +28,10 @@ import java.util.*;
|
|||||||
public class ResTable {
|
public class ResTable {
|
||||||
private final AndrolibResources mAndRes;
|
private final AndrolibResources mAndRes;
|
||||||
|
|
||||||
private final Map<Integer, ResPackage> mPackagesById =
|
private final Map<Integer, ResPackage> mPackagesById = new HashMap<Integer, ResPackage>();
|
||||||
new HashMap<Integer, ResPackage>();
|
private final Map<String, ResPackage> mPackagesByName = new HashMap<String, ResPackage>();
|
||||||
private final Map<String, ResPackage> mPackagesByName =
|
private final Set<ResPackage> mMainPackages = new LinkedHashSet<ResPackage>();
|
||||||
new HashMap<String, ResPackage>();
|
private final Set<ResPackage> mFramePackages = new LinkedHashSet<ResPackage>();
|
||||||
private final Set<ResPackage> mMainPackages =
|
|
||||||
new LinkedHashSet<ResPackage>();
|
|
||||||
private final Set<ResPackage> mFramePackages =
|
|
||||||
new LinkedHashSet<ResPackage>();
|
|
||||||
|
|
||||||
private String mFrameTag;
|
private String mFrameTag;
|
||||||
|
|
||||||
@ -103,8 +99,8 @@ public class ResTable {
|
|||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
Integer id = pkg.getId();
|
Integer id = pkg.getId();
|
||||||
if (mPackagesById.containsKey(id)) {
|
if (mPackagesById.containsKey(id)) {
|
||||||
throw new AndrolibException(
|
throw new AndrolibException("Multiple packages: id="
|
||||||
"Multiple packages: id=" + id.toString());
|
+ id.toString());
|
||||||
}
|
}
|
||||||
String name = pkg.getName();
|
String name = pkg.getName();
|
||||||
if (mPackagesByName.containsKey(name)) {
|
if (mPackagesByName.containsKey(name)) {
|
||||||
|
@ -25,14 +25,12 @@ import java.util.*;
|
|||||||
*/
|
*/
|
||||||
public final class ResType {
|
public final class ResType {
|
||||||
private final String mName;
|
private final String mName;
|
||||||
private final Map<String, ResResSpec> mResSpecs =
|
private final Map<String, ResResSpec> mResSpecs = new LinkedHashMap<String, ResResSpec>();
|
||||||
new LinkedHashMap<String, ResResSpec>();
|
|
||||||
|
|
||||||
private final ResTable mResTable;
|
private final ResTable mResTable;
|
||||||
private final ResPackage mPackage;
|
private final ResPackage mPackage;
|
||||||
|
|
||||||
public ResType(String name, ResTable resTable,
|
public ResType(String name, ResTable resTable, ResPackage package_) {
|
||||||
ResPackage package_) {
|
|
||||||
this.mName = name;
|
this.mName = name;
|
||||||
this.mResTable = resTable;
|
this.mResTable = resTable;
|
||||||
this.mPackage = package_;
|
this.mPackage = package_;
|
||||||
@ -49,14 +47,13 @@ public final class ResType {
|
|||||||
public ResResSpec getResSpec(String name) throws AndrolibException {
|
public ResResSpec getResSpec(String name) throws AndrolibException {
|
||||||
ResResSpec spec = mResSpecs.get(name);
|
ResResSpec spec = mResSpecs.get(name);
|
||||||
if (spec == null) {
|
if (spec == null) {
|
||||||
throw new UndefinedResObject(String.format(
|
throw new UndefinedResObject(String.format("resource spec: %s/%s",
|
||||||
"resource spec: %s/%s", getName(), name));
|
getName(), name));
|
||||||
}
|
}
|
||||||
return spec;
|
return spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addResSpec(ResResSpec spec)
|
public void addResSpec(ResResSpec spec) throws AndrolibException {
|
||||||
throws AndrolibException {
|
|
||||||
if (mResSpecs.put(spec.getName(), spec) != null) {
|
if (mResSpecs.put(spec.getName(), spec) != null) {
|
||||||
throw new AndrolibException(String.format(
|
throw new AndrolibException(String.format(
|
||||||
"Multiple res specs: %s/%s", getName(), spec.getName()));
|
"Multiple res specs: %s/%s", getName(), spec.getName()));
|
||||||
|
@ -26,8 +26,7 @@ public class ResValuesFile {
|
|||||||
private final ResPackage mPackage;
|
private final ResPackage mPackage;
|
||||||
private final ResType mType;
|
private final ResType mType;
|
||||||
private final ResConfig mConfig;
|
private final ResConfig mConfig;
|
||||||
private final Set<ResResource> mResources =
|
private final Set<ResResource> mResources = new LinkedHashSet<ResResource>();
|
||||||
new LinkedHashSet<ResResource>();
|
|
||||||
|
|
||||||
public ResValuesFile(ResPackage pkg, ResType type, ResConfig config) {
|
public ResValuesFile(ResPackage pkg, ResType type, ResConfig config) {
|
||||||
this.mPackage = pkg;
|
this.mPackage = pkg;
|
||||||
@ -36,9 +35,8 @@ public class ResValuesFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getPath() {
|
public String getPath() {
|
||||||
return "values" + mConfig.getFlags().getQualifiers()
|
return "values" + mConfig.getFlags().getQualifiers() + "/"
|
||||||
+ "/" + mType.getName()
|
+ mType.getName() + (mType.getName().endsWith("s") ? "" : "s")
|
||||||
+ (mType.getName().endsWith("s") ? "" : "s")
|
|
||||||
+ ".xml";
|
+ ".xml";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,10 +69,12 @@ public class ResValuesFile {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final ResValuesFile other = (ResValuesFile) obj;
|
final ResValuesFile other = (ResValuesFile) obj;
|
||||||
if (this.mType != other.mType && (this.mType == null || !this.mType.equals(other.mType))) {
|
if (this.mType != other.mType
|
||||||
|
&& (this.mType == null || !this.mType.equals(other.mType))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.mConfig != other.mConfig && (this.mConfig == null || !this.mConfig.equals(other.mConfig))) {
|
if (this.mConfig != other.mConfig
|
||||||
|
&& (this.mConfig == null || !this.mConfig.equals(other.mConfig))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -22,15 +22,15 @@ import brut.androlib.res.xml.ResValuesXmlSerializable;
|
|||||||
import brut.util.Duo;
|
import brut.util.Duo;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import org.xmlpull.v1.XmlSerializer;
|
import org.xmlpull.v1.XmlSerializer;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||||
*/
|
*/
|
||||||
public class ResArrayValue extends ResBagValue implements ResValuesXmlSerializable {
|
public class ResArrayValue extends ResBagValue implements
|
||||||
|
ResValuesXmlSerializable {
|
||||||
private String mRawItems;
|
private String mRawItems;
|
||||||
ResArrayValue(ResReferenceValue parent,
|
|
||||||
Duo<Integer, ResScalarValue>[] items) {
|
ResArrayValue(ResReferenceValue parent, Duo<Integer, ResScalarValue>[] items) {
|
||||||
super(parent);
|
super(parent);
|
||||||
|
|
||||||
mItems = new ResScalarValue[items.length];
|
mItems = new ResScalarValue[items.length];
|
||||||
@ -45,15 +45,15 @@ public class ResArrayValue extends ResBagValue implements ResValuesXmlSerializab
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void serializeToResValuesXml(XmlSerializer serializer, ResResource res)
|
public void serializeToResValuesXml(XmlSerializer serializer,
|
||||||
throws IOException, AndrolibException {
|
ResResource res) throws IOException, AndrolibException {
|
||||||
String type = getType();
|
String type = getType();
|
||||||
type = (type == null ? "" : type + "-") + "array";
|
type = (type == null ? "" : type + "-") + "array";
|
||||||
// reference array (04 10 2012, BurgerZ)
|
// reference array (04 10 2012, BurgerZ)
|
||||||
if ("reference-array".equals(type)) {
|
if ("reference-array".equals(type)) {
|
||||||
type = "string-array";
|
type = "string-array";
|
||||||
}
|
}
|
||||||
// reference array (04 10 2012, BurgerZ)
|
// reference array (04 10 2012, BurgerZ)
|
||||||
serializer.startTag(null, type);
|
serializer.startTag(null, type);
|
||||||
serializer.attribute(null, "name", res.getResSpec().getName());
|
serializer.attribute(null, "name", res.getResSpec().getName());
|
||||||
for (int i = 0; i < mItems.length; i++) {
|
for (int i = 0; i < mItems.length; i++) {
|
||||||
@ -73,7 +73,8 @@ public class ResArrayValue extends ResBagValue implements ResValuesXmlSerializab
|
|||||||
|
|
||||||
if (mItems[i].encodeAsResXmlItemValue().startsWith("@string")) {
|
if (mItems[i].encodeAsResXmlItemValue().startsWith("@string")) {
|
||||||
return "string";
|
return "string";
|
||||||
} else if (mItems[i].encodeAsResXmlItemValue().startsWith("@drawable")) {
|
} else if (mItems[i].encodeAsResXmlItemValue().startsWith(
|
||||||
|
"@drawable")) {
|
||||||
return null;
|
return null;
|
||||||
} else if (!"string".equals(type) && !"integer".equals(type)) {
|
} else if (!"string".equals(type) && !"integer".equals(type)) {
|
||||||
return null;
|
return null;
|
||||||
@ -86,6 +87,5 @@ public class ResArrayValue extends ResBagValue implements ResValuesXmlSerializab
|
|||||||
|
|
||||||
private final ResScalarValue[] mItems;
|
private final ResScalarValue[] mItems;
|
||||||
|
|
||||||
|
|
||||||
public static final int BAG_KEY_ARRAY_START = 0x02000000;
|
public static final int BAG_KEY_ARRAY_START = 0x02000000;
|
||||||
}
|
}
|
||||||
|
@ -43,8 +43,8 @@ public class ResAttr extends ResBagValue implements ResValuesXmlSerializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void serializeToResValuesXml(XmlSerializer serializer, ResResource res)
|
public void serializeToResValuesXml(XmlSerializer serializer,
|
||||||
throws IOException, AndrolibException {
|
ResResource res) throws IOException, AndrolibException {
|
||||||
String type = getTypeAsString();
|
String type = getTypeAsString();
|
||||||
|
|
||||||
serializer.startTag(null, "attr");
|
serializer.startTag(null, "attr");
|
||||||
@ -65,7 +65,6 @@ public class ResAttr extends ResBagValue implements ResValuesXmlSerializable {
|
|||||||
serializer.endTag(null, "attr");
|
serializer.endTag(null, "attr");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static ResAttr factory(ResReferenceValue parent,
|
public static ResAttr factory(ResReferenceValue parent,
|
||||||
Duo<Integer, ResScalarValue>[] items, ResValueFactory factory,
|
Duo<Integer, ResScalarValue>[] items, ResValueFactory factory,
|
||||||
ResPackage pkg) throws AndrolibException {
|
ResPackage pkg) throws AndrolibException {
|
||||||
@ -93,29 +92,31 @@ public class ResAttr extends ResBagValue implements ResValuesXmlSerializable {
|
|||||||
if (i == items.length) {
|
if (i == items.length) {
|
||||||
return new ResAttr(parent, scalarType, min, max, l10n);
|
return new ResAttr(parent, scalarType, min, max, l10n);
|
||||||
}
|
}
|
||||||
Duo<ResReferenceValue, ResIntValue>[] attrItems =
|
Duo<ResReferenceValue, ResIntValue>[] attrItems = new Duo[items.length
|
||||||
new Duo[items.length - i];
|
- i];
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for (; i < items.length; i++) {
|
for (; i < items.length; i++) {
|
||||||
int resId = items[i].m1;
|
int resId = items[i].m1;
|
||||||
pkg.addSynthesizedRes(resId);
|
pkg.addSynthesizedRes(resId);
|
||||||
attrItems[j++] = new Duo<ResReferenceValue, ResIntValue>(
|
attrItems[j++] = new Duo<ResReferenceValue, ResIntValue>(
|
||||||
factory.newReference(resId, null), (ResIntValue) items[i].m2);
|
factory.newReference(resId, null),
|
||||||
|
(ResIntValue) items[i].m2);
|
||||||
}
|
}
|
||||||
switch (type & 0xff0000) {
|
switch (type & 0xff0000) {
|
||||||
case TYPE_ENUM:
|
case TYPE_ENUM:
|
||||||
return new ResEnumAttr(
|
return new ResEnumAttr(parent, scalarType, min, max, l10n,
|
||||||
parent, scalarType, min, max, l10n, attrItems);
|
attrItems);
|
||||||
case TYPE_FLAGS:
|
case TYPE_FLAGS:
|
||||||
return new ResFlagsAttr(
|
return new ResFlagsAttr(parent, scalarType, min, max, l10n,
|
||||||
parent, scalarType, min, max, l10n, attrItems);
|
attrItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new AndrolibException("Could not decode attr value");
|
throw new AndrolibException("Could not decode attr value");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void serializeBody(XmlSerializer serializer, ResResource res)
|
protected void serializeBody(XmlSerializer serializer, ResResource res)
|
||||||
throws AndrolibException, IOException {}
|
throws AndrolibException, IOException {
|
||||||
|
}
|
||||||
|
|
||||||
protected String getTypeAsString() {
|
protected String getTypeAsString() {
|
||||||
String s = "";
|
String s = "";
|
||||||
@ -154,7 +155,6 @@ public class ResAttr extends ResBagValue implements ResValuesXmlSerializable {
|
|||||||
private final Integer mMax;
|
private final Integer mMax;
|
||||||
private final Boolean mL10n;
|
private final Boolean mL10n;
|
||||||
|
|
||||||
|
|
||||||
public static final int BAG_KEY_ATTR_TYPE = 0x01000000;
|
public static final int BAG_KEY_ATTR_TYPE = 0x01000000;
|
||||||
private static final int BAG_KEY_ATTR_MIN = 0x01000001;
|
private static final int BAG_KEY_ATTR_MIN = 0x01000001;
|
||||||
private static final int BAG_KEY_ATTR_MAX = 0x01000002;
|
private static final int BAG_KEY_ATTR_MAX = 0x01000002;
|
||||||
|
@ -33,8 +33,9 @@ public class ResBagValue extends ResValue implements ResValuesXmlSerializable {
|
|||||||
this.mParent = parent;
|
this.mParent = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void serializeToResValuesXml(XmlSerializer serializer, ResResource res)
|
@Override
|
||||||
throws IOException, AndrolibException {
|
public void serializeToResValuesXml(XmlSerializer serializer,
|
||||||
|
ResResource res) throws IOException, AndrolibException {
|
||||||
String type = res.getResSpec().getType().getName();
|
String type = res.getResSpec().getType().getName();
|
||||||
if ("style".equals(type)) {
|
if ("style".equals(type)) {
|
||||||
new ResStyleValue(mParent, new Duo[0], null)
|
new ResStyleValue(mParent, new Duo[0], null)
|
||||||
@ -42,13 +43,13 @@ public class ResBagValue extends ResValue implements ResValuesXmlSerializable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ("array".equals(type)) {
|
if ("array".equals(type)) {
|
||||||
new ResArrayValue(mParent, new Duo[0])
|
new ResArrayValue(mParent, new Duo[0]).serializeToResValuesXml(
|
||||||
.serializeToResValuesXml(serializer, res);
|
serializer, res);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ("plurals".equals(type)) {
|
if ("plurals".equals(type)) {
|
||||||
new ResPluralsValue(mParent, new Duo[0])
|
new ResPluralsValue(mParent, new Duo[0]).serializeToResValuesXml(
|
||||||
.serializeToResValuesXml(serializer, res);
|
serializer, res);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ public class ResBoolValue extends ResScalarValue {
|
|||||||
return mValue;
|
return mValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected String encodeAsResXml() {
|
protected String encodeAsResXml() {
|
||||||
return mValue ? "true" : "false";
|
return mValue ? "true" : "false";
|
||||||
}
|
}
|
||||||
|
@ -77,8 +77,6 @@ public class ResEnumAttr extends ResAttr {
|
|||||||
return value2;
|
return value2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private final Duo<ResReferenceValue, ResIntValue>[] mItems;
|
private final Duo<ResReferenceValue, ResIntValue>[] mItems;
|
||||||
private final Map<Integer, String> mItemsCache =
|
private final Map<Integer, String> mItemsCache = new HashMap<Integer, String>();
|
||||||
new HashMap<Integer, String>();
|
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ public class ResFileValue extends ResValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getStrippedPath() throws AndrolibException {
|
public String getStrippedPath() throws AndrolibException {
|
||||||
if (! mPath.startsWith("res/")) {
|
if (!mPath.startsWith("res/")) {
|
||||||
throw new AndrolibException(
|
throw new AndrolibException(
|
||||||
"File path does not start with \"res/\": " + mPath);
|
"File path does not start with \"res/\": " + mPath);
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,8 @@ import org.xmlpull.v1.XmlSerializer;
|
|||||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||||
*/
|
*/
|
||||||
public class ResFlagsAttr extends ResAttr {
|
public class ResFlagsAttr extends ResAttr {
|
||||||
ResFlagsAttr(ResReferenceValue parent, int type, Integer min, Integer max, Boolean l10n, Duo<ResReferenceValue, ResIntValue>[] items) {
|
ResFlagsAttr(ResReferenceValue parent, int type, Integer min, Integer max,
|
||||||
|
Boolean l10n, Duo<ResReferenceValue, ResIntValue>[] items) {
|
||||||
super(parent, type, min, max, l10n);
|
super(parent, type, min, max, l10n);
|
||||||
|
|
||||||
mItems = new FlagItem[items.length];
|
mItems = new FlagItem[items.length];
|
||||||
@ -40,7 +41,7 @@ public class ResFlagsAttr extends ResAttr {
|
|||||||
@Override
|
@Override
|
||||||
public String convertToResXmlFormat(ResScalarValue value)
|
public String convertToResXmlFormat(ResScalarValue value)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
if (! (value instanceof ResIntValue)) {
|
if (!(value instanceof ResIntValue)) {
|
||||||
return super.convertToResXmlFormat(value);
|
return super.convertToResXmlFormat(value);
|
||||||
}
|
}
|
||||||
loadFlags();
|
loadFlags();
|
||||||
@ -61,7 +62,7 @@ public class ResFlagsAttr extends ResAttr {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! isSubpartOf(flag, flags)) {
|
if (!isSubpartOf(flag, flags)) {
|
||||||
flags[flagsCount] = flag;
|
flags[flagsCount] = flag;
|
||||||
flagItems[flagsCount++] = flagItem;
|
flagItems[flagsCount++] = flagItem;
|
||||||
}
|
}
|
||||||
@ -126,20 +127,19 @@ public class ResFlagsAttr extends ResAttr {
|
|||||||
mFlags = Arrays.copyOf(flags, flagsCount);
|
mFlags = Arrays.copyOf(flags, flagsCount);
|
||||||
|
|
||||||
Arrays.sort(mFlags, new Comparator<FlagItem>() {
|
Arrays.sort(mFlags, new Comparator<FlagItem>() {
|
||||||
|
@Override
|
||||||
public int compare(FlagItem o1, FlagItem o2) {
|
public int compare(FlagItem o1, FlagItem o2) {
|
||||||
return Integer.valueOf(Integer.bitCount(o2.flag))
|
return Integer.valueOf(Integer.bitCount(o2.flag)).compareTo(
|
||||||
.compareTo(Integer.bitCount(o1.flag));
|
Integer.bitCount(o1.flag));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private final FlagItem[] mItems;
|
private final FlagItem[] mItems;
|
||||||
|
|
||||||
private FlagItem[] mZeroFlags;
|
private FlagItem[] mZeroFlags;
|
||||||
private FlagItem[] mFlags;
|
private FlagItem[] mFlags;
|
||||||
|
|
||||||
|
|
||||||
private static class FlagItem {
|
private static class FlagItem {
|
||||||
public final ResReferenceValue ref;
|
public final ResReferenceValue ref;
|
||||||
public final int flag;
|
public final int flag;
|
||||||
|
@ -31,6 +31,7 @@ public class ResFloatValue extends ResScalarValue {
|
|||||||
return mValue;
|
return mValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected String encodeAsResXml() {
|
protected String encodeAsResXml() {
|
||||||
return String.valueOf(mValue);
|
return String.valueOf(mValue);
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,12 @@ import org.xmlpull.v1.XmlSerializer;
|
|||||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||||
*/
|
*/
|
||||||
public class ResIdValue extends ResValue implements ResValuesXmlSerializable {
|
public class ResIdValue extends ResValue implements ResValuesXmlSerializable {
|
||||||
public void serializeToResValuesXml(XmlSerializer serializer, ResResource res) throws IOException, AndrolibException {
|
@Override
|
||||||
|
public void serializeToResValuesXml(XmlSerializer serializer,
|
||||||
|
ResResource res) throws IOException, AndrolibException {
|
||||||
serializer.startTag(null, "item");
|
serializer.startTag(null, "item");
|
||||||
serializer.attribute(null, "type", res.getResSpec().getType().getName());
|
serializer
|
||||||
|
.attribute(null, "type", res.getResSpec().getType().getName());
|
||||||
serializer.attribute(null, "name", res.getResSpec().getName());
|
serializer.attribute(null, "name", res.getResSpec().getName());
|
||||||
serializer.endTag(null, "item");
|
serializer.endTag(null, "item");
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ public class ResIntValue extends ResScalarValue {
|
|||||||
return mValue;
|
return mValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected String encodeAsResXml() throws AndrolibException {
|
protected String encodeAsResXml() throws AndrolibException {
|
||||||
return TypedValue.coerceToString(type, mValue);
|
return TypedValue.coerceToString(type, mValue);
|
||||||
}
|
}
|
||||||
|
@ -28,21 +28,21 @@ import org.xmlpull.v1.XmlSerializer;
|
|||||||
/**
|
/**
|
||||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||||
*/
|
*/
|
||||||
public class ResPluralsValue extends ResBagValue implements ResValuesXmlSerializable {
|
public class ResPluralsValue extends ResBagValue implements
|
||||||
|
ResValuesXmlSerializable {
|
||||||
ResPluralsValue(ResReferenceValue parent,
|
ResPluralsValue(ResReferenceValue parent,
|
||||||
Duo<Integer, ResScalarValue>[] items) {
|
Duo<Integer, ResScalarValue>[] items) {
|
||||||
super(parent);
|
super(parent);
|
||||||
|
|
||||||
mItems = new ResScalarValue[6];
|
mItems = new ResScalarValue[6];
|
||||||
for (int i = 0; i < items.length; i++) {
|
for (int i = 0; i < items.length; i++) {
|
||||||
mItems[items[i].m1 - BAG_KEY_PLURALS_START] =
|
mItems[items[i].m1 - BAG_KEY_PLURALS_START] = items[i].m2;
|
||||||
(ResScalarValue) items[i].m2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void serializeToResValuesXml(XmlSerializer serializer, ResResource res)
|
public void serializeToResValuesXml(XmlSerializer serializer,
|
||||||
throws IOException, AndrolibException {
|
ResResource res) throws IOException, AndrolibException {
|
||||||
serializer.startTag(null, "plurals");
|
serializer.startTag(null, "plurals");
|
||||||
serializer.attribute(null, "name", res.getResSpec().getName());
|
serializer.attribute(null, "name", res.getResSpec().getName());
|
||||||
for (int i = 0; i < mItems.length; i++) {
|
for (int i = 0; i < mItems.length; i++) {
|
||||||
@ -55,13 +55,18 @@ public class ResPluralsValue extends ResBagValue implements ResValuesXmlSerializ
|
|||||||
|
|
||||||
serializer.startTag(null, "item");
|
serializer.startTag(null, "item");
|
||||||
serializer.attribute(null, "quantity", QUANTITY_MAP[i]);
|
serializer.attribute(null, "quantity", QUANTITY_MAP[i]);
|
||||||
if (ResXmlEncoders.hasMultipleNonPositionalSubstitutions(rawValue.encodeAsResXmlValue())) {
|
if (ResXmlEncoders.hasMultipleNonPositionalSubstitutions(rawValue
|
||||||
|
.encodeAsResXmlValue())) {
|
||||||
serializer.text(item.encodeAsResXmlValueExt());
|
serializer.text(item.encodeAsResXmlValueExt());
|
||||||
} else {
|
} else {
|
||||||
String recode = item.encodeAsResXmlValue();
|
String recode = item.encodeAsResXmlValue();
|
||||||
//Dirty, but working fix @miuirussia
|
// Dirty, but working fix @miuirussia
|
||||||
for (int j = 0; j < 10; j++) {
|
for (int j = 0; j < 10; j++) {
|
||||||
recode = StringUtils.replace(recode, "%" + Integer.toString(j) + "$" + Integer.toString(j) + "$", "%" + Integer.toString(j) + "$");
|
recode = StringUtils.replace(
|
||||||
|
recode,
|
||||||
|
"%" + Integer.toString(j) + "$"
|
||||||
|
+ Integer.toString(j) + "$",
|
||||||
|
"%" + Integer.toString(j) + "$");
|
||||||
}
|
}
|
||||||
serializer.text(recode);
|
serializer.text(recode);
|
||||||
}
|
}
|
||||||
@ -70,12 +75,10 @@ public class ResPluralsValue extends ResBagValue implements ResValuesXmlSerializ
|
|||||||
serializer.endTag(null, "plurals");
|
serializer.endTag(null, "plurals");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private final ResScalarValue[] mItems;
|
private final ResScalarValue[] mItems;
|
||||||
|
|
||||||
|
|
||||||
public static final int BAG_KEY_PLURALS_START = 0x01000004;
|
public static final int BAG_KEY_PLURALS_START = 0x01000004;
|
||||||
public static final int BAG_KEY_PLURALS_END = 0x01000009;
|
public static final int BAG_KEY_PLURALS_END = 0x01000009;
|
||||||
private static final String[] QUANTITY_MAP =
|
private static final String[] QUANTITY_MAP = new String[] { "other",
|
||||||
new String[] {"other", "zero", "one", "two", "few", "many"};
|
"zero", "one", "two", "few", "many" };
|
||||||
}
|
}
|
||||||
|
@ -38,23 +38,23 @@ public class ResReferenceValue extends ResIntValue {
|
|||||||
mTheme = theme;
|
mTheme = theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected String encodeAsResXml() throws AndrolibException {
|
protected String encodeAsResXml() throws AndrolibException {
|
||||||
if (isNull()) {
|
if (isNull()) {
|
||||||
return "@null";
|
return "@null";
|
||||||
}
|
}
|
||||||
|
|
||||||
ResResSpec spec = getReferent();
|
ResResSpec spec = getReferent();
|
||||||
boolean newId =
|
boolean newId = spec.hasDefaultResource()
|
||||||
spec.hasDefaultResource() &&
|
&& spec.getDefaultResource().getValue() instanceof ResIdValue;
|
||||||
spec.getDefaultResource().getValue() instanceof ResIdValue;
|
|
||||||
|
|
||||||
// generate the beginning to fix @android
|
// generate the beginning to fix @android
|
||||||
String mStart = (mTheme ? '?' : '@') + (newId ? "+" : "");
|
String mStart = (mTheme ? '?' : '@') + (newId ? "+" : "");
|
||||||
//mStart = mStart.replace("@android", "@*android");
|
// mStart = mStart.replace("@android", "@*android");
|
||||||
|
|
||||||
return mStart +
|
return mStart
|
||||||
spec.getFullName(mPackage,
|
+ spec.getFullName(mPackage, mTheme
|
||||||
mTheme && spec.getType().getName().equals("attr"));
|
&& spec.getType().getName().equals("attr"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResResSpec getReferent() throws AndrolibException {
|
public ResResSpec getReferent() throws AndrolibException {
|
||||||
|
@ -27,8 +27,8 @@ import org.xmlpull.v1.XmlSerializer;
|
|||||||
/**
|
/**
|
||||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||||
*/
|
*/
|
||||||
public abstract class ResScalarValue extends ResValue
|
public abstract class ResScalarValue extends ResValue implements
|
||||||
implements ResXmlEncodable, ResValuesXmlSerializable {
|
ResXmlEncodable, ResValuesXmlSerializable {
|
||||||
protected final String mType;
|
protected final String mType;
|
||||||
protected final String mRawValue;
|
protected final String mRawValue;
|
||||||
|
|
||||||
@ -37,6 +37,7 @@ public abstract class ResScalarValue extends ResValue
|
|||||||
mRawValue = rawValue;
|
mRawValue = rawValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String encodeAsResXmlAttr() throws AndrolibException {
|
public String encodeAsResXmlAttr() throws AndrolibException {
|
||||||
if (mRawValue != null) {
|
if (mRawValue != null) {
|
||||||
return mRawValue;
|
return mRawValue;
|
||||||
@ -48,6 +49,7 @@ public abstract class ResScalarValue extends ResValue
|
|||||||
return encodeAsResXmlValue().replace("@android:", "@*android:");
|
return encodeAsResXmlValue().replace("@android:", "@*android:");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String encodeAsResXmlValue() throws AndrolibException {
|
public String encodeAsResXmlValue() throws AndrolibException {
|
||||||
if (mRawValue != null) {
|
if (mRawValue != null) {
|
||||||
return mRawValue;
|
return mRawValue;
|
||||||
@ -63,19 +65,19 @@ public abstract class ResScalarValue extends ResValue
|
|||||||
StringBuilder result = new StringBuilder();
|
StringBuilder result = new StringBuilder();
|
||||||
String tmp1[] = rawValue.split("%%", -1);
|
String tmp1[] = rawValue.split("%%", -1);
|
||||||
int tmp1_sz = tmp1.length;
|
int tmp1_sz = tmp1.length;
|
||||||
for(int i=0;i<tmp1_sz;i++) {
|
for (int i = 0; i < tmp1_sz; i++) {
|
||||||
String cur1 = tmp1[i];
|
String cur1 = tmp1[i];
|
||||||
String tmp2[] = cur1.split("%", -1);
|
String tmp2[] = cur1.split("%", -1);
|
||||||
int tmp2_sz = tmp2.length;
|
int tmp2_sz = tmp2.length;
|
||||||
for(int j=0;j<tmp2_sz;j++) {
|
for (int j = 0; j < tmp2_sz; j++) {
|
||||||
String cur2 = tmp2[j];
|
String cur2 = tmp2[j];
|
||||||
result.append(cur2);
|
result.append(cur2);
|
||||||
if(j != (tmp2_sz-1)) {
|
if (j != (tmp2_sz - 1)) {
|
||||||
result.append('%').append(count).append('$');
|
result.append('%').append(count).append('$');
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(i != (tmp1_sz-1)) {
|
if (i != (tmp1_sz - 1)) {
|
||||||
result.append("%%");
|
result.append("%%");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,17 +88,17 @@ public abstract class ResScalarValue extends ResValue
|
|||||||
return encodeAsResXml();
|
return encodeAsResXml();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void serializeToResValuesXml(XmlSerializer serializer, ResResource res)
|
public void serializeToResValuesXml(XmlSerializer serializer,
|
||||||
throws IOException, AndrolibException {
|
ResResource res) throws IOException, AndrolibException {
|
||||||
String type = res.getResSpec().getType().getName();
|
String type = res.getResSpec().getType().getName();
|
||||||
boolean item = !"reference".equals(mType) && !type.equals(mType);
|
boolean item = !"reference".equals(mType) && !type.equals(mType);
|
||||||
|
|
||||||
String body = encodeAsResXmlValue();
|
String body = encodeAsResXmlValue();
|
||||||
|
|
||||||
// check for resource reference
|
// check for resource reference
|
||||||
if (body.contains("@")){
|
if (body.contains("@")) {
|
||||||
if(!res.getFilePath().contains("string")) {
|
if (!res.getFilePath().contains("string")) {
|
||||||
item = true;
|
item = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,7 +114,7 @@ public abstract class ResScalarValue extends ResValue
|
|||||||
|
|
||||||
serializeExtraXmlAttrs(serializer, res);
|
serializeExtraXmlAttrs(serializer, res);
|
||||||
|
|
||||||
if (! body.isEmpty()) {
|
if (!body.isEmpty()) {
|
||||||
serializer.ignorableWhitespace(body);
|
serializer.ignorableWhitespace(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,8 +42,9 @@ public class ResStringValue extends ResScalarValue {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String encodeAsResXmlItemValue() {
|
public String encodeAsResXmlItemValue() {
|
||||||
return ResXmlEncoders.enumerateNonPositionalSubstitutions(
|
return ResXmlEncoders
|
||||||
ResXmlEncoders.encodeAsXmlValue(mRawValue));
|
.enumerateNonPositionalSubstitutions(ResXmlEncoders
|
||||||
|
.encodeAsXmlValue(mRawValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -27,7 +27,8 @@ import org.xmlpull.v1.XmlSerializer;
|
|||||||
/**
|
/**
|
||||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||||
*/
|
*/
|
||||||
public class ResStyleValue extends ResBagValue implements ResValuesXmlSerializable {
|
public class ResStyleValue extends ResBagValue implements
|
||||||
|
ResValuesXmlSerializable {
|
||||||
ResStyleValue(ResReferenceValue parent,
|
ResStyleValue(ResReferenceValue parent,
|
||||||
Duo<Integer, ResScalarValue>[] items, ResValueFactory factory) {
|
Duo<Integer, ResScalarValue>[] items, ResValueFactory factory) {
|
||||||
super(parent);
|
super(parent);
|
||||||
@ -40,18 +41,19 @@ public class ResStyleValue extends ResBagValue implements ResValuesXmlSerializab
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void serializeToResValuesXml(XmlSerializer serializer, ResResource res)
|
public void serializeToResValuesXml(XmlSerializer serializer,
|
||||||
throws IOException, AndrolibException {
|
ResResource res) throws IOException, AndrolibException {
|
||||||
serializer.startTag(null, "style");
|
serializer.startTag(null, "style");
|
||||||
serializer.attribute(null, "name", res.getResSpec().getName());
|
serializer.attribute(null, "name", res.getResSpec().getName());
|
||||||
if (! mParent.isNull()) {
|
if (!mParent.isNull()) {
|
||||||
serializer.attribute(null, "parent", mParent.encodeAsResXmlAttr());
|
serializer.attribute(null, "parent", mParent.encodeAsResXmlAttr());
|
||||||
}
|
}
|
||||||
for (int i = 0; i < mItems.length; i++) {
|
for (int i = 0; i < mItems.length; i++) {
|
||||||
ResResSpec spec = mItems[i].m1.getReferent();
|
ResResSpec spec = mItems[i].m1.getReferent();
|
||||||
|
|
||||||
// hacky-fix remove bad ReferenceVars
|
// hacky-fix remove bad ReferenceVars
|
||||||
if (spec.getDefaultResource().getValue().toString().contains("ResReferenceValue@")) {
|
if (spec.getDefaultResource().getValue().toString()
|
||||||
|
.contains("ResReferenceValue@")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ResAttr attr = (ResAttr) spec.getDefaultResource().getValue();
|
ResAttr attr = (ResAttr) spec.getDefaultResource().getValue();
|
||||||
@ -74,6 +76,5 @@ public class ResStyleValue extends ResBagValue implements ResValuesXmlSerializab
|
|||||||
serializer.endTag(null, "style");
|
serializer.endTag(null, "style");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private final Duo<ResReferenceValue, ResScalarValue>[] mItems;
|
private final Duo<ResReferenceValue, ResScalarValue>[] mItems;
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ public class ResValueFactory {
|
|||||||
return new ResIntValue(value, rawValue, type);
|
return new ResIntValue(value, rawValue, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new AndrolibException("Invalid value type: "+ type);
|
throw new AndrolibException("Invalid value type: " + type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResValue factory(String value) {
|
public ResValue factory(String value) {
|
||||||
|
@ -47,10 +47,8 @@ public class ARSCDecoder {
|
|||||||
ARSCDecoder decoder = new ARSCDecoder(arscStream, resTable,
|
ARSCDecoder decoder = new ARSCDecoder(arscStream, resTable,
|
||||||
findFlagsOffsets, keepBroken);
|
findFlagsOffsets, keepBroken);
|
||||||
ResPackage[] pkgs = decoder.readTable();
|
ResPackage[] pkgs = decoder.readTable();
|
||||||
return new ARSCData(
|
return new ARSCData(pkgs, decoder.mFlagsOffsets == null ? null
|
||||||
pkgs,
|
: decoder.mFlagsOffsets.toArray(new FlagsOffset[0]),
|
||||||
decoder.mFlagsOffsets == null ? null :
|
|
||||||
decoder.mFlagsOffsets.toArray(new FlagsOffset[0]),
|
|
||||||
resTable);
|
resTable);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new AndrolibException("Could not decode arsc file", ex);
|
throw new AndrolibException("Could not decode arsc file", ex);
|
||||||
@ -94,10 +92,10 @@ public class ARSCDecoder {
|
|||||||
checkChunkType(Header.TYPE_PACKAGE);
|
checkChunkType(Header.TYPE_PACKAGE);
|
||||||
int id = (byte) mIn.readInt();
|
int id = (byte) mIn.readInt();
|
||||||
String name = mIn.readNulEndedString(128, true);
|
String name = mIn.readNulEndedString(128, true);
|
||||||
/*typeNameStrings*/ mIn.skipInt();
|
/* typeNameStrings */mIn.skipInt();
|
||||||
/*typeNameCount*/ mIn.skipInt();
|
/* typeNameCount */mIn.skipInt();
|
||||||
/*specNameStrings*/ mIn.skipInt();
|
/* specNameStrings */mIn.skipInt();
|
||||||
/*specNameCount*/ mIn.skipInt();
|
/* specNameCount */mIn.skipInt();
|
||||||
|
|
||||||
mTypeNames = StringBlock.read(mIn);
|
mTypeNames = StringBlock.read(mIn);
|
||||||
mSpecNames = StringBlock.read(mIn);
|
mSpecNames = StringBlock.read(mIn);
|
||||||
@ -125,7 +123,7 @@ public class ARSCDecoder {
|
|||||||
if (mFlagsOffsets != null) {
|
if (mFlagsOffsets != null) {
|
||||||
mFlagsOffsets.add(new FlagsOffset(mCountIn.getCount(), entryCount));
|
mFlagsOffsets.add(new FlagsOffset(mCountIn.getCount(), entryCount));
|
||||||
}
|
}
|
||||||
/*flags*/ mIn.skipBytes(entryCount * 4);
|
/* flags */mIn.skipBytes(entryCount * 4);
|
||||||
|
|
||||||
mResId = (0xff000000 & mResId) | id << 16;
|
mResId = (0xff000000 & mResId) | id << 16;
|
||||||
mType = new ResType(mTypeNames.getString(id - 1), mResTable, mPkg);
|
mType = new ResType(mTypeNames.getString(id - 1), mResTable, mPkg);
|
||||||
@ -142,9 +140,9 @@ public class ARSCDecoder {
|
|||||||
|
|
||||||
private ResConfig readConfig() throws IOException, AndrolibException {
|
private ResConfig readConfig() throws IOException, AndrolibException {
|
||||||
checkChunkType(Header.TYPE_CONFIG);
|
checkChunkType(Header.TYPE_CONFIG);
|
||||||
/*typeId*/ mIn.skipInt();
|
/* typeId */mIn.skipInt();
|
||||||
int entryCount = mIn.readInt();
|
int entryCount = mIn.readInt();
|
||||||
/*entriesStart*/ mIn.skipInt();
|
/* entriesStart */mIn.skipInt();
|
||||||
|
|
||||||
ResConfigFlags flags = readConfigFlags();
|
ResConfigFlags flags = readConfigFlags();
|
||||||
int[] entryOffsets = mIn.readIntArray(entryCount);
|
int[] entryOffsets = mIn.readIntArray(entryCount);
|
||||||
@ -152,16 +150,15 @@ public class ARSCDecoder {
|
|||||||
if (flags.isInvalid) {
|
if (flags.isInvalid) {
|
||||||
String resName = mType.getName() + flags.getQualifiers();
|
String resName = mType.getName() + flags.getQualifiers();
|
||||||
if (mKeepBroken) {
|
if (mKeepBroken) {
|
||||||
LOGGER.warning(
|
LOGGER.warning("Invalid config flags detected: " + resName);
|
||||||
"Invalid config flags detected: " + resName);
|
|
||||||
} else {
|
} else {
|
||||||
LOGGER.warning(
|
LOGGER.warning("Invalid config flags detected. Dropping resources: "
|
||||||
"Invalid config flags detected. Dropping resources: " + resName);
|
+ resName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mConfig = flags.isInvalid && ! mKeepBroken ?
|
mConfig = flags.isInvalid && !mKeepBroken ? null : mPkg
|
||||||
null : mPkg.getOrCreateConfig(flags);
|
.getOrCreateConfig(flags);
|
||||||
|
|
||||||
for (int i = 0; i < entryOffsets.length; i++) {
|
for (int i = 0; i < entryOffsets.length; i++) {
|
||||||
if (entryOffsets[i] != -1) {
|
if (entryOffsets[i] != -1) {
|
||||||
@ -175,12 +172,12 @@ public class ARSCDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void readEntry() throws IOException, AndrolibException {
|
private void readEntry() throws IOException, AndrolibException {
|
||||||
/*size*/ mIn.skipBytes(2);
|
/* size */mIn.skipBytes(2);
|
||||||
short flags = mIn.readShort();
|
short flags = mIn.readShort();
|
||||||
int specNamesId = mIn.readInt();
|
int specNamesId = mIn.readInt();
|
||||||
|
|
||||||
ResValue value = (flags & ENTRY_FLAG_COMPLEX) == 0 ?
|
ResValue value = (flags & ENTRY_FLAG_COMPLEX) == 0 ? readValue()
|
||||||
readValue() : readComplexEntry();
|
: readComplexEntry();
|
||||||
|
|
||||||
if (mConfig == null) {
|
if (mConfig == null) {
|
||||||
return;
|
return;
|
||||||
@ -191,8 +188,8 @@ public class ARSCDecoder {
|
|||||||
if (mPkg.hasResSpec(resId)) {
|
if (mPkg.hasResSpec(resId)) {
|
||||||
spec = mPkg.getResSpec(resId);
|
spec = mPkg.getResSpec(resId);
|
||||||
} else {
|
} else {
|
||||||
spec = new ResResSpec(
|
spec = new ResResSpec(resId, mSpecNames.getString(specNamesId),
|
||||||
resId, mSpecNames.getString(specNamesId), mPkg, mType);
|
mPkg, mType);
|
||||||
mPkg.addResSpec(spec);
|
mPkg.addResSpec(spec);
|
||||||
mType.addResSpec(spec);
|
mType.addResSpec(spec);
|
||||||
}
|
}
|
||||||
@ -211,25 +208,26 @@ public class ARSCDecoder {
|
|||||||
ResValueFactory factory = mPkg.getValueFactory();
|
ResValueFactory factory = mPkg.getValueFactory();
|
||||||
Duo<Integer, ResScalarValue>[] items = new Duo[count];
|
Duo<Integer, ResScalarValue>[] items = new Duo[count];
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
items[i] = new Duo<Integer, ResScalarValue>(
|
items[i] = new Duo<Integer, ResScalarValue>(mIn.readInt(),
|
||||||
mIn.readInt(), (ResScalarValue) readValue());
|
(ResScalarValue) readValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
return factory.bagFactory(parent, items);
|
return factory.bagFactory(parent, items);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResValue readValue() throws IOException, AndrolibException {
|
private ResValue readValue() throws IOException, AndrolibException {
|
||||||
/*size*/ mIn.skipCheckShort((short) 8);
|
/* size */mIn.skipCheckShort((short) 8);
|
||||||
/*zero*/ mIn.skipCheckByte((byte) 0);
|
/* zero */mIn.skipCheckByte((byte) 0);
|
||||||
byte type = mIn.readByte();
|
byte type = mIn.readByte();
|
||||||
int data = mIn.readInt();
|
int data = mIn.readInt();
|
||||||
|
|
||||||
return type == TypedValue.TYPE_STRING ?
|
return type == TypedValue.TYPE_STRING ? mPkg.getValueFactory().factory(
|
||||||
mPkg.getValueFactory().factory(mTableStrings.getHTML(data)) :
|
mTableStrings.getHTML(data)) : mPkg.getValueFactory().factory(
|
||||||
mPkg.getValueFactory().factory(type, data, null);
|
type, data, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResConfigFlags readConfigFlags() throws IOException, AndrolibException {
|
private ResConfigFlags readConfigFlags() throws IOException,
|
||||||
|
AndrolibException {
|
||||||
int size = mIn.readInt();
|
int size = mIn.readInt();
|
||||||
if (size < 28) {
|
if (size < 28) {
|
||||||
throw new AndrolibException("Config size < 28");
|
throw new AndrolibException("Config size < 28");
|
||||||
@ -240,10 +238,10 @@ public class ARSCDecoder {
|
|||||||
short mcc = mIn.readShort();
|
short mcc = mIn.readShort();
|
||||||
short mnc = mIn.readShort();
|
short mnc = mIn.readShort();
|
||||||
|
|
||||||
char[] language = new char[]{
|
char[] language = new char[] { (char) mIn.readByte(),
|
||||||
(char) mIn.readByte(), (char) mIn.readByte()};
|
(char) mIn.readByte() };
|
||||||
char[] country = new char[]{
|
char[] country = new char[] { (char) mIn.readByte(),
|
||||||
(char) mIn.readByte(), (char) mIn.readByte()};
|
(char) mIn.readByte() };
|
||||||
|
|
||||||
byte orientation = mIn.readByte();
|
byte orientation = mIn.readByte();
|
||||||
byte touchscreen = mIn.readByte();
|
byte touchscreen = mIn.readByte();
|
||||||
@ -252,13 +250,13 @@ public class ARSCDecoder {
|
|||||||
byte keyboard = mIn.readByte();
|
byte keyboard = mIn.readByte();
|
||||||
byte navigation = mIn.readByte();
|
byte navigation = mIn.readByte();
|
||||||
byte inputFlags = mIn.readByte();
|
byte inputFlags = mIn.readByte();
|
||||||
/*inputPad0*/ mIn.skipBytes(1);
|
/* inputPad0 */mIn.skipBytes(1);
|
||||||
|
|
||||||
short screenWidth = mIn.readShort();
|
short screenWidth = mIn.readShort();
|
||||||
short screenHeight = mIn.readShort();
|
short screenHeight = mIn.readShort();
|
||||||
|
|
||||||
short sdkVersion = mIn.readShort();
|
short sdkVersion = mIn.readShort();
|
||||||
/*minorVersion, now must always be 0*/ mIn.skipBytes(2);
|
/* minorVersion, now must always be 0 */mIn.skipBytes(2);
|
||||||
|
|
||||||
byte screenLayout = 0;
|
byte screenLayout = 0;
|
||||||
byte uiMode = 0;
|
byte uiMode = 0;
|
||||||
@ -278,7 +276,8 @@ public class ARSCDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
short layoutDirection = 0;
|
short layoutDirection = 0;
|
||||||
if (size >= 38 && sdkVersion >= 17 && !this.mPkg.getName().equalsIgnoreCase("com.htc")) {
|
if (size >= 38 && sdkVersion >= 17
|
||||||
|
&& !this.mPkg.getName().equalsIgnoreCase("com.htc")) {
|
||||||
layoutDirection = mIn.readShort();
|
layoutDirection = mIn.readShort();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,8 +288,8 @@ public class ARSCDecoder {
|
|||||||
BigInteger exceedingBI = new BigInteger(1, buf);
|
BigInteger exceedingBI = new BigInteger(1, buf);
|
||||||
|
|
||||||
if (exceedingBI.equals(BigInteger.ZERO)) {
|
if (exceedingBI.equals(BigInteger.ZERO)) {
|
||||||
LOGGER.fine(String.format(
|
LOGGER.fine(String
|
||||||
"Config flags size > %d, but exceeding bytes are all zero, so it should be ok.",
|
.format("Config flags size > %d, but exceeding bytes are all zero, so it should be ok.",
|
||||||
KNOWN_CONFIG_BYTES));
|
KNOWN_CONFIG_BYTES));
|
||||||
} else {
|
} else {
|
||||||
LOGGER.warning(String.format(
|
LOGGER.warning(String.format(
|
||||||
@ -300,17 +299,18 @@ public class ARSCDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ResConfigFlags(mcc, mnc, language, country, layoutDirection, orientation,
|
return new ResConfigFlags(mcc, mnc, language, country, layoutDirection,
|
||||||
touchscreen, density, keyboard, navigation, inputFlags,
|
orientation, touchscreen, density, keyboard, navigation,
|
||||||
screenWidth, screenHeight, sdkVersion, screenLayout, uiMode,
|
inputFlags, screenWidth, screenHeight, sdkVersion,
|
||||||
smallestScreenWidthDp, screenWidthDp, screenHeightDp, isInvalid);
|
screenLayout, uiMode, smallestScreenWidthDp, screenWidthDp,
|
||||||
|
screenHeightDp, isInvalid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addMissingResSpecs() throws AndrolibException {
|
private void addMissingResSpecs() throws AndrolibException {
|
||||||
int resId = mResId & 0xffff0000;
|
int resId = mResId & 0xffff0000;
|
||||||
|
|
||||||
for (int i = 0; i < mMissingResSpecs.length; i++) {
|
for (int i = 0; i < mMissingResSpecs.length; i++) {
|
||||||
if (! mMissingResSpecs[i]) {
|
if (!mMissingResSpecs[i]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,8 +340,8 @@ public class ARSCDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void nextChunkCheckType(int expectedType)
|
private void nextChunkCheckType(int expectedType) throws IOException,
|
||||||
throws IOException, AndrolibException {
|
AndrolibException {
|
||||||
nextChunk();
|
nextChunk();
|
||||||
checkChunkType(expectedType);
|
checkChunkType(expectedType);
|
||||||
}
|
}
|
||||||
@ -362,10 +362,8 @@ public class ARSCDecoder {
|
|||||||
private int mResId;
|
private int mResId;
|
||||||
private boolean[] mMissingResSpecs;
|
private boolean[] mMissingResSpecs;
|
||||||
|
|
||||||
|
|
||||||
private final static short ENTRY_FLAG_COMPLEX = 0x0001;
|
private final static short ENTRY_FLAG_COMPLEX = 0x0001;
|
||||||
|
|
||||||
|
|
||||||
public static class Header {
|
public static class Header {
|
||||||
public final short type;
|
public final short type;
|
||||||
public final int chunkSize;
|
public final int chunkSize;
|
||||||
@ -386,11 +384,8 @@ public class ARSCDecoder {
|
|||||||
return new Header(type, in.readInt());
|
return new Header(type, in.readInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
public final static short
|
public final static short TYPE_NONE = -1, TYPE_TABLE = 0x0002,
|
||||||
TYPE_NONE = -1,
|
TYPE_PACKAGE = 0x0200, TYPE_TYPE = 0x0202,
|
||||||
TYPE_TABLE = 0x0002,
|
|
||||||
TYPE_PACKAGE = 0x0200,
|
|
||||||
TYPE_TYPE = 0x0202,
|
|
||||||
TYPE_CONFIG = 0x0201;
|
TYPE_CONFIG = 0x0201;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,11 +399,10 @@ public class ARSCDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Logger LOGGER =
|
private static final Logger LOGGER = Logger.getLogger(ARSCDecoder.class
|
||||||
Logger.getLogger(ARSCDecoder.class.getName());
|
.getName());
|
||||||
private static final int KNOWN_CONFIG_BYTES = 36;
|
private static final int KNOWN_CONFIG_BYTES = 36;
|
||||||
|
|
||||||
|
|
||||||
public static class ARSCData {
|
public static class ARSCData {
|
||||||
|
|
||||||
public ARSCData(ResPackage[] packages, FlagsOffset[] flagsOffsets,
|
public ARSCData(ResPackage[] packages, FlagsOffset[] flagsOffsets,
|
||||||
|
@ -34,11 +34,11 @@ import org.xmlpull.v1.XmlPullParserException;
|
|||||||
*
|
*
|
||||||
* Binary xml files parser.
|
* Binary xml files parser.
|
||||||
*
|
*
|
||||||
* Parser has only two states: (1) Operational state, which parser obtains after
|
* Parser has only two states: (1) Operational state, which parser
|
||||||
* first successful call to next() and retains until open(), close(), or failed
|
* obtains after first successful call to next() and retains until
|
||||||
* call to next(). (2) Closed state, which parser obtains after open(), close(),
|
* open(), close(), or failed call to next(). (2) Closed state, which
|
||||||
* or failed call to next(). In this state methods return invalid values or
|
* parser obtains after open(), close(), or failed call to next(). In
|
||||||
* throw exceptions.
|
* this state methods return invalid values or throw exceptions.
|
||||||
*
|
*
|
||||||
* TODO: * check all methods in closed state
|
* TODO: * check all methods in closed state
|
||||||
*
|
*
|
||||||
@ -69,17 +69,17 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
public void open(InputStream stream) {
|
public void open(InputStream stream) {
|
||||||
close();
|
close();
|
||||||
if (stream != null) {
|
if (stream != null) {
|
||||||
m_reader = new ExtDataInput(
|
m_reader = new ExtDataInput(new LEDataInputStream(stream));
|
||||||
new LEDataInputStream(stream));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
if (!m_operational) {
|
if (!m_operational) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_operational = false;
|
m_operational = false;
|
||||||
// m_reader.close();
|
// m_reader.close();
|
||||||
m_reader = null;
|
m_reader = null;
|
||||||
m_strings = null;
|
m_strings = null;
|
||||||
m_resourceIDs = null;
|
m_resourceIDs = null;
|
||||||
@ -87,10 +87,12 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
resetEventInfo();
|
resetEventInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////// iteration
|
// ///////////////////////////////// iteration
|
||||||
|
@Override
|
||||||
public int next() throws XmlPullParserException, IOException {
|
public int next() throws XmlPullParserException, IOException {
|
||||||
if (m_reader == null) {
|
if (m_reader == null) {
|
||||||
throw new XmlPullParserException("Parser is not opened.", this, null);
|
throw new XmlPullParserException("Parser is not opened.", this,
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
doNext();
|
doNext();
|
||||||
@ -101,60 +103,77 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int nextToken() throws XmlPullParserException, IOException {
|
public int nextToken() throws XmlPullParserException, IOException {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int nextTag() throws XmlPullParserException, IOException {
|
public int nextTag() throws XmlPullParserException, IOException {
|
||||||
int eventType = next();
|
int eventType = next();
|
||||||
if (eventType == TEXT && isWhitespace()) {
|
if (eventType == TEXT && isWhitespace()) {
|
||||||
eventType = next();
|
eventType = next();
|
||||||
}
|
}
|
||||||
if (eventType != START_TAG && eventType != END_TAG) {
|
if (eventType != START_TAG && eventType != END_TAG) {
|
||||||
throw new XmlPullParserException("Expected start or end tag.", this, null);
|
throw new XmlPullParserException("Expected start or end tag.",
|
||||||
|
this, null);
|
||||||
}
|
}
|
||||||
return eventType;
|
return eventType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String nextText() throws XmlPullParserException, IOException {
|
public String nextText() throws XmlPullParserException, IOException {
|
||||||
if (getEventType() != START_TAG) {
|
if (getEventType() != START_TAG) {
|
||||||
throw new XmlPullParserException("Parser must be on START_TAG to read next text.", this, null);
|
throw new XmlPullParserException(
|
||||||
|
"Parser must be on START_TAG to read next text.", this,
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
int eventType = next();
|
int eventType = next();
|
||||||
if (eventType == TEXT) {
|
if (eventType == TEXT) {
|
||||||
String result = getText();
|
String result = getText();
|
||||||
eventType = next();
|
eventType = next();
|
||||||
if (eventType != END_TAG) {
|
if (eventType != END_TAG) {
|
||||||
throw new XmlPullParserException("Event TEXT must be immediately followed by END_TAG.", this, null);
|
throw new XmlPullParserException(
|
||||||
|
"Event TEXT must be immediately followed by END_TAG.",
|
||||||
|
this, null);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} else if (eventType == END_TAG) {
|
} else if (eventType == END_TAG) {
|
||||||
return "";
|
return "";
|
||||||
} else {
|
} else {
|
||||||
throw new XmlPullParserException("Parser must be on START_TAG or TEXT to read text.", this, null);
|
throw new XmlPullParserException(
|
||||||
|
"Parser must be on START_TAG or TEXT to read text.", this,
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void require(int type, String namespace, String name) throws XmlPullParserException, IOException {
|
@Override
|
||||||
|
public void require(int type, String namespace, String name)
|
||||||
|
throws XmlPullParserException, IOException {
|
||||||
if (type != getEventType()
|
if (type != getEventType()
|
||||||
|| (namespace != null && !namespace.equals(getNamespace()))
|
|| (namespace != null && !namespace.equals(getNamespace()))
|
||||||
|| (name != null && !name.equals(getName()))) {
|
|| (name != null && !name.equals(getName()))) {
|
||||||
throw new XmlPullParserException(TYPES[type] + " is expected.", this, null);
|
throw new XmlPullParserException(TYPES[type] + " is expected.",
|
||||||
|
this, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getDepth() {
|
public int getDepth() {
|
||||||
return m_namespaces.getDepth() - 1;
|
return m_namespaces.getDepth() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getEventType() throws XmlPullParserException {
|
public int getEventType() throws XmlPullParserException {
|
||||||
return m_event;
|
return m_event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getLineNumber() {
|
public int getLineNumber() {
|
||||||
return m_lineNumber;
|
return m_lineNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
if (m_name == -1 || (m_event != START_TAG && m_event != END_TAG)) {
|
if (m_name == -1 || (m_event != START_TAG && m_event != END_TAG)) {
|
||||||
return null;
|
return null;
|
||||||
@ -162,6 +181,7 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return m_strings.getString(m_name);
|
return m_strings.getString(m_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getText() {
|
public String getText() {
|
||||||
if (m_name == -1 || m_event != TEXT) {
|
if (m_name == -1 || m_event != TEXT) {
|
||||||
return null;
|
return null;
|
||||||
@ -169,6 +189,7 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return m_strings.getString(m_name);
|
return m_strings.getString(m_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public char[] getTextCharacters(int[] holderForStartAndLength) {
|
public char[] getTextCharacters(int[] holderForStartAndLength) {
|
||||||
String text = getText();
|
String text = getText();
|
||||||
if (text == null) {
|
if (text == null) {
|
||||||
@ -181,34 +202,41 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return chars;
|
return chars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getNamespace() {
|
public String getNamespace() {
|
||||||
return m_strings.getString(m_namespaceUri);
|
return m_strings.getString(m_namespaceUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getPrefix() {
|
public String getPrefix() {
|
||||||
int prefix = m_namespaces.findPrefix(m_namespaceUri);
|
int prefix = m_namespaces.findPrefix(m_namespaceUri);
|
||||||
return m_strings.getString(prefix);
|
return m_strings.getString(prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getPositionDescription() {
|
public String getPositionDescription() {
|
||||||
return "XML line #" + getLineNumber();
|
return "XML line #" + getLineNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getNamespaceCount(int depth) throws XmlPullParserException {
|
public int getNamespaceCount(int depth) throws XmlPullParserException {
|
||||||
return m_namespaces.getAccumulatedCount(depth);
|
return m_namespaces.getAccumulatedCount(depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getNamespacePrefix(int pos) throws XmlPullParserException {
|
public String getNamespacePrefix(int pos) throws XmlPullParserException {
|
||||||
int prefix = m_namespaces.getPrefix(pos);
|
int prefix = m_namespaces.getPrefix(pos);
|
||||||
return m_strings.getString(prefix);
|
return m_strings.getString(prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getNamespaceUri(int pos) throws XmlPullParserException {
|
public String getNamespaceUri(int pos) throws XmlPullParserException {
|
||||||
int uri = m_namespaces.getUri(pos);
|
int uri = m_namespaces.getUri(pos);
|
||||||
return m_strings.getString(uri);
|
return m_strings.getString(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////// attributes
|
// ///////////////////////////////// attributes
|
||||||
|
@Override
|
||||||
public String getClassAttribute() {
|
public String getClassAttribute() {
|
||||||
if (m_classAttribute == -1) {
|
if (m_classAttribute == -1) {
|
||||||
return null;
|
return null;
|
||||||
@ -218,6 +246,7 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return m_strings.getString(value);
|
return m_strings.getString(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getIdAttribute() {
|
public String getIdAttribute() {
|
||||||
if (m_idAttribute == -1) {
|
if (m_idAttribute == -1) {
|
||||||
return null;
|
return null;
|
||||||
@ -227,6 +256,7 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return m_strings.getString(value);
|
return m_strings.getString(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getIdAttributeResourceValue(int defaultValue) {
|
public int getIdAttributeResourceValue(int defaultValue) {
|
||||||
if (m_idAttribute == -1) {
|
if (m_idAttribute == -1) {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
@ -239,6 +269,7 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return m_attributes[offset + ATTRIBUTE_IX_VALUE_DATA];
|
return m_attributes[offset + ATTRIBUTE_IX_VALUE_DATA];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getStyleAttribute() {
|
public int getStyleAttribute() {
|
||||||
if (m_styleAttribute == -1) {
|
if (m_styleAttribute == -1) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -247,6 +278,7 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return m_attributes[offset + ATTRIBUTE_IX_VALUE_DATA];
|
return m_attributes[offset + ATTRIBUTE_IX_VALUE_DATA];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getAttributeCount() {
|
public int getAttributeCount() {
|
||||||
if (m_event != START_TAG) {
|
if (m_event != START_TAG) {
|
||||||
return -1;
|
return -1;
|
||||||
@ -254,6 +286,7 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return m_attributes.length / ATTRIBUTE_LENGHT;
|
return m_attributes.length / ATTRIBUTE_LENGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getAttributeNamespace(int index) {
|
public String getAttributeNamespace(int index) {
|
||||||
int offset = getAttributeOffset(index);
|
int offset = getAttributeOffset(index);
|
||||||
int namespace = m_attributes[offset + ATTRIBUTE_IX_NAMESPACE_URI];
|
int namespace = m_attributes[offset + ATTRIBUTE_IX_NAMESPACE_URI];
|
||||||
@ -263,6 +296,7 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return m_strings.getString(namespace);
|
return m_strings.getString(namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getAttributePrefix(int index) {
|
public String getAttributePrefix(int index) {
|
||||||
int offset = getAttributeOffset(index);
|
int offset = getAttributeOffset(index);
|
||||||
int uri = m_attributes[offset + ATTRIBUTE_IX_NAMESPACE_URI];
|
int uri = m_attributes[offset + ATTRIBUTE_IX_NAMESPACE_URI];
|
||||||
@ -273,6 +307,7 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return m_strings.getString(prefix);
|
return m_strings.getString(prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getAttributeName(int index) {
|
public String getAttributeName(int index) {
|
||||||
int offset = getAttributeOffset(index);
|
int offset = getAttributeOffset(index);
|
||||||
int name = m_attributes[offset + ATTRIBUTE_IX_NAME];
|
int name = m_attributes[offset + ATTRIBUTE_IX_NAME];
|
||||||
@ -282,26 +317,29 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return m_strings.getString(name);
|
return m_strings.getString(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getAttributeNameResource(int index) {
|
public int getAttributeNameResource(int index) {
|
||||||
int offset = getAttributeOffset(index);
|
int offset = getAttributeOffset(index);
|
||||||
int name = m_attributes[offset + ATTRIBUTE_IX_NAME];
|
int name = m_attributes[offset + ATTRIBUTE_IX_NAME];
|
||||||
if (m_resourceIDs == null
|
if (m_resourceIDs == null || name < 0 || name >= m_resourceIDs.length) {
|
||||||
|| name < 0 || name >= m_resourceIDs.length) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return m_resourceIDs[name];
|
return m_resourceIDs[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getAttributeValueType(int index) {
|
public int getAttributeValueType(int index) {
|
||||||
int offset = getAttributeOffset(index);
|
int offset = getAttributeOffset(index);
|
||||||
return m_attributes[offset + ATTRIBUTE_IX_VALUE_TYPE];
|
return m_attributes[offset + ATTRIBUTE_IX_VALUE_TYPE];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getAttributeValueData(int index) {
|
public int getAttributeValueData(int index) {
|
||||||
int offset = getAttributeOffset(index);
|
int offset = getAttributeOffset(index);
|
||||||
return m_attributes[offset + ATTRIBUTE_IX_VALUE_DATA];
|
return m_attributes[offset + ATTRIBUTE_IX_VALUE_DATA];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getAttributeValue(int index) {
|
public String getAttributeValue(int index) {
|
||||||
int offset = getAttributeOffset(index);
|
int offset = getAttributeOffset(index);
|
||||||
int valueType = m_attributes[offset + ATTRIBUTE_IX_VALUE_TYPE];
|
int valueType = m_attributes[offset + ATTRIBUTE_IX_VALUE_TYPE];
|
||||||
@ -310,9 +348,11 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
|
|
||||||
if (mAttrDecoder != null) {
|
if (mAttrDecoder != null) {
|
||||||
try {
|
try {
|
||||||
return mAttrDecoder.decode(valueType, valueData,
|
return mAttrDecoder.decode(
|
||||||
valueRaw == -1 ? null : ResXmlEncoders.escapeXmlChars(
|
valueType,
|
||||||
m_strings.getString(valueRaw)),
|
valueData,
|
||||||
|
valueRaw == -1 ? null : ResXmlEncoders
|
||||||
|
.escapeXmlChars(m_strings.getString(valueRaw)),
|
||||||
getAttributeNameResource(index));
|
getAttributeNameResource(index));
|
||||||
} catch (AndrolibException ex) {
|
} catch (AndrolibException ex) {
|
||||||
setFirstError(ex);
|
setFirstError(ex);
|
||||||
@ -324,17 +364,20 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (valueType == TypedValue.TYPE_STRING) {
|
if (valueType == TypedValue.TYPE_STRING) {
|
||||||
return ResXmlEncoders.escapeXmlChars(m_strings.getString(valueRaw));
|
return ResXmlEncoders.escapeXmlChars(m_strings
|
||||||
|
.getString(valueRaw));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return TypedValue.coerceToString(valueType, valueData);
|
return TypedValue.coerceToString(valueType, valueData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean getAttributeBooleanValue(int index, boolean defaultValue) {
|
public boolean getAttributeBooleanValue(int index, boolean defaultValue) {
|
||||||
return getAttributeIntValue(index, defaultValue ? 1 : 0) != 0;
|
return getAttributeIntValue(index, defaultValue ? 1 : 0) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public float getAttributeFloatValue(int index, float defaultValue) {
|
public float getAttributeFloatValue(int index, float defaultValue) {
|
||||||
int offset = getAttributeOffset(index);
|
int offset = getAttributeOffset(index);
|
||||||
int valueType = m_attributes[offset + ATTRIBUTE_IX_VALUE_TYPE];
|
int valueType = m_attributes[offset + ATTRIBUTE_IX_VALUE_TYPE];
|
||||||
@ -345,6 +388,7 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getAttributeIntValue(int index, int defaultValue) {
|
public int getAttributeIntValue(int index, int defaultValue) {
|
||||||
int offset = getAttributeOffset(index);
|
int offset = getAttributeOffset(index);
|
||||||
int valueType = m_attributes[offset + ATTRIBUTE_IX_VALUE_TYPE];
|
int valueType = m_attributes[offset + ATTRIBUTE_IX_VALUE_TYPE];
|
||||||
@ -355,10 +399,12 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getAttributeUnsignedIntValue(int index, int defaultValue) {
|
public int getAttributeUnsignedIntValue(int index, int defaultValue) {
|
||||||
return getAttributeIntValue(index, defaultValue);
|
return getAttributeIntValue(index, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getAttributeResourceValue(int index, int defaultValue) {
|
public int getAttributeResourceValue(int index, int defaultValue) {
|
||||||
int offset = getAttributeOffset(index);
|
int offset = getAttributeOffset(index);
|
||||||
int valueType = m_attributes[offset + ATTRIBUTE_IX_VALUE_TYPE];
|
int valueType = m_attributes[offset + ATTRIBUTE_IX_VALUE_TYPE];
|
||||||
@ -368,6 +414,7 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getAttributeValue(String namespace, String attribute) {
|
public String getAttributeValue(String namespace, String attribute) {
|
||||||
int index = findAttribute(namespace, attribute);
|
int index = findAttribute(namespace, attribute);
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
@ -376,7 +423,9 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return getAttributeValue(index);
|
return getAttributeValue(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getAttributeBooleanValue(String namespace, String attribute, boolean defaultValue) {
|
@Override
|
||||||
|
public boolean getAttributeBooleanValue(String namespace, String attribute,
|
||||||
|
boolean defaultValue) {
|
||||||
int index = findAttribute(namespace, attribute);
|
int index = findAttribute(namespace, attribute);
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
@ -384,7 +433,9 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return getAttributeBooleanValue(index, defaultValue);
|
return getAttributeBooleanValue(index, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getAttributeFloatValue(String namespace, String attribute, float defaultValue) {
|
@Override
|
||||||
|
public float getAttributeFloatValue(String namespace, String attribute,
|
||||||
|
float defaultValue) {
|
||||||
int index = findAttribute(namespace, attribute);
|
int index = findAttribute(namespace, attribute);
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
@ -392,7 +443,9 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return getAttributeFloatValue(index, defaultValue);
|
return getAttributeFloatValue(index, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getAttributeIntValue(String namespace, String attribute, int defaultValue) {
|
@Override
|
||||||
|
public int getAttributeIntValue(String namespace, String attribute,
|
||||||
|
int defaultValue) {
|
||||||
int index = findAttribute(namespace, attribute);
|
int index = findAttribute(namespace, attribute);
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
@ -400,7 +453,9 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return getAttributeIntValue(index, defaultValue);
|
return getAttributeIntValue(index, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getAttributeUnsignedIntValue(String namespace, String attribute, int defaultValue) {
|
@Override
|
||||||
|
public int getAttributeUnsignedIntValue(String namespace, String attribute,
|
||||||
|
int defaultValue) {
|
||||||
int index = findAttribute(namespace, attribute);
|
int index = findAttribute(namespace, attribute);
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
@ -408,7 +463,9 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return getAttributeUnsignedIntValue(index, defaultValue);
|
return getAttributeUnsignedIntValue(index, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getAttributeResourceValue(String namespace, String attribute, int defaultValue) {
|
@Override
|
||||||
|
public int getAttributeResourceValue(String namespace, String attribute,
|
||||||
|
int defaultValue) {
|
||||||
int index = findAttribute(namespace, attribute);
|
int index = findAttribute(namespace, attribute);
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
@ -416,74 +473,96 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
return getAttributeResourceValue(index, defaultValue);
|
return getAttributeResourceValue(index, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getAttributeListValue(int index, String[] options, int defaultValue) {
|
@Override
|
||||||
|
public int getAttributeListValue(int index, String[] options,
|
||||||
|
int defaultValue) {
|
||||||
// TODO implement
|
// TODO implement
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getAttributeListValue(String namespace, String attribute, String[] options, int defaultValue) {
|
@Override
|
||||||
|
public int getAttributeListValue(String namespace, String attribute,
|
||||||
|
String[] options, int defaultValue) {
|
||||||
// TODO implement
|
// TODO implement
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getAttributeType(int index) {
|
public String getAttributeType(int index) {
|
||||||
return "CDATA";
|
return "CDATA";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isAttributeDefault(int index) {
|
public boolean isAttributeDefault(int index) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////// dummies
|
// ///////////////////////////////// dummies
|
||||||
public void setInput(InputStream stream, String inputEncoding) throws XmlPullParserException {
|
@Override
|
||||||
|
public void setInput(InputStream stream, String inputEncoding)
|
||||||
|
throws XmlPullParserException {
|
||||||
open(stream);
|
open(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setInput(Reader reader) throws XmlPullParserException {
|
public void setInput(Reader reader) throws XmlPullParserException {
|
||||||
throw new XmlPullParserException(E_NOT_SUPPORTED);
|
throw new XmlPullParserException(E_NOT_SUPPORTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getInputEncoding() {
|
public String getInputEncoding() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getColumnNumber() {
|
public int getColumnNumber() {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isEmptyElementTag() throws XmlPullParserException {
|
public boolean isEmptyElementTag() throws XmlPullParserException {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isWhitespace() throws XmlPullParserException {
|
public boolean isWhitespace() throws XmlPullParserException {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void defineEntityReplacementText(String entityName, String replacementText) throws XmlPullParserException {
|
@Override
|
||||||
|
public void defineEntityReplacementText(String entityName,
|
||||||
|
String replacementText) throws XmlPullParserException {
|
||||||
throw new XmlPullParserException(E_NOT_SUPPORTED);
|
throw new XmlPullParserException(E_NOT_SUPPORTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getNamespace(String prefix) {
|
public String getNamespace(String prefix) {
|
||||||
throw new RuntimeException(E_NOT_SUPPORTED);
|
throw new RuntimeException(E_NOT_SUPPORTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Object getProperty(String name) {
|
public Object getProperty(String name) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setProperty(String name, Object value) throws XmlPullParserException {
|
@Override
|
||||||
|
public void setProperty(String name, Object value)
|
||||||
|
throws XmlPullParserException {
|
||||||
throw new XmlPullParserException(E_NOT_SUPPORTED);
|
throw new XmlPullParserException(E_NOT_SUPPORTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean getFeature(String feature) {
|
public boolean getFeature(String feature) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFeature(String name, boolean value) throws XmlPullParserException {
|
@Override
|
||||||
|
public void setFeature(String name, boolean value)
|
||||||
|
throws XmlPullParserException {
|
||||||
throw new XmlPullParserException(E_NOT_SUPPORTED);
|
throw new XmlPullParserException(E_NOT_SUPPORTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////// implementation
|
// /////////////////////////////////////////// implementation
|
||||||
/**
|
/**
|
||||||
* Namespace stack, holds prefix+uri pairs, as well as depth information.
|
* Namespace stack, holds prefix+uri pairs, as well as depth information.
|
||||||
* All information is stored in one int[] array. Array consists of depth
|
* All information is stored in one int[] array. Array consists of depth
|
||||||
@ -574,10 +653,7 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
m_data[offset] = count;
|
m_data[offset] = count;
|
||||||
offset -= (1 + 2 + count * 2);
|
offset -= (1 + 2 + count * 2);
|
||||||
m_data[offset] = count;
|
m_data[offset] = count;
|
||||||
System.arraycopy(
|
System.arraycopy(m_data, o + 2, m_data, o, m_dataLength - o);
|
||||||
m_data, o + 2,
|
|
||||||
m_data, o,
|
|
||||||
m_dataLength - o);
|
|
||||||
}
|
}
|
||||||
m_dataLength -= 2;
|
m_dataLength -= 2;
|
||||||
m_count -= 1;
|
m_count -= 1;
|
||||||
@ -703,58 +779,61 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int[] m_data;
|
private int[] m_data;
|
||||||
private int m_dataLength;
|
private int m_dataLength;
|
||||||
private int m_count;
|
private int m_count;
|
||||||
private int m_depth;
|
private int m_depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////// package-visible
|
// ///////////////////////////////// package-visible
|
||||||
// final void fetchAttributes(int[] styleableIDs,TypedArray result) {
|
// final void fetchAttributes(int[] styleableIDs,TypedArray result) {
|
||||||
// result.resetIndices();
|
// result.resetIndices();
|
||||||
// if (m_attributes==null || m_resourceIDs==null) {
|
// if (m_attributes==null || m_resourceIDs==null) {
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
// boolean needStrings=false;
|
// boolean needStrings=false;
|
||||||
// for (int i=0,e=styleableIDs.length;i!=e;++i) {
|
// for (int i=0,e=styleableIDs.length;i!=e;++i) {
|
||||||
// int id=styleableIDs[i];
|
// int id=styleableIDs[i];
|
||||||
// for (int o=0;o!=m_attributes.length;o+=ATTRIBUTE_LENGHT) {
|
// for (int o=0;o!=m_attributes.length;o+=ATTRIBUTE_LENGHT) {
|
||||||
// int name=m_attributes[o+ATTRIBUTE_IX_NAME];
|
// int name=m_attributes[o+ATTRIBUTE_IX_NAME];
|
||||||
// if (name>=m_resourceIDs.length ||
|
// if (name>=m_resourceIDs.length ||
|
||||||
// m_resourceIDs[name]!=id)
|
// m_resourceIDs[name]!=id)
|
||||||
// {
|
// {
|
||||||
// continue;
|
// continue;
|
||||||
// }
|
// }
|
||||||
// int valueType=m_attributes[o+ATTRIBUTE_IX_VALUE_TYPE];
|
// int valueType=m_attributes[o+ATTRIBUTE_IX_VALUE_TYPE];
|
||||||
// int valueData;
|
// int valueData;
|
||||||
// int assetCookie;
|
// int assetCookie;
|
||||||
// if (valueType==TypedValue.TYPE_STRING) {
|
// if (valueType==TypedValue.TYPE_STRING) {
|
||||||
// valueData=m_attributes[o+ATTRIBUTE_IX_VALUE_STRING];
|
// valueData=m_attributes[o+ATTRIBUTE_IX_VALUE_STRING];
|
||||||
// assetCookie=-1;
|
// assetCookie=-1;
|
||||||
// needStrings=true;
|
// needStrings=true;
|
||||||
// } else {
|
// } else {
|
||||||
// valueData=m_attributes[o+ATTRIBUTE_IX_VALUE_DATA];
|
// valueData=m_attributes[o+ATTRIBUTE_IX_VALUE_DATA];
|
||||||
// assetCookie=0;
|
// assetCookie=0;
|
||||||
// }
|
// }
|
||||||
// result.addValue(i,valueType,valueData,assetCookie,id,0);
|
// result.addValue(i,valueType,valueData,assetCookie,id,0);
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// if (needStrings) {
|
// if (needStrings) {
|
||||||
// result.setStrings(m_strings);
|
// result.setStrings(m_strings);
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
final StringBlock getStrings() {
|
final StringBlock getStrings() {
|
||||||
return m_strings;
|
return m_strings;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////
|
// /////////////////////////////////
|
||||||
private final int getAttributeOffset(int index) {
|
private final int getAttributeOffset(int index) {
|
||||||
if (m_event != START_TAG) {
|
if (m_event != START_TAG) {
|
||||||
throw new IndexOutOfBoundsException("Current event is not START_TAG.");
|
throw new IndexOutOfBoundsException(
|
||||||
|
"Current event is not START_TAG.");
|
||||||
}
|
}
|
||||||
int offset = index * ATTRIBUTE_LENGHT;
|
int offset = index * ATTRIBUTE_LENGHT;
|
||||||
if (offset >= m_attributes.length) {
|
if (offset >= m_attributes.length) {
|
||||||
throw new IndexOutOfBoundsException("Invalid attribute index (" + index + ").");
|
throw new IndexOutOfBoundsException("Invalid attribute index ("
|
||||||
|
+ index + ").");
|
||||||
}
|
}
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
@ -767,12 +846,11 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
if (name == -1) {
|
if (name == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int uri = (namespace != null)
|
int uri = (namespace != null) ? m_strings.find(namespace) : -1;
|
||||||
? m_strings.find(namespace)
|
for (int o = 0; o != m_attributes.length; o += ATTRIBUTE_LENGHT) {
|
||||||
: -1;
|
|
||||||
for (int o = 0; o != m_attributes.length; o+=ATTRIBUTE_LENGHT) {
|
|
||||||
if (name == m_attributes[o + ATTRIBUTE_IX_NAME]
|
if (name == m_attributes[o + ATTRIBUTE_IX_NAME]
|
||||||
&& (uri == -1 || uri == m_attributes[o + ATTRIBUTE_IX_NAMESPACE_URI])) {
|
&& (uri == -1 || uri == m_attributes[o
|
||||||
|
+ ATTRIBUTE_IX_NAMESPACE_URI])) {
|
||||||
return o / ATTRIBUTE_LENGHT;
|
return o / ATTRIBUTE_LENGHT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -796,7 +874,7 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
m_reader.skipCheckInt(CHUNK_AXML_FILE);
|
m_reader.skipCheckInt(CHUNK_AXML_FILE);
|
||||||
/*
|
/*
|
||||||
* chunkSize
|
* chunkSize
|
||||||
*/ m_reader.skipInt();
|
*/m_reader.skipInt();
|
||||||
m_strings = StringBlock.read(m_reader);
|
m_strings = StringBlock.read(m_reader);
|
||||||
m_namespaces.increaseDepth();
|
m_namespaces.increaseDepth();
|
||||||
m_operational = true;
|
m_operational = true;
|
||||||
@ -816,8 +894,7 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fake END_DOCUMENT event.
|
// Fake END_DOCUMENT event.
|
||||||
if (event == END_TAG
|
if (event == END_TAG && m_namespaces.getDepth() == 1
|
||||||
&& m_namespaces.getDepth() == 1
|
|
||||||
&& m_namespaces.getCurrentCount() == 0) {
|
&& m_namespaces.getCurrentCount() == 0) {
|
||||||
m_event = END_DOCUMENT;
|
m_event = END_DOCUMENT;
|
||||||
break;
|
break;
|
||||||
@ -834,7 +911,8 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
if (chunkType == CHUNK_RESOURCEIDS) {
|
if (chunkType == CHUNK_RESOURCEIDS) {
|
||||||
int chunkSize = m_reader.readInt();
|
int chunkSize = m_reader.readInt();
|
||||||
if (chunkSize < 8 || (chunkSize % 4) != 0) {
|
if (chunkSize < 8 || (chunkSize % 4) != 0) {
|
||||||
throw new IOException("Invalid resource ids size (" + chunkSize + ").");
|
throw new IOException("Invalid resource ids size ("
|
||||||
|
+ chunkSize + ").");
|
||||||
}
|
}
|
||||||
m_resourceIDs = m_reader.readIntArray(chunkSize / 4 - 2);
|
m_resourceIDs = m_reader.readIntArray(chunkSize / 4 - 2);
|
||||||
continue;
|
continue;
|
||||||
@ -851,9 +929,9 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Common header.
|
// Common header.
|
||||||
/*chunkSize*/ m_reader.skipInt();
|
/* chunkSize */m_reader.skipInt();
|
||||||
int lineNumber = m_reader.readInt();
|
int lineNumber = m_reader.readInt();
|
||||||
/*0xFFFFFFFF*/ m_reader.skipInt();
|
/* 0xFFFFFFFF */m_reader.skipInt();
|
||||||
|
|
||||||
if (chunkType == CHUNK_XML_START_NAMESPACE
|
if (chunkType == CHUNK_XML_START_NAMESPACE
|
||||||
|| chunkType == CHUNK_XML_END_NAMESPACE) {
|
|| chunkType == CHUNK_XML_END_NAMESPACE) {
|
||||||
@ -862,8 +940,8 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
int uri = m_reader.readInt();
|
int uri = m_reader.readInt();
|
||||||
m_namespaces.push(prefix, uri);
|
m_namespaces.push(prefix, uri);
|
||||||
} else {
|
} else {
|
||||||
/*prefix*/ m_reader.skipInt();
|
/* prefix */m_reader.skipInt();
|
||||||
/*uri*/ m_reader.skipInt();
|
/* uri */m_reader.skipInt();
|
||||||
m_namespaces.pop();
|
m_namespaces.pop();
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@ -874,14 +952,15 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
if (chunkType == CHUNK_XML_START_TAG) {
|
if (chunkType == CHUNK_XML_START_TAG) {
|
||||||
m_namespaceUri = m_reader.readInt();
|
m_namespaceUri = m_reader.readInt();
|
||||||
m_name = m_reader.readInt();
|
m_name = m_reader.readInt();
|
||||||
/*flags?*/ m_reader.skipInt();
|
/* flags? */m_reader.skipInt();
|
||||||
int attributeCount = m_reader.readInt();
|
int attributeCount = m_reader.readInt();
|
||||||
m_idAttribute = (attributeCount >>> 16) - 1;
|
m_idAttribute = (attributeCount >>> 16) - 1;
|
||||||
attributeCount &= 0xFFFF;
|
attributeCount &= 0xFFFF;
|
||||||
m_classAttribute = m_reader.readInt();
|
m_classAttribute = m_reader.readInt();
|
||||||
m_styleAttribute = (m_classAttribute >>> 16) - 1;
|
m_styleAttribute = (m_classAttribute >>> 16) - 1;
|
||||||
m_classAttribute = (m_classAttribute & 0xFFFF) - 1;
|
m_classAttribute = (m_classAttribute & 0xFFFF) - 1;
|
||||||
m_attributes = m_reader.readIntArray(attributeCount * ATTRIBUTE_LENGHT);
|
m_attributes = m_reader.readIntArray(attributeCount
|
||||||
|
* ATTRIBUTE_LENGHT);
|
||||||
for (int i = ATTRIBUTE_IX_VALUE_TYPE; i < m_attributes.length;) {
|
for (int i = ATTRIBUTE_IX_VALUE_TYPE; i < m_attributes.length;) {
|
||||||
m_attributes[i] = (m_attributes[i] >>> 24);
|
m_attributes[i] = (m_attributes[i] >>> 24);
|
||||||
i += ATTRIBUTE_LENGHT;
|
i += ATTRIBUTE_LENGHT;
|
||||||
@ -901,8 +980,8 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
|
|
||||||
if (chunkType == CHUNK_XML_TEXT) {
|
if (chunkType == CHUNK_XML_TEXT) {
|
||||||
m_name = m_reader.readInt();
|
m_name = m_reader.readInt();
|
||||||
/*?*/ m_reader.skipInt();
|
/* ? */m_reader.skipInt();
|
||||||
/*?*/ m_reader.skipInt();
|
/* ? */m_reader.skipInt();
|
||||||
m_event = TEXT;
|
m_event = TEXT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -932,44 +1011,49 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean compareAttr(int[] attr1, int[] attr2) {
|
private boolean compareAttr(int[] attr1, int[] attr2) {
|
||||||
//TODO: sort Attrs
|
// TODO: sort Attrs
|
||||||
/*
|
/*
|
||||||
* ATTRIBUTE_IX_VALUE_TYPE == TYPE_STRING : ATTRIBUTE_IX_VALUE_STRING :
|
* ATTRIBUTE_IX_VALUE_TYPE == TYPE_STRING : ATTRIBUTE_IX_VALUE_STRING :
|
||||||
* ATTRIBUTE_IX_NAMESPACE_URI ATTRIBUTE_IX_NAMESPACE_URI :
|
* ATTRIBUTE_IX_NAMESPACE_URI ATTRIBUTE_IX_NAMESPACE_URI :
|
||||||
* ATTRIBUTE_IX_NAME id
|
* ATTRIBUTE_IX_NAME id
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
if (attr1[ATTRIBUTE_IX_VALUE_TYPE] == TypedValue.TYPE_STRING
|
if (attr1[ATTRIBUTE_IX_VALUE_TYPE] == TypedValue.TYPE_STRING
|
||||||
&& attr1[ATTRIBUTE_IX_VALUE_TYPE] == attr2[ATTRIBUTE_IX_VALUE_TYPE]
|
&& attr1[ATTRIBUTE_IX_VALUE_TYPE] == attr2[ATTRIBUTE_IX_VALUE_TYPE]
|
||||||
&& //(m_strings.touch(attr1[ATTRIBUTE_IX_VALUE_STRING], m_name) ||
|
&& // (m_strings.touch(attr1[ATTRIBUTE_IX_VALUE_STRING], m_name)
|
||||||
// m_strings.touch(attr2[ATTRIBUTE_IX_VALUE_STRING], m_name)) &&
|
// ||
|
||||||
//m_strings.touch(attr1[ATTRIBUTE_IX_VALUE_STRING], m_name) &&
|
// m_strings.touch(attr2[ATTRIBUTE_IX_VALUE_STRING],
|
||||||
|
// m_name)) &&
|
||||||
|
// m_strings.touch(attr1[ATTRIBUTE_IX_VALUE_STRING], m_name)
|
||||||
|
// &&
|
||||||
attr1[ATTRIBUTE_IX_VALUE_STRING] != attr2[ATTRIBUTE_IX_VALUE_STRING]) {
|
attr1[ATTRIBUTE_IX_VALUE_STRING] != attr2[ATTRIBUTE_IX_VALUE_STRING]) {
|
||||||
return (attr1[ATTRIBUTE_IX_VALUE_STRING] < attr2[ATTRIBUTE_IX_VALUE_STRING]);
|
return (attr1[ATTRIBUTE_IX_VALUE_STRING] < attr2[ATTRIBUTE_IX_VALUE_STRING]);
|
||||||
} else if ((attr1[ATTRIBUTE_IX_NAMESPACE_URI] == attr2[ATTRIBUTE_IX_NAMESPACE_URI]) && (attr1[ATTRIBUTE_IX_NAMESPACE_URI] != -1)
|
} else if ((attr1[ATTRIBUTE_IX_NAMESPACE_URI] == attr2[ATTRIBUTE_IX_NAMESPACE_URI])
|
||||||
&& //(m_strings.touch(attr1[ATTRIBUTE_IX_NAME], m_name) ||
|
&& (attr1[ATTRIBUTE_IX_NAMESPACE_URI] != -1) && // (m_strings.touch(attr1[ATTRIBUTE_IX_NAME],
|
||||||
// m_strings.touch(attr2[ATTRIBUTE_IX_NAME], m_name)) &&
|
// m_name) ||
|
||||||
//m_strings.touch(attr1[ATTRIBUTE_IX_NAME], m_name) &&
|
// m_strings.touch(attr2[ATTRIBUTE_IX_NAME],
|
||||||
|
// m_name)) &&
|
||||||
|
// m_strings.touch(attr1[ATTRIBUTE_IX_NAME],
|
||||||
|
// m_name) &&
|
||||||
(attr1[ATTRIBUTE_IX_NAME] != attr2[ATTRIBUTE_IX_NAME])) {
|
(attr1[ATTRIBUTE_IX_NAME] != attr2[ATTRIBUTE_IX_NAME])) {
|
||||||
return (attr1[ATTRIBUTE_IX_NAME] < attr2[ATTRIBUTE_IX_NAME]);
|
return (attr1[ATTRIBUTE_IX_NAME] < attr2[ATTRIBUTE_IX_NAME]);
|
||||||
//} else if (attr1[ATTRIBUTE_IX_NAMESPACE_URI] < attr2[ATTRIBUTE_IX_NAMESPACE_URI]) {
|
// } else if (attr1[ATTRIBUTE_IX_NAMESPACE_URI] <
|
||||||
|
// attr2[ATTRIBUTE_IX_NAMESPACE_URI]) {
|
||||||
// return true;
|
// return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void setFirstError(AndrolibException error) {
|
private void setFirstError(AndrolibException error) {
|
||||||
if (mFirstError == null) {
|
if (mFirstError == null) {
|
||||||
mFirstError = error;
|
mFirstError = error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////// data
|
// ///////////////////////////////// data
|
||||||
/*
|
/*
|
||||||
* All values are essentially indices, e.g. m_name is
|
* All values are essentially indices, e.g. m_name is an index of name in
|
||||||
* an index of name in m_strings.
|
* m_strings.
|
||||||
*/
|
*/
|
||||||
private ExtDataInput m_reader;
|
private ExtDataInput m_reader;
|
||||||
private ResAttrDecoder mAttrDecoder;
|
private ResAttrDecoder mAttrDecoder;
|
||||||
@ -989,25 +1073,18 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
private int m_classAttribute;
|
private int m_classAttribute;
|
||||||
private int m_styleAttribute;
|
private int m_styleAttribute;
|
||||||
|
|
||||||
private final static Logger LOGGER =
|
private final static Logger LOGGER = Logger
|
||||||
Logger.getLogger(AXmlResourceParser.class.getName());
|
.getLogger(AXmlResourceParser.class.getName());
|
||||||
private static final String E_NOT_SUPPORTED = "Method is not supported.";
|
private static final String E_NOT_SUPPORTED = "Method is not supported.";
|
||||||
private static final int
|
private static final int ATTRIBUTE_IX_NAMESPACE_URI = 0,
|
||||||
ATTRIBUTE_IX_NAMESPACE_URI = 0,
|
ATTRIBUTE_IX_NAME = 1, ATTRIBUTE_IX_VALUE_STRING = 2,
|
||||||
ATTRIBUTE_IX_NAME = 1,
|
ATTRIBUTE_IX_VALUE_TYPE = 3, ATTRIBUTE_IX_VALUE_DATA = 4,
|
||||||
ATTRIBUTE_IX_VALUE_STRING = 2,
|
|
||||||
ATTRIBUTE_IX_VALUE_TYPE = 3,
|
|
||||||
ATTRIBUTE_IX_VALUE_DATA = 4,
|
|
||||||
ATTRIBUTE_LENGHT = 5;
|
ATTRIBUTE_LENGHT = 5;
|
||||||
|
|
||||||
private static final int
|
private static final int CHUNK_AXML_FILE = 0x00080003,
|
||||||
CHUNK_AXML_FILE = 0x00080003,
|
CHUNK_RESOURCEIDS = 0x00080180, CHUNK_XML_FIRST = 0x00100100,
|
||||||
CHUNK_RESOURCEIDS = 0x00080180,
|
|
||||||
CHUNK_XML_FIRST = 0x00100100,
|
|
||||||
CHUNK_XML_START_NAMESPACE = 0x00100100,
|
CHUNK_XML_START_NAMESPACE = 0x00100100,
|
||||||
CHUNK_XML_END_NAMESPACE = 0x00100101,
|
CHUNK_XML_END_NAMESPACE = 0x00100101,
|
||||||
CHUNK_XML_START_TAG = 0x00100102,
|
CHUNK_XML_START_TAG = 0x00100102, CHUNK_XML_END_TAG = 0x00100103,
|
||||||
CHUNK_XML_END_TAG = 0x00100103,
|
CHUNK_XML_TEXT = 0x00100104, CHUNK_XML_LAST = 0x00100104;
|
||||||
CHUNK_XML_TEXT = 0x00100104,
|
|
||||||
CHUNK_XML_LAST = 0x00100104;
|
|
||||||
}
|
}
|
@ -28,6 +28,7 @@ import org.apache.commons.io.IOUtils;
|
|||||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||||
*/
|
*/
|
||||||
public class Res9patchStreamDecoder implements ResStreamDecoder {
|
public class Res9patchStreamDecoder implements ResStreamDecoder {
|
||||||
|
@Override
|
||||||
public void decode(InputStream in, OutputStream out)
|
public void decode(InputStream in, OutputStream out)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
try {
|
try {
|
||||||
@ -36,8 +37,8 @@ public class Res9patchStreamDecoder implements ResStreamDecoder {
|
|||||||
BufferedImage im = ImageIO.read(new ByteArrayInputStream(data));
|
BufferedImage im = ImageIO.read(new ByteArrayInputStream(data));
|
||||||
int w = im.getWidth(), h = im.getHeight();
|
int w = im.getWidth(), h = im.getHeight();
|
||||||
|
|
||||||
BufferedImage im2 = new BufferedImage(
|
BufferedImage im2 = new BufferedImage(w + 2, h + 2,
|
||||||
w + 2, h + 2, BufferedImage.TYPE_4BYTE_ABGR);
|
BufferedImage.TYPE_4BYTE_ABGR);
|
||||||
if (im.getType() == BufferedImage.TYPE_4BYTE_ABGR) {
|
if (im.getType() == BufferedImage.TYPE_4BYTE_ABGR) {
|
||||||
im2.getRaster().setRect(1, 1, im.getRaster());
|
im2.getRaster().setRect(1, 1, im.getRaster());
|
||||||
} else {
|
} else {
|
||||||
@ -64,15 +65,15 @@ public class Res9patchStreamDecoder implements ResStreamDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private NinePatch getNinePatch(byte[] data)
|
private NinePatch getNinePatch(byte[] data) throws AndrolibException,
|
||||||
throws AndrolibException, IOException {
|
IOException {
|
||||||
ExtDataInput di = new ExtDataInput(new ByteArrayInputStream(data));
|
ExtDataInput di = new ExtDataInput(new ByteArrayInputStream(data));
|
||||||
find9patchChunk(di);
|
find9patchChunk(di);
|
||||||
return NinePatch.decode(di);
|
return NinePatch.decode(di);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void find9patchChunk(DataInput di)
|
private void find9patchChunk(DataInput di) throws AndrolibException,
|
||||||
throws AndrolibException, IOException {
|
IOException {
|
||||||
di.skipBytes(8);
|
di.skipBytes(8);
|
||||||
while (true) {
|
while (true) {
|
||||||
int size;
|
int size;
|
||||||
@ -103,7 +104,6 @@ public class Res9patchStreamDecoder implements ResStreamDecoder {
|
|||||||
private static final int NP_CHUNK_TYPE = 0x6e705463; // npTc
|
private static final int NP_CHUNK_TYPE = 0x6e705463; // npTc
|
||||||
private static final int NP_COLOR = 0xff000000;
|
private static final int NP_COLOR = 0xff000000;
|
||||||
|
|
||||||
|
|
||||||
private static class NinePatch {
|
private static class NinePatch {
|
||||||
public final int padLeft, padRight, padTop, padBottom;
|
public final int padLeft, padRight, padTop, padBottom;
|
||||||
public final int[] xDivs, yDivs;
|
public final int[] xDivs, yDivs;
|
||||||
@ -132,8 +132,8 @@ public class Res9patchStreamDecoder implements ResStreamDecoder {
|
|||||||
int[] xDivs = di.readIntArray(numXDivs);
|
int[] xDivs = di.readIntArray(numXDivs);
|
||||||
int[] yDivs = di.readIntArray(numYDivs);
|
int[] yDivs = di.readIntArray(numYDivs);
|
||||||
|
|
||||||
return new NinePatch(padLeft, padRight, padTop, padBottom,
|
return new NinePatch(padLeft, padRight, padTop, padBottom, xDivs,
|
||||||
xDivs, yDivs);
|
yDivs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -27,8 +27,8 @@ import brut.androlib.res.data.value.ResScalarValue;
|
|||||||
public class ResAttrDecoder {
|
public class ResAttrDecoder {
|
||||||
public String decode(int type, int value, String rawValue, int attrResId)
|
public String decode(int type, int value, String rawValue, int attrResId)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
ResScalarValue resValue = mCurrentPackage.getValueFactory()
|
ResScalarValue resValue = mCurrentPackage.getValueFactory().factory(
|
||||||
.factory(type, value, rawValue);
|
type, value, rawValue);
|
||||||
|
|
||||||
String decoded = null;
|
String decoded = null;
|
||||||
if (attrResId != 0) {
|
if (attrResId != 0) {
|
||||||
|
@ -70,19 +70,19 @@ public class ResFileDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
decode(
|
decode(inDir, inFileName, outDir, outFileName, "9patch");
|
||||||
inDir, inFileName, outDir, outFileName, "9patch");
|
|
||||||
return;
|
return;
|
||||||
} catch (CantFind9PatchChunk ex) {
|
} catch (CantFind9PatchChunk ex) {
|
||||||
LOGGER.log(Level.WARNING, String.format(
|
LOGGER.log(
|
||||||
|
Level.WARNING,
|
||||||
|
String.format(
|
||||||
"Cant find 9patch chunk in file: \"%s\". Renaming it to *.png.",
|
"Cant find 9patch chunk in file: \"%s\". Renaming it to *.png.",
|
||||||
inFileName
|
inFileName), ex);
|
||||||
), ex);
|
|
||||||
outDir.removeFile(outFileName);
|
outDir.removeFile(outFileName);
|
||||||
outFileName = outResName + ext;
|
outFileName = outResName + ext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (! ".xml".equals(ext)) {
|
if (!".xml".equals(ext)) {
|
||||||
decode(inDir, inFileName, outDir, outFileName, "raw");
|
decode(inDir, inFileName, outDir, outFileName, "raw");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -108,7 +108,7 @@ public class ResFileDecoder {
|
|||||||
} catch (DirectoryException ex) {
|
} catch (DirectoryException ex) {
|
||||||
throw new AndrolibException(ex);
|
throw new AndrolibException(ex);
|
||||||
} finally {
|
} finally {
|
||||||
try{
|
try {
|
||||||
if (in != null) {
|
if (in != null) {
|
||||||
in.close();
|
in.close();
|
||||||
}
|
}
|
||||||
@ -121,18 +121,19 @@ public class ResFileDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void decodeManifest(Directory inDir, String inFileName, Directory outDir,
|
public void decodeManifest(Directory inDir, String inFileName,
|
||||||
String outFileName) throws AndrolibException {
|
Directory outDir, String outFileName) throws AndrolibException {
|
||||||
InputStream in = null;
|
InputStream in = null;
|
||||||
OutputStream out = null;
|
OutputStream out = null;
|
||||||
try {
|
try {
|
||||||
in = inDir.getFileInput(inFileName);
|
in = inDir.getFileInput(inFileName);
|
||||||
out = outDir.getFileOutput(outFileName);
|
out = outDir.getFileOutput(outFileName);
|
||||||
((XmlPullStreamDecoder)mDecoders.getDecoder("xml")).decodeManifest(in, out);
|
((XmlPullStreamDecoder) mDecoders.getDecoder("xml"))
|
||||||
|
.decodeManifest(in, out);
|
||||||
} catch (DirectoryException ex) {
|
} catch (DirectoryException ex) {
|
||||||
throw new AndrolibException(ex);
|
throw new AndrolibException(ex);
|
||||||
} finally {
|
} finally {
|
||||||
try{
|
try {
|
||||||
if (in != null) {
|
if (in != null) {
|
||||||
in.close();
|
in.close();
|
||||||
}
|
}
|
||||||
@ -145,6 +146,6 @@ public class ResFileDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static Logger LOGGER =
|
private final static Logger LOGGER = Logger.getLogger(ResFileDecoder.class
|
||||||
Logger.getLogger(ResFileDecoder.class.getName());
|
.getName());
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ import org.apache.commons.io.IOUtils;
|
|||||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||||
*/
|
*/
|
||||||
public class ResRawStreamDecoder implements ResStreamDecoder {
|
public class ResRawStreamDecoder implements ResStreamDecoder {
|
||||||
|
@Override
|
||||||
public void decode(InputStream in, OutputStream out)
|
public void decode(InputStream in, OutputStream out)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
try {
|
try {
|
||||||
|
@ -26,8 +26,7 @@ import java.util.Map;
|
|||||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||||
*/
|
*/
|
||||||
public class ResStreamDecoderContainer {
|
public class ResStreamDecoderContainer {
|
||||||
private final Map<String, ResStreamDecoder> mDecoders =
|
private final Map<String, ResStreamDecoder> mDecoders = new HashMap<String, ResStreamDecoder>();
|
||||||
new HashMap<String, ResStreamDecoder>();
|
|
||||||
|
|
||||||
public void decode(InputStream in, OutputStream out, String decoderName)
|
public void decode(InputStream in, OutputStream out, String decoderName)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
|
@ -30,15 +30,14 @@ import java.util.logging.Logger;
|
|||||||
*
|
*
|
||||||
* Block of strings, used in binary xml and arsc.
|
* Block of strings, used in binary xml and arsc.
|
||||||
*
|
*
|
||||||
* TODO:
|
* TODO: - implement get()
|
||||||
* - implement get()
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class StringBlock {
|
public class StringBlock {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads whole (including chunk type) string block from stream.
|
* Reads whole (including chunk type) string block from stream. Stream must
|
||||||
* Stream must be at the chunk type.
|
* be at the chunk type.
|
||||||
*/
|
*/
|
||||||
public static StringBlock read(ExtDataInput reader) throws IOException {
|
public static StringBlock read(ExtDataInput reader) throws IOException {
|
||||||
reader.skipCheckInt(CHUNK_TYPE);
|
reader.skipCheckInt(CHUNK_TYPE);
|
||||||
@ -53,16 +52,18 @@ public class StringBlock {
|
|||||||
block.m_isUTF8 = (flags & UTF8_FLAG) != 0;
|
block.m_isUTF8 = (flags & UTF8_FLAG) != 0;
|
||||||
block.m_stringOffsets = reader.readIntArray(stringCount);
|
block.m_stringOffsets = reader.readIntArray(stringCount);
|
||||||
block.m_stringOwns = new int[stringCount];
|
block.m_stringOwns = new int[stringCount];
|
||||||
for (int i=0;i<stringCount;i++) {
|
for (int i = 0; i < stringCount; i++) {
|
||||||
block.m_stringOwns[i] = -1;
|
block.m_stringOwns[i] = -1;
|
||||||
}
|
}
|
||||||
if (styleOffsetCount != 0) {
|
if (styleOffsetCount != 0) {
|
||||||
block.m_styleOffsets = reader.readIntArray(styleOffsetCount);
|
block.m_styleOffsets = reader.readIntArray(styleOffsetCount);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
int size = ((stylesOffset == 0) ? chunkSize : stylesOffset) - stringsOffset;
|
int size = ((stylesOffset == 0) ? chunkSize : stylesOffset)
|
||||||
|
- stringsOffset;
|
||||||
if ((size % 4) != 0) {
|
if ((size % 4) != 0) {
|
||||||
throw new IOException("String data size is not multiple of 4 (" + size + ").");
|
throw new IOException("String data size is not multiple of 4 ("
|
||||||
|
+ size + ").");
|
||||||
}
|
}
|
||||||
block.m_strings = new byte[size];
|
block.m_strings = new byte[size];
|
||||||
reader.readFully(block.m_strings);
|
reader.readFully(block.m_strings);
|
||||||
@ -70,7 +71,8 @@ public class StringBlock {
|
|||||||
if (stylesOffset != 0) {
|
if (stylesOffset != 0) {
|
||||||
int size = (chunkSize - stylesOffset);
|
int size = (chunkSize - stylesOffset);
|
||||||
if ((size % 4) != 0) {
|
if ((size % 4) != 0) {
|
||||||
throw new IOException("Style data size is not multiple of 4 (" + size + ").");
|
throw new IOException("Style data size is not multiple of 4 ("
|
||||||
|
+ size + ").");
|
||||||
}
|
}
|
||||||
block.m_styles = reader.readIntArray(size / 4);
|
block.m_styles = reader.readIntArray(size / 4);
|
||||||
}
|
}
|
||||||
@ -82,24 +84,21 @@ public class StringBlock {
|
|||||||
* Returns number of strings in block.
|
* Returns number of strings in block.
|
||||||
*/
|
*/
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
return m_stringOffsets != null
|
return m_stringOffsets != null ? m_stringOffsets.length : 0;
|
||||||
? m_stringOffsets.length
|
|
||||||
: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns raw string (without any styling information) at specified index.
|
* Returns raw string (without any styling information) at specified index.
|
||||||
*/
|
*/
|
||||||
public String getString(int index) {
|
public String getString(int index) {
|
||||||
if (index < 0
|
if (index < 0 || m_stringOffsets == null
|
||||||
|| m_stringOffsets == null
|
|
||||||
|| index >= m_stringOffsets.length) {
|
|| index >= m_stringOffsets.length) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
int offset = m_stringOffsets[index];
|
int offset = m_stringOffsets[index];
|
||||||
int length;
|
int length;
|
||||||
|
|
||||||
if (! m_isUTF8) {
|
if (!m_isUTF8) {
|
||||||
length = getShort(m_strings, offset) * 2;
|
length = getShort(m_strings, offset) * 2;
|
||||||
offset += 2;
|
offset += 2;
|
||||||
} else {
|
} else {
|
||||||
@ -153,16 +152,16 @@ public class StringBlock {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (offset <= end) {
|
if (offset <= end) {
|
||||||
html.append(ResXmlEncoders.escapeXmlChars(
|
html.append(ResXmlEncoders.escapeXmlChars(raw.substring(
|
||||||
raw.substring(offset, end + 1)));
|
offset, end + 1)));
|
||||||
offset = end + 1;
|
offset = end + 1;
|
||||||
}
|
}
|
||||||
outputStyleTag(getString(style[last]), html, true);
|
outputStyleTag(getString(style[last]), html, true);
|
||||||
}
|
}
|
||||||
depth = j + 1;
|
depth = j + 1;
|
||||||
if (offset < start) {
|
if (offset < start) {
|
||||||
html.append(ResXmlEncoders.escapeXmlChars(
|
html.append(ResXmlEncoders.escapeXmlChars(raw.substring(offset,
|
||||||
raw.substring(offset, start)));
|
start)));
|
||||||
offset = start;
|
offset = start;
|
||||||
}
|
}
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
@ -175,8 +174,7 @@ public class StringBlock {
|
|||||||
return html.toString();
|
return html.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void outputStyleTag(String tag, StringBuilder builder,
|
private void outputStyleTag(String tag, StringBuilder builder, boolean close) {
|
||||||
boolean close) {
|
|
||||||
builder.append('<');
|
builder.append('<');
|
||||||
if (close) {
|
if (close) {
|
||||||
builder.append('/');
|
builder.append('/');
|
||||||
@ -187,7 +185,7 @@ public class StringBlock {
|
|||||||
builder.append(tag);
|
builder.append(tag);
|
||||||
} else {
|
} else {
|
||||||
builder.append(tag.substring(0, pos));
|
builder.append(tag.substring(0, pos));
|
||||||
if (! close) {
|
if (!close) {
|
||||||
boolean loop = true;
|
boolean loop = true;
|
||||||
while (loop) {
|
while (loop) {
|
||||||
int pos2 = tag.indexOf('=', pos + 1);
|
int pos2 = tag.indexOf('=', pos + 1);
|
||||||
@ -203,8 +201,8 @@ public class StringBlock {
|
|||||||
val = tag.substring(pos2 + 1);
|
val = tag.substring(pos2 + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.append(ResXmlEncoders.escapeXmlChars(val))
|
builder.append(ResXmlEncoders.escapeXmlChars(val)).append(
|
||||||
.append('"');
|
'"');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -212,8 +210,7 @@ public class StringBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds index of the string.
|
* Finds index of the string. Returns -1 if the string was not found.
|
||||||
* Returns -1 if the string was not found.
|
|
||||||
*/
|
*/
|
||||||
public int find(String string) {
|
public int find(String string) {
|
||||||
if (string == null) {
|
if (string == null) {
|
||||||
@ -239,16 +236,14 @@ public class StringBlock {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////// implementation
|
// /////////////////////////////////////////// implementation
|
||||||
private StringBlock() {
|
private StringBlock() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns style information - array of int triplets,
|
* Returns style information - array of int triplets, where in each triplet:
|
||||||
* where in each triplet:
|
* * first int is index of tag name ('b','i', etc.) * second int is tag
|
||||||
* * first int is index of tag name ('b','i', etc.)
|
* start index in string * third int is tag end index in string
|
||||||
* * second int is tag start index in string
|
|
||||||
* * third int is tag end index in string
|
|
||||||
*/
|
*/
|
||||||
private int[] getStyle(int index) {
|
private int[] getStyle(int index) {
|
||||||
if (m_styleOffsets == null || m_styles == null
|
if (m_styleOffsets == null || m_styles == null
|
||||||
@ -307,20 +302,18 @@ public class StringBlock {
|
|||||||
boolean more = (val & 0x80) != 0;
|
boolean more = (val & 0x80) != 0;
|
||||||
val &= 0x7f;
|
val &= 0x7f;
|
||||||
|
|
||||||
if (! more) {
|
if (!more) {
|
||||||
return new int[]{val, 1};
|
return new int[] { val, 1 };
|
||||||
} else {
|
} else {
|
||||||
return new int[]{val << 8 | array[offset + 1] & 0xff, 2};
|
return new int[] { val << 8 | array[offset + 1] & 0xff, 2 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean touch(int index, int own) {
|
public boolean touch(int index, int own) {
|
||||||
if (index < 0
|
if (index < 0 || m_stringOwns == null || index >= m_stringOwns.length) {
|
||||||
|| m_stringOwns == null
|
|
||||||
|| index >= m_stringOwns.length) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(m_stringOwns[index] == -1) {
|
if (m_stringOwns[index] == -1) {
|
||||||
m_stringOwns[index] = own;
|
m_stringOwns[index] = own;
|
||||||
return true;
|
return true;
|
||||||
} else if (m_stringOwns[index] == own) {
|
} else if (m_stringOwns[index] == own) {
|
||||||
@ -336,12 +329,12 @@ public class StringBlock {
|
|||||||
private int[] m_styles;
|
private int[] m_styles;
|
||||||
private boolean m_isUTF8;
|
private boolean m_isUTF8;
|
||||||
private int[] m_stringOwns;
|
private int[] m_stringOwns;
|
||||||
private static final CharsetDecoder UTF16LE_DECODER =
|
private static final CharsetDecoder UTF16LE_DECODER = Charset.forName(
|
||||||
Charset.forName("UTF-16LE").newDecoder();
|
"UTF-16LE").newDecoder();
|
||||||
private static final CharsetDecoder UTF8_DECODER =
|
private static final CharsetDecoder UTF8_DECODER = Charset.forName("UTF-8")
|
||||||
Charset.forName("UTF-8").newDecoder();
|
.newDecoder();
|
||||||
private static final Logger LOGGER =
|
private static final Logger LOGGER = Logger.getLogger(StringBlock.class
|
||||||
Logger.getLogger(StringBlock.class.getName());
|
.getName());
|
||||||
private static final int CHUNK_TYPE = 0x001C0001;
|
private static final int CHUNK_TYPE = 0x001C0001;
|
||||||
private static final int UTF8_FLAG = 0x00000100;
|
private static final int UTF8_FLAG = 0x00000100;
|
||||||
}
|
}
|
||||||
|
@ -42,80 +42,91 @@ public class XmlPullStreamDecoder implements ResStreamDecoder {
|
|||||||
this.mSerial = serializer;
|
this.mSerial = serializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void decode(InputStream in, OutputStream out)
|
public void decode(InputStream in, OutputStream out)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
try {
|
try {
|
||||||
XmlPullWrapperFactory factory = XmlPullWrapperFactory.newInstance();
|
XmlPullWrapperFactory factory = XmlPullWrapperFactory.newInstance();
|
||||||
XmlPullParserWrapper par = factory.newPullParserWrapper(mParser);
|
XmlPullParserWrapper par = factory.newPullParserWrapper(mParser);
|
||||||
final ResTable resTable = ((AXmlResourceParser)mParser).getAttrDecoder().getCurrentPackage().getResTable();
|
final ResTable resTable = ((AXmlResourceParser) mParser)
|
||||||
|
.getAttrDecoder().getCurrentPackage().getResTable();
|
||||||
|
|
||||||
XmlSerializerWrapper ser = new StaticXmlSerializerWrapper(mSerial, factory){
|
XmlSerializerWrapper ser = new StaticXmlSerializerWrapper(mSerial,
|
||||||
|
factory) {
|
||||||
boolean hideSdkInfo = false;
|
boolean hideSdkInfo = false;
|
||||||
boolean hidePackageInfo = false;
|
boolean hidePackageInfo = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void event(XmlPullParser pp) throws XmlPullParserException, IOException {
|
public void event(XmlPullParser pp)
|
||||||
|
throws XmlPullParserException, IOException {
|
||||||
int type = pp.getEventType();
|
int type = pp.getEventType();
|
||||||
|
|
||||||
if (type == XmlPullParser.START_TAG) {
|
if (type == XmlPullParser.START_TAG) {
|
||||||
if ("manifest".equalsIgnoreCase(pp.getName())) {
|
if ("manifest".equalsIgnoreCase(pp.getName())) {
|
||||||
try {
|
try {
|
||||||
hidePackageInfo = parseManifest(pp);
|
hidePackageInfo = parseManifest(pp);
|
||||||
} catch (AndrolibException e) {}
|
} catch (AndrolibException e) {
|
||||||
}else if ("uses-sdk".equalsIgnoreCase(pp.getName())) {
|
}
|
||||||
|
} else if ("uses-sdk".equalsIgnoreCase(pp.getName())) {
|
||||||
try {
|
try {
|
||||||
hideSdkInfo = parseAttr(pp);
|
hideSdkInfo = parseAttr(pp);
|
||||||
if(hideSdkInfo) {
|
if (hideSdkInfo) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (AndrolibException e) {}
|
} catch (AndrolibException e) {
|
||||||
}
|
}
|
||||||
} else if (hideSdkInfo && type == XmlPullParser.END_TAG &&
|
}
|
||||||
"uses-sdk".equalsIgnoreCase(pp.getName())) {
|
} else if (hideSdkInfo && type == XmlPullParser.END_TAG
|
||||||
|
&& "uses-sdk".equalsIgnoreCase(pp.getName())) {
|
||||||
return;
|
return;
|
||||||
} else if (hidePackageInfo && type == XmlPullParser.END_TAG &&
|
} else if (hidePackageInfo && type == XmlPullParser.END_TAG
|
||||||
"manifest".equalsIgnoreCase(pp.getName())) {
|
&& "manifest".equalsIgnoreCase(pp.getName())) {
|
||||||
super.event(pp);
|
super.event(pp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
super.event(pp);
|
super.event(pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean parseManifest(XmlPullParser pp) throws AndrolibException {
|
private boolean parseManifest(XmlPullParser pp)
|
||||||
|
throws AndrolibException {
|
||||||
ResTable restable = resTable;
|
ResTable restable = resTable;
|
||||||
|
|
||||||
// read <manifest> for package:
|
// read <manifest> for package:
|
||||||
for (int i = 0; i < pp.getAttributeCount(); i++) {
|
for (int i = 0; i < pp.getAttributeCount(); i++) {
|
||||||
if (pp.getAttributeName(i).equalsIgnoreCase(("package"))) {
|
if (pp.getAttributeName(i)
|
||||||
restable.addPackageInfo("orig_package", pp.getAttributeValue(i));
|
.equalsIgnoreCase(("package"))) {
|
||||||
|
restable.addPackageInfo("orig_package",
|
||||||
|
pp.getAttributeValue(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean parseAttr(XmlPullParser pp) throws AndrolibException {
|
private boolean parseAttr(XmlPullParser pp)
|
||||||
|
throws AndrolibException {
|
||||||
ResTable restable = resTable;
|
ResTable restable = resTable;
|
||||||
for (int i = 0; i < pp.getAttributeCount(); i++) {
|
for (int i = 0; i < pp.getAttributeCount(); i++) {
|
||||||
final String a_ns = "http://schemas.android.com/apk/res/android";
|
final String a_ns = "http://schemas.android.com/apk/res/android";
|
||||||
String ns = pp.getAttributeNamespace (i);
|
String ns = pp.getAttributeNamespace(i);
|
||||||
|
|
||||||
if (a_ns.equalsIgnoreCase(ns)) {
|
if (a_ns.equalsIgnoreCase(ns)) {
|
||||||
String name = pp.getAttributeName (i);
|
String name = pp.getAttributeName(i);
|
||||||
String value = pp.getAttributeValue (i);
|
String value = pp.getAttributeValue(i);
|
||||||
if (name != null && value != null) {
|
if (name != null && value != null) {
|
||||||
if (name.equalsIgnoreCase("minSdkVersion") ||
|
if (name.equalsIgnoreCase("minSdkVersion")
|
||||||
name.equalsIgnoreCase("targetSdkVersion") ||
|
|| name.equalsIgnoreCase("targetSdkVersion")
|
||||||
name.equalsIgnoreCase("maxSdkVersion")) {
|
|| name.equalsIgnoreCase("maxSdkVersion")) {
|
||||||
restable.addSdkInfo(name, value);
|
restable.addSdkInfo(name, value);
|
||||||
} else {
|
} else {
|
||||||
restable.clearSdkInfo();
|
restable.clearSdkInfo();
|
||||||
return false;//Found unknown flags
|
return false;// Found unknown flags
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resTable.clearSdkInfo();
|
resTable.clearSdkInfo();
|
||||||
|
|
||||||
if (i >= pp.getAttributeCount()) {
|
if (i >= pp.getAttributeCount()) {
|
||||||
return false;//Found unknown flags
|
return false;// Found unknown flags
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,6 +163,6 @@ public class XmlPullStreamDecoder implements ResStreamDecoder {
|
|||||||
|
|
||||||
private boolean mOptimizeForManifest = false;
|
private boolean mOptimizeForManifest = false;
|
||||||
|
|
||||||
private final static Logger LOGGER =
|
private final static Logger LOGGER = Logger
|
||||||
Logger.getLogger(XmlPullStreamDecoder.class.getName());
|
.getLogger(XmlPullStreamDecoder.class.getName());
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,5 @@ public class ExtFile extends File {
|
|||||||
return mDirectory;
|
return mDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Directory mDirectory;
|
private Directory mDirectory;
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,8 @@ import org.xmlpull.mxp1_serializer.MXSerializer;
|
|||||||
*/
|
*/
|
||||||
public class ExtMXSerializer extends MXSerializer implements ExtXmlSerializer {
|
public class ExtMXSerializer extends MXSerializer implements ExtXmlSerializer {
|
||||||
@Override
|
@Override
|
||||||
public void startDocument(String encoding, Boolean standalone) throws
|
public void startDocument(String encoding, Boolean standalone)
|
||||||
IOException, IllegalArgumentException, IllegalStateException {
|
throws IOException, IllegalArgumentException, IllegalStateException {
|
||||||
super.startDocument(encoding != null ? encoding : mDefaultEncoding,
|
super.startDocument(encoding != null ? encoding : mDefaultEncoding,
|
||||||
standalone);
|
standalone);
|
||||||
this.newLine();
|
this.newLine();
|
||||||
@ -64,11 +64,13 @@ public class ExtMXSerializer extends MXSerializer implements ExtXmlSerializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public ExtXmlSerializer newLine() throws IOException {
|
public ExtXmlSerializer newLine() throws IOException {
|
||||||
super.out.write(lineSeparator);
|
super.out.write(lineSeparator);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setDisabledAttrEscape(boolean disabled) {
|
public void setDisabledAttrEscape(boolean disabled) {
|
||||||
mIsDisabledAttrEscape = disabled;
|
mIsDisabledAttrEscape = disabled;
|
||||||
}
|
}
|
||||||
|
@ -25,11 +25,10 @@ import org.xmlpull.v1.XmlSerializer;
|
|||||||
public interface ExtXmlSerializer extends XmlSerializer {
|
public interface ExtXmlSerializer extends XmlSerializer {
|
||||||
|
|
||||||
public ExtXmlSerializer newLine() throws IOException;
|
public ExtXmlSerializer newLine() throws IOException;
|
||||||
|
|
||||||
public void setDisabledAttrEscape(boolean disabled);
|
public void setDisabledAttrEscape(boolean disabled);
|
||||||
|
|
||||||
public static final String PROPERTY_SERIALIZER_INDENTATION =
|
public static final String PROPERTY_SERIALIZER_INDENTATION = "http://xmlpull.org/v1/doc/properties.html#serializer-indentation";
|
||||||
"http://xmlpull.org/v1/doc/properties.html#serializer-indentation";
|
public static final String PROPERTY_SERIALIZER_LINE_SEPARATOR = "http://xmlpull.org/v1/doc/properties.html#serializer-line-separator";
|
||||||
public static final String PROPERTY_SERIALIZER_LINE_SEPARATOR =
|
|
||||||
"http://xmlpull.org/v1/doc/properties.html#serializer-line-separator";
|
|
||||||
public static final String PROPERTY_DEFAULT_ENCODING = "DEFAULT_ENCODING";
|
public static final String PROPERTY_DEFAULT_ENCODING = "DEFAULT_ENCODING";
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,6 @@ import org.xmlpull.v1.XmlSerializer;
|
|||||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||||
*/
|
*/
|
||||||
public interface ResValuesXmlSerializable {
|
public interface ResValuesXmlSerializable {
|
||||||
public void serializeToResValuesXml(XmlSerializer serializer, ResResource res)
|
public void serializeToResValuesXml(XmlSerializer serializer,
|
||||||
throws IOException, AndrolibException;
|
ResResource res) throws IOException, AndrolibException;
|
||||||
}
|
}
|
||||||
|
@ -23,5 +23,6 @@ import brut.androlib.AndrolibException;
|
|||||||
*/
|
*/
|
||||||
public interface ResXmlEncodable {
|
public interface ResXmlEncodable {
|
||||||
public String encodeAsResXmlAttr() throws AndrolibException;
|
public String encodeAsResXmlAttr() throws AndrolibException;
|
||||||
|
|
||||||
public String encodeAsResXmlValue() throws AndrolibException;
|
public String encodeAsResXmlValue() throws AndrolibException;
|
||||||
}
|
}
|
||||||
|
@ -166,7 +166,7 @@ public final class ResXmlEncoders {
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
int length = str.length();
|
int length = str.length();
|
||||||
List<Integer> ret = new ArrayList<Integer>();
|
List<Integer> ret = new ArrayList<Integer>();
|
||||||
while((pos2 = (pos = str.indexOf('%', pos2)) + 1) != 0) {
|
while ((pos2 = (pos = str.indexOf('%', pos2)) + 1) != 0) {
|
||||||
if (pos2 == length) {
|
if (pos2 == length) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -194,9 +194,7 @@ public final class ResXmlEncoders {
|
|||||||
|
|
||||||
private static boolean isPrintableChar(char c) {
|
private static boolean isPrintableChar(char c) {
|
||||||
Character.UnicodeBlock block = Character.UnicodeBlock.of(c);
|
Character.UnicodeBlock block = Character.UnicodeBlock.of(c);
|
||||||
return !Character.isISOControl(c)
|
return !Character.isISOControl(c) && c != KeyEvent.CHAR_UNDEFINED
|
||||||
&& c != KeyEvent.CHAR_UNDEFINED
|
&& block != null && block != Character.UnicodeBlock.SPECIALS;
|
||||||
&& block != null
|
|
||||||
&& block != Character.UnicodeBlock.SPECIALS;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,6 @@ import java.util.*;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import org.jf.dexlib.Code.Analysis.RegisterType;
|
import org.jf.dexlib.Code.Analysis.RegisterType;
|
||||||
import org.jf.dexlib.Code.Opcode;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||||
@ -40,10 +39,8 @@ public class DebugInjector {
|
|||||||
|
|
||||||
private void inject() throws AndrolibException {
|
private void inject() throws AndrolibException {
|
||||||
String definition = nextAndAppend();
|
String definition = nextAndAppend();
|
||||||
if (
|
if (definition.contains(" abstract ")
|
||||||
definition.contains(" abstract ") ||
|
|| definition.contains(" native ")) {
|
||||||
definition.contains(" native ")
|
|
||||||
) {
|
|
||||||
nextAndAppend();
|
nextAndAppend();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -68,7 +65,7 @@ public class DebugInjector {
|
|||||||
|
|
||||||
int i = definition.contains(" static ") ? 0 : 1;
|
int i = definition.contains(" static ") ? 0 : 1;
|
||||||
int argc = TypeName.listFromInternalName(params).size() + i;
|
int argc = TypeName.listFromInternalName(params).size() + i;
|
||||||
while(i < argc) {
|
while (i < argc) {
|
||||||
mOut.append(".parameter \"p").append(i).append("\"\n");
|
mOut.append(".parameter \"p").append(i).append("\"\n");
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@ -121,8 +118,7 @@ public class DebugInjector {
|
|||||||
case Uninit:
|
case Uninit:
|
||||||
case Conflicted:
|
case Conflicted:
|
||||||
if (mInitializedRegisters.remove(localName)) {
|
if (mInitializedRegisters.remove(localName)) {
|
||||||
mOut.append(".end local ").append(localName)
|
mOut.append(".end local ").append(localName).append('\n');
|
||||||
.append('\n');
|
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
case Short:
|
case Short:
|
||||||
@ -153,7 +149,8 @@ public class DebugInjector {
|
|||||||
|
|
||||||
mInitializedRegisters.add(localName);
|
mInitializedRegisters.add(localName);
|
||||||
mOut.append(".local ").append(localName).append(", ")
|
mOut.append(".local ").append(localName).append(", ")
|
||||||
.append(localName).append(':').append(localType).append('\n');
|
.append(localName).append(':').append(localType)
|
||||||
|
.append('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -161,13 +158,9 @@ public class DebugInjector {
|
|||||||
|
|
||||||
private boolean processDirective(String line) {
|
private boolean processDirective(String line) {
|
||||||
String line2 = line.substring(1);
|
String line2 = line.substring(1);
|
||||||
if (
|
if (line2.startsWith("line ") || line2.equals("prologue")
|
||||||
line2.startsWith("line ") ||
|
|| line2.startsWith("parameter") || line2.startsWith("local ")
|
||||||
line2.equals("prologue") ||
|
|| line2.startsWith("end local ")) {
|
||||||
line2.startsWith("parameter") ||
|
|
||||||
line2.startsWith("local ") ||
|
|
||||||
line2.startsWith("end local ")
|
|
||||||
) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,13 +168,10 @@ public class DebugInjector {
|
|||||||
if (line2.equals("end method")) {
|
if (line2.equals("end method")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (
|
if (line2.startsWith("annotation ") || line2.equals("sparse-switch")
|
||||||
line2.startsWith("annotation ") ||
|
|| line2.startsWith("packed-switch ")
|
||||||
line2.equals("sparse-switch") ||
|
|| line2.startsWith("array-data ")) {
|
||||||
line2.startsWith("packed-switch ") ||
|
while (true) {
|
||||||
line2.startsWith("array-data ")
|
|
||||||
) {
|
|
||||||
while(true) {
|
|
||||||
line2 = nextAndAppend();
|
line2 = nextAndAppend();
|
||||||
if (line2.startsWith(".end ")) {
|
if (line2.startsWith(".end ")) {
|
||||||
break;
|
break;
|
||||||
@ -196,8 +186,8 @@ public class DebugInjector {
|
|||||||
mOut.append(".prologue\n");
|
mOut.append(".prologue\n");
|
||||||
mFirstInstruction = false;
|
mFirstInstruction = false;
|
||||||
}
|
}
|
||||||
mOut.append(".line ").append(mIt.nextIndex()).append('\n')
|
mOut.append(".line ").append(mIt.nextIndex()).append('\n').append(line)
|
||||||
.append(line).append('\n');
|
.append('\n');
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -222,6 +212,6 @@ public class DebugInjector {
|
|||||||
private boolean mFirstInstruction = true;
|
private boolean mFirstInstruction = true;
|
||||||
private final Set<String> mInitializedRegisters = new HashSet<String>();
|
private final Set<String> mInitializedRegisters = new HashSet<String>();
|
||||||
|
|
||||||
private static final Pattern REGISTER_INFO_PATTERN =
|
private static final Pattern REGISTER_INFO_PATTERN = Pattern
|
||||||
Pattern.compile("((?:p|v)\\d+)=\\(([^)]+)\\);");
|
.compile("((?:p|v)\\d+)=\\(([^)]+)\\);");
|
||||||
}
|
}
|
||||||
|
@ -40,10 +40,9 @@ public class DexFileBuilder {
|
|||||||
public void addSmaliFile(InputStream smaliStream, String name)
|
public void addSmaliFile(InputStream smaliStream, String name)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
try {
|
try {
|
||||||
if (! SmaliMod.assembleSmaliFile(
|
if (!SmaliMod.assembleSmaliFile(smaliStream, name, mDexFile, false,
|
||||||
smaliStream, name, mDexFile, false, false, false)) {
|
false, false)) {
|
||||||
throw new AndrolibException(
|
throw new AndrolibException("Could not smali file: " + name);
|
||||||
"Could not smali file: " + name);
|
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new AndrolibException(ex);
|
throw new AndrolibException(ex);
|
||||||
@ -58,14 +57,14 @@ public class DexFileBuilder {
|
|||||||
out.write(getAsByteArray());
|
out.write(getAsByteArray());
|
||||||
out.close();
|
out.close();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new AndrolibException(
|
throw new AndrolibException("Could not write dex to file: "
|
||||||
"Could not write dex to file: " + dexFile, ex);
|
+ dexFile, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getAsByteArray() {
|
public byte[] getAsByteArray() {
|
||||||
mDexFile.place();
|
mDexFile.place();
|
||||||
for (CodeItem codeItem: mDexFile.CodeItemsSection.getItems()) {
|
for (CodeItem codeItem : mDexFile.CodeItemsSection.getItems()) {
|
||||||
codeItem.fixInstructions(true, true);
|
codeItem.fixInstructions(true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,12 +32,12 @@ import org.apache.commons.io.IOUtils;
|
|||||||
public class SmaliBuilder {
|
public class SmaliBuilder {
|
||||||
|
|
||||||
public static void build(ExtFile smaliDir, File dexFile,
|
public static void build(ExtFile smaliDir, File dexFile,
|
||||||
HashMap<String, Boolean> flags)
|
HashMap<String, Boolean> flags) throws AndrolibException {
|
||||||
throws AndrolibException {
|
|
||||||
new SmaliBuilder(smaliDir, dexFile, flags).build();
|
new SmaliBuilder(smaliDir, dexFile, flags).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private SmaliBuilder(ExtFile smaliDir, File dexFile, HashMap<String, Boolean> flags) {
|
private SmaliBuilder(ExtFile smaliDir, File dexFile,
|
||||||
|
HashMap<String, Boolean> flags) {
|
||||||
mSmaliDir = smaliDir;
|
mSmaliDir = smaliDir;
|
||||||
mDexFile = dexFile;
|
mDexFile = dexFile;
|
||||||
mFlags = flags;
|
mFlags = flags;
|
||||||
@ -66,7 +66,7 @@ public class SmaliBuilder {
|
|||||||
mDexBuilder.addSmaliFile(inFile);
|
mDexBuilder.addSmaliFile(inFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (! fileName.endsWith(".java")) {
|
if (!fileName.endsWith(".java")) {
|
||||||
LOGGER.warning("Unknown file type, ignoring: " + inFile);
|
LOGGER.warning("Unknown file type, ignoring: " + inFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -87,8 +87,8 @@ public class SmaliBuilder {
|
|||||||
out.append(".source \"").append(inFile.getName()).append("\"\n");
|
out.append(".source \"").append(inFile.getName()).append("\"\n");
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
String line = it.next().trim();
|
String line = it.next().trim();
|
||||||
if (line.isEmpty() || line.charAt(0) == '#' ||
|
if (line.isEmpty() || line.charAt(0) == '#'
|
||||||
line.startsWith(".source")) {
|
|| line.startsWith(".source")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (line.startsWith(".method ")) {
|
if (line.startsWith(".method ")) {
|
||||||
@ -100,8 +100,8 @@ public class SmaliBuilder {
|
|||||||
out.append(line).append('\n');
|
out.append(line).append('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mDexBuilder.addSmaliFile(
|
mDexBuilder.addSmaliFile(IOUtils.toInputStream(out.toString()),
|
||||||
IOUtils.toInputStream(out.toString()), fileName);
|
fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ExtFile mSmaliDir;
|
private final ExtFile mSmaliDir;
|
||||||
@ -110,7 +110,6 @@ public class SmaliBuilder {
|
|||||||
|
|
||||||
private DexFileBuilder mDexBuilder;
|
private DexFileBuilder mDexBuilder;
|
||||||
|
|
||||||
|
private final static Logger LOGGER = Logger.getLogger(SmaliBuilder.class
|
||||||
private final static Logger LOGGER =
|
.getName());
|
||||||
Logger.getLogger(SmaliBuilder.class.getName());
|
|
||||||
}
|
}
|
||||||
|
@ -29,12 +29,13 @@ import org.jf.dexlib.DexFile;
|
|||||||
*/
|
*/
|
||||||
public class SmaliDecoder {
|
public class SmaliDecoder {
|
||||||
|
|
||||||
public static void decode(File apkFile, File outDir, boolean debug, boolean bakdeb)
|
public static void decode(File apkFile, File outDir, boolean debug,
|
||||||
throws AndrolibException {
|
boolean bakdeb) throws AndrolibException {
|
||||||
new SmaliDecoder(apkFile, outDir, debug, bakdeb).decode();
|
new SmaliDecoder(apkFile, outDir, debug, bakdeb).decode();
|
||||||
}
|
}
|
||||||
|
|
||||||
private SmaliDecoder(File apkFile, File outDir, boolean debug, boolean bakdeb) {
|
private SmaliDecoder(File apkFile, File outDir, boolean debug,
|
||||||
|
boolean bakdeb) {
|
||||||
mApkFile = apkFile;
|
mApkFile = apkFile;
|
||||||
mOutDir = outDir;
|
mOutDir = outDir;
|
||||||
mDebug = debug;
|
mDebug = debug;
|
||||||
@ -47,9 +48,9 @@ public class SmaliDecoder {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
baksmali.disassembleDexFile(mApkFile.getAbsolutePath(),
|
baksmali.disassembleDexFile(mApkFile.getAbsolutePath(),
|
||||||
new DexFile(mApkFile), false, mOutDir.getAbsolutePath(), null,
|
new DexFile(mApkFile), false, mOutDir.getAbsolutePath(),
|
||||||
null, null, false, true, true, mBakDeb, false, false,
|
null, null, null, false, true, true, mBakDeb, false, false,
|
||||||
mDebug ? main.DIFFPRE: 0, false, false, null, false);
|
mDebug ? main.DIFFPRE : 0, false, false, null, false);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new AndrolibException(ex);
|
throw new AndrolibException(ex);
|
||||||
}
|
}
|
||||||
|
@ -51,10 +51,10 @@ public class TypeName {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getName(boolean excludePackage, boolean separateInner) {
|
public String getName(boolean excludePackage, boolean separateInner) {
|
||||||
String name =
|
String name = (package_ == null || excludePackage ? "" : package_ + '.')
|
||||||
(package_ == null || excludePackage ? "" : package_ + '.') +
|
+ type
|
||||||
type +
|
+ (innerType != null ? (separateInner ? '$' : '.') + innerType
|
||||||
(innerType != null ? (separateInner ? '$' : '.') + innerType : "");
|
: "");
|
||||||
for (int i = 0; i < array; i++) {
|
for (int i = 0; i < array; i++) {
|
||||||
name += "[]";
|
name += "[]";
|
||||||
}
|
}
|
||||||
@ -104,8 +104,7 @@ public class TypeName {
|
|||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
Duo<TypeName, Integer> duo = fetchFromInternalName(internal);
|
Duo<TypeName, Integer> duo = fetchFromInternalName(internal);
|
||||||
if (duo.m2 != internal.length()) {
|
if (duo.m2 != internal.length()) {
|
||||||
throw new AndrolibException(
|
throw new AndrolibException("Invalid internal name: " + internal);
|
||||||
"Invalid internal name: " + internal);
|
|
||||||
}
|
}
|
||||||
return duo.m1;
|
return duo.m1;
|
||||||
}
|
}
|
||||||
@ -113,7 +112,7 @@ public class TypeName {
|
|||||||
public static List<TypeName> listFromInternalName(String internal)
|
public static List<TypeName> listFromInternalName(String internal)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
List<TypeName> types = new ArrayList<TypeName>();
|
List<TypeName> types = new ArrayList<TypeName>();
|
||||||
while (! internal.isEmpty()) {
|
while (!internal.isEmpty()) {
|
||||||
Duo<TypeName, Integer> duo = fetchFromInternalName(internal);
|
Duo<TypeName, Integer> duo = fetchFromInternalName(internal);
|
||||||
types.add(duo.m1);
|
types.add(duo.m1);
|
||||||
internal = internal.substring(duo.m2);
|
internal = internal.substring(duo.m2);
|
||||||
@ -129,8 +128,8 @@ public class TypeName {
|
|||||||
boolean isArray = false;
|
boolean isArray = false;
|
||||||
do {
|
do {
|
||||||
if (internal.isEmpty()) {
|
if (internal.isEmpty()) {
|
||||||
throw new AndrolibException(
|
throw new AndrolibException("Invalid internal name: "
|
||||||
"Invalid internal name: " + origInternal);
|
+ origInternal);
|
||||||
}
|
}
|
||||||
isArray = internal.charAt(0) == '[';
|
isArray = internal.charAt(0) == '[';
|
||||||
if (isArray) {
|
if (isArray) {
|
||||||
@ -174,8 +173,8 @@ public class TypeName {
|
|||||||
case 'L':
|
case 'L':
|
||||||
int pos = internal.indexOf(';');
|
int pos = internal.indexOf(';');
|
||||||
if (pos == -1) {
|
if (pos == -1) {
|
||||||
throw new AndrolibException(
|
throw new AndrolibException("Invalid internal name: "
|
||||||
"Invalid internal name: " + origInternal);
|
+ origInternal);
|
||||||
}
|
}
|
||||||
length += pos;
|
length += pos;
|
||||||
internal = internal.substring(1, pos);
|
internal = internal.substring(1, pos);
|
||||||
@ -196,14 +195,13 @@ public class TypeName {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new AndrolibException(
|
throw new AndrolibException("Invalid internal name: "
|
||||||
"Invalid internal name: " + origInternal);
|
+ origInternal);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Duo<TypeName, Integer>(
|
return new Duo<TypeName, Integer>(new TypeName(package_, type,
|
||||||
new TypeName(package_, type, innerType, array), length);
|
innerType, array), length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Boolean mIsFileOwner;
|
private Boolean mIsFileOwner;
|
||||||
}
|
}
|
||||||
|
@ -25,18 +25,17 @@ import java.io.InputStream;
|
|||||||
/**
|
/**
|
||||||
* Little-Endian version of DataInputStream.
|
* Little-Endian version of DataInputStream.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Very similar to DataInputStream except it reads
|
* Very similar to DataInputStream except it reads little-endian instead of
|
||||||
* little-endian instead of big-endian binary data. We can't extend
|
* big-endian binary data. We can't extend DataInputStream directly since it has
|
||||||
* DataInputStream directly since it has only final methods, though
|
* only final methods, though DataInputStream itself is not final. This forces
|
||||||
* DataInputStream itself is not final. This forces us implement
|
* us implement LEDataInputStream with a DataInputStream object, and use wrapper
|
||||||
* LEDataInputStream with a DataInputStream object, and use wrapper methods.
|
* methods.
|
||||||
*
|
*
|
||||||
* @author Roedy Green, Canadian Mind Products
|
* @author Roedy Green, Canadian Mind Products
|
||||||
* @version 1.8 2007-05-24
|
* @version 1.8 2007-05-24
|
||||||
* @since 1998
|
* @since 1998
|
||||||
*/
|
*/
|
||||||
public final class LEDataInputStream implements DataInput
|
public final class LEDataInputStream implements DataInput {
|
||||||
{
|
|
||||||
// ------------------------------ CONSTANTS ------------------------------
|
// ------------------------------ CONSTANTS ------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,8 +43,7 @@ public final class LEDataInputStream implements DataInput
|
|||||||
*
|
*
|
||||||
* @noinspection UnusedDeclaration
|
* @noinspection UnusedDeclaration
|
||||||
*/
|
*/
|
||||||
private static final String EMBEDDED_COPYRIGHT =
|
private static final String EMBEDDED_COPYRIGHT = "copyright (c) 1999-2010 Roedy Green, Canadian Mind Products, http://mindprod.com";
|
||||||
"copyright (c) 1999-2010 Roedy Green, Canadian Mind Products, http://mindprod.com";
|
|
||||||
|
|
||||||
// ------------------------------ FIELDS ------------------------------
|
// ------------------------------ FIELDS ------------------------------
|
||||||
|
|
||||||
@ -69,70 +67,78 @@ public final class LEDataInputStream implements DataInput
|
|||||||
* @noinspection WeakerAccess
|
* @noinspection WeakerAccess
|
||||||
*/
|
*/
|
||||||
protected final byte[] work;
|
protected final byte[] work;
|
||||||
// -------------------------- PUBLIC STATIC METHODS --------------------------
|
|
||||||
|
// -------------------------- PUBLIC STATIC METHODS
|
||||||
|
// --------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note. This is a STATIC method!
|
* Note. This is a STATIC method!
|
||||||
*
|
*
|
||||||
* @param in stream to read UTF chars from (endian irrelevant)
|
* @param in
|
||||||
|
* stream to read UTF chars from (endian irrelevant)
|
||||||
*
|
*
|
||||||
* @return string from stream
|
* @return string from stream
|
||||||
* @throws IOException if read fails.
|
* @throws IOException
|
||||||
|
* if read fails.
|
||||||
*/
|
*/
|
||||||
public static String readUTF( DataInput in ) throws IOException
|
public static String readUTF(DataInput in) throws IOException {
|
||||||
{
|
return DataInputStream.readUTF(in);
|
||||||
return DataInputStream.readUTF( in );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------- PUBLIC INSTANCE METHODS --------------------------
|
// -------------------------- PUBLIC INSTANCE METHODS
|
||||||
|
// --------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* constructor.
|
* constructor.
|
||||||
*
|
*
|
||||||
* @param in binary inputstream of little-endian data.
|
* @param in
|
||||||
|
* binary inputstream of little-endian data.
|
||||||
*/
|
*/
|
||||||
public LEDataInputStream( InputStream in )
|
public LEDataInputStream(InputStream in) {
|
||||||
{
|
|
||||||
this.is = in;
|
this.is = in;
|
||||||
this.dis = new DataInputStream( in );
|
this.dis = new DataInputStream(in);
|
||||||
work = new byte[8];
|
work = new byte[8];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* close.
|
* close.
|
||||||
*
|
*
|
||||||
* @throws IOException if close fails.
|
* @throws IOException
|
||||||
|
* if close fails.
|
||||||
*/
|
*/
|
||||||
public final void close() throws IOException
|
public final void close() throws IOException {
|
||||||
{
|
|
||||||
dis.close();
|
dis.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read bytes. Watch out, read may return fewer bytes than requested.
|
* Read bytes. Watch out, read may return fewer bytes than requested.
|
||||||
*
|
*
|
||||||
* @param ba where the bytes go.
|
* @param ba
|
||||||
* @param off offset in buffer, not offset in file.
|
* where the bytes go.
|
||||||
* @param len count of bytes to read.
|
* @param off
|
||||||
|
* offset in buffer, not offset in file.
|
||||||
|
* @param len
|
||||||
|
* count of bytes to read.
|
||||||
*
|
*
|
||||||
* @return how many bytes read.
|
* @return how many bytes read.
|
||||||
* @throws IOException if read fails.
|
* @throws IOException
|
||||||
|
* if read fails.
|
||||||
*/
|
*/
|
||||||
public final int read( byte ba[], int off, int len ) throws IOException
|
public final int read(byte ba[], int off, int len) throws IOException {
|
||||||
{
|
|
||||||
// For efficiency, we avoid one layer of wrapper
|
// For efficiency, we avoid one layer of wrapper
|
||||||
return is.read( ba, off, len );
|
return is.read(ba, off, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* read only a one-byte boolean.
|
* read only a one-byte boolean.
|
||||||
*
|
*
|
||||||
* @return true or false.
|
* @return true or false.
|
||||||
* @throws IOException if read fails.
|
* @throws IOException
|
||||||
|
* if read fails.
|
||||||
* @see java.io.DataInput#readBoolean()
|
* @see java.io.DataInput#readBoolean()
|
||||||
*/
|
*/
|
||||||
public final boolean readBoolean() throws IOException
|
@Override
|
||||||
{
|
public final boolean readBoolean() throws IOException {
|
||||||
return dis.readBoolean();
|
return dis.readBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,11 +146,12 @@ public final class LEDataInputStream implements DataInput
|
|||||||
* read byte.
|
* read byte.
|
||||||
*
|
*
|
||||||
* @return the byte read.
|
* @return the byte read.
|
||||||
* @throws IOException if read fails.
|
* @throws IOException
|
||||||
|
* if read fails.
|
||||||
* @see java.io.DataInput#readByte()
|
* @see java.io.DataInput#readByte()
|
||||||
*/
|
*/
|
||||||
public final byte readByte() throws IOException
|
@Override
|
||||||
{
|
public final byte readByte() throws IOException {
|
||||||
return dis.readByte();
|
return dis.readByte();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,12 +159,13 @@ public final class LEDataInputStream implements DataInput
|
|||||||
* Read on char. like DataInputStream.readChar except little endian.
|
* Read on char. like DataInputStream.readChar except little endian.
|
||||||
*
|
*
|
||||||
* @return little endian 16-bit unicode char from the stream.
|
* @return little endian 16-bit unicode char from the stream.
|
||||||
* @throws IOException if read fails.
|
* @throws IOException
|
||||||
|
* if read fails.
|
||||||
*/
|
*/
|
||||||
public final char readChar() throws IOException
|
@Override
|
||||||
{
|
public final char readChar() throws IOException {
|
||||||
dis.readFully( work, 0, 2 );
|
dis.readFully(work, 0, 2);
|
||||||
return ( char ) ( ( work[ 1 ] & 0xff ) << 8 | ( work[ 0 ] & 0xff ) );
|
return (char) ((work[1] & 0xff) << 8 | (work[0] & 0xff));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -166,20 +174,21 @@ public final class LEDataInputStream implements DataInput
|
|||||||
* @return little endian IEEE double from the datastream.
|
* @return little endian IEEE double from the datastream.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public final double readDouble() throws IOException
|
@Override
|
||||||
{
|
public final double readDouble() throws IOException {
|
||||||
return Double.longBitsToDouble( readLong() );
|
return Double.longBitsToDouble(readLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read one float. Like DataInputStream.readFloat except little endian.
|
* Read one float. Like DataInputStream.readFloat except little endian.
|
||||||
*
|
*
|
||||||
* @return little endian IEEE float from the datastream.
|
* @return little endian IEEE float from the datastream.
|
||||||
* @throws IOException if read fails.
|
* @throws IOException
|
||||||
|
* if read fails.
|
||||||
*/
|
*/
|
||||||
public final float readFloat() throws IOException
|
@Override
|
||||||
{
|
public final float readFloat() throws IOException {
|
||||||
return Float.intBitsToFloat( readInt() );
|
return Float.intBitsToFloat(readInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -187,50 +196,50 @@ public final class LEDataInputStream implements DataInput
|
|||||||
*
|
*
|
||||||
* @see java.io.DataInput#readFully(byte[])
|
* @see java.io.DataInput#readFully(byte[])
|
||||||
*/
|
*/
|
||||||
public final void readFully( byte ba[] ) throws IOException
|
@Override
|
||||||
{
|
public final void readFully(byte ba[]) throws IOException {
|
||||||
dis.readFully( ba, 0, ba.length );
|
dis.readFully(ba, 0, ba.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read bytes until the count is satisfied.
|
* Read bytes until the count is satisfied.
|
||||||
*
|
*
|
||||||
* @throws IOException if read fails.
|
* @throws IOException
|
||||||
|
* if read fails.
|
||||||
* @see java.io.DataInput#readFully(byte[],int,int)
|
* @see java.io.DataInput#readFully(byte[],int,int)
|
||||||
*/
|
*/
|
||||||
public final void readFully( byte ba[],
|
@Override
|
||||||
int off,
|
public final void readFully(byte ba[], int off, int len) throws IOException {
|
||||||
int len ) throws IOException
|
dis.readFully(ba, off, len);
|
||||||
{
|
|
||||||
dis.readFully( ba, off, len );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read an int, 32-bits. Like DataInputStream.readInt except little endian.
|
* Read an int, 32-bits. Like DataInputStream.readInt except little endian.
|
||||||
*
|
*
|
||||||
* @return little-endian binary int from the datastream
|
* @return little-endian binary int from the datastream
|
||||||
* @throws IOException if read fails.
|
* @throws IOException
|
||||||
|
* if read fails.
|
||||||
*/
|
*/
|
||||||
public final int readInt() throws IOException
|
@Override
|
||||||
{
|
public final int readInt() throws IOException {
|
||||||
dis.readFully( work, 0, 4 );
|
dis.readFully(work, 0, 4);
|
||||||
return ( work[ 3 ] ) << 24
|
return (work[3]) << 24 | (work[2] & 0xff) << 16 | (work[1] & 0xff) << 8
|
||||||
| ( work[ 2 ] & 0xff ) << 16
|
| (work[0] & 0xff);
|
||||||
| ( work[ 1 ] & 0xff ) << 8
|
|
||||||
| ( work[ 0 ] & 0xff );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read a line.
|
* Read a line.
|
||||||
*
|
*
|
||||||
* @return a rough approximation of the 8-bit stream as a 16-bit unicode string
|
* @return a rough approximation of the 8-bit stream as a 16-bit unicode
|
||||||
|
* string
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @noinspection deprecation
|
* @noinspection deprecation
|
||||||
* @deprecated This method does not properly convert bytes to characters. Use a Reader instead with a little-endian
|
* @deprecated This method does not properly convert bytes to characters.
|
||||||
* encoding.
|
* Use a Reader instead with a little-endian encoding.
|
||||||
*/
|
*/
|
||||||
public final String readLine() throws IOException
|
@Deprecated
|
||||||
{
|
@Override
|
||||||
|
public final String readLine() throws IOException {
|
||||||
return dis.readLine();
|
return dis.readLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,31 +249,28 @@ public final class LEDataInputStream implements DataInput
|
|||||||
* @return little-endian binary long from the datastream.
|
* @return little-endian binary long from the datastream.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public final long readLong() throws IOException
|
@Override
|
||||||
{
|
public final long readLong() throws IOException {
|
||||||
dis.readFully( work, 0, 8 );
|
dis.readFully(work, 0, 8);
|
||||||
return ( long ) ( work[ 7 ] ) << 56
|
return (long) (work[7]) << 56 |
|
||||||
|
|
|
||||||
/* long cast needed or shift done modulo 32 */
|
/* long cast needed or shift done modulo 32 */
|
||||||
( long ) ( work[ 6 ] & 0xff ) << 48
|
(long) (work[6] & 0xff) << 48 | (long) (work[5] & 0xff) << 40
|
||||||
| ( long ) ( work[ 5 ] & 0xff ) << 40
|
| (long) (work[4] & 0xff) << 32 | (long) (work[3] & 0xff) << 24
|
||||||
| ( long ) ( work[ 4 ] & 0xff ) << 32
|
| (long) (work[2] & 0xff) << 16 | (long) (work[1] & 0xff) << 8
|
||||||
| ( long ) ( work[ 3 ] & 0xff ) << 24
|
| work[0] & 0xff;
|
||||||
| ( long ) ( work[ 2 ] & 0xff ) << 16
|
|
||||||
| ( long ) ( work[ 1 ] & 0xff ) << 8
|
|
||||||
| ( long ) ( work[ 0 ] & 0xff );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read short, 16-bits. Like DataInputStream.readShort except little endian.
|
* Read short, 16-bits. Like DataInputStream.readShort except little endian.
|
||||||
*
|
*
|
||||||
* @return little endian binary short from stream.
|
* @return little endian binary short from stream.
|
||||||
* @throws IOException if read fails.
|
* @throws IOException
|
||||||
|
* if read fails.
|
||||||
*/
|
*/
|
||||||
public final short readShort() throws IOException
|
@Override
|
||||||
{
|
public final short readShort() throws IOException {
|
||||||
dis.readFully( work, 0, 2 );
|
dis.readFully(work, 0, 2);
|
||||||
return ( short ) ( ( work[ 1 ] & 0xff ) << 8 | ( work[ 0 ] & 0xff ) );
|
return (short) ((work[1] & 0xff) << 8 | (work[0] & 0xff));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -272,48 +278,53 @@ public final class LEDataInputStream implements DataInput
|
|||||||
*
|
*
|
||||||
* @return String read.
|
* @return String read.
|
||||||
*/
|
*/
|
||||||
public final String readUTF() throws IOException
|
@Override
|
||||||
{
|
public final String readUTF() throws IOException {
|
||||||
return dis.readUTF();
|
return dis.readUTF();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read an unsigned byte. Note: returns an int, even though says Byte (non-Javadoc)
|
* Read an unsigned byte. Note: returns an int, even though says Byte
|
||||||
|
* (non-Javadoc)
|
||||||
*
|
*
|
||||||
* @throws IOException if read fails.
|
* @throws IOException
|
||||||
|
* if read fails.
|
||||||
* @see java.io.DataInput#readUnsignedByte()
|
* @see java.io.DataInput#readUnsignedByte()
|
||||||
*/
|
*/
|
||||||
public final int readUnsignedByte() throws IOException
|
@Override
|
||||||
{
|
public final int readUnsignedByte() throws IOException {
|
||||||
return dis.readUnsignedByte();
|
return dis.readUnsignedByte();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read an unsigned short, 16 bits. Like DataInputStream.readUnsignedShort except little endian. Note, returns int
|
* Read an unsigned short, 16 bits. Like DataInputStream.readUnsignedShort
|
||||||
* even though it reads a short.
|
* except little endian. Note, returns int even though it reads a short.
|
||||||
*
|
*
|
||||||
* @return little-endian int from the stream.
|
* @return little-endian int from the stream.
|
||||||
* @throws IOException if read fails.
|
* @throws IOException
|
||||||
|
* if read fails.
|
||||||
*/
|
*/
|
||||||
public final int readUnsignedShort() throws IOException
|
@Override
|
||||||
{
|
public final int readUnsignedShort() throws IOException {
|
||||||
dis.readFully( work, 0, 2 );
|
dis.readFully(work, 0, 2);
|
||||||
return ( ( work[ 1 ] & 0xff ) << 8 | ( work[ 0 ] & 0xff ) );
|
return ((work[1] & 0xff) << 8 | (work[0] & 0xff));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Skip over bytes in the stream. See the general contract of the <code>skipBytes</code> method of
|
* Skip over bytes in the stream. See the general contract of the
|
||||||
* <code>DataInput</code>.
|
* <code>skipBytes</code> method of <code>DataInput</code>.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Bytes for this operation are read from the contained input stream.
|
* Bytes for this operation are read from the contained input stream.
|
||||||
*
|
*
|
||||||
* @param n the number of bytes to be skipped.
|
* @param n
|
||||||
|
* the number of bytes to be skipped.
|
||||||
*
|
*
|
||||||
* @return the actual number of bytes skipped.
|
* @return the actual number of bytes skipped.
|
||||||
* @throws IOException if an I/O error occurs.
|
* @throws IOException
|
||||||
|
* if an I/O error occurs.
|
||||||
*/
|
*/
|
||||||
public final int skipBytes( int n ) throws IOException
|
@Override
|
||||||
{
|
public final int skipBytes(int n) throws IOException {
|
||||||
return dis.skipBytes( n );
|
return dis.skipBytes(n);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -26,7 +26,6 @@ import org.junit.*;
|
|||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||||
*/
|
*/
|
||||||
@ -52,14 +51,14 @@ public class BuildAndDecodeTest {
|
|||||||
assertEquals(true, isAaptPresent());
|
assertEquals(true, isAaptPresent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void encodeAndDecodeTest() throws BrutException, IOException {
|
public void encodeAndDecodeTest() throws BrutException, IOException {
|
||||||
|
|
||||||
LOGGER.info("Building testapp.apk...");
|
LOGGER.info("Building testapp.apk...");
|
||||||
File testApk = new File(sTmpDir, "testapp.apk");
|
File testApk = new File(sTmpDir, "testapp.apk");
|
||||||
ExtFile blank = null;
|
ExtFile blank = null;
|
||||||
new Androlib().build(sTestOrigDir, testApk, BuildAndDecodeTest.returnStock(),blank,"");
|
new Androlib().build(sTestOrigDir, testApk,
|
||||||
|
BuildAndDecodeTest.returnStock(), blank, "");
|
||||||
|
|
||||||
LOGGER.info("Decoding testapp.apk...");
|
LOGGER.info("Decoding testapp.apk...");
|
||||||
ApkDecoder apkDecoder = new ApkDecoder(testApk);
|
ApkDecoder apkDecoder = new ApkDecoder(testApk);
|
||||||
@ -67,7 +66,6 @@ public class BuildAndDecodeTest {
|
|||||||
apkDecoder.decode();
|
apkDecoder.decode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void valuesArraysTest() throws BrutException {
|
public void valuesArraysTest() throws BrutException {
|
||||||
compareValuesFiles("values-mcc001/arrays.xml");
|
compareValuesFiles("values-mcc001/arrays.xml");
|
||||||
@ -128,40 +126,40 @@ public class BuildAndDecodeTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void qualifiersTest() throws BrutException {
|
public void qualifiersTest() throws BrutException {
|
||||||
compareValuesFiles("values-mcc004-mnc4-en-rUS-ldrtl-sw100dp-w200dp-h300dp" +
|
compareValuesFiles("values-mcc004-mnc4-en-rUS-ldrtl-sw100dp-w200dp-h300dp"
|
||||||
"-xlarge-long-land-desk-night-xhdpi-finger-keyssoft-12key" +
|
+ "-xlarge-long-land-desk-night-xhdpi-finger-keyssoft-12key"
|
||||||
"-navhidden-dpad/strings.xml");
|
+ "-navhidden-dpad/strings.xml");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isAaptPresent() throws Exception {
|
private static boolean isAaptPresent() throws Exception {
|
||||||
boolean result = true;
|
boolean result = true;
|
||||||
try
|
try {
|
||||||
{
|
|
||||||
Process proc = Runtime.getRuntime().exec("aapt");
|
Process proc = Runtime.getRuntime().exec("aapt");
|
||||||
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
|
BufferedReader br = new BufferedReader(new InputStreamReader(
|
||||||
|
proc.getErrorStream()));
|
||||||
String line = null;
|
String line = null;
|
||||||
while ( (line = br.readLine()) != null){}
|
while ((line = br.readLine()) != null) {
|
||||||
} catch (Exception ex){
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void compareValuesFiles(String path) throws BrutException {
|
private void compareValuesFiles(String path) throws BrutException {
|
||||||
compareXmlFiles("res/" + path,
|
compareXmlFiles("res/" + path, new ElementNameAndAttributeQualifier(
|
||||||
new ElementNameAndAttributeQualifier("name"));
|
"name"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void compareXmlFiles(String path) throws BrutException {
|
private void compareXmlFiles(String path) throws BrutException {
|
||||||
compareXmlFiles(path, null);
|
compareXmlFiles(path, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void compareXmlFiles(String path,
|
private void compareXmlFiles(String path, ElementQualifier qualifier)
|
||||||
ElementQualifier qualifier) throws BrutException {
|
throws BrutException {
|
||||||
DetailedDiff diff;
|
DetailedDiff diff;
|
||||||
try {
|
try {
|
||||||
Reader control = new FileReader(
|
Reader control = new FileReader(new File(sTestOrigDir, path));
|
||||||
new File(sTestOrigDir, path));
|
|
||||||
Reader test = new FileReader(new File(sTestNewDir, path));
|
Reader test = new FileReader(new File(sTestNewDir, path));
|
||||||
|
|
||||||
diff = new DetailedDiff(new Diff(control, test));
|
diff = new DetailedDiff(new Diff(control, test));
|
||||||
@ -175,8 +173,8 @@ public class BuildAndDecodeTest {
|
|||||||
diff.overrideElementQualifier(qualifier);
|
diff.overrideElementQualifier(qualifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue(path + ": " +
|
assertTrue(path + ": " + diff.getAllDifferences().toString(),
|
||||||
diff.getAllDifferences().toString(), diff.similar());
|
diff.similar());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HashMap<String, Boolean> returnStock() throws BrutException {
|
private static HashMap<String, Boolean> returnStock() throws BrutException {
|
||||||
@ -195,6 +193,6 @@ public class BuildAndDecodeTest {
|
|||||||
private static ExtFile sTestOrigDir;
|
private static ExtFile sTestOrigDir;
|
||||||
private static ExtFile sTestNewDir;
|
private static ExtFile sTestNewDir;
|
||||||
|
|
||||||
private final static Logger LOGGER =
|
private final static Logger LOGGER = Logger
|
||||||
Logger.getLogger(BuildAndDecodeTest.class.getName());
|
.getLogger(BuildAndDecodeTest.class.getName());
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2011 Ryszard Wiśniewski <brut.alll@gmail.com>
|
* Copyright 2011 Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -35,7 +35,8 @@ public abstract class TestUtils {
|
|||||||
public static Map<String, String> parseStringsXml(File file)
|
public static Map<String, String> parseStringsXml(File file)
|
||||||
throws BrutException {
|
throws BrutException {
|
||||||
try {
|
try {
|
||||||
XmlPullParser xpp = XmlPullParserFactory.newInstance().newPullParser();
|
XmlPullParser xpp = XmlPullParserFactory.newInstance()
|
||||||
|
.newPullParser();
|
||||||
xpp.setInput(new FileReader(file));
|
xpp.setInput(new FileReader(file));
|
||||||
|
|
||||||
int eventType;
|
int eventType;
|
||||||
@ -75,13 +76,14 @@ public abstract class TestUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: move to brut.util.Jar - it's not possible for now, because below
|
/*
|
||||||
|
* TODO: move to brut.util.Jar - it's not possible for now, because below
|
||||||
* implementation uses brut.dir. I think I should merge all my projects to
|
* implementation uses brut.dir. I think I should merge all my projects to
|
||||||
* single brut.common .
|
* single brut.common .
|
||||||
*/
|
*/
|
||||||
public static void copyResourceDir(Class class_, String dirPath, File out)
|
public static void copyResourceDir(Class class_, String dirPath, File out)
|
||||||
throws BrutException {
|
throws BrutException {
|
||||||
if (! out.exists()) {
|
if (!out.exists()) {
|
||||||
out.mkdirs();
|
out.mkdirs();
|
||||||
}
|
}
|
||||||
copyResourceDir(class_, dirPath, new FileDirectory(out));
|
copyResourceDir(class_, dirPath, new FileDirectory(out));
|
||||||
@ -104,12 +106,12 @@ public abstract class TestUtils {
|
|||||||
dirURL = class_.getClassLoader().getResource(className);
|
dirURL = class_.getClassLoader().getResource(className);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (dirURL.getProtocol().equals("jar")) {
|
if (dirURL.getProtocol().equals("jar")) {
|
||||||
String jarPath;
|
String jarPath;
|
||||||
try {
|
try {
|
||||||
jarPath = URLDecoder.decode(dirURL.getPath().substring(
|
jarPath = URLDecoder.decode(
|
||||||
5, dirURL.getPath().indexOf("!")), "UTF-8");
|
dirURL.getPath().substring(5,
|
||||||
|
dirURL.getPath().indexOf("!")), "UTF-8");
|
||||||
} catch (UnsupportedEncodingException ex) {
|
} catch (UnsupportedEncodingException ex) {
|
||||||
throw new BrutException(ex);
|
throw new BrutException(ex);
|
||||||
}
|
}
|
||||||
@ -117,9 +119,9 @@ public abstract class TestUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class ResValueElementQualifier implements ElementQualifier {
|
public static class ResValueElementQualifier implements ElementQualifier {
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean qualifyForComparison(Element control, Element test) {
|
public boolean qualifyForComparison(Element control, Element test) {
|
||||||
String controlType = control.getTagName();
|
String controlType = control.getTagName();
|
||||||
if ("item".equals(controlType)) {
|
if ("item".equals(controlType)) {
|
||||||
@ -131,8 +133,9 @@ public abstract class TestUtils {
|
|||||||
testType = test.getAttribute("type");
|
testType = test.getAttribute("type");
|
||||||
}
|
}
|
||||||
|
|
||||||
return controlType.equals(testType) && control.getAttribute("name")
|
return controlType.equals(testType)
|
||||||
.equals(test.getAttribute("name"));
|
&& control.getAttribute("name").equals(
|
||||||
|
test.getAttribute("name"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user