Merged in "yyj" fixes along with a few of my own. 95% yyj work :)

This commit is contained in:
Connor Tumbleson 2012-07-08 10:33:49 -05:00
parent e9738642b2
commit 282bdae126
17 changed files with 328 additions and 70 deletions

View File

@ -211,8 +211,9 @@ public class Main {
System.out.println( System.out.println(
"Apktool v" + Androlib.getVersion() + " - a tool for reengineering Android apk files\n" + "Apktool v" + Androlib.getVersion() + " - a tool for reengineering Android apk files\n" +
"Copyright 2010 Ryszard Wiśniewski <brut.alll@gmail.com>\n" + "Copyright 2010 Ryszard Wiśniewski <brut.alll@gmail.com>\n" +
"with baksmali/smali " + smaliVersion + " (http://smali.googlecode.com)\n" + "with smali v" + ApktoolProperties.get("smaliVersion") +
"Updated by iBotPeaches (@iBotPeaches) \n" + ", 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" + "Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)\n" +
"\n" + "\n" +
"Usage: apktool [-q|--quiet OR -v|--verbose] COMMAND [...]\n" + "Usage: apktool [-q|--quiet OR -v|--verbose] COMMAND [...]\n" +

View File

@ -44,8 +44,6 @@ public class TypedValue {
* of a container. */ * of a container. */
public static final int TYPE_FRACTION = 0x06; public static final int TYPE_FRACTION = 0x06;
public static final int TYPE_LAYOUT = 0x07;
/** Identifies the start of plain integer values. Any type value /** Identifies the start of plain integer values. Any type value
* from this to {@link #TYPE_LAST_INT} means the * from this to {@link #TYPE_LAST_INT} means the
* <var>data</var> field holds a generic integer value. */ * <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) { 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) { } 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; return null;
} }
}; };

View File

@ -24,8 +24,7 @@ import brut.androlib.res.util.ExtFile;
import brut.androlib.src.SmaliBuilder; import brut.androlib.src.SmaliBuilder;
import brut.androlib.src.SmaliDecoder; import brut.androlib.src.SmaliDecoder;
import brut.common.BrutException; import brut.common.BrutException;
import brut.directory.Directory; import brut.directory.*;
import brut.directory.DirectoryException;
import brut.util.BrutIO; import brut.util.BrutIO;
import brut.util.OS; import brut.util.OS;
import java.io.*; import java.io.*;
@ -42,7 +41,11 @@ public class Androlib {
private final AndrolibResources mAndRes = new AndrolibResources(); private final AndrolibResources mAndRes = new AndrolibResources();
public ResTable getResTable(ExtFile apkFile) throws AndrolibException { 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) public void decodeSourcesRaw(ExtFile apkFile, File outDir, boolean debug)
@ -78,6 +81,22 @@ public class Androlib {
new AndrolibJava().decode(apkFile, outDir); 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) public void decodeResourcesRaw(ExtFile apkFile, File outDir)
throws AndrolibException { throws AndrolibException {
try { try {
@ -248,6 +267,8 @@ public class Androlib {
throws AndrolibException { throws AndrolibException {
if (! buildResourcesRaw(appDir, forceBuildAll) if (! buildResourcesRaw(appDir, forceBuildAll)
&& ! buildResourcesFull(appDir, forceBuildAll, framework, && ! buildResourcesFull(appDir, forceBuildAll, framework,
usesFramework)
&& ! buildManifest(appDir, forceBuildAll, framework,
usesFramework)) { usesFramework)) {
LOGGER.warning("Could not find resources"); 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) public void buildLib(File appDir, boolean forceBuildAll)
throws AndrolibException { throws AndrolibException {
File working = new File(appDir, "lib"); File working = new File(appDir, "lib");
@ -441,4 +521,6 @@ public class Androlib {
new String[]{"resources.arsc", "AndroidManifest.xml"}; new String[]{"resources.arsc", "AndroidManifest.xml"};
private final static String[] APP_RESOURCES_FILENAMES = private final static String[] APP_RESOURCES_FILENAMES =
new String[]{"AndroidManifest.xml", "res"}; new String[]{"AndroidManifest.xml", "res"};
private final static String[] APK_MANIFEST_FILENAMES =
new String[]{"AndroidManifest.xml"};
} }

View File

@ -26,10 +26,7 @@ import brut.common.BrutException;
import brut.directory.DirectoryException; import brut.directory.DirectoryException;
import brut.util.OS; import brut.util.OS;
import java.io.File; import java.io.File;
import java.util.Arrays; import java.util.*;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
/** /**
* @author Ryszard Wiśniewski <brut.alll@gmail.com> * @author Ryszard Wiśniewski <brut.alll@gmail.com>
@ -92,6 +89,7 @@ public class ApkDecoder {
break; break;
} }
} }
if (hasResources()) { if (hasResources()) {
switch (mDecodeResources) { switch (mDecodeResources) {
case DECODE_RESOURCES_NONE: case DECODE_RESOURCES_NONE:
@ -102,7 +100,22 @@ public class ApkDecoder {
getResTable()); getResTable());
break; 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); mAndrolib.decodeRawFiles(mApkFile, outDir);
writeMetaFile(); writeMetaFile();
} }
@ -143,12 +156,14 @@ public class ApkDecoder {
public ResTable getResTable() throws AndrolibException { public ResTable getResTable() throws AndrolibException {
if (mResTable == null) { if (mResTable == null) {
if (! hasResources()) { boolean hasResources = hasResources();
boolean hasManifest = hasManifest();
if (! (hasManifest || hasResources)) {
throw new AndrolibException( 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; AndrolibResources.sKeepBroken = mKeepBrokenResources;
mResTable = mAndrolib.getResTable(mApkFile); mResTable = mAndrolib.getResTable(mApkFile, hasResources);
mResTable.setFrameTag(mFrameTag); mResTable.setFrameTag(mFrameTag);
} }
return mResTable; 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 { public boolean hasResources() throws AndrolibException {
try { try {
return mApkFile.getDirectory().containsFile("resources.arsc"); return mApkFile.getDirectory().containsFile("resources.arsc");
@ -190,7 +213,7 @@ public class ApkDecoder {
meta.put("version", Androlib.getVersion()); meta.put("version", Androlib.getVersion());
meta.put("apkFileName", mApkFile.getName()); meta.put("apkFileName", mApkFile.getName());
if (mDecodeResources != DECODE_RESOURCES_NONE && hasResources()) { if (mDecodeResources != DECODE_RESOURCES_NONE && (hasManifest() || hasResources())) {
meta.put("isFrameworkApk", meta.put("isFrameworkApk",
Boolean.valueOf(mAndrolib.isFrameworkApk(getResTable()))); Boolean.valueOf(mAndrolib.isFrameworkApk(getResTable())));
putUsesFramework(meta); putUsesFramework(meta);

View File

@ -21,6 +21,9 @@ 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>
*/ */
@ -46,6 +49,25 @@ public class ApktoolProperties {
} catch (IOException ex) { } catch (IOException ex) {
LOGGER.warning("Can't load properties."); 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; private static Properties sProps;

View File

@ -39,8 +39,14 @@ import org.xmlpull.v1.XmlSerializer;
*/ */
final public class AndrolibResources { final public class AndrolibResources {
public ResTable getResTable(ExtFile apkFile) throws AndrolibException { 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); ResTable resTable = new ResTable(this);
loadMainPkg(resTable, apkFile); if (loadMainPkg) {
loadMainPkg(resTable, apkFile);
}
return resTable; return resTable;
} }
@ -97,6 +103,36 @@ final public class AndrolibResources {
return pkg; 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) public void decode(ResTable resTable, ExtFile apkFile, File outDir)
throws AndrolibException { throws AndrolibException {
Duo<ResFileDecoder, AXmlResourceParser> duo = getResFileDecoder(); Duo<ResFileDecoder, AXmlResourceParser> duo = getResFileDecoder();
@ -111,6 +147,7 @@ final public class AndrolibResources {
inApk = apkFile.getDirectory(); inApk = apkFile.getDirectory();
out = new FileDirectory(outDir); out = new FileDirectory(outDir);
LOGGER.info("Decoding AndroidManifest.xml with resources...");
fileDecoder.decode( fileDecoder.decode(
inApk, "AndroidManifest.xml", out, "AndroidManifest.xml", inApk, "AndroidManifest.xml", out, "AndroidManifest.xml",
"xml"); "xml");
@ -238,6 +275,19 @@ final public class AndrolibResources {
new ResFileDecoder(decoders), axmlParser); 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() { public ExtMXSerializer getResXmlSerializer() {
ExtMXSerializer serial = new ExtMXSerializer(); ExtMXSerializer serial = new ExtMXSerializer();
serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_INDENTATION serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_INDENTATION

View File

@ -196,6 +196,10 @@ public class ResConfigFlags {
case UI_MODE_TYPE_DESK: case UI_MODE_TYPE_DESK:
ret.append("-desk"); ret.append("-desk");
break; break;
case UI_MODE_TYPE_APPLIANCE:
ret.append("-appliance");
break;
} }
switch (uiMode & MASK_UI_MODE_NIGHT) { switch (uiMode & MASK_UI_MODE_NIGHT) {
case UI_MODE_NIGHT_YES: 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_DESK = 0x02;
public final static byte UI_MODE_TYPE_CAR = 0x03; 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_TELEVISION = 0x04;
public final static byte UI_MODE_TYPE_APPLIANCE = 0x05;
public final static byte MASK_UI_MODE_NIGHT = 0x30; public final static byte MASK_UI_MODE_NIGHT = 0x30;
public final static byte UI_MODE_NIGHT_ANY = 0x00; public final static byte UI_MODE_NIGHT_ANY = 0x00;

View File

@ -16,16 +16,22 @@
package brut.androlib.res.data.value; package brut.androlib.res.data.value;
import android.util.TypedValue;
/** /**
* @author Ryszard Wiśniewski <brut.alll@gmail.com> * @author Ryszard Wiśniewski <brut.alll@gmail.com>
*/ */
public class ResColorValue extends ResIntValue { 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"); super(value, rawValue, "color");
this.type = type;
} }
@Override @Override
protected String encodeAsResXml() { protected String encodeAsResXml() {
return String.format("#%08x", mValue); return TypedValue.coerceToString(type, mValue);
} }
} }

View File

@ -16,6 +16,7 @@
package brut.androlib.res.data.value; package brut.androlib.res.data.value;
import android.util.TypedValue;
import brut.androlib.AndrolibException; import brut.androlib.AndrolibException;
/** /**
@ -23,9 +24,11 @@ import brut.androlib.AndrolibException;
*/ */
public class ResIntValue extends ResScalarValue { public class ResIntValue extends ResScalarValue {
protected final int mValue; 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(value, rawValue, "integer");
this.type = type;
} }
public ResIntValue(int value, String rawValue, String type) { public ResIntValue(int value, String rawValue, String type) {
@ -38,6 +41,6 @@ public class ResIntValue extends ResScalarValue {
} }
protected String encodeAsResXml() throws AndrolibException { protected String encodeAsResXml() throws AndrolibException {
return String.valueOf(mValue); return TypedValue.coerceToString(type, mValue);
} }
} }

View File

@ -16,10 +16,9 @@
package brut.androlib.res.data.value; package brut.androlib.res.data.value;
import brut.androlib.res.xml.ResValuesXmlSerializable;
import brut.androlib.AndrolibException; import brut.androlib.AndrolibException;
import brut.androlib.res.data.ResResource; import brut.androlib.res.data.ResResource;
import brut.androlib.res.xml.ResXmlEncoders; 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;
@ -52,15 +51,13 @@ 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]);
String item2 = item.encodeAsResXmlValue(); 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.
* peaches fix regarding formatted=false /*if (ResXmlEncoders.hasMultipleNonPositionalSubstitutions(rawValue)) {
*/
if (ResXmlEncoders.hasMultipleNonPositionalSubstitutions(item2)) {
serializer.attribute(null, "formatted", "false"); serializer.attribute(null, "formatted", "false");
} }*/
serializer.text(item2); serializer.text(rawValue);
serializer.endTag(null, "item"); serializer.endTag(null, "item");
} }

View File

@ -20,6 +20,7 @@ import brut.androlib.res.xml.ResValuesXmlSerializable;
import brut.androlib.res.xml.ResXmlEncodable; import brut.androlib.res.xml.ResXmlEncodable;
import brut.androlib.AndrolibException; import brut.androlib.AndrolibException;
import brut.androlib.res.data.ResResource; import brut.androlib.res.data.ResResource;
import brut.androlib.res.xml.ResXmlEncoders;
import java.io.IOException; import java.io.IOException;
import org.xmlpull.v1.XmlSerializer; import org.xmlpull.v1.XmlSerializer;
@ -54,6 +55,38 @@ public abstract class ResScalarValue extends ResValue
return encodeAsResXml(); 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) public void serializeToResValuesXml(XmlSerializer serializer, ResResource res)
throws IOException, AndrolibException { throws IOException, AndrolibException {
String type = res.getResSpec().getType().getName(); String type = res.getResSpec().getType().getName();

View File

@ -52,11 +52,11 @@ public class ResValueFactory {
if (type >= TypedValue.TYPE_FIRST_COLOR_INT if (type >= TypedValue.TYPE_FIRST_COLOR_INT
&& type <= TypedValue.TYPE_LAST_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 if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) { && type <= TypedValue.TYPE_LAST_INT) {
return new ResIntValue(value, rawValue); return new ResIntValue(value, rawValue, type);
} }
throw new AndrolibException("Invalid value type: "+ type); throw new AndrolibException("Invalid value type: "+ type);

View File

@ -325,6 +325,10 @@ public class AXmlResourceParser implements XmlResourceParser {
valueData valueData
), ex); ), ex);
} }
} else {
if (valueType==TypedValue.TYPE_STRING) {
return m_strings.getString(valueRaw);
}
} }
return TypedValue.coerceToString(valueType, valueData); return TypedValue.coerceToString(valueType, valueData);
@ -370,7 +374,7 @@ public class AXmlResourceParser implements XmlResourceParser {
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) {
return null; return "";
} }
return getAttributeValue(index); return getAttributeValue(index);
} }
@ -755,7 +759,7 @@ public class AXmlResourceParser implements XmlResourceParser {
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 * 5; 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 + ").");
} }

View File

@ -34,35 +34,31 @@ public class Res9patchStreamDecoder implements ResStreamDecoder {
throws AndrolibException { throws AndrolibException {
try { try {
byte[] data = IOUtils.toByteArray(in); byte[] data = IOUtils.toByteArray(in);
NinePatch np = getNinePatch(data);
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(w + 2, h + 2, BufferedImage.TYPE_4BYTE_ABGR); BufferedImage im2 = new BufferedImage(
w + 2, h + 2, BufferedImage.TYPE_4BYTE_ABGR);
Raster src = im.getRaster(); Raster src = im.getRaster();
NinePatch np = getNinePatch(data);
WritableRaster dst = im2.getRaster(); WritableRaster dst = im2.getRaster();
int nbands = im.getSampleModel().getNumBands(); int nbands = im.getSampleModel().getNumBands();
int[] bands = new int[4]; int[] bands = new int[4];
if (nbands == 2) { if (nbands == 2) {
bands[0] = bands[1] = bands[2] = 0; bands[0] = bands[1] = bands[2] = 0;
bands[3] = 1; bands[3] = 1;
} else { } else {
bands[0] = 0; bands[0] = 0; bands[1] = 1; bands[2] = 2; bands[3] = 3;
bands[1] = 1;
bands[2] = 2;
bands[3] = 3;
} }
int[] band = null; int[] band = null;
for (int y = 0; y < h; y++) { for (int y = 0; y < h; y++) {
for (int bi = 0; bi < 4; bi++) { for (int bi = 0; bi < 4; bi++) {
band = src.getSamples(0, y, w, 1, bands[bi], band); band = src.getSamples(0, y, w, 1, bands[bi], band);
dst.setSamples(1, y + 1, w, 1, bi, band); dst.setSamples(1, y + 1, w, 1, bi, band);
} }
} }
drawHLine(im2, h + 1, np.padLeft + 1, w - np.padRight); drawHLine(im2, h + 1, np.padLeft + 1, w - np.padRight);
drawVLine(im2, w + 1, np.padTop + 1, h - np.padBottom); drawVLine(im2, w + 1, np.padTop + 1, h - np.padBottom);

View File

@ -94,16 +94,25 @@ public class ResFileDecoder {
public void decode(Directory inDir, String inFileName, Directory outDir, public void decode(Directory inDir, String inFileName, Directory outDir,
String outFileName, String decoder) throws AndrolibException { String outFileName, String decoder) throws AndrolibException {
InputStream in = null;
OutputStream out = null;
try { try {
InputStream in = inDir.getFileInput(inFileName); in = inDir.getFileInput(inFileName);
OutputStream out = outDir.getFileOutput(outFileName); out = outDir.getFileOutput(outFileName);
mDecoders.decode(in, out, decoder); mDecoders.decode(in, out, decoder);
in.close();
out.close();
} catch (IOException ex) {
throw new AndrolibException(ex);
} catch (DirectoryException ex) { } catch (DirectoryException ex) {
throw new AndrolibException(ex); throw new AndrolibException(ex);
} finally {
try{
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
} catch (IOException ex) {
throw new AndrolibException(ex);
}
} }
} }