mirror of
https://github.com/revanced/Apktool.git
synced 2024-12-12 05:47:46 +01:00
increased v1.4.8, merging more of yyj fixes in hopes to fix this arsc error
This commit is contained in:
parent
282bdae126
commit
ba345ac6b9
@ -3,7 +3,7 @@
|
||||
|
||||
<groupId>brut.apktool</groupId>
|
||||
<artifactId>apktool-cli</artifactId>
|
||||
<version>1.4.7-SNAPSHOT</version>
|
||||
<version>1.4.8-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
<groupId>brut.apktool</groupId>
|
||||
<artifactId>apktool-lib</artifactId>
|
||||
<version>1.4.7-SNAPSHOT</version>
|
||||
<version>1.4.8-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
|
@ -93,7 +93,7 @@ public class Androlib {
|
||||
}
|
||||
|
||||
public void decodeManifestFull(ExtFile apkFile, File outDir,
|
||||
ResTable resTable) throws AndrolibException {
|
||||
ResTable resTable) throws AndrolibException {
|
||||
mAndRes.decodeManifest(resTable, apkFile, outDir);
|
||||
}
|
||||
|
||||
@ -523,4 +523,4 @@ public class Androlib {
|
||||
new String[]{"AndroidManifest.xml", "res"};
|
||||
private final static String[] APK_MANIFEST_FILENAMES =
|
||||
new String[]{"AndroidManifest.xml"};
|
||||
}
|
||||
}
|
||||
|
@ -217,6 +217,7 @@ public class ApkDecoder {
|
||||
meta.put("isFrameworkApk",
|
||||
Boolean.valueOf(mAndrolib.isFrameworkApk(getResTable())));
|
||||
putUsesFramework(meta);
|
||||
putSdkInfo(meta);
|
||||
}
|
||||
|
||||
mAndrolib.writeMetaFile(mOutDir, meta);
|
||||
@ -246,6 +247,15 @@ public class ApkDecoder {
|
||||
meta.put("usesFramework", uses);
|
||||
}
|
||||
|
||||
private void putSdkInfo(Map<String, Object> meta)
|
||||
throws AndrolibException {
|
||||
Map<String, String> info = getResTable().getSdkInfo();
|
||||
if (info.size() > 0) {
|
||||
meta.put("sdkInfo", info);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final Androlib mAndrolib;
|
||||
|
||||
private ExtFile mApkFile;
|
||||
|
@ -124,9 +124,8 @@ final public class AndrolibResources {
|
||||
out = new FileDirectory(outDir);
|
||||
|
||||
LOGGER.info("Decoding AndroidManifest.xml with only framework resources...");
|
||||
fileDecoder.decode(
|
||||
inApk, "AndroidManifest.xml", out, "AndroidManifest.xml",
|
||||
"xml");
|
||||
fileDecoder.decodeManifest(
|
||||
inApk, "AndroidManifest.xml", out, "AndroidManifest.xml");
|
||||
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
@ -148,9 +147,9 @@ final public class AndrolibResources {
|
||||
out = new FileDirectory(outDir);
|
||||
|
||||
LOGGER.info("Decoding AndroidManifest.xml with resources...");
|
||||
fileDecoder.decode(
|
||||
inApk, "AndroidManifest.xml", out, "AndroidManifest.xml",
|
||||
"xml");
|
||||
|
||||
fileDecoder.decodeManifest(
|
||||
inApk, "AndroidManifest.xml", out, "AndroidManifest.xml");
|
||||
|
||||
if (inApk.containsDir("res")) {
|
||||
in = inApk.getDir("res");
|
||||
@ -183,6 +182,14 @@ final public class AndrolibResources {
|
||||
}
|
||||
}
|
||||
|
||||
public void setSdkInfo(Map<String, String> map) {
|
||||
if(map != null) {
|
||||
mMinSdkVersion = map.get("minSdkVersion");
|
||||
mTargetSdkVersion = map.get("targetSdkVersion");
|
||||
mMaxSdkVersion = map.get("maxSdkVersion");
|
||||
}
|
||||
}
|
||||
|
||||
public void aaptPackage(File apkFile, File manifest, File resDir,
|
||||
File rawDir, File assetDir, File[] include,
|
||||
boolean update, boolean framework) throws AndrolibException {
|
||||
@ -193,6 +200,18 @@ final public class AndrolibResources {
|
||||
if (update) {
|
||||
cmd.add("-u");
|
||||
}
|
||||
if (mMinSdkVersion != null) {
|
||||
cmd.add("--min-sdk-version");
|
||||
cmd.add(mMinSdkVersion);
|
||||
}
|
||||
if (mTargetSdkVersion != null) {
|
||||
cmd.add("--target-sdk-version");
|
||||
cmd.add(mTargetSdkVersion);
|
||||
}
|
||||
if (mMaxSdkVersion != null) {
|
||||
cmd.add("--max-sdk-version");
|
||||
cmd.add(mMaxSdkVersion);
|
||||
}
|
||||
cmd.add("-F");
|
||||
cmd.add(apkFile.getAbsolutePath());
|
||||
|
||||
@ -541,4 +560,9 @@ final public class AndrolibResources {
|
||||
|
||||
private final static Logger LOGGER =
|
||||
Logger.getLogger(AndrolibResources.class.getName());
|
||||
}
|
||||
|
||||
private String mMinSdkVersion = null;
|
||||
private String mMaxSdkVersion = null;
|
||||
private String mTargetSdkVersion = null;
|
||||
|
||||
}
|
||||
|
@ -196,7 +196,9 @@ public class ResConfigFlags {
|
||||
case UI_MODE_TYPE_DESK:
|
||||
ret.append("-desk");
|
||||
break;
|
||||
|
||||
case UI_MODE_TYPE_TELEVISION:
|
||||
ret.append("-television");
|
||||
break;
|
||||
case UI_MODE_TYPE_APPLIANCE:
|
||||
ret.append("-appliance");
|
||||
break;
|
||||
|
@ -39,6 +39,8 @@ public class ResTable {
|
||||
|
||||
private String mFrameTag;
|
||||
|
||||
private Map<String, String> mSdkInfo = new LinkedHashMap<String, String>();
|
||||
|
||||
public ResTable() {
|
||||
mAndRes = null;
|
||||
}
|
||||
@ -120,4 +122,16 @@ public class ResTable {
|
||||
public void setFrameTag(String tag) {
|
||||
mFrameTag = tag;
|
||||
}
|
||||
|
||||
public Map<String, String> getSdkInfo() {
|
||||
return mSdkInfo;
|
||||
}
|
||||
|
||||
public void addSdkInfo(String key, String value) {
|
||||
mSdkInfo.put(key, value);
|
||||
}
|
||||
|
||||
public void clearSdkInfo() {
|
||||
mSdkInfo.clear();
|
||||
}
|
||||
}
|
||||
|
@ -16,9 +16,10 @@
|
||||
|
||||
package brut.androlib.res.data.value;
|
||||
|
||||
import brut.androlib.res.xml.ResValuesXmlSerializable;
|
||||
import brut.androlib.res.xml.ResXmlEncoders;
|
||||
import brut.androlib.AndrolibException;
|
||||
import brut.androlib.res.data.ResResource;
|
||||
import brut.androlib.res.xml.ResValuesXmlSerializable;
|
||||
import brut.util.Duo;
|
||||
import java.io.IOException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
@ -63,7 +64,8 @@ public class ResPluralsValue extends ResBagValue implements ResValuesXmlSerializ
|
||||
}
|
||||
serializer.endTag(null, "plurals");
|
||||
}
|
||||
|
||||
|
||||
|
||||
private final ResScalarValue[] mItems;
|
||||
|
||||
|
||||
|
@ -18,9 +18,9 @@ package brut.androlib.res.data.value;
|
||||
|
||||
import brut.androlib.res.xml.ResValuesXmlSerializable;
|
||||
import brut.androlib.res.xml.ResXmlEncodable;
|
||||
import brut.androlib.res.xml.ResXmlEncoders;
|
||||
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,7 +54,7 @@ public abstract class ResScalarValue extends ResValue
|
||||
}
|
||||
return encodeAsResXml();
|
||||
}
|
||||
|
||||
|
||||
public String encodeAsResXmlValueExt() throws AndrolibException {
|
||||
String rawValue = mRawValue;
|
||||
if (rawValue != null) {
|
||||
|
@ -139,8 +139,7 @@ public class ARSCDecoder {
|
||||
checkChunkType(Header.TYPE_CONFIG);
|
||||
/*typeId*/ mIn.skipInt();
|
||||
int entryCount = mIn.readInt();
|
||||
/*entriesStart*/
|
||||
mIn.skipInt();
|
||||
/*entriesStart*/ mIn.skipInt();
|
||||
|
||||
ResConfigFlags flags = readConfigFlags();
|
||||
int[] entryOffsets = mIn.readIntArray(entryCount);
|
||||
@ -248,13 +247,13 @@ public class ARSCDecoder {
|
||||
byte keyboard = mIn.readByte();
|
||||
byte navigation = mIn.readByte();
|
||||
byte inputFlags = mIn.readByte();
|
||||
mIn.skipBytes(1);
|
||||
/*inputPad0*/ mIn.skipBytes(1);
|
||||
|
||||
short screenWidth = mIn.readShort();
|
||||
short screenHeight = mIn.readShort();
|
||||
|
||||
short sdkVersion = mIn.readShort();
|
||||
mIn.skipBytes(2);
|
||||
/*minorVersion, now must always be 0*/ mIn.skipBytes(2);
|
||||
|
||||
byte screenLayout = 0;
|
||||
byte uiMode = 0;
|
||||
|
@ -17,9 +17,14 @@
|
||||
package brut.androlib.res.decoder;
|
||||
|
||||
import android.content.res.XmlResourceParser;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import android.util.TypedValue;
|
||||
import brut.androlib.AndrolibException;
|
||||
@ -812,7 +817,9 @@ public class AXmlResourceParser implements XmlResourceParser {
|
||||
}
|
||||
|
||||
int event = m_event;
|
||||
resetEventInfo();
|
||||
if (event != START_DOCUMENT) {//keep m_lineNumber
|
||||
resetEventInfo();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (m_decreaseDepth) {
|
||||
@ -834,47 +841,49 @@ public class AXmlResourceParser implements XmlResourceParser {
|
||||
chunkType = CHUNK_XML_START_TAG;
|
||||
} else {
|
||||
chunkType = m_reader.readInt();
|
||||
}
|
||||
|
||||
if (chunkType == CHUNK_RESOURCEIDS) {
|
||||
int chunkSize = m_reader.readInt();
|
||||
if (chunkSize < 8 || (chunkSize % 4) != 0) {
|
||||
throw new IOException("Invalid resource ids size (" + chunkSize + ").");
|
||||
if (chunkType == CHUNK_RESOURCEIDS) {
|
||||
int chunkSize = m_reader.readInt();
|
||||
if (chunkSize < 8 || (chunkSize % 4) != 0) {
|
||||
throw new IOException("Invalid resource ids size (" + chunkSize + ").");
|
||||
}
|
||||
m_resourceIDs = m_reader.readIntArray(chunkSize / 4 - 2);
|
||||
continue;
|
||||
}
|
||||
m_resourceIDs = m_reader.readIntArray(chunkSize / 4 - 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (chunkType < CHUNK_XML_FIRST || chunkType > CHUNK_XML_LAST) {
|
||||
throw new IOException("Invalid chunk type (" + chunkType + ").");
|
||||
}
|
||||
|
||||
// Fake START_DOCUMENT event.
|
||||
if (chunkType == CHUNK_XML_START_TAG && event == -1) {
|
||||
m_event = START_DOCUMENT;
|
||||
break;
|
||||
}
|
||||
|
||||
// Common header.
|
||||
/*chunkSize*/ m_reader.skipInt();
|
||||
int lineNumber = m_reader.readInt();
|
||||
/*0xFFFFFFFF*/ m_reader.skipInt();
|
||||
|
||||
if (chunkType == CHUNK_XML_START_NAMESPACE
|
||||
|| chunkType == CHUNK_XML_END_NAMESPACE) {
|
||||
if (chunkType == CHUNK_XML_START_NAMESPACE) {
|
||||
int prefix = m_reader.readInt();
|
||||
int uri = m_reader.readInt();
|
||||
m_namespaces.push(prefix, uri);
|
||||
} else {
|
||||
/*prefix*/ m_reader.skipInt();
|
||||
/*uri*/ m_reader.skipInt();
|
||||
m_namespaces.pop();
|
||||
if (chunkType < CHUNK_XML_FIRST || chunkType > CHUNK_XML_LAST) {
|
||||
throw new IOException("Invalid chunk type (" + chunkType + ").");
|
||||
}
|
||||
continue;
|
||||
|
||||
// Common header.
|
||||
/*chunkSize*/ m_reader.skipInt();
|
||||
int lineNumber = m_reader.readInt();
|
||||
/*0xFFFFFFFF*/ m_reader.skipInt();
|
||||
|
||||
// Fake START_DOCUMENT event.
|
||||
if (chunkType == CHUNK_XML_START_TAG && event == -1) {
|
||||
m_event = START_DOCUMENT;
|
||||
m_lineNumber = lineNumber;
|
||||
break;
|
||||
}
|
||||
|
||||
if (chunkType == CHUNK_XML_START_NAMESPACE
|
||||
|| chunkType == CHUNK_XML_END_NAMESPACE) {
|
||||
if (chunkType == CHUNK_XML_START_NAMESPACE) {
|
||||
int prefix = m_reader.readInt();
|
||||
int uri = m_reader.readInt();
|
||||
m_namespaces.push(prefix, uri);
|
||||
} else {
|
||||
/*prefix*/ m_reader.skipInt();
|
||||
/*uri*/ m_reader.skipInt();
|
||||
m_namespaces.pop();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
m_lineNumber = lineNumber;
|
||||
}
|
||||
|
||||
m_lineNumber = lineNumber;
|
||||
|
||||
if (chunkType == CHUNK_XML_START_TAG) {
|
||||
m_namespaceUri = m_reader.readInt();
|
||||
@ -893,6 +902,13 @@ public class AXmlResourceParser implements XmlResourceParser {
|
||||
}
|
||||
m_namespaces.increaseDepth();
|
||||
m_event = START_TAG;
|
||||
m_strings.touch(m_name, m_name);
|
||||
for(int i = 0; i<attributeCount; i++) {
|
||||
m_strings.touch(m_attributes[ATTRIBUTE_IX_NAME], m_name);
|
||||
m_strings.touch(m_attributes[ATTRIBUTE_IX_VALUE_STRING], m_name);
|
||||
}
|
||||
m_strings.touch(m_name, m_name);
|
||||
sortAttrs();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -914,7 +930,97 @@ public class AXmlResourceParser implements XmlResourceParser {
|
||||
}
|
||||
}
|
||||
|
||||
private void setFirstError(AndrolibException error) {
|
||||
private static String formatArray(int[] array, int min, int max) {
|
||||
if(max > array.length)
|
||||
max = array.length;
|
||||
if(min < 0)
|
||||
min = 0;
|
||||
StringBuffer sb = new StringBuffer("[");
|
||||
int i = min;
|
||||
while(true) {
|
||||
sb.append(array[i]);
|
||||
i++;
|
||||
if(i < max) {
|
||||
sb.append(", ");
|
||||
} else {
|
||||
sb.append("]");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private boolean compareAttr(int[] attr1, int[] attr2) {
|
||||
//TODO: sort Attrs
|
||||
/*
|
||||
* ATTRIBUTE_IX_VALUE_TYPE == TYPE_STRING : ATTRIBUTE_IX_VALUE_STRING
|
||||
* : ATTRIBUTE_IX_NAMESPACE_URI
|
||||
* ATTRIBUTE_IX_NAMESPACE_URI : ATTRIBUTE_IX_NAME
|
||||
* id
|
||||
*
|
||||
*/
|
||||
if(attr1[ATTRIBUTE_IX_VALUE_TYPE] == TypedValue.TYPE_STRING &&
|
||||
attr1[ATTRIBUTE_IX_VALUE_TYPE] == attr2[ATTRIBUTE_IX_VALUE_TYPE] &&
|
||||
//(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]) {
|
||||
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) &&
|
||||
//(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])) {
|
||||
return (attr1[ATTRIBUTE_IX_NAME] < attr2[ATTRIBUTE_IX_NAME]);
|
||||
//} else if (attr1[ATTRIBUTE_IX_NAMESPACE_URI] < attr2[ATTRIBUTE_IX_NAMESPACE_URI]) {
|
||||
// return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void sortAttrs() {
|
||||
int attributeCount = m_attributes.length/ATTRIBUTE_LENGHT;
|
||||
int tmp1[][] = new int[attributeCount][];
|
||||
int tmp2[] = null;
|
||||
for (int i = 0; i < attributeCount;i++) {
|
||||
tmp1[i] = new int[ATTRIBUTE_LENGHT+1];
|
||||
for(int j = 0; j < ATTRIBUTE_LENGHT; j++) {
|
||||
tmp1[i][j] = m_attributes[i*ATTRIBUTE_LENGHT+j];
|
||||
}
|
||||
tmp1[i][ATTRIBUTE_LENGHT] = i;
|
||||
if(DBG) {
|
||||
try {
|
||||
if (dbgOut == null) {
|
||||
dbgOut = new BufferedWriter(new FileWriter("C:\\res.log",false));
|
||||
}
|
||||
dbgOut.write("Namespace: " + getAttributeNamespace (i) +
|
||||
", Name: " + getAttributeName (i)+
|
||||
", Value: " + getAttributeValue (i) + ", Array: " +
|
||||
formatArray(tmp1[i], 0, ATTRIBUTE_LENGHT) + "\n");
|
||||
dbgOut.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int j = 1; j < attributeCount;j++) {
|
||||
for (int i = 1; i < attributeCount;i++) {
|
||||
if(compareAttr(tmp1[i], tmp1[i-1])) {
|
||||
tmp2 = tmp1[i-1];
|
||||
tmp1[i-1] = tmp1[i];
|
||||
tmp1[i] = tmp2;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < attributeCount;i++) {
|
||||
for(int j = 0; j < ATTRIBUTE_LENGHT; j++) {
|
||||
m_attributes[i*ATTRIBUTE_LENGHT+j] = tmp1[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setFirstError(AndrolibException error) {
|
||||
if (mFirstError == null) {
|
||||
mFirstError = error;
|
||||
}
|
||||
@ -964,4 +1070,6 @@ public class AXmlResourceParser implements XmlResourceParser {
|
||||
CHUNK_XML_END_TAG = 0x00100103,
|
||||
CHUNK_XML_TEXT = 0x00100104,
|
||||
CHUNK_XML_LAST = 0x00100104;
|
||||
private Writer dbgOut = null;
|
||||
private final static boolean DBG = false;
|
||||
}
|
@ -116,6 +116,30 @@ public class ResFileDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
public void decodeManifest(Directory inDir, String inFileName, Directory outDir,
|
||||
String outFileName) throws AndrolibException {
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
try {
|
||||
in = inDir.getFileInput(inFileName);
|
||||
out = outDir.getFileOutput(outFileName);
|
||||
((XmlPullStreamDecoder)mDecoders.getDecoder("xml")).decodeManifest(in, out);
|
||||
} 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());
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import brut.util.ExtDataInput;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@ -53,6 +54,10 @@ public class StringBlock {
|
||||
StringBlock block = new StringBlock();
|
||||
block.m_isUTF8 = (flags & UTF8_FLAG) != 0;
|
||||
block.m_stringOffsets = reader.readIntArray(stringCount);
|
||||
block.m_stringOwns = new int[stringCount];
|
||||
for (int i=0;i<stringCount;i++) {
|
||||
block.m_stringOwns[i] = -1;
|
||||
}
|
||||
if (styleOffsetCount != 0) {
|
||||
block.m_styleOffsets = reader.readIntArray(styleOffsetCount);
|
||||
}
|
||||
@ -311,11 +316,28 @@ public class StringBlock {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean touch(int index, int own) {
|
||||
if (index < 0
|
||||
|| m_stringOwns == null
|
||||
|| index >= m_stringOwns.length) {
|
||||
return false;
|
||||
}
|
||||
if(m_stringOwns[index] == -1) {
|
||||
m_stringOwns[index] = own;
|
||||
return true;
|
||||
} else if (m_stringOwns[index] == own) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private int[] m_stringOffsets;
|
||||
private byte[] m_strings;
|
||||
private int[] m_styleOffsets;
|
||||
private int[] m_styles;
|
||||
private boolean m_isUTF8;
|
||||
private int[] m_stringOwns;
|
||||
private static final CharsetDecoder UTF16LE_DECODER =
|
||||
Charset.forName("UTF-16LE").newDecoder();
|
||||
private static final CharsetDecoder UTF8_DECODER =
|
||||
|
@ -17,10 +17,15 @@
|
||||
package brut.androlib.res.decoder;
|
||||
|
||||
import brut.androlib.AndrolibException;
|
||||
import brut.androlib.res.AndrolibResources;
|
||||
import brut.androlib.res.data.ResTable;
|
||||
import brut.androlib.res.util.ExtXmlSerializer;
|
||||
import java.io.*;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.xmlpull.v1.*;
|
||||
import org.xmlpull.v1.wrapper.*;
|
||||
import org.xmlpull.v1.wrapper.classic.StaticXmlSerializerWrapper;
|
||||
|
||||
/**
|
||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||
@ -37,7 +42,74 @@ public class XmlPullStreamDecoder implements ResStreamDecoder {
|
||||
try {
|
||||
XmlPullWrapperFactory factory = XmlPullWrapperFactory.newInstance();
|
||||
XmlPullParserWrapper par = factory.newPullParserWrapper(mParser);
|
||||
XmlSerializerWrapper ser = factory.newSerializerWrapper(mSerial);
|
||||
final ResTable resTable = ((AXmlResourceParser)mParser).getAttrDecoder().getCurrentPackage().getResTable();
|
||||
final boolean optimizeForManifest = mOptimizeForManifest;
|
||||
XmlSerializerWrapper ser = new StaticXmlSerializerWrapper(mSerial, factory){
|
||||
boolean hideSdkInfo = false;
|
||||
@Override
|
||||
public void event(XmlPullParser pp) throws XmlPullParserException, IOException {
|
||||
int type = pp.getEventType();
|
||||
int newLine = pp.getLineNumber();
|
||||
if ((!optimizeForManifest) || newLine != 0) {
|
||||
((ExtXmlSerializer)xs).setLineNumber(newLine, type);
|
||||
super.event(pp);
|
||||
} else {
|
||||
if (type == XmlPullParser.START_TAG) {
|
||||
if ("uses-sdk".equalsIgnoreCase(pp.getName())) {
|
||||
|
||||
//TODO: parse uses-sdk( and some others?)
|
||||
/*
|
||||
* (--version-code)
|
||||
* (--version-name)
|
||||
* (debuggable)
|
||||
* (...)
|
||||
* --min-sdk-version
|
||||
* --target-sdk-version
|
||||
* --max-sdk-version
|
||||
*/
|
||||
try {
|
||||
hideSdkInfo = parseAttr(pp);
|
||||
if(hideSdkInfo) {
|
||||
return;
|
||||
}
|
||||
} catch (AndrolibException e) {}
|
||||
}
|
||||
LOGGER.warning("Found generated line but parse failed, output it in xml.");
|
||||
} else if (hideSdkInfo && type == XmlPullParser.END_TAG &&
|
||||
"uses-sdk".equalsIgnoreCase(pp.getName())) {
|
||||
return;
|
||||
}
|
||||
//((ExtXmlSerializer)xs).setLineNumber(newLine, type);
|
||||
super.event(pp);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean parseAttr(XmlPullParser pp) throws AndrolibException {
|
||||
ResTable restable = resTable;
|
||||
for (int i = 0; i < pp.getAttributeCount(); i++) {
|
||||
final String a_ns = "http://schemas.android.com/apk/res/android";
|
||||
String ns = pp.getAttributeNamespace (i);
|
||||
if (a_ns.equalsIgnoreCase(ns)) {
|
||||
String name = pp.getAttributeName (i);
|
||||
String value = pp.getAttributeValue (i);
|
||||
if (name != null && value != null) {
|
||||
if (name.equalsIgnoreCase("minSdkVersion") ||
|
||||
name.equalsIgnoreCase("targetSdkVersion") ||
|
||||
name.equalsIgnoreCase("maxSdkVersion")) {
|
||||
restable.addSdkInfo(name, value);
|
||||
} else {
|
||||
restable.clearSdkInfo();
|
||||
return false;//Found unknown flags
|
||||
}
|
||||
}
|
||||
} else {
|
||||
resTable.clearSdkInfo();
|
||||
return false;//Found unknown flags
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};//factory.newSerializerWrapper(mSerial);
|
||||
|
||||
par.setInput(in, null);
|
||||
ser.setOutput(out, null);
|
||||
@ -54,6 +126,21 @@ public class XmlPullStreamDecoder implements ResStreamDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
public void decodeManifest(InputStream in, OutputStream out)
|
||||
throws AndrolibException {
|
||||
mOptimizeForManifest = true;
|
||||
try {
|
||||
decode(in, out);
|
||||
} finally {
|
||||
mOptimizeForManifest = false;
|
||||
}
|
||||
}
|
||||
|
||||
private final XmlPullParser mParser;
|
||||
private final ExtXmlSerializer mSerial;
|
||||
|
||||
private boolean mOptimizeForManifest = false;
|
||||
|
||||
private final static Logger LOGGER =
|
||||
Logger.getLogger(XmlPullStreamDecoder.class.getName());
|
||||
}
|
||||
|
@ -17,7 +17,10 @@
|
||||
package brut.androlib.res.util;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.xmlpull.mxp1_serializer.MXSerializer;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
/**
|
||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||
@ -26,9 +29,11 @@ public class ExtMXSerializer extends MXSerializer implements ExtXmlSerializer {
|
||||
@Override
|
||||
public void startDocument(String encoding, Boolean standalone) throws
|
||||
IOException, IllegalArgumentException, IllegalStateException {
|
||||
super.startDocument(encoding != null ? encoding : mDefaultEncoding,
|
||||
standalone);
|
||||
this.newLine();
|
||||
if (!enableLineOpt || mNewLine >= 1) {
|
||||
super.startDocument(encoding != null ? encoding : mDefaultEncoding,
|
||||
standalone);
|
||||
this.newLine();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -66,13 +71,129 @@ public class ExtMXSerializer extends MXSerializer implements ExtXmlSerializer {
|
||||
|
||||
public ExtXmlSerializer newLine() throws IOException {
|
||||
super.out.write(lineSeparator);
|
||||
mCurLine ++;
|
||||
dbg("Nline: " + mCurLine);
|
||||
return this;
|
||||
}
|
||||
|
||||
//XmlPullParser.START_TAG("</")
|
||||
// if(doIndent) writeIndent();
|
||||
@Override
|
||||
protected void writeIndent() throws IOException {
|
||||
if(!enableLineOpt || mCurLine < mNewLine) {
|
||||
super.writeIndent();
|
||||
mCurLine ++;
|
||||
dbg("Iline: "+mCurLine);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtXmlSerializer setLineNumber(int newLine, int event) throws IOException {
|
||||
dbg(/*"curline: " + mCurLine + */", event: " + XmlPullParser.TYPES[event] +
|
||||
", newline: " + newLine);
|
||||
if (newLine == -1) {//Can`t fount line number info
|
||||
enableLineOpt = false;
|
||||
} else {
|
||||
enableLineOpt = true;
|
||||
if (event == XmlPullParser.START_DOCUMENT) {
|
||||
if (newLine > 1) {
|
||||
mNewLine = 1;
|
||||
} else {
|
||||
mNewLine = 0;
|
||||
}
|
||||
} else {
|
||||
mNewLine = newLine;
|
||||
if (!startTagIncomplete) {//XmlPullParser.START_TAG("<")
|
||||
dbg(", old event:"+XmlPullParser.TYPES[mLastEvent]);
|
||||
if(mLastEvent != XmlPullParser.END_TAG) {
|
||||
moveToLine (newLine);
|
||||
} else {
|
||||
moveToLine (newLine - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
mLastEvent = event;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
//XmlPullParser.END_TAG(" />") and XmlPullParser.START_TAG("><")
|
||||
@Override
|
||||
protected void writeNamespaceDeclarations() throws IOException {
|
||||
super.writeNamespaceDeclarations();
|
||||
if (enableLineOpt) {
|
||||
if (mLastEvent == XmlPullParser.END_TAG) {
|
||||
moveToLine (mNewLine);
|
||||
} else {
|
||||
moveToLine (mNewLine - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ExtXmlSerializer moveToLine(int newLine) throws IOException {
|
||||
int addLines = newLine - mCurLine;
|
||||
dbg(", addLines: " + addLines);
|
||||
for (; addLines > 0; addLines --) {
|
||||
newLine();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void reset() {
|
||||
super.reset();
|
||||
mCurLine = 1;
|
||||
mLastEvent = XmlPullParser.START_DOCUMENT;
|
||||
enableLineOpt = false;
|
||||
}
|
||||
|
||||
public void setDisabledAttrEscape(boolean disabled) {
|
||||
mIsDisabledAttrEscape = disabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XmlSerializer text(String text) throws IOException {
|
||||
if (enableLineOpt) {
|
||||
mCurLine += (getTextLineNum(text) - 1);
|
||||
}
|
||||
return super.text(text);
|
||||
}
|
||||
|
||||
private int getTextLineNum(String text) {
|
||||
String str = "." + text + ".";
|
||||
int linenum = str.split("\\n").length + str.split("\\r").length
|
||||
- str.split("\\n\\r").length;//(Unix(LF)-1) + (Mac(CR)-1) - (Win(CRLF)-1) + 1
|
||||
return linenum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XmlSerializer text(char[] buf, int start, int len)
|
||||
throws IOException {
|
||||
if (enableLineOpt) {
|
||||
mCurLine += (getTextLineNum(new String(buf, start, len)) - 1);
|
||||
}
|
||||
return super.text(buf, start, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ignorableWhitespace(String text) throws IOException {
|
||||
if (enableLineOpt) {
|
||||
mCurLine += (getTextLineNum(text) - 1);
|
||||
}
|
||||
super.ignorableWhitespace(text);
|
||||
}
|
||||
|
||||
private String mDefaultEncoding;
|
||||
private boolean mIsDisabledAttrEscape = false;
|
||||
private int mCurLine;
|
||||
private int mNewLine;
|
||||
private int mLastEvent;
|
||||
private boolean enableLineOpt = false;
|
||||
private final static boolean DBG = false;
|
||||
|
||||
public ExtXmlSerializer dbg(String str) throws IOException {
|
||||
if(DBG)
|
||||
super.out.write("<!--"+str+"-->");
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,8 @@ public interface ExtXmlSerializer extends XmlSerializer {
|
||||
|
||||
public ExtXmlSerializer newLine() throws IOException;
|
||||
public void setDisabledAttrEscape(boolean disabled);
|
||||
public ExtXmlSerializer setLineNumber(int newLine, int event) throws IOException;
|
||||
public ExtXmlSerializer dbg(String str) throws IOException;
|
||||
|
||||
public static final String PROPERTY_SERIALIZER_INDENTATION =
|
||||
"http://xmlpull.org/v1/doc/properties.html#serializer-indentation";
|
||||
|
@ -44,7 +44,7 @@ public class SmaliDecoder {
|
||||
baksmali.disassembleDexFile(mApkFile.getAbsolutePath(),
|
||||
new DexFile(mApkFile), false, mOutDir.getAbsolutePath(), null,
|
||||
null, null, false, true, true, true, false, false,
|
||||
mDebug ? main.FULLMERGE : 0, false, false, null);
|
||||
mDebug ? main.ALLPRE : 0, false, false, null);
|
||||
} catch (IOException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user