mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-05-01 22:54:26 +02:00
fix XML encode errors
This commit is contained in:
parent
1b9ed9c291
commit
7389358a18
@ -42,9 +42,11 @@ import java.util.*;
|
|||||||
private final ApkModule apkModule;
|
private final ApkModule apkModule;
|
||||||
private final Map<Integer, Set<ResConfig>> decodedEntries;
|
private final Map<Integer, Set<ResConfig>> decodedEntries;
|
||||||
private XMLBagDecoder xmlBagDecoder;
|
private XMLBagDecoder xmlBagDecoder;
|
||||||
|
private final Set<String> mDecodedPaths;
|
||||||
public ApkModuleXmlDecoder(ApkModule apkModule){
|
public ApkModuleXmlDecoder(ApkModule apkModule){
|
||||||
this.apkModule=apkModule;
|
this.apkModule=apkModule;
|
||||||
this.decodedEntries = new HashMap<>();
|
this.decodedEntries = new HashMap<>();
|
||||||
|
this.mDecodedPaths = new HashSet<>();
|
||||||
}
|
}
|
||||||
public void decodeTo(File outDir)
|
public void decodeTo(File outDir)
|
||||||
throws IOException, XMLException {
|
throws IOException, XMLException {
|
||||||
@ -60,6 +62,8 @@ import java.util.*;
|
|||||||
|
|
||||||
decodeAndroidManifest(entryStore, outDir);
|
decodeAndroidManifest(entryStore, outDir);
|
||||||
|
|
||||||
|
addDecodedPath(TableBlock.FILE_NAME);
|
||||||
|
|
||||||
logMessage("Decoding resource files ...");
|
logMessage("Decoding resource files ...");
|
||||||
List<ResFile> resFileList=apkModule.listResFiles();
|
List<ResFile> resFileList=apkModule.listResFiles();
|
||||||
for(ResFile resFile:resFileList){
|
for(ResFile resFile:resFileList){
|
||||||
@ -76,6 +80,7 @@ import java.util.*;
|
|||||||
}else {
|
}else {
|
||||||
decodeResRaw(outDir, resFile);
|
decodeResRaw(outDir, resFile);
|
||||||
}
|
}
|
||||||
|
addDecodedPath(resFile.getFilePath());
|
||||||
}
|
}
|
||||||
private void decodeResRaw(File outDir, ResFile resFile)
|
private void decodeResRaw(File outDir, ResFile resFile)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
@ -147,6 +152,7 @@ import java.util.*;
|
|||||||
int currentPackageId= manifestBlock.guessCurrentPackageId();
|
int currentPackageId= manifestBlock.guessCurrentPackageId();
|
||||||
XMLDocument xmlDocument=manifestBlock.decodeToXml(entryStore, currentPackageId);
|
XMLDocument xmlDocument=manifestBlock.decodeToXml(entryStore, currentPackageId);
|
||||||
xmlDocument.save(file, true);
|
xmlDocument.save(file, true);
|
||||||
|
addDecodedPath(AndroidManifestBlock.FILE_NAME);
|
||||||
}
|
}
|
||||||
private void addDecodedEntry(Collection<EntryBlock> entryBlockList){
|
private void addDecodedEntry(Collection<EntryBlock> entryBlockList){
|
||||||
for(EntryBlock entryBlock:entryBlockList){
|
for(EntryBlock entryBlock:entryBlockList){
|
||||||
@ -245,7 +251,11 @@ import java.util.*;
|
|||||||
logMessage("Extracting root files");
|
logMessage("Extracting root files");
|
||||||
File rootDir = new File(outDir, "root");
|
File rootDir = new File(outDir, "root");
|
||||||
for(InputSource inputSource:apkModule.getApkArchive().listInputSources()){
|
for(InputSource inputSource:apkModule.getApkArchive().listInputSources()){
|
||||||
|
if(containsDecodedPath(inputSource.getAlias())){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
extractRootFiles(rootDir, inputSource);
|
extractRootFiles(rootDir, inputSource);
|
||||||
|
addDecodedPath(inputSource.getAlias());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void extractRootFiles(File rootDir, InputSource inputSource) throws IOException {
|
private void extractRootFiles(File rootDir, InputSource inputSource) throws IOException {
|
||||||
@ -260,6 +270,12 @@ import java.util.*;
|
|||||||
inputSource.write(outputStream);
|
inputSource.write(outputStream);
|
||||||
outputStream.close();
|
outputStream.close();
|
||||||
}
|
}
|
||||||
|
private boolean containsDecodedPath(String path){
|
||||||
|
return mDecodedPaths.contains(path);
|
||||||
|
}
|
||||||
|
private void addDecodedPath(String path){
|
||||||
|
mDecodedPaths.add(path);
|
||||||
|
}
|
||||||
|
|
||||||
private void logMessage(String msg) {
|
private void logMessage(String msg) {
|
||||||
APKLogger apkLogger=apkModule.getApkLogger();
|
APKLogger apkLogger=apkModule.getApkLogger();
|
||||||
|
@ -49,7 +49,7 @@ public class ApkUtil {
|
|||||||
public static List<File> recursiveFiles(File dir, String ext){
|
public static List<File> recursiveFiles(File dir, String ext){
|
||||||
List<File> results=new ArrayList<>();
|
List<File> results=new ArrayList<>();
|
||||||
if(dir.isFile()){
|
if(dir.isFile()){
|
||||||
if(ext==null || dir.getName().endsWith(ext)){
|
if(hasExtension(dir, ext)){
|
||||||
results.add(dir);
|
results.add(dir);
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
@ -63,7 +63,7 @@ public class ApkUtil {
|
|||||||
}
|
}
|
||||||
for(File file:files){
|
for(File file:files){
|
||||||
if(file.isFile()){
|
if(file.isFile()){
|
||||||
if(ext!=null && !file.getName().endsWith(ext)){
|
if(!hasExtension(file, ext)){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
results.add(file);
|
results.add(file);
|
||||||
@ -74,26 +74,7 @@ public class ApkUtil {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
public static List<File> recursiveFiles(File dir){
|
public static List<File> recursiveFiles(File dir){
|
||||||
List<File> results=new ArrayList<>();
|
return recursiveFiles(dir, null);
|
||||||
if(dir.isFile()){
|
|
||||||
results.add(dir);
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
if(!dir.isDirectory()){
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
File[] files=dir.listFiles();
|
|
||||||
if(files==null){
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
for(File file:files){
|
|
||||||
if(file.isFile()){
|
|
||||||
results.add(file);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
results.addAll(recursiveFiles(file));
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
}
|
||||||
public static List<File> listDirectories(File dir){
|
public static List<File> listDirectories(File dir){
|
||||||
List<File> results=new ArrayList<>();
|
List<File> results=new ArrayList<>();
|
||||||
@ -116,7 +97,7 @@ public class ApkUtil {
|
|||||||
}
|
}
|
||||||
for(File file:files){
|
for(File file:files){
|
||||||
if(file.isFile()){
|
if(file.isFile()){
|
||||||
if(ext!=null && !file.getName().endsWith(ext)){
|
if(!hasExtension(file, ext)){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
results.add(file);
|
results.add(file);
|
||||||
@ -124,6 +105,14 @@ public class ApkUtil {
|
|||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
private static boolean hasExtension(File file, String ext){
|
||||||
|
if(ext==null){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String name=file.getName().toLowerCase();
|
||||||
|
ext=ext.toLowerCase();
|
||||||
|
return name.endsWith(ext);
|
||||||
|
}
|
||||||
public static String toModuleName(File file){
|
public static String toModuleName(File file){
|
||||||
String name=file.getName();
|
String name=file.getName();
|
||||||
int i=name.lastIndexOf('.');
|
int i=name.lastIndexOf('.');
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
private PackageBlock currentPackage;
|
private PackageBlock currentPackage;
|
||||||
private final Set<FrameworkTable> frameworkTables = new HashSet<>();
|
private final Set<FrameworkTable> frameworkTables = new HashSet<>();
|
||||||
private APKLogger apkLogger;
|
private APKLogger apkLogger;
|
||||||
|
private boolean mForceCreateNamespaces = true;
|
||||||
public EncodeMaterials(){
|
public EncodeMaterials(){
|
||||||
}
|
}
|
||||||
public SpecString getSpecString(String name){
|
public SpecString getSpecString(String name){
|
||||||
@ -278,6 +279,11 @@
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EncodeMaterials setForceCreateNamespaces(boolean force) {
|
||||||
|
this.mForceCreateNamespaces = force;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
public EncodeMaterials setPackageIds(ResourceIds.Table.Package packageIds) {
|
public EncodeMaterials setPackageIds(ResourceIds.Table.Package packageIds) {
|
||||||
this.packageIds = packageIds;
|
this.packageIds = packageIds;
|
||||||
return this;
|
return this;
|
||||||
@ -302,6 +308,10 @@
|
|||||||
public PackageBlock getCurrentPackage() {
|
public PackageBlock getCurrentPackage() {
|
||||||
return currentPackage;
|
return currentPackage;
|
||||||
}
|
}
|
||||||
|
public boolean isForceCreateNamespaces() {
|
||||||
|
return mForceCreateNamespaces;
|
||||||
|
}
|
||||||
|
|
||||||
public String getCurrentPackageName(){
|
public String getCurrentPackageName(){
|
||||||
return currentPackage.getName();
|
return currentPackage.getName();
|
||||||
}
|
}
|
||||||
|
@ -113,4 +113,9 @@ package com.reandroid.lib.apk.xmlencoder;
|
|||||||
}
|
}
|
||||||
public static final String NULL_PACKAGE_NAME = "NULL_PACKAGE_NAME";
|
public static final String NULL_PACKAGE_NAME = "NULL_PACKAGE_NAME";
|
||||||
private static final Pattern PATTERN_TYPE=Pattern.compile("^([a-z]+)[^a-z]*.*$");
|
private static final Pattern PATTERN_TYPE=Pattern.compile("^([a-z]+)[^a-z]*.*$");
|
||||||
|
|
||||||
|
public static final String URI_ANDROID = "http://schemas.android.com/apk/res/android";
|
||||||
|
public static final String URI_APP = "http://schemas.android.com/apk/res-auto";
|
||||||
|
public static final String PREFIX_ANDROID = "android";
|
||||||
|
public static final String PREFIX_APP = "app";
|
||||||
}
|
}
|
||||||
|
@ -63,10 +63,12 @@ public class XMLEncodeSource extends ByteInputSource {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
XMLFileEncoder xmlFileEncoder=new XMLFileEncoder(encodeMaterials);
|
XMLFileEncoder xmlFileEncoder=new XMLFileEncoder(encodeMaterials);
|
||||||
|
xmlFileEncoder.setCurrentPath(xmlSource.getPath());
|
||||||
encodeMaterials.logVerbose("Encoding xml: "+xmlSource.getPath());
|
encodeMaterials.logVerbose("Encoding xml: "+xmlSource.getPath());
|
||||||
resXmlBlock = xmlFileEncoder.encode(xmlSource.getXMLDocument());
|
resXmlBlock = xmlFileEncoder.encode(xmlSource.getXMLDocument());
|
||||||
} catch (XMLException ex) {
|
} catch (XMLException ex) {
|
||||||
throw new IOException(ex.getMessage(), ex);
|
throw new EncodeException("XMLException on: '"+xmlSource.getPath()
|
||||||
|
+"'\n '"+ex.getMessage()+"'");
|
||||||
}
|
}
|
||||||
return resXmlBlock;
|
return resXmlBlock;
|
||||||
}
|
}
|
||||||
|
@ -30,9 +30,15 @@ import java.io.InputStream;
|
|||||||
public class XMLFileEncoder {
|
public class XMLFileEncoder {
|
||||||
private final EncodeMaterials materials;
|
private final EncodeMaterials materials;
|
||||||
private ResXmlBlock resXmlBlock;
|
private ResXmlBlock resXmlBlock;
|
||||||
|
private String mCurrentPath;
|
||||||
public XMLFileEncoder(EncodeMaterials materials){
|
public XMLFileEncoder(EncodeMaterials materials){
|
||||||
this.materials=materials;
|
this.materials=materials;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Just for logging purpose
|
||||||
|
public void setCurrentPath(String path) {
|
||||||
|
this.mCurrentPath = path;
|
||||||
|
}
|
||||||
public ResXmlBlock encode(String xmlString){
|
public ResXmlBlock encode(String xmlString){
|
||||||
try {
|
try {
|
||||||
return encode(XMLDocument.load(xmlString));
|
return encode(XMLDocument.load(xmlString));
|
||||||
@ -50,6 +56,7 @@ public class XMLFileEncoder {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
public ResXmlBlock encode(File xmlFile){
|
public ResXmlBlock encode(File xmlFile){
|
||||||
|
setCurrentPath(xmlFile.getAbsolutePath());
|
||||||
try {
|
try {
|
||||||
return encode(XMLDocument.load(xmlFile));
|
return encode(XMLDocument.load(xmlFile));
|
||||||
} catch (XMLException ex) {
|
} catch (XMLException ex) {
|
||||||
@ -100,6 +107,14 @@ public class XMLFileEncoder {
|
|||||||
String prefix=attribute.getNamePrefix();
|
String prefix=attribute.getNamePrefix();
|
||||||
if(prefix!=null){
|
if(prefix!=null){
|
||||||
ResXmlStartNamespace ns = resXmlElement.getStartNamespaceByPrefix(prefix);
|
ResXmlStartNamespace ns = resXmlElement.getStartNamespaceByPrefix(prefix);
|
||||||
|
if(ns==null){
|
||||||
|
ns=forceCreateNamespace(resXmlElement, resourceId, prefix);
|
||||||
|
}
|
||||||
|
if(ns==null){
|
||||||
|
throw new EncodeException("Namespace not found: "
|
||||||
|
+attribute.toString()
|
||||||
|
+", path="+mCurrentPath);
|
||||||
|
}
|
||||||
xmlAttribute.setNamespaceReference(ns.getUriReference());
|
xmlAttribute.setNamespaceReference(ns.getUriReference());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,15 +140,14 @@ public class XMLFileEncoder {
|
|||||||
xmlAttribute.setRawValue(encodeResult.value);
|
xmlAttribute.setRawValue(encodeResult.value);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(attributeBag.contains(AttributeValueType.STRING)) {
|
if(attributeBag.isEqualType(AttributeValueType.STRING)) {
|
||||||
xmlAttribute.setValueAsString(valueText);
|
xmlAttribute.setValueAsString(valueText);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(EncodeUtil.isEmpty(valueText)) {
|
if(EncodeUtil.isEmpty(valueText)) {
|
||||||
xmlAttribute.setValueType(ValueType.NULL);
|
xmlAttribute.setValueAsString("");
|
||||||
xmlAttribute.setRawValue(0);
|
|
||||||
}else{
|
}else{
|
||||||
ValueDecoder.EncodeResult encodeResult =
|
ValueDecoder.EncodeResult encodeResult =
|
||||||
ValueDecoder.encodeGuessAny(valueText);
|
ValueDecoder.encodeGuessAny(valueText);
|
||||||
@ -145,6 +159,7 @@ public class XMLFileEncoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
resXmlElement.calculatePositions();
|
||||||
}
|
}
|
||||||
private void ensureNamespaces(XMLElement element, ResXmlElement resXmlElement){
|
private void ensureNamespaces(XMLElement element, ResXmlElement resXmlElement){
|
||||||
int count=element.getAttributeCount();
|
int count=element.getAttributeCount();
|
||||||
@ -181,4 +196,21 @@ public class XMLFileEncoder {
|
|||||||
idBuilder.add(entryBlock.getResourceId(), entryBlock.getName());
|
idBuilder.add(entryBlock.getResourceId(), entryBlock.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private ResXmlStartNamespace forceCreateNamespace(ResXmlElement resXmlElement,
|
||||||
|
int resourceId, String prefix){
|
||||||
|
if(!materials.isForceCreateNamespaces()){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int pkgId = (resourceId>>24) & 0xff;
|
||||||
|
String uri;
|
||||||
|
if(pkgId==materials.getCurrentPackageId()){
|
||||||
|
uri=EncodeUtil.URI_APP;
|
||||||
|
}else {
|
||||||
|
uri=EncodeUtil.URI_ANDROID;
|
||||||
|
}
|
||||||
|
ResXmlElement root=resXmlElement.getRootResXmlElement();
|
||||||
|
ResXmlStartNamespace ns=root.getOrCreateNamespace(uri, prefix);
|
||||||
|
materials.logMessage("Force created ns: "+prefix+":"+uri);
|
||||||
|
return ns;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,10 +52,8 @@ class XMLValuesEncoder {
|
|||||||
|
|
||||||
encodeValue(entryBlock, element);
|
encodeValue(entryBlock, element);
|
||||||
|
|
||||||
if(!entryBlock.isNull()){
|
SpecString specString = getMaterials().getSpecString(name);
|
||||||
SpecString specString = getMaterials().getSpecString(name);
|
entryBlock.setSpecReference(specString);
|
||||||
entryBlock.setSpecReference(specString);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void encodeValue(EntryBlock entryBlock, XMLElement element){
|
void encodeValue(EntryBlock entryBlock, XMLElement element){
|
||||||
String value = getValue(element);
|
String value = getValue(element);
|
||||||
|
@ -65,7 +65,7 @@ class XMLValuesEncoderStyle extends XMLValuesEncoderBag{
|
|||||||
bagItem.setType(ValueType.REFERENCE);
|
bagItem.setType(ValueType.REFERENCE);
|
||||||
}
|
}
|
||||||
bagItem.setData(getMaterials().resolveReference(valueText));
|
bagItem.setData(getMaterials().resolveReference(valueText));
|
||||||
}else if(attributeBag.contains(AttributeValueType.STRING)) {
|
}else if(attributeBag.isEqualType(AttributeValueType.STRING)) {
|
||||||
bagItem.setValueAsString(valueText);
|
bagItem.setValueAsString(valueText);
|
||||||
}else if(EncodeUtil.isEmpty(valueText)) {
|
}else if(EncodeUtil.isEmpty(valueText)) {
|
||||||
bagItem.setTypeAndData(ValueType.NULL, 0);
|
bagItem.setTypeAndData(ValueType.NULL, 0);
|
||||||
|
@ -247,7 +247,7 @@ public class TypeBlockArray extends BlockArray<TypeBlock>
|
|||||||
public int getHighestEntryCount(){
|
public int getHighestEntryCount(){
|
||||||
int result=0;
|
int result=0;
|
||||||
for(TypeBlock typeBlock:getChildes()){
|
for(TypeBlock typeBlock:getChildes()){
|
||||||
int count=typeBlock.getEntryCount();
|
int count=typeBlock.getEntryBlockArray().childesCount();
|
||||||
if(count>result){
|
if(count>result){
|
||||||
result=count;
|
result=count;
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,12 @@ import java.util.*;
|
|||||||
addChild(4, mEndElementContainer);
|
addChild(4, mEndElementContainer);
|
||||||
addChild(5, mEndNamespaceList);
|
addChild(5, mEndNamespaceList);
|
||||||
}
|
}
|
||||||
|
public void calculatePositions(){
|
||||||
|
ResXmlStartElement start = getStartElement();
|
||||||
|
if(start!=null){
|
||||||
|
start.calculatePositions();
|
||||||
|
}
|
||||||
|
}
|
||||||
public ResXmlAttribute newAttribute(){
|
public ResXmlAttribute newAttribute(){
|
||||||
return getStartElement().newAttribute();
|
return getStartElement().newAttribute();
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ import java.util.regex.Pattern;
|
|||||||
return new EncodeResult(ValueType.INT_HEX, parseHex(numString));
|
return new EncodeResult(ValueType.INT_HEX, parseHex(numString));
|
||||||
}
|
}
|
||||||
if(isInteger(numString)){
|
if(isInteger(numString)){
|
||||||
return new EncodeResult(ValueType.INT_DEC, parseHex(numString));
|
return new EncodeResult(ValueType.INT_DEC, parseInteger(numString));
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ public class EntryGroup extends ItemGroup<EntryBlock> {
|
|||||||
}
|
}
|
||||||
boolean renameOk=false;
|
boolean renameOk=false;
|
||||||
for(EntryBlock block:items){
|
for(EntryBlock block:items){
|
||||||
if(block==null||block.isNull()){
|
if(block==null){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(block.getSpecReference()==specReference){
|
if(block.getSpecReference()==specReference){
|
||||||
@ -87,15 +87,22 @@ public class EntryGroup extends ItemGroup<EntryBlock> {
|
|||||||
return renameOk;
|
return renameOk;
|
||||||
}
|
}
|
||||||
public EntryBlock pickOne(){
|
public EntryBlock pickOne(){
|
||||||
EntryBlock defEntryBlock=getDefault();
|
EntryBlock[] items=getItems();
|
||||||
if(defEntryBlock!=null){
|
if(items==null){
|
||||||
return defEntryBlock;
|
return null;
|
||||||
}
|
}
|
||||||
Iterator<EntryBlock> itr=iterator(true);
|
EntryBlock result = null;
|
||||||
while (itr.hasNext()){
|
for(EntryBlock entryBlock:items){
|
||||||
return itr.next();
|
if(entryBlock==null){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(result==null || result.isNull()){
|
||||||
|
result=entryBlock;
|
||||||
|
}else if(entryBlock.isDefault()){
|
||||||
|
return entryBlock;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return result;
|
||||||
}
|
}
|
||||||
public EntryBlock getDefault(){
|
public EntryBlock getDefault(){
|
||||||
Iterator<EntryBlock> itr=iterator(true);
|
Iterator<EntryBlock> itr=iterator(true);
|
||||||
|
@ -278,28 +278,45 @@ public class EntryBlock extends Block implements JSONConvert<JSONObject> {
|
|||||||
private void setByteFlagsB(byte b){
|
private void setByteFlagsB(byte b){
|
||||||
mByteFlagsB.set(b);
|
mByteFlagsB.set(b);
|
||||||
}
|
}
|
||||||
public IntegerItem getSpecReferenceBlock(){
|
private IntegerItem getSpecReferenceBlock(){
|
||||||
return mSpecReference;
|
return mSpecReference;
|
||||||
}
|
}
|
||||||
public int getSpecReference(){
|
public int getSpecReference(){
|
||||||
|
if(mSpecReference==null){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
return mSpecReference.get();
|
return mSpecReference.get();
|
||||||
}
|
}
|
||||||
public void setSpecReference(int ref){
|
public void setSpecReference(int ref){
|
||||||
if(mSpecReference==null){
|
boolean created = createNullSpecReference();
|
||||||
return;
|
|
||||||
}
|
|
||||||
int old=mSpecReference.get();
|
int old=mSpecReference.get();
|
||||||
if(ref==old){
|
if(ref==old){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mSpecReference.set(ref);
|
mSpecReference.set(ref);
|
||||||
updateSpecRef(old, ref);
|
updateSpecRef(old, ref);
|
||||||
|
if(created){
|
||||||
|
updatePackage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public void setSpecReference(SpecString specString){
|
public void setSpecReference(SpecString specString){
|
||||||
removeSpecRef();
|
removeSpecRef();
|
||||||
if(mSpecReference!=null){
|
if(specString==null){
|
||||||
mSpecReference.set(specString.getIndex());
|
return;
|
||||||
}
|
}
|
||||||
|
boolean created = createNullSpecReference();
|
||||||
|
mSpecReference.set(specString.getIndex());
|
||||||
|
if(created){
|
||||||
|
updatePackage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private boolean createNullSpecReference(){
|
||||||
|
if(mSpecReference==null){
|
||||||
|
mSpecReference = new IntegerItem();
|
||||||
|
mSpecReference.setNull(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
public BaseResValue getResValue(){
|
public BaseResValue getResValue(){
|
||||||
return mResValue;
|
return mResValue;
|
||||||
@ -352,6 +369,13 @@ public class EntryBlock extends Block implements JSONConvert<JSONObject> {
|
|||||||
}
|
}
|
||||||
return specString.get();
|
return specString.get();
|
||||||
}
|
}
|
||||||
|
public String getNameOrHex(){
|
||||||
|
String name = getName();
|
||||||
|
if(name==null){
|
||||||
|
name = String.format("@0x%08x", getResourceId());
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
private void setName(String name){
|
private void setName(String name){
|
||||||
PackageBlock packageBlock=getPackageBlock();
|
PackageBlock packageBlock=getPackageBlock();
|
||||||
EntryGroup entryGroup = packageBlock.getEntryGroup(getResourceId());
|
EntryGroup entryGroup = packageBlock.getEntryGroup(getResourceId());
|
||||||
@ -378,6 +402,9 @@ public class EntryBlock extends Block implements JSONConvert<JSONObject> {
|
|||||||
return packageBlock.getName();
|
return packageBlock.getName();
|
||||||
}
|
}
|
||||||
public SpecString getSpecString(){
|
public SpecString getSpecString(){
|
||||||
|
if(mSpecReference==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
PackageBlock packageBlock=getPackageBlock();
|
PackageBlock packageBlock=getPackageBlock();
|
||||||
if(packageBlock==null){
|
if(packageBlock==null){
|
||||||
return null;
|
return null;
|
||||||
@ -486,7 +513,11 @@ public class EntryBlock extends Block implements JSONConvert<JSONObject> {
|
|||||||
this.mHeaderSize =new ShortItem();
|
this.mHeaderSize =new ShortItem();
|
||||||
this.mFlagEntryType =new ByteItem();
|
this.mFlagEntryType =new ByteItem();
|
||||||
this.mByteFlagsB=new ByteItem();
|
this.mByteFlagsB=new ByteItem();
|
||||||
this.mSpecReference = new IntegerItem();
|
if(mSpecReference==null){
|
||||||
|
this.mSpecReference = new IntegerItem();
|
||||||
|
}else if(mSpecReference.isNull()){
|
||||||
|
mSpecReference.setNull(false);
|
||||||
|
}
|
||||||
|
|
||||||
mHeaderSize.setIndex(0);
|
mHeaderSize.setIndex(0);
|
||||||
mFlagEntryType.setIndex(1);
|
mFlagEntryType.setIndex(1);
|
||||||
@ -625,11 +656,7 @@ public class EntryBlock extends Block implements JSONConvert<JSONObject> {
|
|||||||
updateSpecRef(-1, getSpecReference());
|
updateSpecRef(-1, getSpecReference());
|
||||||
}
|
}
|
||||||
private void updateSpecRef(int oldRef, int newNef){
|
private void updateSpecRef(int oldRef, int newNef){
|
||||||
TypeBlock typeBlock=getTypeBlock();
|
PackageBlock packageBlock=getPackageBlock();
|
||||||
if(typeBlock==null){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PackageBlock packageBlock=typeBlock.getPackageBlock();
|
|
||||||
if(packageBlock==null){
|
if(packageBlock==null){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -647,11 +674,7 @@ public class EntryBlock extends Block implements JSONConvert<JSONObject> {
|
|||||||
if(mSpecReference==null){
|
if(mSpecReference==null){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
TypeBlock typeBlock=getTypeBlock();
|
PackageBlock packageBlock=getPackageBlock();
|
||||||
if(typeBlock==null){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PackageBlock packageBlock=typeBlock.getPackageBlock();
|
|
||||||
if(packageBlock==null){
|
if(packageBlock==null){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -662,11 +685,7 @@ public class EntryBlock extends Block implements JSONConvert<JSONObject> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void updatePackage(){
|
private void updatePackage(){
|
||||||
TypeBlock typeBlock=getTypeBlock();
|
PackageBlock packageBlock=getPackageBlock();
|
||||||
if(typeBlock==null){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PackageBlock packageBlock=typeBlock.getPackageBlock();
|
|
||||||
if(packageBlock==null){
|
if(packageBlock==null){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -761,37 +780,6 @@ public class EntryBlock extends Block implements JSONConvert<JSONObject> {
|
|||||||
}
|
}
|
||||||
return new ResValueInt();
|
return new ResValueInt();
|
||||||
}
|
}
|
||||||
@Override
|
|
||||||
public String toString(){
|
|
||||||
StringBuilder builder=new StringBuilder();
|
|
||||||
builder.append(getClass().getSimpleName());
|
|
||||||
builder.append(": ");
|
|
||||||
ResConfig resConfig=getResConfig();
|
|
||||||
if(resConfig!=null){
|
|
||||||
builder.append(resConfig.toString());
|
|
||||||
builder.append(", ");
|
|
||||||
}
|
|
||||||
builder.append(" resId=");
|
|
||||||
builder.append(String.format("0x%08x", getResourceId()));
|
|
||||||
if(isNull()){
|
|
||||||
builder.append(", null entry");
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
String name=getResourceName();
|
|
||||||
if(name!=null){
|
|
||||||
builder.append('(');
|
|
||||||
builder.append(name);
|
|
||||||
builder.append(')');
|
|
||||||
}
|
|
||||||
BaseResValue baseResValue=getResValue();
|
|
||||||
if(baseResValue instanceof ResValueInt){
|
|
||||||
ResValueInt resValueInt=(ResValueInt)baseResValue;
|
|
||||||
builder.append(" '");
|
|
||||||
builder.append(resValueInt.toString());
|
|
||||||
builder.append(" '");
|
|
||||||
}
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
public static String buildResourceName(char prefix, String packageName, String type, String name){
|
public static String buildResourceName(char prefix, String packageName, String type, String name){
|
||||||
if(name==null){
|
if(name==null){
|
||||||
return null;
|
return null;
|
||||||
@ -811,6 +799,39 @@ public class EntryBlock extends Block implements JSONConvert<JSONObject> {
|
|||||||
builder.append(name);
|
builder.append(name);
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
StringBuilder builder=new StringBuilder();
|
||||||
|
builder.append(getClass().getSimpleName());
|
||||||
|
builder.append(": ");
|
||||||
|
ResConfig resConfig=getResConfig();
|
||||||
|
if(resConfig!=null){
|
||||||
|
builder.append(resConfig.toString());
|
||||||
|
builder.append(", ");
|
||||||
|
}
|
||||||
|
String name=getResourceName();
|
||||||
|
if(name==null){
|
||||||
|
name=getNameOrHex();
|
||||||
|
}else{
|
||||||
|
builder.append(" id=");
|
||||||
|
builder.append(String.format("0x%08x", getResourceId()));
|
||||||
|
}
|
||||||
|
builder.append('(');
|
||||||
|
builder.append(name);
|
||||||
|
builder.append(')');
|
||||||
|
if(isNull()){
|
||||||
|
builder.append(", null entry");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
BaseResValue baseResValue=getResValue();
|
||||||
|
if(baseResValue instanceof ResValueInt){
|
||||||
|
ResValueInt resValueInt=(ResValueInt)baseResValue;
|
||||||
|
builder.append(" '");
|
||||||
|
builder.append(resValueInt.toString());
|
||||||
|
builder.append(" '");
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
private final static short HEADER_SIZE_BAG = 0x0010;
|
private final static short HEADER_SIZE_BAG = 0x0010;
|
||||||
private final static short HEADER_SIZE_INT = 0x0008;
|
private final static short HEADER_SIZE_INT = 0x0008;
|
||||||
|
@ -31,6 +31,9 @@ public class AttributeBag {
|
|||||||
public boolean contains(AttributeValueType valueType){
|
public boolean contains(AttributeValueType valueType){
|
||||||
return getFormat().contains(valueType);
|
return getFormat().contains(valueType);
|
||||||
}
|
}
|
||||||
|
public boolean isEqualType(AttributeValueType valueType){
|
||||||
|
return getFormat().isEqualType(valueType);
|
||||||
|
}
|
||||||
public ValueDecoder.EncodeResult encodeEnumOrFlagValue(String valueString){
|
public ValueDecoder.EncodeResult encodeEnumOrFlagValue(String valueString){
|
||||||
if(valueString==null || !isEnumOrFlag()){
|
if(valueString==null || !isEnumOrFlag()){
|
||||||
return null;
|
return null;
|
||||||
|
@ -92,6 +92,14 @@ public class AttributeBagItem {
|
|||||||
int dataLow = 0xffff & getBagItem().getDataLow();
|
int dataLow = 0xffff & getBagItem().getDataLow();
|
||||||
return (dataLow & value) == value;
|
return (dataLow & value) == value;
|
||||||
}
|
}
|
||||||
|
public boolean isEqualType(AttributeValueType valueType){
|
||||||
|
if(valueType == null || getItemType()!=AttributeItemType.FORMAT){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int value = 0xff & valueType.getByte();
|
||||||
|
int dataLow = 0xffff & getBagItem().getDataLow();
|
||||||
|
return (dataLow == value);
|
||||||
|
}
|
||||||
public AttributeValueType[] getValueTypes(){
|
public AttributeValueType[] getValueTypes(){
|
||||||
AttributeItemType type=getItemType();
|
AttributeItemType type=getItemType();
|
||||||
if(type!=AttributeItemType.FORMAT){
|
if(type!=AttributeItemType.FORMAT){
|
||||||
|
@ -33,12 +33,6 @@ public class XMLTextAttribute extends XMLAttribute {
|
|||||||
if(unEscape){
|
if(unEscape){
|
||||||
return XMLUtil.unEscapeXmlChars(mText);
|
return XMLUtil.unEscapeXmlChars(mText);
|
||||||
}
|
}
|
||||||
if(mText!=null){
|
|
||||||
String junk= XMLUtil.unEscapeXmlChars(mText);
|
|
||||||
if(!mText.equals(junk)){
|
|
||||||
junk.trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mText;
|
return mText;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
|
@ -530,30 +530,17 @@ public class MXParser implements XmlPullParser
|
|||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
public String getPositionDescription ()
|
@Override
|
||||||
|
public String getPositionDescription()
|
||||||
{
|
{
|
||||||
String fragment = null;
|
return "line="+getLineNumber()+", col="+getColumnNumber();
|
||||||
if(posStart <= pos) {
|
|
||||||
final int start = findFragment(0, buf, posStart, pos);
|
|
||||||
|
|
||||||
if(start < pos) {
|
|
||||||
fragment = new String(buf, start, pos - start);
|
|
||||||
}
|
|
||||||
if(bufAbsoluteStart > 0 || start > 0) {
|
|
||||||
fragment = "..." + fragment;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return " "+TYPES[ eventType ] +
|
|
||||||
(fragment != null ? " seen "+printable(fragment)+"..." : "")
|
|
||||||
+" "+(location != null ? location : "")
|
|
||||||
+"@"+getLineNumber()+":"+getColumnNumber();
|
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public int getLineNumber()
|
public int getLineNumber()
|
||||||
{
|
{
|
||||||
return lineNumber;
|
return lineNumber;
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public int getColumnNumber()
|
public int getColumnNumber()
|
||||||
{
|
{
|
||||||
return columnNumber;
|
return columnNumber;
|
||||||
@ -740,11 +727,13 @@ public class MXParser implements XmlPullParser
|
|||||||
return attributeValue[ index ];
|
return attributeValue[ index ];
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAttributeValue(String namespace,
|
@Override
|
||||||
String name)
|
public String getAttributeValue(String namespace, String name)
|
||||||
{
|
{
|
||||||
if(eventType != START_TAG) throw new IndexOutOfBoundsException(
|
if(eventType != START_TAG) {
|
||||||
"only START_TAG can have attributes"+getPositionDescription());
|
throw new IndexOutOfBoundsException("only START_TAG can have attributes "
|
||||||
|
+getPositionDescription());
|
||||||
|
}
|
||||||
if(name == null) {
|
if(name == null) {
|
||||||
throw new IllegalArgumentException("attribute name can not be null");
|
throw new IllegalArgumentException("attribute name can not be null");
|
||||||
}
|
}
|
||||||
@ -1651,7 +1640,7 @@ public class MXParser implements XmlPullParser
|
|||||||
} // skip additional spaces
|
} // skip additional spaces
|
||||||
if(ch != '=') {
|
if(ch != '=') {
|
||||||
throw new XmlPullParserException(
|
throw new XmlPullParserException(
|
||||||
"expected = after attribute name", this, null);
|
"expected = after attribute name '"+name+processNamespaces+"'", this, null);
|
||||||
}
|
}
|
||||||
ch = more();
|
ch = more();
|
||||||
while(isS(ch)) {
|
while(isS(ch)) {
|
||||||
@ -2689,7 +2678,7 @@ public class MXParser implements XmlPullParser
|
|||||||
return (ch < LOOKUP_MAX_CHAR && lookupNameChar[ ch ])
|
return (ch < LOOKUP_MAX_CHAR && lookupNameChar[ ch ])
|
||||||
|| (ch >= LOOKUP_MAX_CHAR && ch <= '\u2027')
|
|| (ch >= LOOKUP_MAX_CHAR && ch <= '\u2027')
|
||||||
|| (ch >= '\u202A' && ch <= '\u218F')
|
|| (ch >= '\u202A' && ch <= '\u218F')
|
||||||
|| (ch >= '\u2800' && ch <= '\uFFEF');
|
|| (ch >= '\u2800' && ch <= '\uFFEF') || ch=='@';
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isS(char ch) {
|
protected boolean isS(char ch) {
|
||||||
|
@ -17,10 +17,7 @@ public class XmlPullParserException extends Exception {
|
|||||||
super(s);
|
super(s);
|
||||||
}
|
}
|
||||||
public XmlPullParserException(String msg, XmlPullParser parser, Throwable chain) {
|
public XmlPullParserException(String msg, XmlPullParser parser, Throwable chain) {
|
||||||
super ((msg == null ? "" : msg+" ")
|
super(buildMessage(msg, parser));
|
||||||
+ (parser == null ? "" : "(position:"+parser.getPositionDescription()+") ")
|
|
||||||
+ (chain == null ? "" : "caused by: "+chain));
|
|
||||||
|
|
||||||
if (parser != null) {
|
if (parser != null) {
|
||||||
this.row = parser.getLineNumber();
|
this.row = parser.getLineNumber();
|
||||||
this.column = parser.getColumnNumber();
|
this.column = parser.getColumnNumber();
|
||||||
@ -30,5 +27,19 @@ public class XmlPullParserException extends Exception {
|
|||||||
public Throwable getDetail() { return detail; }
|
public Throwable getDetail() { return detail; }
|
||||||
public int getLineNumber() { return row; }
|
public int getLineNumber() { return row; }
|
||||||
public int getColumnNumber() { return column; }
|
public int getColumnNumber() { return column; }
|
||||||
|
private static String buildMessage(String msg, XmlPullParser parser){
|
||||||
|
StringBuilder builder=new StringBuilder();
|
||||||
|
if(parser!=null){
|
||||||
|
builder.append("[line=");
|
||||||
|
builder.append(parser.getLineNumber());
|
||||||
|
builder.append(", col=");
|
||||||
|
builder.append(parser.getColumnNumber());
|
||||||
|
builder.append("] ");
|
||||||
|
}
|
||||||
|
if(msg!=null){
|
||||||
|
builder.append(msg);
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user