mirror of
https://github.com/revanced/Apktool.git
synced 2024-12-12 05:47:46 +01:00
Merged in "yyj" fixes along with a few of my own. 95% yyj work :)
This commit is contained in:
parent
e9738642b2
commit
282bdae126
@ -211,8 +211,9 @@ public class Main {
|
||||
System.out.println(
|
||||
"Apktool v" + Androlib.getVersion() + " - a tool for reengineering Android apk files\n" +
|
||||
"Copyright 2010 Ryszard Wiśniewski <brut.alll@gmail.com>\n" +
|
||||
"with baksmali/smali " + smaliVersion + " (http://smali.googlecode.com)\n" +
|
||||
"Updated by iBotPeaches (@iBotPeaches) \n" +
|
||||
"with smali v" + ApktoolProperties.get("smaliVersion") +
|
||||
", and baksmali v" + ApktoolProperties.get("baksmaliVersion") + "\n" +
|
||||
"Updated by iBotPeaches (@iBotPeaches) and yyj \n" +
|
||||
"Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)\n" +
|
||||
"\n" +
|
||||
"Usage: apktool [-q|--quiet OR -v|--verbose] COMMAND [...]\n" +
|
||||
|
@ -44,8 +44,6 @@ public class TypedValue {
|
||||
* of a container. */
|
||||
public static final int TYPE_FRACTION = 0x06;
|
||||
|
||||
public static final int TYPE_LAYOUT = 0x07;
|
||||
|
||||
/** Identifies the start of plain integer values. Any type value
|
||||
* from this to {@link #TYPE_LAST_INT} means the
|
||||
* <var>data</var> field holds a generic integer value. */
|
||||
@ -224,13 +222,42 @@ public class TypedValue {
|
||||
}
|
||||
|
||||
if (type >= TYPE_FIRST_COLOR_INT && type <= TYPE_LAST_COLOR_INT) {
|
||||
return "#" + Integer.toHexString(data);
|
||||
String res =String.format("%08x", data);
|
||||
char[] vals = res.toCharArray();
|
||||
switch (type) {
|
||||
default:
|
||||
case TYPE_INT_COLOR_ARGB8://#AaRrGgBb
|
||||
break;
|
||||
case TYPE_INT_COLOR_RGB8://#FFRrGgBb->#RrGgBb
|
||||
res = res.substring(2);
|
||||
break;
|
||||
case TYPE_INT_COLOR_ARGB4://#AARRGGBB->#ARGB
|
||||
res = new StringBuffer().append(vals[0]).append(vals[2]).append(vals[4]).append(vals[6]).toString();
|
||||
break;
|
||||
case TYPE_INT_COLOR_RGB4://#FFRRGGBB->#RGB
|
||||
res = new StringBuffer().append(vals[2]).append(vals[4]).append(vals[6]).toString();
|
||||
break;
|
||||
}
|
||||
return "#" + res;
|
||||
} else if (type >= TYPE_FIRST_INT && type <= TYPE_LAST_INT) {
|
||||
return Integer.toString(data);
|
||||
String res;
|
||||
switch (type) {
|
||||
default:
|
||||
case TYPE_INT_DEC:
|
||||
res = Integer.toString(data);
|
||||
break;
|
||||
//defined before
|
||||
/*case TYPE_INT_HEX:
|
||||
res = "0x" + Integer.toHexString(data);
|
||||
break;
|
||||
case TYPE_INT_BOOLEAN:
|
||||
res = (data != 0) ? "true":"false";
|
||||
break;*/
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
@ -24,8 +24,7 @@ import brut.androlib.res.util.ExtFile;
|
||||
import brut.androlib.src.SmaliBuilder;
|
||||
import brut.androlib.src.SmaliDecoder;
|
||||
import brut.common.BrutException;
|
||||
import brut.directory.Directory;
|
||||
import brut.directory.DirectoryException;
|
||||
import brut.directory.*;
|
||||
import brut.util.BrutIO;
|
||||
import brut.util.OS;
|
||||
import java.io.*;
|
||||
@ -42,7 +41,11 @@ public class Androlib {
|
||||
private final AndrolibResources mAndRes = new AndrolibResources();
|
||||
|
||||
public ResTable getResTable(ExtFile apkFile) throws AndrolibException {
|
||||
return mAndRes.getResTable(apkFile);
|
||||
return mAndRes.getResTable(apkFile, true);
|
||||
}
|
||||
|
||||
public ResTable getResTable(ExtFile apkFile, boolean loadMainPkg) throws AndrolibException {
|
||||
return mAndRes.getResTable(apkFile, loadMainPkg);
|
||||
}
|
||||
|
||||
public void decodeSourcesRaw(ExtFile apkFile, File outDir, boolean debug)
|
||||
@ -78,6 +81,22 @@ public class Androlib {
|
||||
new AndrolibJava().decode(apkFile, outDir);
|
||||
}
|
||||
|
||||
public void decodeManifestRaw(ExtFile apkFile, File outDir)
|
||||
throws AndrolibException {
|
||||
try {
|
||||
Directory apk = apkFile.getDirectory();
|
||||
LOGGER.info("Copying raw manifest...");
|
||||
apkFile.getDirectory().copyToDir(outDir, APK_MANIFEST_FILENAMES);
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void decodeManifestFull(ExtFile apkFile, File outDir,
|
||||
ResTable resTable) throws AndrolibException {
|
||||
mAndRes.decodeManifest(resTable, apkFile, outDir);
|
||||
}
|
||||
|
||||
public void decodeResourcesRaw(ExtFile apkFile, File outDir)
|
||||
throws AndrolibException {
|
||||
try {
|
||||
@ -248,6 +267,8 @@ public class Androlib {
|
||||
throws AndrolibException {
|
||||
if (! buildResourcesRaw(appDir, forceBuildAll)
|
||||
&& ! buildResourcesFull(appDir, forceBuildAll, framework,
|
||||
usesFramework)
|
||||
&& ! buildManifest(appDir, forceBuildAll, framework,
|
||||
usesFramework)) {
|
||||
LOGGER.warning("Could not find resources");
|
||||
}
|
||||
@ -320,6 +341,65 @@ public class Androlib {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean buildManifestRaw(ExtFile appDir, boolean forceBuildAll)
|
||||
throws AndrolibException {
|
||||
try {
|
||||
File apkDir = new File(appDir, APK_DIRNAME);
|
||||
LOGGER.info("Copying raw AndroidManifest.xml...");
|
||||
appDir.getDirectory()
|
||||
.copyToDir(apkDir, APK_MANIFEST_FILENAMES);
|
||||
return true;
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean buildManifest(ExtFile appDir, boolean forceBuildAll,
|
||||
boolean framework, Map<String, Object> usesFramework)
|
||||
throws AndrolibException {
|
||||
try {
|
||||
if (! new File(appDir, "AndroidManifest.xml").exists()) {
|
||||
return false;
|
||||
}
|
||||
if (! forceBuildAll) {
|
||||
LOGGER.info("Checking whether resources has changed...");
|
||||
}
|
||||
File apkDir = new File(appDir, APK_DIRNAME);
|
||||
if (forceBuildAll || isModified(
|
||||
newFiles(APK_MANIFEST_FILENAMES, appDir),
|
||||
newFiles(APK_MANIFEST_FILENAMES, apkDir))) {
|
||||
LOGGER.info("Building AndroidManifest.xml...");
|
||||
|
||||
File apkFile = File.createTempFile("APKTOOL", null);
|
||||
apkFile.delete();
|
||||
|
||||
File ninePatch = new File(appDir, "9patch");
|
||||
if (! ninePatch.exists()) {
|
||||
ninePatch = null;
|
||||
}
|
||||
|
||||
mAndRes.aaptPackage(
|
||||
apkFile,
|
||||
new File(appDir, "AndroidManifest.xml"),
|
||||
null,
|
||||
ninePatch, null, parseUsesFramework(usesFramework),
|
||||
false, framework
|
||||
);
|
||||
|
||||
Directory tmpDir = new ExtFile(apkFile).getDirectory();
|
||||
tmpDir.copyToDir(apkDir, APK_MANIFEST_FILENAMES);
|
||||
}
|
||||
return true;
|
||||
} catch (IOException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
} catch (AndrolibException ex) {
|
||||
LOGGER.warning("Parse AndroidManifest.xml failed, treat it as raw file.");
|
||||
return buildManifestRaw(appDir, forceBuildAll);
|
||||
}
|
||||
}
|
||||
|
||||
public void buildLib(File appDir, boolean forceBuildAll)
|
||||
throws AndrolibException {
|
||||
File working = new File(appDir, "lib");
|
||||
@ -441,4 +521,6 @@ public class Androlib {
|
||||
new String[]{"resources.arsc", "AndroidManifest.xml"};
|
||||
private final static String[] APP_RESOURCES_FILENAMES =
|
||||
new String[]{"AndroidManifest.xml", "res"};
|
||||
private final static String[] APK_MANIFEST_FILENAMES =
|
||||
new String[]{"AndroidManifest.xml"};
|
||||
}
|
@ -26,10 +26,7 @@ import brut.common.BrutException;
|
||||
import brut.directory.DirectoryException;
|
||||
import brut.util.OS;
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||
@ -92,6 +89,7 @@ public class ApkDecoder {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasResources()) {
|
||||
switch (mDecodeResources) {
|
||||
case DECODE_RESOURCES_NONE:
|
||||
@ -102,7 +100,22 @@ public class ApkDecoder {
|
||||
getResTable());
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// if there's no resources.asrc, decode the manifest without looking up
|
||||
// attribute references
|
||||
if (hasManifest()) {
|
||||
switch (mDecodeResources) {
|
||||
case DECODE_RESOURCES_NONE:
|
||||
mAndrolib.decodeManifestRaw(mApkFile, outDir);
|
||||
break;
|
||||
case DECODE_RESOURCES_FULL:
|
||||
mAndrolib.decodeManifestFull(mApkFile, outDir,
|
||||
getResTable());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mAndrolib.decodeRawFiles(mApkFile, outDir);
|
||||
writeMetaFile();
|
||||
}
|
||||
@ -143,12 +156,14 @@ public class ApkDecoder {
|
||||
|
||||
public ResTable getResTable() throws AndrolibException {
|
||||
if (mResTable == null) {
|
||||
if (! hasResources()) {
|
||||
boolean hasResources = hasResources();
|
||||
boolean hasManifest = hasManifest();
|
||||
if (! (hasManifest || hasResources)) {
|
||||
throw new AndrolibException(
|
||||
"Apk doesn't containt resources.arsc file");
|
||||
"Apk doesn't contain either AndroidManifest.xml file or resources.arsc file");
|
||||
}
|
||||
AndrolibResources.sKeepBroken = mKeepBrokenResources;
|
||||
mResTable = mAndrolib.getResTable(mApkFile);
|
||||
mResTable = mAndrolib.getResTable(mApkFile, hasResources);
|
||||
mResTable.setFrameTag(mFrameTag);
|
||||
}
|
||||
return mResTable;
|
||||
@ -162,6 +177,14 @@ public class ApkDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasManifest() throws AndrolibException {
|
||||
try {
|
||||
return mApkFile.getDirectory().containsFile("AndroidManifest.xml");
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasResources() throws AndrolibException {
|
||||
try {
|
||||
return mApkFile.getDirectory().containsFile("resources.arsc");
|
||||
@ -190,7 +213,7 @@ public class ApkDecoder {
|
||||
meta.put("version", Androlib.getVersion());
|
||||
meta.put("apkFileName", mApkFile.getName());
|
||||
|
||||
if (mDecodeResources != DECODE_RESOURCES_NONE && hasResources()) {
|
||||
if (mDecodeResources != DECODE_RESOURCES_NONE && (hasManifest() || hasResources())) {
|
||||
meta.put("isFrameworkApk",
|
||||
Boolean.valueOf(mAndrolib.isFrameworkApk(getResTable())));
|
||||
putUsesFramework(meta);
|
||||
|
@ -21,6 +21,9 @@ import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jf.baksmali.baksmali;
|
||||
import org.jf.smali.main;
|
||||
|
||||
/**
|
||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||
*/
|
||||
@ -46,6 +49,25 @@ public class ApktoolProperties {
|
||||
} catch (IOException ex) {
|
||||
LOGGER.warning("Can't load properties.");
|
||||
}
|
||||
|
||||
InputStream templateStream = baksmali.class.getClassLoader().getResourceAsStream("baksmali.properties");
|
||||
Properties properties = new Properties();
|
||||
String version = "(unknown)";
|
||||
try {
|
||||
properties.load(templateStream);
|
||||
version = properties.getProperty("application.version");
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
sProps.put("baksmaliVersion", version);
|
||||
templateStream = main.class.getClassLoader().getResourceAsStream("smali.properties");
|
||||
properties = new Properties();
|
||||
version = "(unknown)";
|
||||
try {
|
||||
properties.load(templateStream);
|
||||
version = properties.getProperty("application.version");
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
sProps.put("smaliVersion", version);
|
||||
}
|
||||
|
||||
private static Properties sProps;
|
||||
|
@ -39,8 +39,14 @@ import org.xmlpull.v1.XmlSerializer;
|
||||
*/
|
||||
final public class AndrolibResources {
|
||||
public ResTable getResTable(ExtFile apkFile) throws AndrolibException {
|
||||
return getResTable(apkFile, true);
|
||||
}
|
||||
|
||||
public ResTable getResTable(ExtFile apkFile, boolean loadMainPkg) throws AndrolibException {
|
||||
ResTable resTable = new ResTable(this);
|
||||
loadMainPkg(resTable, apkFile);
|
||||
if (loadMainPkg) {
|
||||
loadMainPkg(resTable, apkFile);
|
||||
}
|
||||
return resTable;
|
||||
}
|
||||
|
||||
@ -97,6 +103,36 @@ final public class AndrolibResources {
|
||||
return pkg;
|
||||
}
|
||||
|
||||
public void decodeManifest(ResTable resTable, ExtFile apkFile, File outDir)
|
||||
throws AndrolibException {
|
||||
|
||||
Duo<ResFileDecoder, AXmlResourceParser> duo = getManifestFileDecoder();
|
||||
ResFileDecoder fileDecoder = duo.m1;
|
||||
|
||||
|
||||
// Set ResAttrDecoder
|
||||
|
||||
duo.m2.setAttrDecoder(new ResAttrDecoder());
|
||||
|
||||
ResAttrDecoder attrDecoder = duo.m2.getAttrDecoder();
|
||||
// Fake ResPackage
|
||||
attrDecoder.setCurrentPackage(new ResPackage(resTable, 0, null));
|
||||
|
||||
Directory inApk, out;
|
||||
try {
|
||||
inApk = apkFile.getDirectory();
|
||||
out = new FileDirectory(outDir);
|
||||
|
||||
LOGGER.info("Decoding AndroidManifest.xml with only framework resources...");
|
||||
fileDecoder.decode(
|
||||
inApk, "AndroidManifest.xml", out, "AndroidManifest.xml",
|
||||
"xml");
|
||||
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void decode(ResTable resTable, ExtFile apkFile, File outDir)
|
||||
throws AndrolibException {
|
||||
Duo<ResFileDecoder, AXmlResourceParser> duo = getResFileDecoder();
|
||||
@ -111,6 +147,7 @@ final public class AndrolibResources {
|
||||
inApk = apkFile.getDirectory();
|
||||
out = new FileDirectory(outDir);
|
||||
|
||||
LOGGER.info("Decoding AndroidManifest.xml with resources...");
|
||||
fileDecoder.decode(
|
||||
inApk, "AndroidManifest.xml", out, "AndroidManifest.xml",
|
||||
"xml");
|
||||
@ -238,6 +275,19 @@ final public class AndrolibResources {
|
||||
new ResFileDecoder(decoders), axmlParser);
|
||||
}
|
||||
|
||||
public Duo<ResFileDecoder, AXmlResourceParser> getManifestFileDecoder() {
|
||||
ResStreamDecoderContainer decoders =
|
||||
new ResStreamDecoderContainer();
|
||||
|
||||
AXmlResourceParser axmlParser = new AXmlResourceParser();
|
||||
|
||||
decoders.setDecoder("xml",
|
||||
new XmlPullStreamDecoder(axmlParser, getResXmlSerializer()));
|
||||
|
||||
return new Duo<ResFileDecoder, AXmlResourceParser>(
|
||||
new ResFileDecoder(decoders), axmlParser);
|
||||
}
|
||||
|
||||
public ExtMXSerializer getResXmlSerializer() {
|
||||
ExtMXSerializer serial = new ExtMXSerializer();
|
||||
serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_INDENTATION
|
||||
|
@ -196,6 +196,10 @@ public class ResConfigFlags {
|
||||
case UI_MODE_TYPE_DESK:
|
||||
ret.append("-desk");
|
||||
break;
|
||||
|
||||
case UI_MODE_TYPE_APPLIANCE:
|
||||
ret.append("-appliance");
|
||||
break;
|
||||
}
|
||||
switch (uiMode & MASK_UI_MODE_NIGHT) {
|
||||
case UI_MODE_NIGHT_YES:
|
||||
@ -410,6 +414,7 @@ public class ResConfigFlags {
|
||||
public final static byte UI_MODE_TYPE_DESK = 0x02;
|
||||
public final static byte UI_MODE_TYPE_CAR = 0x03;
|
||||
public final static byte UI_MODE_TYPE_TELEVISION = 0x04;
|
||||
public final static byte UI_MODE_TYPE_APPLIANCE = 0x05;
|
||||
|
||||
public final static byte MASK_UI_MODE_NIGHT = 0x30;
|
||||
public final static byte UI_MODE_NIGHT_ANY = 0x00;
|
||||
|
@ -16,16 +16,22 @@
|
||||
|
||||
package brut.androlib.res.data.value;
|
||||
|
||||
import android.util.TypedValue;
|
||||
|
||||
/**
|
||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||
*/
|
||||
public class ResColorValue extends ResIntValue {
|
||||
public ResColorValue(int value, String rawValue) {
|
||||
private int type;
|
||||
|
||||
public ResColorValue(int value, String rawValue, int type) {
|
||||
super(value, rawValue, "color");
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String encodeAsResXml() {
|
||||
return String.format("#%08x", mValue);
|
||||
return TypedValue.coerceToString(type, mValue);
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
|
||||
package brut.androlib.res.data.value;
|
||||
|
||||
import android.util.TypedValue;
|
||||
import brut.androlib.AndrolibException;
|
||||
|
||||
/**
|
||||
@ -23,9 +24,11 @@ import brut.androlib.AndrolibException;
|
||||
*/
|
||||
public class ResIntValue extends ResScalarValue {
|
||||
protected final int mValue;
|
||||
private int type;
|
||||
|
||||
public ResIntValue(int value, String rawValue) {
|
||||
public ResIntValue(int value, String rawValue, int type) {
|
||||
this(value, rawValue, "integer");
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public ResIntValue(int value, String rawValue, String type) {
|
||||
@ -38,6 +41,6 @@ public class ResIntValue extends ResScalarValue {
|
||||
}
|
||||
|
||||
protected String encodeAsResXml() throws AndrolibException {
|
||||
return String.valueOf(mValue);
|
||||
return TypedValue.coerceToString(type, mValue);
|
||||
}
|
||||
}
|
@ -16,10 +16,9 @@
|
||||
|
||||
package brut.androlib.res.data.value;
|
||||
|
||||
import brut.androlib.res.xml.ResValuesXmlSerializable;
|
||||
import brut.androlib.AndrolibException;
|
||||
import brut.androlib.res.data.ResResource;
|
||||
import brut.androlib.res.xml.ResXmlEncoders;
|
||||
import brut.androlib.res.xml.ResValuesXmlSerializable;
|
||||
import brut.util.Duo;
|
||||
import java.io.IOException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
@ -52,15 +51,13 @@ public class ResPluralsValue extends ResBagValue implements ResValuesXmlSerializ
|
||||
serializer.startTag(null, "item");
|
||||
serializer.attribute(null, "quantity", QUANTITY_MAP[i]);
|
||||
|
||||
String item2 = item.encodeAsResXmlValue();
|
||||
|
||||
/*
|
||||
* peaches fix regarding formatted=false
|
||||
*/
|
||||
if (ResXmlEncoders.hasMultipleNonPositionalSubstitutions(item2)) {
|
||||
String rawValue = item.encodeAsResXmlValueExt();
|
||||
//AAPT don`t parse formatted for item tag(only for string and string-array tag),
|
||||
// so adding "formatted='fasle'" is useless.
|
||||
/*if (ResXmlEncoders.hasMultipleNonPositionalSubstitutions(rawValue)) {
|
||||
serializer.attribute(null, "formatted", "false");
|
||||
}
|
||||
serializer.text(item2);
|
||||
}*/
|
||||
serializer.text(rawValue);
|
||||
|
||||
serializer.endTag(null, "item");
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import brut.androlib.res.xml.ResValuesXmlSerializable;
|
||||
import brut.androlib.res.xml.ResXmlEncodable;
|
||||
import brut.androlib.AndrolibException;
|
||||
import brut.androlib.res.data.ResResource;
|
||||
import brut.androlib.res.xml.ResXmlEncoders;
|
||||
import java.io.IOException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
@ -54,6 +55,38 @@ public abstract class ResScalarValue extends ResValue
|
||||
return encodeAsResXml();
|
||||
}
|
||||
|
||||
public String encodeAsResXmlValueExt() throws AndrolibException {
|
||||
String rawValue = mRawValue;
|
||||
if (rawValue != null) {
|
||||
if (ResXmlEncoders.hasMultipleNonPositionalSubstitutions(rawValue)) {
|
||||
int count = 1;
|
||||
StringBuffer result = new StringBuffer();
|
||||
String tmp1[] = rawValue.split("%%", -1);
|
||||
int tmp1_sz = tmp1.length;
|
||||
for(int i=0;i<tmp1_sz;i++) {
|
||||
String cur1 = tmp1[i];
|
||||
String tmp2[] = cur1.split("%", -1);
|
||||
int tmp2_sz = tmp2.length;
|
||||
for(int j=0;j<tmp2_sz;j++) {
|
||||
String cur2 = tmp2[j];
|
||||
result.append(cur2);
|
||||
if(j != (tmp2_sz-1)) {
|
||||
result.append('%').append(count).append('$');
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if(i != (tmp1_sz-1)) {
|
||||
result.append("%%");
|
||||
}
|
||||
}
|
||||
rawValue = result.toString();
|
||||
}
|
||||
return rawValue;
|
||||
}
|
||||
return encodeAsResXml();
|
||||
}
|
||||
|
||||
|
||||
public void serializeToResValuesXml(XmlSerializer serializer, ResResource res)
|
||||
throws IOException, AndrolibException {
|
||||
String type = res.getResSpec().getType().getName();
|
||||
|
@ -52,11 +52,11 @@ public class ResValueFactory {
|
||||
|
||||
if (type >= TypedValue.TYPE_FIRST_COLOR_INT
|
||||
&& type <= TypedValue.TYPE_LAST_COLOR_INT) {
|
||||
return new ResColorValue(value, rawValue);
|
||||
return new ResColorValue(value, rawValue, type);
|
||||
}
|
||||
if (type >= TypedValue.TYPE_FIRST_INT
|
||||
&& type <= TypedValue.TYPE_LAST_INT) {
|
||||
return new ResIntValue(value, rawValue);
|
||||
return new ResIntValue(value, rawValue, type);
|
||||
}
|
||||
|
||||
throw new AndrolibException("Invalid value type: "+ type);
|
||||
|
@ -325,6 +325,10 @@ public class AXmlResourceParser implements XmlResourceParser {
|
||||
valueData
|
||||
), ex);
|
||||
}
|
||||
} else {
|
||||
if (valueType==TypedValue.TYPE_STRING) {
|
||||
return m_strings.getString(valueRaw);
|
||||
}
|
||||
}
|
||||
|
||||
return TypedValue.coerceToString(valueType, valueData);
|
||||
@ -370,7 +374,7 @@ public class AXmlResourceParser implements XmlResourceParser {
|
||||
public String getAttributeValue(String namespace, String attribute) {
|
||||
int index = findAttribute(namespace, attribute);
|
||||
if (index == -1) {
|
||||
return null;
|
||||
return "";
|
||||
}
|
||||
return getAttributeValue(index);
|
||||
}
|
||||
@ -755,7 +759,7 @@ public class AXmlResourceParser implements XmlResourceParser {
|
||||
if (m_event != START_TAG) {
|
||||
throw new IndexOutOfBoundsException("Current event is not START_TAG.");
|
||||
}
|
||||
int offset = index * 5;
|
||||
int offset = index * ATTRIBUTE_LENGHT;
|
||||
if (offset >= m_attributes.length) {
|
||||
throw new IndexOutOfBoundsException("Invalid attribute index (" + index + ").");
|
||||
}
|
||||
|
@ -34,35 +34,31 @@ public class Res9patchStreamDecoder implements ResStreamDecoder {
|
||||
throws AndrolibException {
|
||||
try {
|
||||
byte[] data = IOUtils.toByteArray(in);
|
||||
NinePatch np = getNinePatch(data);
|
||||
|
||||
BufferedImage im = ImageIO.read(new ByteArrayInputStream(data));
|
||||
int w = im.getWidth(), h = im.getHeight();
|
||||
|
||||
BufferedImage im2 = new BufferedImage(w + 2, h + 2, BufferedImage.TYPE_4BYTE_ABGR);
|
||||
BufferedImage im2 = new BufferedImage(
|
||||
w + 2, h + 2, BufferedImage.TYPE_4BYTE_ABGR);
|
||||
Raster src = im.getRaster();
|
||||
|
||||
NinePatch np = getNinePatch(data);
|
||||
WritableRaster dst = im2.getRaster();
|
||||
int nbands = im.getSampleModel().getNumBands();
|
||||
int[] bands = new int[4];
|
||||
if (nbands == 2) {
|
||||
bands[0] = bands[1] = bands[2] = 0;
|
||||
bands[3] = 1;
|
||||
bands[0] = bands[1] = bands[2] = 0;
|
||||
bands[3] = 1;
|
||||
} else {
|
||||
bands[0] = 0;
|
||||
bands[1] = 1;
|
||||
bands[2] = 2;
|
||||
bands[3] = 3;
|
||||
bands[0] = 0; bands[1] = 1; bands[2] = 2; bands[3] = 3;
|
||||
}
|
||||
int[] band = null;
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int bi = 0; bi < 4; bi++) {
|
||||
band = src.getSamples(0, y, w, 1, bands[bi], band);
|
||||
dst.setSamples(1, y + 1, w, 1, bi, band);
|
||||
}
|
||||
for (int bi = 0; bi < 4; bi++) {
|
||||
band = src.getSamples(0, y, w, 1, bands[bi], band);
|
||||
dst.setSamples(1, y + 1, w, 1, bi, band);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
drawHLine(im2, h + 1, np.padLeft + 1, w - np.padRight);
|
||||
drawVLine(im2, w + 1, np.padTop + 1, h - np.padBottom);
|
||||
|
||||
|
@ -94,16 +94,25 @@ public class ResFileDecoder {
|
||||
|
||||
public void decode(Directory inDir, String inFileName, Directory outDir,
|
||||
String outFileName, String decoder) throws AndrolibException {
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
try {
|
||||
InputStream in = inDir.getFileInput(inFileName);
|
||||
OutputStream out = outDir.getFileOutput(outFileName);
|
||||
in = inDir.getFileInput(inFileName);
|
||||
out = outDir.getFileOutput(outFileName);
|
||||
mDecoders.decode(in, out, decoder);
|
||||
in.close();
|
||||
out.close();
|
||||
} catch (IOException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
} finally {
|
||||
try{
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user