diff --git a/apktool-cli/src/main/java/brut/apktool/Main.java b/apktool-cli/src/main/java/brut/apktool/Main.java index 1e04c3e6..5f427483 100644 --- a/apktool-cli/src/main/java/brut/apktool/Main.java +++ b/apktool-cli/src/main/java/brut/apktool/Main.java @@ -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 \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" + diff --git a/apktool-lib/src/main/java/android/util/AttributeSet.java b/apktool-lib/src/main/java/android/util/AttributeSet.java index 72026146..1da422fd 100644 --- a/apktool-lib/src/main/java/android/util/AttributeSet.java +++ b/apktool-lib/src/main/java/android/util/AttributeSet.java @@ -46,4 +46,4 @@ public interface AttributeSet { //TODO: remove int getAttributeValueType(int index); int getAttributeValueData(int index); -} +} \ No newline at end of file diff --git a/apktool-lib/src/main/java/android/util/TypedValue.java b/apktool-lib/src/main/java/android/util/TypedValue.java index a11a176a..d7b5295d 100644 --- a/apktool-lib/src/main/java/android/util/TypedValue.java +++ b/apktool-lib/src/main/java/android/util/TypedValue.java @@ -43,8 +43,6 @@ public class TypedValue { /** The data field holds a complex number encoding a fraction * 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 @@ -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; } }; - diff --git a/apktool-lib/src/main/java/brut/androlib/Androlib.java b/apktool-lib/src/main/java/brut/androlib/Androlib.java index 9124ee78..077eecf6 100644 --- a/apktool-lib/src/main/java/brut/androlib/Androlib.java +++ b/apktool-lib/src/main/java/brut/androlib/Androlib.java @@ -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 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"}; +} \ No newline at end of file diff --git a/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java b/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java index a39128b8..8e0c5be1 100644 --- a/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java +++ b/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java @@ -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 @@ -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); @@ -234,4 +257,4 @@ public class ApkDecoder { private boolean mForceDelete = false; private String mFrameTag; private boolean mKeepBrokenResources = false; -} +} \ No newline at end of file diff --git a/apktool-lib/src/main/java/brut/androlib/ApktoolProperties.java b/apktool-lib/src/main/java/brut/androlib/ApktoolProperties.java index 92fc30aa..2d76f40f 100644 --- a/apktool-lib/src/main/java/brut/androlib/ApktoolProperties.java +++ b/apktool-lib/src/main/java/brut/androlib/ApktoolProperties.java @@ -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 */ @@ -46,10 +49,29 @@ 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; private static final Logger LOGGER = Logger.getLogger(ApktoolProperties.class.getName()); -} +} \ No newline at end of file diff --git a/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java b/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java index 86bda2c7..f770ddd3 100644 --- a/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java +++ b/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java @@ -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 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 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 getManifestFileDecoder() { + ResStreamDecoderContainer decoders = + new ResStreamDecoderContainer(); + + AXmlResourceParser axmlParser = new AXmlResourceParser(); + + decoders.setDecoder("xml", + new XmlPullStreamDecoder(axmlParser, getResXmlSerializer())); + + return new Duo( + new ResFileDecoder(decoders), axmlParser); + } + public ExtMXSerializer getResXmlSerializer() { ExtMXSerializer serial = new ExtMXSerializer(); serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_INDENTATION @@ -491,4 +541,4 @@ final public class AndrolibResources { private final static Logger LOGGER = Logger.getLogger(AndrolibResources.class.getName()); -} +} \ No newline at end of file diff --git a/apktool-lib/src/main/java/brut/androlib/res/data/ResConfigFlags.java b/apktool-lib/src/main/java/brut/androlib/res/data/ResConfigFlags.java index 0e392e2e..e10ae9e0 100644 --- a/apktool-lib/src/main/java/brut/androlib/res/data/ResConfigFlags.java +++ b/apktool-lib/src/main/java/brut/androlib/res/data/ResConfigFlags.java @@ -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; diff --git a/apktool-lib/src/main/java/brut/androlib/res/data/value/ResColorValue.java b/apktool-lib/src/main/java/brut/androlib/res/data/value/ResColorValue.java index 23077b6f..5b147a3c 100644 --- a/apktool-lib/src/main/java/brut/androlib/res/data/value/ResColorValue.java +++ b/apktool-lib/src/main/java/brut/androlib/res/data/value/ResColorValue.java @@ -16,16 +16,22 @@ package brut.androlib.res.data.value; +import android.util.TypedValue; + /** * @author Ryszard Wiśniewski */ 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); } -} +} \ No newline at end of file diff --git a/apktool-lib/src/main/java/brut/androlib/res/data/value/ResIntValue.java b/apktool-lib/src/main/java/brut/androlib/res/data/value/ResIntValue.java index bc3a5ee3..d1139995 100644 --- a/apktool-lib/src/main/java/brut/androlib/res/data/value/ResIntValue.java +++ b/apktool-lib/src/main/java/brut/androlib/res/data/value/ResIntValue.java @@ -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); } -} +} \ No newline at end of file diff --git a/apktool-lib/src/main/java/brut/androlib/res/data/value/ResPluralsValue.java b/apktool-lib/src/main/java/brut/androlib/res/data/value/ResPluralsValue.java index df0b12dd..60b4a5cd 100644 --- a/apktool-lib/src/main/java/brut/androlib/res/data/value/ResPluralsValue.java +++ b/apktool-lib/src/main/java/brut/androlib/res/data/value/ResPluralsValue.java @@ -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,16 +51,14 @@ 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"); } serializer.endTag(null, "plurals"); diff --git a/apktool-lib/src/main/java/brut/androlib/res/data/value/ResScalarValue.java b/apktool-lib/src/main/java/brut/androlib/res/data/value/ResScalarValue.java index 20844a74..92d95344 100644 --- a/apktool-lib/src/main/java/brut/androlib/res/data/value/ResScalarValue.java +++ b/apktool-lib/src/main/java/brut/androlib/res/data/value/ResScalarValue.java @@ -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; @@ -53,6 +54,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= 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); @@ -98,4 +98,4 @@ public class ResValueFactory { boolean theme) { return new ResReferenceValue(mPackage, resID, rawValue, theme); } -} +} \ No newline at end of file diff --git a/apktool-lib/src/main/java/brut/androlib/res/decoder/AXmlResourceParser.java b/apktool-lib/src/main/java/brut/androlib/res/decoder/AXmlResourceParser.java index 80a58c48..11a55b97 100644 --- a/apktool-lib/src/main/java/brut/androlib/res/decoder/AXmlResourceParser.java +++ b/apktool-lib/src/main/java/brut/androlib/res/decoder/AXmlResourceParser.java @@ -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 + ")."); } @@ -960,4 +964,4 @@ public class AXmlResourceParser implements XmlResourceParser { CHUNK_XML_END_TAG = 0x00100103, CHUNK_XML_TEXT = 0x00100104, CHUNK_XML_LAST = 0x00100104; -} +} \ No newline at end of file diff --git a/apktool-lib/src/main/java/brut/androlib/res/decoder/Res9patchStreamDecoder.java b/apktool-lib/src/main/java/brut/androlib/res/decoder/Res9patchStreamDecoder.java index 6342fcc2..5d87d1ff 100644 --- a/apktool-lib/src/main/java/brut/androlib/res/decoder/Res9patchStreamDecoder.java +++ b/apktool-lib/src/main/java/brut/androlib/res/decoder/Res9patchStreamDecoder.java @@ -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); @@ -154,4 +150,4 @@ public class Res9patchStreamDecoder implements ResStreamDecoder { xDivs, yDivs); } } -} +} \ No newline at end of file diff --git a/apktool-lib/src/main/java/brut/androlib/res/decoder/ResFileDecoder.java b/apktool-lib/src/main/java/brut/androlib/res/decoder/ResFileDecoder.java index c5d67d52..b0c9ca48 100644 --- a/apktool-lib/src/main/java/brut/androlib/res/decoder/ResFileDecoder.java +++ b/apktool-lib/src/main/java/brut/androlib/res/decoder/ResFileDecoder.java @@ -94,19 +94,28 @@ 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); + } } } private final static Logger LOGGER = Logger.getLogger(ResFileDecoder.class.getName()); -} +} \ No newline at end of file diff --git a/apktool-lib/src/main/java/com/mindprod/ledatastream/LEDataInputStream.java b/apktool-lib/src/main/java/com/mindprod/ledatastream/LEDataInputStream.java index 5f7453ae..83656341 100644 --- a/apktool-lib/src/main/java/com/mindprod/ledatastream/LEDataInputStream.java +++ b/apktool-lib/src/main/java/com/mindprod/ledatastream/LEDataInputStream.java @@ -316,4 +316,4 @@ public final class LEDataInputStream implements DataInput { return dis.skipBytes( n ); } - } + } \ No newline at end of file