diff --git a/src/main/java/com/reandroid/apk/PathSanitizer.java b/src/main/java/com/reandroid/apk/PathSanitizer.java index a682fd9..94cb0bb 100644 --- a/src/main/java/com/reandroid/apk/PathSanitizer.java +++ b/src/main/java/com/reandroid/apk/PathSanitizer.java @@ -16,6 +16,7 @@ package com.reandroid.apk; import com.reandroid.archive.InputSource; +import com.reandroid.arsc.util.HexUtil; import java.util.Collection; import java.util.HashSet; @@ -148,7 +149,7 @@ public class PathSanitizer { } private static String createUniqueName(String name){ int hash = name.hashCode(); - return String.format("alias_%08x", hash).toLowerCase(); + return "alias_" + HexUtil.toHexNoPrefix8(hash); } private static boolean isGoodSimpleName(String name){ if(name==null){ diff --git a/src/main/java/com/reandroid/apk/ResourceIds.java b/src/main/java/com/reandroid/apk/ResourceIds.java index 7ebcc87..b1c195e 100644 --- a/src/main/java/com/reandroid/apk/ResourceIds.java +++ b/src/main/java/com/reandroid/apk/ResourceIds.java @@ -1,4 +1,4 @@ - /* +/* * Copyright (C) 2022 github.com/REAndroid * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,6 +19,7 @@ import com.reandroid.arsc.chunk.PackageBlock; import com.reandroid.arsc.chunk.TableBlock; import com.reandroid.arsc.group.EntryGroup; import com.reandroid.arsc.pool.SpecStringPool; +import com.reandroid.arsc.util.HexUtil; import com.reandroid.arsc.util.ResNameMap; import com.reandroid.json.JSONArray; import com.reandroid.json.JSONObject; @@ -379,7 +380,7 @@ import java.util.*; type.add(entry); } public String getHexId(){ - return String.format("0x%02x", id); + return HexUtil.toHex2(id); } public JSONObject toJson(){ JSONObject jsonObject=new JSONObject(); @@ -575,7 +576,7 @@ import java.util.*; return entryMap.get(entryId); } public String getHexId(){ - return String.format("0x%02x", id); + return HexUtil.toHex2(id); } public void add(Entry entry){ if(entry==null){ @@ -733,7 +734,7 @@ import java.util.*; | (getEntryId() & 0xffff); } public String getHexId(){ - return String.format("0x%08x", getResourceId()); + return HexUtil.toHex8(getResourceId()); } public void writeXml(String indent, Writer writer) throws IOException{ diff --git a/src/main/java/com/reandroid/apk/TableBlockJson.java b/src/main/java/com/reandroid/apk/TableBlockJson.java index a926e44..bf48d61 100644 --- a/src/main/java/com/reandroid/apk/TableBlockJson.java +++ b/src/main/java/com/reandroid/apk/TableBlockJson.java @@ -21,6 +21,7 @@ import com.reandroid.arsc.chunk.StagedAlias; import com.reandroid.arsc.chunk.TableBlock; import com.reandroid.arsc.chunk.TypeBlock; import com.reandroid.arsc.container.SpecTypePair; +import com.reandroid.arsc.util.HexUtil; import com.reandroid.json.JSONObject; import java.io.File; @@ -73,7 +74,7 @@ public class TableBlockJson { private String getFileName(TypeBlock typeBlock){ StringBuilder builder=new StringBuilder(); builder.append(String.format("%03d-", typeBlock.getIndex())); - builder.append(String.format("0x%02x", typeBlock.getTypeId())); + builder.append(HexUtil.toHex2(typeBlock.getTypeId())); String name= typeBlock.getTypeName(); builder.append('-').append(name); builder.append(typeBlock.getResConfig().getQualifiers()); @@ -81,7 +82,7 @@ public class TableBlockJson { } private String getDirName(PackageBlock packageBlock){ StringBuilder builder=new StringBuilder(); - builder.append(String.format("0x%02x", packageBlock.getId())); + builder.append(HexUtil.toHex2((byte) packageBlock.getId())); builder.append("-"); builder.append(packageBlock.getIndex()); String name= ApkUtil.sanitizeForFileName(packageBlock.getName()); diff --git a/src/main/java/com/reandroid/apk/xmldecoder/BagDecoderAttr.java b/src/main/java/com/reandroid/apk/xmldecoder/BagDecoderAttr.java index 5c98eb6..9b8d966 100644 --- a/src/main/java/com/reandroid/apk/xmldecoder/BagDecoderAttr.java +++ b/src/main/java/com/reandroid/apk/xmldecoder/BagDecoderAttr.java @@ -16,6 +16,7 @@ package com.reandroid.apk.xmldecoder; import com.reandroid.apk.XmlHelper; +import com.reandroid.arsc.util.HexUtil; import com.reandroid.arsc.value.Entry; import com.reandroid.arsc.value.ResTableMapEntry; import com.reandroid.arsc.value.ValueType; @@ -58,7 +59,7 @@ class BagDecoderAttr extends BagDecoder{ int rawVal = item.getData(); String value; if(item.getBagItem().getValueType() == ValueType.INT_HEX){ - value = String.format("0x%08x", rawVal); + value = HexUtil.toHex8(rawVal); }else { value = String.valueOf(rawVal); } diff --git a/src/main/java/com/reandroid/apk/xmlencoder/EncodeMaterials.java b/src/main/java/com/reandroid/apk/xmlencoder/EncodeMaterials.java index eed5511..b424d93 100644 --- a/src/main/java/com/reandroid/apk/xmlencoder/EncodeMaterials.java +++ b/src/main/java/com/reandroid/apk/xmlencoder/EncodeMaterials.java @@ -1,359 +1,360 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - package com.reandroid.apk.xmlencoder; +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.apk.xmlencoder; - import com.reandroid.apk.APKLogger; - import com.reandroid.apk.FrameworkApk; - import com.reandroid.apk.ResourceIds; - import com.reandroid.arsc.chunk.PackageBlock; - import com.reandroid.arsc.chunk.TableBlock; - import com.reandroid.arsc.chunk.TypeBlock; - import com.reandroid.arsc.container.SpecTypePair; - import com.reandroid.arsc.decoder.ValueDecoder; - import com.reandroid.arsc.group.EntryGroup; - import com.reandroid.arsc.item.SpecString; - import com.reandroid.arsc.util.FrameworkTable; - import com.reandroid.arsc.util.ResNameMap; - import com.reandroid.arsc.value.Entry; - import com.reandroid.common.Frameworks; +import com.reandroid.apk.APKLogger; +import com.reandroid.apk.FrameworkApk; +import com.reandroid.apk.ResourceIds; +import com.reandroid.arsc.chunk.PackageBlock; +import com.reandroid.arsc.chunk.TableBlock; +import com.reandroid.arsc.chunk.TypeBlock; +import com.reandroid.arsc.container.SpecTypePair; +import com.reandroid.arsc.decoder.ValueDecoder; +import com.reandroid.arsc.group.EntryGroup; +import com.reandroid.arsc.item.SpecString; +import com.reandroid.arsc.util.FrameworkTable; +import com.reandroid.arsc.util.HexUtil; +import com.reandroid.arsc.util.ResNameMap; +import com.reandroid.arsc.value.Entry; +import com.reandroid.common.Frameworks; - import java.util.HashSet; - import java.util.Set; - import java.util.regex.Matcher; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Matcher; - public class EncodeMaterials { - private final Set packageIdSet = new HashSet<>(); - private PackageBlock currentPackage; - private final Set frameworkTables = new HashSet<>(); - private APKLogger apkLogger; - private boolean mForceCreateNamespaces = true; - private Set mFrameworkPackageNames; - private final ResNameMap mLocalResNameMap = new ResNameMap<>(); - public EncodeMaterials(){ - } - public SpecString getSpecString(String name){ - return currentPackage.getSpecStringPool() - .get(name) - .get(0); - } - public Entry getAttributeBlock(String refString){ - String type = "attr"; - Entry entry = getAttributeBlock(type, refString); - if(entry == null){ - type = "^attr-private"; - entry = getAttributeBlock(type, refString); - } - return entry; - } - private Entry getAttributeBlock(String type, String refString){ - String packageName = null; - String name = refString; - int i=refString.lastIndexOf(':'); - if(i>=0){ - packageName=refString.substring(0, i); - name=refString.substring(i+1); - } - if(EncodeUtil.isEmpty(packageName) - || packageName.equals(getCurrentPackageName()) - || !isFrameworkPackageName(packageName)){ +public class EncodeMaterials { + private final Set packageIdSet = new HashSet<>(); + private PackageBlock currentPackage; + private final Set frameworkTables = new HashSet<>(); + private APKLogger apkLogger; + private boolean mForceCreateNamespaces = true; + private Set mFrameworkPackageNames; + private final ResNameMap mLocalResNameMap = new ResNameMap<>(); + public EncodeMaterials(){ + } + public SpecString getSpecString(String name){ + return currentPackage.getSpecStringPool() + .get(name) + .get(0); + } + public Entry getAttributeBlock(String refString){ + String type = "attr"; + Entry entry = getAttributeBlock(type, refString); + if(entry == null){ + type = "^attr-private"; + entry = getAttributeBlock(type, refString); + } + return entry; + } + private Entry getAttributeBlock(String type, String refString){ + String packageName = null; + String name = refString; + int i=refString.lastIndexOf(':'); + if(i>=0){ + packageName=refString.substring(0, i); + name=refString.substring(i+1); + } + if(EncodeUtil.isEmpty(packageName) + || packageName.equals(getCurrentPackageName()) + || !isFrameworkPackageName(packageName)){ - return getLocalEntry(type, name); - } - return getFrameworkEntry(type, name); - } - public int resolveReference(String refString){ - if("@null".equals(refString)){ - return 0; - } - Matcher matcher = ValueDecoder.PATTERN_REFERENCE.matcher(refString); - if(!matcher.find()){ - ValueDecoder.EncodeResult ref = ValueDecoder.encodeHexReference(refString); - if(ref!=null){ - return ref.value; - } - ref = ValueDecoder.encodeNullReference(refString); - if(ref!=null){ - return ref.value; - } - throw new EncodeException( - "Not proper reference string: '"+refString+"'"); - } - String prefix=matcher.group(1); - String packageName = matcher.group(2); - if(packageName!=null && packageName.endsWith(":")){ - packageName=packageName.substring(0, packageName.length()-1); - } - String type = matcher.group(4); - String name = matcher.group(5); - if(EncodeUtil.isEmpty(packageName) - || packageName.equals(getCurrentPackageName()) - || !isFrameworkPackageName(packageName)){ - return resolveLocalResourceId(type, name); - } - return resolveFrameworkResourceId(packageName, type, name); - } - public int resolveLocalResourceId(String type, String name){ - for(ResourceIds.Table.Package pkg:packageIdSet){ - Integer resId = pkg.getResourceId(type, name); - if(resId!=null){ - return resId; - } - } - EntryGroup entryGroup=getLocalEntryGroup(type, name); - if(entryGroup!=null){ - return entryGroup.getResourceId(); - } - throw new EncodeException("Local entry not found: " + - "type="+type+ - ", name="+name); - } - public int resolveFrameworkResourceId(String packageName, String type, String name){ - Entry entry = getFrameworkEntry(packageName, type, name); - if(entry !=null){ - return entry.getResourceId(); - } - throw new EncodeException("Framework entry not found: " + - "package="+packageName+ - ", type="+type+ - ", name="+name); - } - public int resolveFrameworkResourceId(int packageId, String type, String name){ - Entry entry = getFrameworkEntry(packageId, type, name); - if(entry !=null){ - return entry.getResourceId(); - } - throw new EncodeException("Framework entry not found: " + - "packageId="+String.format("0x%02x", packageId)+ - ", type="+type+ - ", name="+name); - } - public EntryGroup getLocalEntryGroup(String type, String name){ - for(EntryGroup entryGroup : currentPackage.listEntryGroup()){ - if(type.equals(entryGroup.getTypeName()) && - name.equals(entryGroup.getSpecName())){ - return entryGroup; - } - } - for(PackageBlock packageBlock:currentPackage.getTableBlock().listPackages()){ - for(EntryGroup entryGroup : packageBlock.listEntryGroup()){ - if(type.equals(entryGroup.getTypeName()) && - name.equals(entryGroup.getSpecName())){ - return entryGroup; - } - } - } - return null; - } - public Entry getLocalEntry(String type, String name){ - Entry entry =mLocalResNameMap.get(type, name); - if(entry !=null){ - return entry; - } - loadLocalEntryMap(type); - entry =mLocalResNameMap.get(type, name); - if(entry !=null){ - return entry; - } - entry = searchLocalEntry(type, name); - if(entry !=null){ - mLocalResNameMap.add(type, name, entry); - } - return entry; - } - private Entry searchLocalEntry(String type, String name){ - for(EntryGroup entryGroup : currentPackage.listEntryGroup()){ - if(type.equals(entryGroup.getTypeName()) && - name.equals(entryGroup.getSpecName())){ - return entryGroup.pickOne(); - } - } - SpecTypePair specTypePair=currentPackage.searchByTypeName(type); - if(specTypePair!=null){ - for(TypeBlock typeBlock:specTypePair.listTypeBlocks()){ - for(Entry entry :typeBlock.listEntries(true)){ - if(name.equals(entry.getName())){ - return entry; - } - } - break; - } - } - for(PackageBlock packageBlock:currentPackage.getTableBlock().listPackages()){ - if(packageBlock==currentPackage){ - continue; - } - specTypePair=packageBlock.searchByTypeName(type); - if(specTypePair!=null){ - for(TypeBlock typeBlock:specTypePair.listTypeBlocks()){ - for(Entry entry :typeBlock.listEntries(true)){ - if(name.equals(entry.getName())){ - return entry; - } - } - break; - } - } - } - return null; - } - private void loadLocalEntryMap(String type){ - ResNameMap localMap = mLocalResNameMap; - for(PackageBlock packageBlock:currentPackage.getTableBlock().listPackages()){ - SpecTypePair specTypePair=packageBlock.searchByTypeName(type); - if(specTypePair!=null){ - for(TypeBlock typeBlock:specTypePair.listTypeBlocks()){ - for(Entry entry :typeBlock.listEntries(true)){ - localMap.add(entry.getTypeName(), - entry.getName(), entry); - } - } - } - } - } - public Entry getFrameworkEntry(String type, String name){ - for(FrameworkTable table:frameworkTables){ - Entry entry = table.searchEntry(type, name); - if(entry !=null){ - return entry; - } - } - return null; - } - private boolean isFrameworkPackageName(String packageName){ - return getFrameworkPackageNames().contains(packageName); - } - private Set getFrameworkPackageNames(){ - if(mFrameworkPackageNames!=null){ - return mFrameworkPackageNames; - } - Set results=new HashSet<>(); - for(FrameworkTable table:frameworkTables){ - for(PackageBlock packageBlock:table.listPackages()){ - results.add(packageBlock.getName()); - } - } - mFrameworkPackageNames=results; - return results; - } - public Entry getFrameworkEntry(String packageName, String type, String name){ - for(FrameworkTable table:frameworkTables){ - for(PackageBlock packageBlock:table.listPackages()){ - if(packageName.equals(packageBlock.getName())){ - Entry entry = table.searchEntry(type, name); - if(entry !=null){ - return entry; - } - } - } - } - return null; - } - public Entry getFrameworkEntry(int packageId, String type, String name){ - for(FrameworkTable table:frameworkTables){ - for(PackageBlock packageBlock:table.listPackages()){ - if(packageId==packageBlock.getId()){ - Entry entry = table.searchEntry(type, name); - if(entry !=null){ - return entry; - } - } - } - } - return null; - } - public EncodeMaterials setForceCreateNamespaces(boolean force) { - this.mForceCreateNamespaces = force; - return this; - } - public EncodeMaterials addPackageIds(ResourceIds.Table.Package packageIds) { - packageIds.loadEntryMap(); - this.packageIdSet.add(packageIds); - return this; - } - public EncodeMaterials setCurrentPackage(PackageBlock currentPackage) { - this.currentPackage = currentPackage; - return this; - } - public EncodeMaterials addFramework(FrameworkApk frameworkApk) { - if(frameworkApk!=null){ - addFramework(frameworkApk.getTableBlock()); - } - return this; - } - public EncodeMaterials addFramework(FrameworkTable frameworkTable) { - frameworkTable.loadResourceNameMap(); - this.frameworkTables.add(frameworkTable); - this.mFrameworkPackageNames=null; - return this; - } - public EncodeMaterials setAPKLogger(APKLogger logger) { - this.apkLogger = logger; - return this; - } + return getLocalEntry(type, name); + } + return getFrameworkEntry(type, name); + } + public int resolveReference(String refString){ + if("@null".equals(refString)){ + return 0; + } + Matcher matcher = ValueDecoder.PATTERN_REFERENCE.matcher(refString); + if(!matcher.find()){ + ValueDecoder.EncodeResult ref = ValueDecoder.encodeHexReference(refString); + if(ref!=null){ + return ref.value; + } + ref = ValueDecoder.encodeNullReference(refString); + if(ref!=null){ + return ref.value; + } + throw new EncodeException( + "Not proper reference string: '"+refString+"'"); + } + String prefix=matcher.group(1); + String packageName = matcher.group(2); + if(packageName!=null && packageName.endsWith(":")){ + packageName=packageName.substring(0, packageName.length()-1); + } + String type = matcher.group(4); + String name = matcher.group(5); + if(EncodeUtil.isEmpty(packageName) + || packageName.equals(getCurrentPackageName()) + || !isFrameworkPackageName(packageName)){ + return resolveLocalResourceId(type, name); + } + return resolveFrameworkResourceId(packageName, type, name); + } + public int resolveLocalResourceId(String type, String name){ + for(ResourceIds.Table.Package pkg:packageIdSet){ + Integer resId = pkg.getResourceId(type, name); + if(resId!=null){ + return resId; + } + } + EntryGroup entryGroup=getLocalEntryGroup(type, name); + if(entryGroup!=null){ + return entryGroup.getResourceId(); + } + throw new EncodeException("Local entry not found: " + + "type="+type+ + ", name="+name); + } + public int resolveFrameworkResourceId(String packageName, String type, String name){ + Entry entry = getFrameworkEntry(packageName, type, name); + if(entry !=null){ + return entry.getResourceId(); + } + throw new EncodeException("Framework entry not found: " + + "package="+packageName+ + ", type="+type+ + ", name="+name); + } + public int resolveFrameworkResourceId(int packageId, String type, String name){ + Entry entry = getFrameworkEntry(packageId, type, name); + if(entry !=null){ + return entry.getResourceId(); + } + throw new EncodeException("Framework entry not found: " + + "packageId=" + HexUtil.toHex2((byte) packageId)+ + ", type="+type+ + ", name="+name); + } + public EntryGroup getLocalEntryGroup(String type, String name){ + for(EntryGroup entryGroup : currentPackage.listEntryGroup()){ + if(type.equals(entryGroup.getTypeName()) && + name.equals(entryGroup.getSpecName())){ + return entryGroup; + } + } + for(PackageBlock packageBlock:currentPackage.getTableBlock().listPackages()){ + for(EntryGroup entryGroup : packageBlock.listEntryGroup()){ + if(type.equals(entryGroup.getTypeName()) && + name.equals(entryGroup.getSpecName())){ + return entryGroup; + } + } + } + return null; + } + public Entry getLocalEntry(String type, String name){ + Entry entry =mLocalResNameMap.get(type, name); + if(entry !=null){ + return entry; + } + loadLocalEntryMap(type); + entry =mLocalResNameMap.get(type, name); + if(entry !=null){ + return entry; + } + entry = searchLocalEntry(type, name); + if(entry !=null){ + mLocalResNameMap.add(type, name, entry); + } + return entry; + } + private Entry searchLocalEntry(String type, String name){ + for(EntryGroup entryGroup : currentPackage.listEntryGroup()){ + if(type.equals(entryGroup.getTypeName()) && + name.equals(entryGroup.getSpecName())){ + return entryGroup.pickOne(); + } + } + SpecTypePair specTypePair=currentPackage.searchByTypeName(type); + if(specTypePair!=null){ + for(TypeBlock typeBlock:specTypePair.listTypeBlocks()){ + for(Entry entry :typeBlock.listEntries(true)){ + if(name.equals(entry.getName())){ + return entry; + } + } + break; + } + } + for(PackageBlock packageBlock:currentPackage.getTableBlock().listPackages()){ + if(packageBlock==currentPackage){ + continue; + } + specTypePair=packageBlock.searchByTypeName(type); + if(specTypePair!=null){ + for(TypeBlock typeBlock:specTypePair.listTypeBlocks()){ + for(Entry entry :typeBlock.listEntries(true)){ + if(name.equals(entry.getName())){ + return entry; + } + } + break; + } + } + } + return null; + } + private void loadLocalEntryMap(String type){ + ResNameMap localMap = mLocalResNameMap; + for(PackageBlock packageBlock:currentPackage.getTableBlock().listPackages()){ + SpecTypePair specTypePair=packageBlock.searchByTypeName(type); + if(specTypePair!=null){ + for(TypeBlock typeBlock:specTypePair.listTypeBlocks()){ + for(Entry entry :typeBlock.listEntries(true)){ + localMap.add(entry.getTypeName(), + entry.getName(), entry); + } + } + } + } + } + public Entry getFrameworkEntry(String type, String name){ + for(FrameworkTable table:frameworkTables){ + Entry entry = table.searchEntry(type, name); + if(entry !=null){ + return entry; + } + } + return null; + } + private boolean isFrameworkPackageName(String packageName){ + return getFrameworkPackageNames().contains(packageName); + } + private Set getFrameworkPackageNames(){ + if(mFrameworkPackageNames!=null){ + return mFrameworkPackageNames; + } + Set results=new HashSet<>(); + for(FrameworkTable table:frameworkTables){ + for(PackageBlock packageBlock:table.listPackages()){ + results.add(packageBlock.getName()); + } + } + mFrameworkPackageNames=results; + return results; + } + public Entry getFrameworkEntry(String packageName, String type, String name){ + for(FrameworkTable table:frameworkTables){ + for(PackageBlock packageBlock:table.listPackages()){ + if(packageName.equals(packageBlock.getName())){ + Entry entry = table.searchEntry(type, name); + if(entry !=null){ + return entry; + } + } + } + } + return null; + } + public Entry getFrameworkEntry(int packageId, String type, String name){ + for(FrameworkTable table:frameworkTables){ + for(PackageBlock packageBlock:table.listPackages()){ + if(packageId==packageBlock.getId()){ + Entry entry = table.searchEntry(type, name); + if(entry !=null){ + return entry; + } + } + } + } + return null; + } + public EncodeMaterials setForceCreateNamespaces(boolean force) { + this.mForceCreateNamespaces = force; + return this; + } + public EncodeMaterials addPackageIds(ResourceIds.Table.Package packageIds) { + packageIds.loadEntryMap(); + this.packageIdSet.add(packageIds); + return this; + } + public EncodeMaterials setCurrentPackage(PackageBlock currentPackage) { + this.currentPackage = currentPackage; + return this; + } + public EncodeMaterials addFramework(FrameworkApk frameworkApk) { + if(frameworkApk!=null){ + addFramework(frameworkApk.getTableBlock()); + } + return this; + } + public EncodeMaterials addFramework(FrameworkTable frameworkTable) { + frameworkTable.loadResourceNameMap(); + this.frameworkTables.add(frameworkTable); + this.mFrameworkPackageNames=null; + return this; + } + public EncodeMaterials setAPKLogger(APKLogger logger) { + this.apkLogger = logger; + return this; + } - public PackageBlock getCurrentPackage() { - return currentPackage; - } - public boolean isForceCreateNamespaces() { - return mForceCreateNamespaces; - } + public PackageBlock getCurrentPackage() { + return currentPackage; + } + public boolean isForceCreateNamespaces() { + return mForceCreateNamespaces; + } - public String getCurrentPackageName(){ - return currentPackage.getName(); - } - public int getCurrentPackageId(){ - return currentPackage.getId(); - } + public String getCurrentPackageName(){ + return currentPackage.getName(); + } + public int getCurrentPackageId(){ + return currentPackage.getId(); + } - public void logMessage(String msg) { - if(apkLogger!=null){ - apkLogger.logMessage(msg); - } - } - public void logError(String msg, Throwable tr) { - if(apkLogger!=null){ - apkLogger.logError(msg, tr); - } - } - public void logVerbose(String msg) { - if(apkLogger!=null){ - apkLogger.logVerbose(msg); - } - } - public static EncodeMaterials create(TableBlock tableBlock){ - PackageBlock packageBlock = tableBlock.pickOne(); - if(packageBlock==null){ - throw new EncodeException("No packages found on table block"); - } - return create(packageBlock); - } - public static EncodeMaterials create(PackageBlock packageBlock){ - ResourceIds resourceIds = new ResourceIds(); - resourceIds.loadPackageBlock(packageBlock); - ResourceIds.Table.Package packageId = resourceIds.getTable().listPackages().get(0); - EncodeMaterials encodeMaterials = new EncodeMaterials() - .addPackageIds(packageId) - .setCurrentPackage(packageBlock); - TableBlock tableBlock = packageBlock.getTableBlock(); - for(TableBlock frameworkTable:tableBlock.getFrameWorks()){ - if(frameworkTable instanceof FrameworkTable){ - encodeMaterials.addFramework((FrameworkTable) frameworkTable); - } - } - return encodeMaterials; - } + public void logMessage(String msg) { + if(apkLogger!=null){ + apkLogger.logMessage(msg); + } + } + public void logError(String msg, Throwable tr) { + if(apkLogger!=null){ + apkLogger.logError(msg, tr); + } + } + public void logVerbose(String msg) { + if(apkLogger!=null){ + apkLogger.logVerbose(msg); + } + } + public static EncodeMaterials create(TableBlock tableBlock){ + PackageBlock packageBlock = tableBlock.pickOne(); + if(packageBlock==null){ + throw new EncodeException("No packages found on table block"); + } + return create(packageBlock); + } + public static EncodeMaterials create(PackageBlock packageBlock){ + ResourceIds resourceIds = new ResourceIds(); + resourceIds.loadPackageBlock(packageBlock); + ResourceIds.Table.Package packageId = resourceIds.getTable().listPackages().get(0); + EncodeMaterials encodeMaterials = new EncodeMaterials() + .addPackageIds(packageId) + .setCurrentPackage(packageBlock); + TableBlock tableBlock = packageBlock.getTableBlock(); + for(TableBlock frameworkTable:tableBlock.getFrameWorks()){ + if(frameworkTable instanceof FrameworkTable){ + encodeMaterials.addFramework((FrameworkTable) frameworkTable); + } + } + return encodeMaterials; + } - } +} diff --git a/src/main/java/com/reandroid/archive2/ArchiveEntry.java b/src/main/java/com/reandroid/archive2/ArchiveEntry.java index 9ab58ed..e6856b5 100644 --- a/src/main/java/com/reandroid/archive2/ArchiveEntry.java +++ b/src/main/java/com/reandroid/archive2/ArchiveEntry.java @@ -17,6 +17,7 @@ package com.reandroid.archive2; import com.reandroid.archive2.block.CentralEntryHeader; import com.reandroid.archive2.block.LocalFileHeader; +import com.reandroid.arsc.util.HexUtil; import java.util.zip.ZipEntry; @@ -116,6 +117,7 @@ public class ArchiveEntry extends ZipEntry { @Override public String toString(){ - return "["+ getFileOffset()+"] "+getName()+getComment()+String.format(" 0x%08x", getCrc()); + return "["+ getFileOffset()+"] " + getName() + getComment() + + HexUtil.toHex(" 0x", getCrc(), 8); } } diff --git a/src/main/java/com/reandroid/archive2/block/CentralEntryHeader.java b/src/main/java/com/reandroid/archive2/block/CentralEntryHeader.java index 6770cb3..1a6b7c0 100644 --- a/src/main/java/com/reandroid/archive2/block/CentralEntryHeader.java +++ b/src/main/java/com/reandroid/archive2/block/CentralEntryHeader.java @@ -16,6 +16,7 @@ package com.reandroid.archive2.block; import com.reandroid.archive2.ZipSignature; +import com.reandroid.arsc.util.HexUtil; import java.io.IOException; import java.io.InputStream; @@ -134,12 +135,12 @@ public class CentralEntryHeader extends CommonHeader { builder.append(", "); } builder.append("SIG=").append(getSignature()); - builder.append(", versionMadeBy=").append(String.format("0x%04x", getVersionMadeBy())); - builder.append(", versionExtract=").append(String.format("0x%04x", getVersionExtract())); + builder.append(", versionMadeBy=").append(HexUtil.toHex4((short) getVersionMadeBy())); + builder.append(", versionExtract=").append(HexUtil.toHex4((short) getVersionExtract())); builder.append(", GP={").append(getGeneralPurposeFlag()).append("}"); builder.append(", method=").append(getMethod()); builder.append(", date=").append(getDate()); - builder.append(", crc=").append(String.format("0x%08x", getCrc())); + builder.append(", crc=").append(HexUtil.toHex8(getCrc())); builder.append(", cSize=").append(getCompressedSize()); builder.append(", size=").append(getSize()); builder.append(", fileNameLength=").append(getFileNameLength()); diff --git a/src/main/java/com/reandroid/archive2/block/CommonHeader.java b/src/main/java/com/reandroid/archive2/block/CommonHeader.java index 881360a..db31b27 100644 --- a/src/main/java/com/reandroid/archive2/block/CommonHeader.java +++ b/src/main/java/com/reandroid/archive2/block/CommonHeader.java @@ -16,6 +16,7 @@ package com.reandroid.archive2.block; import com.reandroid.archive2.ZipSignature; +import com.reandroid.arsc.util.HexUtil; import java.io.IOException; import java.io.InputStream; @@ -287,12 +288,12 @@ public abstract class CommonHeader extends ZipHeader { builder.append(", "); } builder.append("SIG=").append(getSignature()); - builder.append(", versionMadeBy=").append(String.format("0x%04x", getVersionMadeBy())); - builder.append(", platform=").append(String.format("0x%02x", getPlatform())); + builder.append(", versionMadeBy=").append(HexUtil.toHex4((short) getVersionMadeBy())); + builder.append(", platform=").append(HexUtil.toHex2((byte) getPlatform())); builder.append(", GP={").append(getGeneralPurposeFlag()).append("}"); builder.append(", method=").append(getMethod()); builder.append(", date=").append(getDate()); - builder.append(", crc=").append(String.format("0x%08x", getCrc())); + builder.append(", crc=").append(HexUtil.toHex8(getCrc())); builder.append(", cSize=").append(getCompressedSize()); builder.append(", size=").append(getSize()); builder.append(", fileNameLength=").append(getFileNameLength()); diff --git a/src/main/java/com/reandroid/archive2/block/DataDescriptor.java b/src/main/java/com/reandroid/archive2/block/DataDescriptor.java index 418d5a5..2aa0cf2 100644 --- a/src/main/java/com/reandroid/archive2/block/DataDescriptor.java +++ b/src/main/java/com/reandroid/archive2/block/DataDescriptor.java @@ -16,6 +16,7 @@ package com.reandroid.archive2.block; import com.reandroid.archive2.ZipSignature; +import com.reandroid.arsc.util.HexUtil; public class DataDescriptor extends ZipHeader{ public DataDescriptor() { @@ -44,7 +45,7 @@ public class DataDescriptor extends ZipHeader{ public String toString(){ StringBuilder builder = new StringBuilder(); builder.append(getSignature()); - builder.append(", crc=").append(String.format("0x%08x", getCrc())); + builder.append(", crc=").append(HexUtil.toHex8(getCrc())); builder.append(", compressed=").append(getCompressedSize()); builder.append(", size=").append(getSize()); return builder.toString(); diff --git a/src/main/java/com/reandroid/archive2/block/EndRecord.java b/src/main/java/com/reandroid/archive2/block/EndRecord.java index da3ba3b..49a4c0f 100644 --- a/src/main/java/com/reandroid/archive2/block/EndRecord.java +++ b/src/main/java/com/reandroid/archive2/block/EndRecord.java @@ -16,6 +16,7 @@ package com.reandroid.archive2.block; import com.reandroid.archive2.ZipSignature; +import com.reandroid.arsc.util.HexUtil; public class EndRecord extends ZipHeader{ public EndRecord() { @@ -78,7 +79,7 @@ public class EndRecord extends ZipHeader{ builder.append(", total dirs=").append(getTotalNumberOfDirectories()); builder.append(", length=").append(getLengthOfCentralDirectory()); builder.append(", offset=").append(getOffsetOfCentralDirectory()); - builder.append(", last=").append(String.format("0x%08x", getLastShort())); + builder.append(", last=").append(HexUtil.toHex8(getLastShort())); return builder.toString(); } diff --git a/src/main/java/com/reandroid/archive2/block/SignatureId.java b/src/main/java/com/reandroid/archive2/block/SignatureId.java index 47a9918..33560ef 100644 --- a/src/main/java/com/reandroid/archive2/block/SignatureId.java +++ b/src/main/java/com/reandroid/archive2/block/SignatureId.java @@ -16,6 +16,7 @@ package com.reandroid.archive2.block; import com.reandroid.arsc.decoder.ValueDecoder; +import com.reandroid.arsc.util.HexUtil; import java.util.Objects; @@ -39,7 +40,7 @@ public class SignatureId implements Comparable{ if (this.name != null) { return name + FILE_EXT_RAW; } - return String.format("0x%08x", id) + FILE_EXT_RAW; + return HexUtil.toHex8(id) + FILE_EXT_RAW; } @Override public boolean equals(Object obj) { @@ -66,7 +67,7 @@ public class SignatureId implements Comparable{ if (name != null) { return name; } - return "UNKNOWN(" + String.format("0x%08x", id) + ")"; + return "UNKNOWN(" + HexUtil.toHex8(id) + ")"; } public static SignatureId valueOf(String name) { if (name == null) { diff --git a/src/main/java/com/reandroid/archive2/io/CountingInputStream.java b/src/main/java/com/reandroid/archive2/io/CountingInputStream.java index 748da0a..a6f1719 100644 --- a/src/main/java/com/reandroid/archive2/io/CountingInputStream.java +++ b/src/main/java/com/reandroid/archive2/io/CountingInputStream.java @@ -15,6 +15,8 @@ */ package com.reandroid.archive2.io; +import com.reandroid.arsc.util.HexUtil; + import java.io.IOException; import java.io.InputStream; import java.util.zip.CRC32; @@ -124,6 +126,6 @@ public class CountingInputStream extends InputStream { if(!mFinished || crc==null){ return "[" + size + "]: " + inputStream.getClass().getSimpleName(); } - return "[size=" + size +", crc=" + String.format("0x%08x", mCheckSum) + "]: " + inputStream.getClass().getSimpleName(); + return "[size=" + size +", crc=" + HexUtil.toHex8(mCheckSum) + "]: " + inputStream.getClass().getSimpleName(); } } diff --git a/src/main/java/com/reandroid/arsc/chunk/ChunkType.java b/src/main/java/com/reandroid/arsc/chunk/ChunkType.java index 594ddb9..70a58a6 100755 --- a/src/main/java/com/reandroid/arsc/chunk/ChunkType.java +++ b/src/main/java/com/reandroid/arsc/chunk/ChunkType.java @@ -1,20 +1,22 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.reandroid.arsc.chunk; +import com.reandroid.arsc.util.HexUtil; + public enum ChunkType { NULL((short)0x0000), @@ -45,7 +47,7 @@ public enum ChunkType { @Override public String toString(){ - return name()+String.format("(0x%04x)", ((int) ID)); + return name() + "(" + HexUtil.toHex4(ID) + ")"; } public static ChunkType get(short id){ diff --git a/src/main/java/com/reandroid/arsc/chunk/PackageBlock.java b/src/main/java/com/reandroid/arsc/chunk/PackageBlock.java index 8534ccd..a898df5 100755 --- a/src/main/java/com/reandroid/arsc/chunk/PackageBlock.java +++ b/src/main/java/com/reandroid/arsc/chunk/PackageBlock.java @@ -29,6 +29,7 @@ import com.reandroid.arsc.list.StagedAliasList; import com.reandroid.arsc.pool.SpecStringPool; import com.reandroid.arsc.pool.TableStringPool; import com.reandroid.arsc.pool.TypeStringPool; +import com.reandroid.arsc.util.HexUtil; import com.reandroid.arsc.value.Entry; import com.reandroid.arsc.value.LibraryInfo; import com.reandroid.arsc.value.ResConfig; @@ -466,7 +467,7 @@ public class PackageBlock extends Chunk StringBuilder builder=new StringBuilder(); builder.append(super.toString()); builder.append(", id="); - builder.append(String.format("0x%02x", getId())); + builder.append(HexUtil.toHex2((byte) getId())); builder.append(", name="); builder.append(getName()); int libCount=getLibraryBlock().getLibraryCount(); diff --git a/src/main/java/com/reandroid/arsc/chunk/SpecBlock.java b/src/main/java/com/reandroid/arsc/chunk/SpecBlock.java index 3aaf081..65873ea 100755 --- a/src/main/java/com/reandroid/arsc/chunk/SpecBlock.java +++ b/src/main/java/com/reandroid/arsc/chunk/SpecBlock.java @@ -1,162 +1,163 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - package com.reandroid.arsc.chunk; +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.arsc.chunk; - import com.reandroid.arsc.array.TypeBlockArray; - import com.reandroid.arsc.container.SpecTypePair; - import com.reandroid.arsc.header.SpecHeader; - import com.reandroid.arsc.item.*; - import com.reandroid.json.JSONConvert; - import com.reandroid.json.JSONObject; +import com.reandroid.arsc.array.TypeBlockArray; +import com.reandroid.arsc.container.SpecTypePair; +import com.reandroid.arsc.header.SpecHeader; +import com.reandroid.arsc.item.*; +import com.reandroid.arsc.util.HexUtil; +import com.reandroid.json.JSONConvert; +import com.reandroid.json.JSONObject; - import java.util.List; +import java.util.List; - public class SpecBlock extends Chunk implements JSONConvert { - private final SpecFlagsArray specFlagsArray; - public SpecBlock() { - super(new SpecHeader(), 1); - SpecHeader header = getHeaderBlock(); - this.specFlagsArray = new SpecFlagsArray(header.getEntryCount()); - addChild(specFlagsArray); - } - public void destroy(){ - setParent(null); - getSpecFlagsArray().clear(); - } - public SpecFlag getSpecFlag(int id){ - return getSpecFlagsArray().getFlag(id); - } - public SpecFlagsArray getSpecFlagsArray(){ - return specFlagsArray; - } - public List listSpecFlags(){ - return specFlagsArray.toList(); - } - public byte getTypeId(){ - return getHeaderBlock().getId().get(); - } - public int getId(){ - return getHeaderBlock().getId().unsignedInt(); - } - public void setId(int id){ - setTypeId((byte) (0xff & id)); - } - public void setTypeId(byte id){ - getHeaderBlock().getId().set(id); - getTypeBlockArray().setTypeId(id); - } - public TypeBlockArray getTypeBlockArray(){ - SpecTypePair specTypePair=getSpecTypePair(); - if(specTypePair!=null){ - return specTypePair.getTypeBlockArray(); - } - return null; - } - SpecTypePair getSpecTypePair(){ - return getParent(SpecTypePair.class); - } - public int getEntryCount() { - return specFlagsArray.size(); - } - public void setEntryCount(int count){ - specFlagsArray.setSize(count); - specFlagsArray.refresh(); - } - @Override - protected void onChunkRefreshed() { - specFlagsArray.refresh(); - } +public class SpecBlock extends Chunk implements JSONConvert { + private final SpecFlagsArray specFlagsArray; + public SpecBlock() { + super(new SpecHeader(), 1); + SpecHeader header = getHeaderBlock(); + this.specFlagsArray = new SpecFlagsArray(header.getEntryCount()); + addChild(specFlagsArray); + } + public void destroy(){ + setParent(null); + getSpecFlagsArray().clear(); + } + public SpecFlag getSpecFlag(int id){ + return getSpecFlagsArray().getFlag(id); + } + public SpecFlagsArray getSpecFlagsArray(){ + return specFlagsArray; + } + public List listSpecFlags(){ + return specFlagsArray.toList(); + } + public byte getTypeId(){ + return getHeaderBlock().getId().get(); + } + public int getId(){ + return getHeaderBlock().getId().unsignedInt(); + } + public void setId(int id){ + setTypeId((byte) (0xff & id)); + } + public void setTypeId(byte id){ + getHeaderBlock().getId().set(id); + getTypeBlockArray().setTypeId(id); + } + public TypeBlockArray getTypeBlockArray(){ + SpecTypePair specTypePair=getSpecTypePair(); + if(specTypePair!=null){ + return specTypePair.getTypeBlockArray(); + } + return null; + } + SpecTypePair getSpecTypePair(){ + return getParent(SpecTypePair.class); + } + public int getEntryCount() { + return specFlagsArray.size(); + } + public void setEntryCount(int count){ + specFlagsArray.setSize(count); + specFlagsArray.refresh(); + } + @Override + protected void onChunkRefreshed() { + specFlagsArray.refresh(); + } - public void merge(SpecBlock specBlock){ - if(specBlock == null || specBlock==this){ - return; - } - this.getSpecFlagsArray().merge(specBlock.getSpecFlagsArray()); - } - @Override - public String toString(){ - StringBuilder builder=new StringBuilder(); - builder.append(super.toString()); - TypeBlockArray typeBlockArray=getTypeBlockArray(); - if(typeBlockArray!=null){ - builder.append(", typesCount="); - builder.append(typeBlockArray.childesCount()); - } - return builder.toString(); - } + public void merge(SpecBlock specBlock){ + if(specBlock == null || specBlock==this){ + return; + } + this.getSpecFlagsArray().merge(specBlock.getSpecFlagsArray()); + } + @Override + public String toString(){ + StringBuilder builder=new StringBuilder(); + builder.append(super.toString()); + TypeBlockArray typeBlockArray=getTypeBlockArray(); + if(typeBlockArray!=null){ + builder.append(", typesCount="); + builder.append(typeBlockArray.childesCount()); + } + return builder.toString(); + } - @Override - public JSONObject toJson() { - JSONObject jsonObject=new JSONObject(); - jsonObject.put(TypeBlock.NAME_id, getId()); - jsonObject.put(NAME_spec_flags, getSpecFlagsArray().toJson()); - return jsonObject; - } + @Override + public JSONObject toJson() { + JSONObject jsonObject=new JSONObject(); + jsonObject.put(TypeBlock.NAME_id, getId()); + jsonObject.put(NAME_spec_flags, getSpecFlagsArray().toJson()); + return jsonObject; + } - @Override - public void fromJson(JSONObject json) { - setId(json.getInt(TypeBlock.NAME_id)); - getSpecFlagsArray().fromJson(json.optJSONArray(NAME_spec_flags)); - } + @Override + public void fromJson(JSONObject json) { + setId(json.getInt(TypeBlock.NAME_id)); + getSpecFlagsArray().fromJson(json.optJSONArray(NAME_spec_flags)); + } - public enum Flag{ - SPEC_PUBLIC((byte) 0x40), - SPEC_STAGED_API((byte) 0x20); + public enum Flag{ + SPEC_PUBLIC((byte) 0x40), + SPEC_STAGED_API((byte) 0x20); - private final byte flag; - Flag(byte flag) { - this.flag = flag; - } - public byte getFlag() { - return flag; - } - public static boolean isPublic(byte flag){ - return (SPEC_PUBLIC.flag & flag) == SPEC_PUBLIC.flag; - } - public static boolean isStagedApi(byte flag){ - return (SPEC_STAGED_API.flag & flag) == SPEC_STAGED_API.flag; - } - public static String toString(byte flagValue){ - StringBuilder builder = new StringBuilder(); - boolean appendOnce = false; - int sum = 0; - int flagValueInt = flagValue & 0xff; - for(Flag flag:values()){ - int flagInt = flag.flag & 0xff; - if((flagInt & flagValueInt) != flagInt){ - continue; - } - if(appendOnce){ - builder.append('|'); - } - builder.append(flag); - appendOnce = true; - sum = sum | flagInt; - } - if(sum != flagValueInt){ - if(appendOnce){ - builder.append('|'); - } - builder.append(String.format("0x%02x", flagValueInt)); - } - return builder.toString(); - } - } + private final byte flag; + Flag(byte flag) { + this.flag = flag; + } + public byte getFlag() { + return flag; + } + public static boolean isPublic(byte flag){ + return (SPEC_PUBLIC.flag & flag) == SPEC_PUBLIC.flag; + } + public static boolean isStagedApi(byte flag){ + return (SPEC_STAGED_API.flag & flag) == SPEC_STAGED_API.flag; + } + public static String toString(byte flagValue){ + StringBuilder builder = new StringBuilder(); + boolean appendOnce = false; + int sum = 0; + int flagValueInt = flagValue & 0xff; + for(Flag flag:values()){ + int flagInt = flag.flag & 0xff; + if((flagInt & flagValueInt) != flagInt){ + continue; + } + if(appendOnce){ + builder.append('|'); + } + builder.append(flag); + appendOnce = true; + sum = sum | flagInt; + } + if(sum != flagValueInt){ + if(appendOnce){ + builder.append('|'); + } + builder.append(HexUtil.toHex2((byte) flagValueInt)); + } + return builder.toString(); + } + } - public static final String NAME_spec = "spec"; - public static final String NAME_spec_flags = "spec_flags"; - public static final String NAME_flag = "flag"; - } + public static final String NAME_spec = "spec"; + public static final String NAME_spec_flags = "spec_flags"; + public static final String NAME_flag = "flag"; +} diff --git a/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlAttribute.java b/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlAttribute.java index f0c96da..a5ea564 100755 --- a/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlAttribute.java +++ b/src/main/java/com/reandroid/arsc/chunk/xml/ResXmlAttribute.java @@ -21,6 +21,7 @@ import com.reandroid.arsc.io.BlockReader; import com.reandroid.arsc.item.*; import com.reandroid.arsc.pool.ResXmlStringPool; import com.reandroid.arsc.pool.StringPool; +import com.reandroid.arsc.util.HexUtil; import com.reandroid.arsc.value.AttributeValue; import com.reandroid.arsc.value.ValueItem; import com.reandroid.arsc.value.ValueType; @@ -419,10 +420,10 @@ public class ResXmlAttribute extends ValueItem implements AttributeValue, Compar if(group==null){ //Lets ignore such error until XML encoder implemented //throw new XMLException("Failed to decode attribute name: " - //+ String.format("@0x%08x", resourceId)); - name=String.format("@0x%08x", resourceId); + //HexUtil.toHex8("@0x", resourceId)); + name = HexUtil.toHex8("@0x", resourceId); }else { - name=group.getSpecName(); + name = group.getSpecName(); } } String prefix = getNamePrefix(); @@ -445,7 +446,7 @@ public class ResXmlAttribute extends ValueItem implements AttributeValue, Compar if(fullName!=null ){ int id=getNameResourceID(); if(id!=0){ - fullName=fullName+"(@"+String.format("0x%08x",id)+")"; + fullName=fullName+"(@"+ HexUtil.toHex8(id)+")"; } String valStr; ValueType valueType=getValueType(); @@ -456,7 +457,7 @@ public class ResXmlAttribute extends ValueItem implements AttributeValue, Compar }else if (valueType==ValueType.INT_DEC){ valStr = String.valueOf(getData()); }else { - valStr = "["+valueType+"] " + String.format("0x%08x",getData()); + valStr = "["+valueType+"] " + HexUtil.toHex8(getData()); } if(valStr!=null){ return fullName+"=\""+valStr+"\""; diff --git a/src/main/java/com/reandroid/arsc/container/SpecTypePair.java b/src/main/java/com/reandroid/arsc/container/SpecTypePair.java index 7d044eb..676b63f 100755 --- a/src/main/java/com/reandroid/arsc/container/SpecTypePair.java +++ b/src/main/java/com/reandroid/arsc/container/SpecTypePair.java @@ -27,6 +27,7 @@ import com.reandroid.arsc.io.BlockReader; import com.reandroid.arsc.item.TypeString; import com.reandroid.arsc.pool.SpecStringPool; import com.reandroid.arsc.pool.TableStringPool; +import com.reandroid.arsc.util.HexUtil; import com.reandroid.arsc.value.Entry; import com.reandroid.arsc.value.ResConfig; import com.reandroid.json.JSONConvert; @@ -338,7 +339,7 @@ public class SpecTypePair extends BlockContainer @Override public String toString(){ StringBuilder builder=new StringBuilder(); - builder.append(String.format("0x%02x", getTypeId())); + builder.append(HexUtil.toHex2(getTypeId())); builder.append(" ("); TypeString ts = getTypeString(); if(ts!=null){ diff --git a/src/main/java/com/reandroid/arsc/decoder/ColorUtil.java b/src/main/java/com/reandroid/arsc/decoder/ColorUtil.java index 41e1330..311fd7d 100644 --- a/src/main/java/com/reandroid/arsc/decoder/ColorUtil.java +++ b/src/main/java/com/reandroid/arsc/decoder/ColorUtil.java @@ -15,6 +15,7 @@ */ package com.reandroid.arsc.decoder; +import com.reandroid.arsc.util.HexUtil; import com.reandroid.arsc.value.ValueType; import java.util.regex.Matcher; @@ -43,7 +44,7 @@ public class ColorUtil { default: return null; } - String hex = String.format("%08x", data); + String hex = HexUtil.toHexNoPrefix8(data); return "#" + hex.substring(index); } public static ValueDecoder.EncodeResult encode(String hexColor){ diff --git a/src/main/java/com/reandroid/arsc/decoder/Decoder.java b/src/main/java/com/reandroid/arsc/decoder/Decoder.java index 62da583..5478e67 100644 --- a/src/main/java/com/reandroid/arsc/decoder/Decoder.java +++ b/src/main/java/com/reandroid/arsc/decoder/Decoder.java @@ -1,18 +1,18 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.reandroid.arsc.decoder; import com.reandroid.apk.AndroidFrameworks; @@ -25,6 +25,7 @@ import com.reandroid.arsc.chunk.xml.AndroidManifestBlock; import com.reandroid.arsc.chunk.xml.ResXmlDocument; import com.reandroid.arsc.group.EntryGroup; import com.reandroid.arsc.util.FrameworkTable; +import com.reandroid.arsc.util.HexUtil; import com.reandroid.arsc.value.AttributeValue; import com.reandroid.arsc.value.Value; import com.reandroid.arsc.value.ValueType; @@ -57,7 +58,7 @@ public class Decoder { return null; } private String hexResourceName(int resourceId){ - return String.format("@0x%08x", resourceId); + return HexUtil.toHex8("@0x", resourceId); } public String decodeValue(Value value){ if(value==null){ diff --git a/src/main/java/com/reandroid/arsc/decoder/ValueDecoder.java b/src/main/java/com/reandroid/arsc/decoder/ValueDecoder.java index e28cc43..13ad345 100755 --- a/src/main/java/com/reandroid/arsc/decoder/ValueDecoder.java +++ b/src/main/java/com/reandroid/arsc/decoder/ValueDecoder.java @@ -20,6 +20,7 @@ import com.reandroid.arsc.chunk.TableBlock; import com.reandroid.arsc.group.EntryGroup; import com.reandroid.arsc.item.TableString; import com.reandroid.arsc.pool.TableStringPool; +import com.reandroid.arsc.util.HexUtil; import com.reandroid.arsc.value.*; import com.reandroid.arsc.value.attribute.AttributeBag; import com.reandroid.common.EntryStore; @@ -265,11 +266,11 @@ public class ValueDecoder { public static String decodeAttributeName(EntryStore store, PackageBlock currentPackage, int resourceId){ EntryGroup entryGroup=searchEntryGroup(store, currentPackage, resourceId); if(entryGroup==null){ - return String.format("@0x%08x", resourceId); + return HexUtil.toHex8("@0x", resourceId); } - Entry entry =entryGroup.pickOne(); - if(entry ==null){ - return String.format("@0x%08x", resourceId); + Entry entry = entryGroup.pickOne(); + if(entry == null){ + return HexUtil.toHex8("@0x", resourceId); } String prefix=null; if(currentPackage!=null){ @@ -705,7 +706,7 @@ public class ValueDecoder { } private static String decodeHex(int rawVal){ - return String.format("0x%x", rawVal); + return HexUtil.toHex(rawVal, 1); } private static String decodeInt(int rawVal){ return String.valueOf(rawVal); @@ -786,7 +787,7 @@ public class ValueDecoder { return entry1; } private static String toHexResourceId(int resourceId){ - return String.format("0x%08x", resourceId); + return HexUtil.toHex8(resourceId); } private static boolean isEqualString(String str1, String str2){ if(isEmpty(str1)){ @@ -810,7 +811,7 @@ public class ValueDecoder { } @Override public String toString(){ - return valueType+": "+String.format("0x%08x", value); + return valueType+": "+HexUtil.toHex8(value); } } diff --git a/src/main/java/com/reandroid/arsc/header/HeaderBlock.java b/src/main/java/com/reandroid/arsc/header/HeaderBlock.java index 84307ff..fded9c4 100755 --- a/src/main/java/com/reandroid/arsc/header/HeaderBlock.java +++ b/src/main/java/com/reandroid/arsc/header/HeaderBlock.java @@ -1,18 +1,18 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.reandroid.arsc.header; import com.reandroid.arsc.base.BlockContainer; @@ -27,11 +27,12 @@ import com.reandroid.arsc.item.ByteArray; import com.reandroid.arsc.item.IntegerItem; import com.reandroid.arsc.item.ShortItem; import com.reandroid.arsc.util.HexBytesWriter; +import com.reandroid.arsc.util.HexUtil; import java.io.*; import java.util.List; - public class HeaderBlock extends ExpandableBlockContainer implements BlockLoad { +public class HeaderBlock extends ExpandableBlockContainer implements BlockLoad { private final ShortItem mType; private final ShortItem mHeaderSize; private final IntegerItem mChunkSize; @@ -57,7 +58,7 @@ import java.util.List; return countBytes(); } public ByteArray getExtraBytes() { - return extraBytes; + return extraBytes; } public void setHeaderLoaded(HeaderLoaded headerLoaded){ this.mHeaderLoaded=headerLoaded; @@ -111,9 +112,9 @@ import java.util.List; } /**Non buffering reader*/ public int readBytes(InputStream inputStream) throws IOException{ - int result = onReadBytes(inputStream); - super.notifyBlockLoad(); - return result; + int result = onReadBytes(inputStream); + super.notifyBlockLoad(); + return result; } private int onReadBytes(InputStream inputStream) throws IOException { int readCount = readBytes(inputStream, this); @@ -218,7 +219,7 @@ import java.util.List; builder.append(type.toString()); }else { builder.append("Unknown type="); - builder.append(String.format("0x%02x", (0xffff & t))); + builder.append(HexUtil.toHex4(t)); } builder.append("{ValueHeader="); builder.append(getHeaderSize()); diff --git a/src/main/java/com/reandroid/arsc/item/ByteItem.java b/src/main/java/com/reandroid/arsc/item/ByteItem.java index b29215d..6d74dba 100755 --- a/src/main/java/com/reandroid/arsc/item/ByteItem.java +++ b/src/main/java/com/reandroid/arsc/item/ByteItem.java @@ -1,4 +1,4 @@ - /* +/* * Copyright (C) 2022 github.com/REAndroid * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,9 @@ package com.reandroid.arsc.item; -public class ByteItem extends BlockItem { + import com.reandroid.arsc.util.HexUtil; + + public class ByteItem extends BlockItem { public ByteItem() { super(1); } @@ -47,7 +49,7 @@ public class ByteItem extends BlockItem { return 0xff & get(); } public String toHex(){ - return String.format("0x%02x", unsignedInt()); + return HexUtil.toHex2(get()); } @Override public String toString(){ diff --git a/src/main/java/com/reandroid/arsc/item/IntegerItem.java b/src/main/java/com/reandroid/arsc/item/IntegerItem.java index ac99ced..cb3c45a 100755 --- a/src/main/java/com/reandroid/arsc/item/IntegerItem.java +++ b/src/main/java/com/reandroid/arsc/item/IntegerItem.java @@ -1,27 +1,27 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.reandroid.arsc.item; +import com.reandroid.arsc.io.BlockReader; +import com.reandroid.arsc.util.HexUtil; - import com.reandroid.arsc.io.BlockReader; +import java.io.IOException; +import java.io.InputStream; - import java.io.IOException; - import java.io.InputStream; - - public class IntegerItem extends BlockItem implements ReferenceItem{ +public class IntegerItem extends BlockItem implements ReferenceItem{ private int mCache; public IntegerItem(){ super(4); @@ -50,7 +50,7 @@ package com.reandroid.arsc.item; return get() & 0x00000000ffffffffL; } public String toHex(){ - return String.format("0x%08x", get()); + return HexUtil.toHex8(get()); } @Override protected void onBytesChanged() { diff --git a/src/main/java/com/reandroid/arsc/item/LongItem.java b/src/main/java/com/reandroid/arsc/item/LongItem.java index 7f0b234..7ca372b 100644 --- a/src/main/java/com/reandroid/arsc/item/LongItem.java +++ b/src/main/java/com/reandroid/arsc/item/LongItem.java @@ -1,20 +1,22 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.reandroid.arsc.item; +import com.reandroid.arsc.util.HexUtil; + public class LongItem extends BlockItem{ private long mCache; public LongItem() { @@ -31,7 +33,7 @@ public class LongItem extends BlockItem{ return mCache; } public String toHex(){ - return String.format("0x%016x", get()); + return HexUtil.toHex(get(), 16); } @Override diff --git a/src/main/java/com/reandroid/arsc/item/ResXmlID.java b/src/main/java/com/reandroid/arsc/item/ResXmlID.java index b41aae5..3535ec0 100755 --- a/src/main/java/com/reandroid/arsc/item/ResXmlID.java +++ b/src/main/java/com/reandroid/arsc/item/ResXmlID.java @@ -1,22 +1,23 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.reandroid.arsc.item; import com.reandroid.arsc.chunk.xml.ResXmlDocument; import com.reandroid.arsc.pool.ResXmlStringPool; +import com.reandroid.arsc.util.HexUtil; import java.util.ArrayList; import java.util.List; @@ -90,7 +91,7 @@ public class ResXmlID extends IntegerItem { builder.append(getIndex()); } builder.append(':'); - builder.append(String.format("0x%08x", get())); + builder.append(HexUtil.toHex8(get())); builder.append('}'); return builder.toString(); } diff --git a/src/main/java/com/reandroid/arsc/item/ShortItem.java b/src/main/java/com/reandroid/arsc/item/ShortItem.java index b30d822..15addb4 100755 --- a/src/main/java/com/reandroid/arsc/item/ShortItem.java +++ b/src/main/java/com/reandroid/arsc/item/ShortItem.java @@ -1,26 +1,27 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.reandroid.arsc.item; - import com.reandroid.arsc.io.BlockReader; +import com.reandroid.arsc.io.BlockReader; +import com.reandroid.arsc.util.HexUtil; - import java.io.IOException; - import java.io.InputStream; +import java.io.IOException; +import java.io.InputStream; - public class ShortItem extends BlockItem { +public class ShortItem extends BlockItem { private short mCache; public ShortItem(){ @@ -46,7 +47,7 @@ package com.reandroid.arsc.item; return 0xffff & get(); } public String toHex(){ - return String.format("0x%04x", unsignedInt()); + return HexUtil.toHex4(get()); } @Override protected void onBytesChanged() { diff --git a/src/main/java/com/reandroid/arsc/item/SpecFlag.java b/src/main/java/com/reandroid/arsc/item/SpecFlag.java index 8c3cbd8..7808b05 100644 --- a/src/main/java/com/reandroid/arsc/item/SpecFlag.java +++ b/src/main/java/com/reandroid/arsc/item/SpecFlag.java @@ -1,21 +1,22 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.reandroid.arsc.item; import com.reandroid.arsc.chunk.SpecBlock; +import com.reandroid.arsc.util.HexUtil; public class SpecFlag extends IndirectItem { public SpecFlag(SpecFlagsArray specFlagsArray, int offset) { @@ -58,7 +59,7 @@ public class SpecFlag extends IndirectItem { } int val = getInteger(); if(val != 0){ - return String.format("0x%08x", val); + return HexUtil.toHex8(val); } return ""; } diff --git a/src/main/java/com/reandroid/arsc/item/TypeString.java b/src/main/java/com/reandroid/arsc/item/TypeString.java index 6aefa0a..55ebba3 100755 --- a/src/main/java/com/reandroid/arsc/item/TypeString.java +++ b/src/main/java/com/reandroid/arsc/item/TypeString.java @@ -17,6 +17,7 @@ package com.reandroid.arsc.item; import com.reandroid.arsc.pool.TypeStringPool; +import com.reandroid.arsc.util.HexUtil; public class TypeString extends StringItem { public TypeString(boolean utf8) { @@ -40,6 +41,6 @@ public class TypeString extends StringItem { } @Override public String toString(){ - return String.format("0x%02x", getId())+':'+get(); + return HexUtil.toHex2((byte) getId())+':'+get(); } } diff --git a/src/main/java/com/reandroid/arsc/util/HexBytesWriter.java b/src/main/java/com/reandroid/arsc/util/HexBytesWriter.java index 646fee1..07cb0de 100644 --- a/src/main/java/com/reandroid/arsc/util/HexBytesWriter.java +++ b/src/main/java/com/reandroid/arsc/util/HexBytesWriter.java @@ -106,7 +106,7 @@ public class HexBytesWriter { } } private void writeHex(Writer writer, byte b) throws IOException { - String hex = String.format("%02x", (0xff & b)).toUpperCase(); + String hex = HexUtil.toHex(null, (0xff & b), 2).toUpperCase(); writer.write(hex); } private void writeString(Writer writer, int width, int position) throws IOException { diff --git a/src/main/java/com/reandroid/arsc/util/HexUtil.java b/src/main/java/com/reandroid/arsc/util/HexUtil.java new file mode 100644 index 0000000..1aa3c26 --- /dev/null +++ b/src/main/java/com/reandroid/arsc/util/HexUtil.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.arsc.util; + +public class HexUtil { + public static String toHex2(byte num){ + return toHex((long)(num & 0x00000000000000ffL), 2); + } + public static String toHex4(short num){ + return toHex((long)(num & 0x000000000000ffffL), 4); + } + public static String toHex8(int num){ + return toHex(num, 8); + } + public static String toHex8(long num){ + return toHex(num, 8); + } + public static String toHex(int num, int minLength){ + return toHex((0x00000000ffffffffL & num), minLength); + } + public static String toHex(long num, int minLength){ + String hex = Long.toHexString(num); + StringBuilder builder = new StringBuilder(); + builder.append('0'); + builder.append('x'); + int rem = minLength - hex.length(); + for(int i=0; i < rem; i++){ + builder.append('0'); + } + builder.append(hex); + return builder.toString(); + } + public static String toHexNoPrefix8(int num){ + return toHex(null, (0x00000000ffffffffL & num), 8); + } + public static String toHexNoPrefix(int num, int minLength){ + return toHex(null, (0x00000000ffffffffL & num), minLength); + } + public static String toHex8(String prefix, int num){ + return toHex(prefix, (0x00000000ffffffffL & num), 8); + } + public static String toHex(String prefix, int num, int minLength){ + return toHex(prefix, (0x00000000ffffffffL & num), minLength); + } + public static String toHex(String prefix, long num, int minLength){ + String hex = Long.toHexString(num); + StringBuilder builder = new StringBuilder(); + if(prefix != null){ + builder.append(prefix); + } + int rem = minLength - hex.length(); + for(int i=0; i < rem; i++){ + builder.append('0'); + } + builder.append(hex); + return builder.toString(); + } + public static int parseHex(String hexString){ + hexString = trim0x(hexString); + return (int) Long.parseLong(hexString, 16); + } + private static String trim0x(String hexString){ + if(hexString == null || hexString.length() < 3){ + return hexString; + } + if(hexString.charAt(0) == '0' && hexString.charAt(1) == 'x'){ + hexString = hexString.substring(2); + } + return hexString; + } +} diff --git a/src/main/java/com/reandroid/arsc/value/Entry.java b/src/main/java/com/reandroid/arsc/value/Entry.java index 0b7a276..9ed77b5 100755 --- a/src/main/java/com/reandroid/arsc/value/Entry.java +++ b/src/main/java/com/reandroid/arsc/value/Entry.java @@ -29,6 +29,7 @@ import com.reandroid.arsc.io.BlockReader; import com.reandroid.arsc.item.*; import com.reandroid.arsc.pool.SpecStringPool; import com.reandroid.arsc.pool.TableStringPool; +import com.reandroid.arsc.util.HexUtil; import com.reandroid.json.JSONConvert; import com.reandroid.json.JSONObject; @@ -429,7 +430,7 @@ public class Entry extends Block implements JSONConvert { @Override public String toString(){ StringBuilder builder = new StringBuilder(); - builder.append(String.format("0x%08x", getResourceId())); + builder.append(HexUtil.toHex8(getResourceId())); builder.append(' '); ResConfig resConfig = getResConfig(); if(resConfig!=null){ diff --git a/src/main/java/com/reandroid/arsc/value/EntryHeaderMap.java b/src/main/java/com/reandroid/arsc/value/EntryHeaderMap.java index ce9ef64..0714e37 100644 --- a/src/main/java/com/reandroid/arsc/value/EntryHeaderMap.java +++ b/src/main/java/com/reandroid/arsc/value/EntryHeaderMap.java @@ -1,20 +1,21 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.reandroid.arsc.value; +import com.reandroid.arsc.util.HexUtil; import com.reandroid.json.JSONObject; public class EntryHeaderMap extends ValueHeader { @@ -92,7 +93,7 @@ public class EntryHeaderMap extends ValueHeader { int parentId = getParentId(); if(parentId!=0){ builder.append(", parentId="); - builder.append(String.format("0x%08x", getParentId())); + builder.append(HexUtil.toHex8(getParentId())); } builder.append(", count=").append(getValuesCount()); return builder.toString(); diff --git a/src/main/java/com/reandroid/arsc/value/LibraryInfo.java b/src/main/java/com/reandroid/arsc/value/LibraryInfo.java index 4089ebc..92bacd0 100755 --- a/src/main/java/com/reandroid/arsc/value/LibraryInfo.java +++ b/src/main/java/com/reandroid/arsc/value/LibraryInfo.java @@ -1,18 +1,18 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.reandroid.arsc.value; import com.reandroid.arsc.base.Block; @@ -20,6 +20,7 @@ import com.reandroid.arsc.base.BlockCounter; import com.reandroid.arsc.io.BlockReader; import com.reandroid.arsc.item.FixedLengthString; import com.reandroid.arsc.item.IntegerItem; +import com.reandroid.arsc.util.HexUtil; import com.reandroid.json.JSONConvert; import com.reandroid.json.JSONObject; @@ -117,7 +118,7 @@ public class LibraryInfo extends Block implements JSONConvert { public String toString(){ StringBuilder builder=new StringBuilder(); builder.append("LIBRARY{"); - builder.append(String.format("0x%02x", getPackageId())); + builder.append(HexUtil.toHex2((byte) getPackageId())); builder.append(':'); String name=getPackageName(); if(name==null){ diff --git a/src/main/java/com/reandroid/arsc/value/ResValueMap.java b/src/main/java/com/reandroid/arsc/value/ResValueMap.java index a6a404d..a60400e 100755 --- a/src/main/java/com/reandroid/arsc/value/ResValueMap.java +++ b/src/main/java/com/reandroid/arsc/value/ResValueMap.java @@ -1,22 +1,23 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.reandroid.arsc.value; import com.reandroid.arsc.base.Block; import com.reandroid.arsc.chunk.PackageBlock; +import com.reandroid.arsc.util.HexUtil; import com.reandroid.json.JSONObject; public class ResValueMap extends ValueItem implements AttributeValue{ @@ -110,7 +111,7 @@ public class ResValueMap extends ValueItem implements AttributeValue{ } @Override public String toString(){ - return "name="+String.format("0x%08x", getName()) + return "name=" + HexUtil.toHex8(getName()) +", "+super.toString(); } diff --git a/src/main/java/com/reandroid/arsc/value/StagedAliasEntry.java b/src/main/java/com/reandroid/arsc/value/StagedAliasEntry.java index 72f5ee4..714b473 100644 --- a/src/main/java/com/reandroid/arsc/value/StagedAliasEntry.java +++ b/src/main/java/com/reandroid/arsc/value/StagedAliasEntry.java @@ -1,6 +1,22 @@ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.reandroid.arsc.value; import com.reandroid.arsc.item.ByteArray; +import com.reandroid.arsc.util.HexUtil; import com.reandroid.json.JSONConvert; import com.reandroid.json.JSONObject; @@ -22,7 +38,7 @@ public class StagedAliasEntry extends ByteArray implements JSONConvert{ - private ReferenceItem mStringReference; - private final int sizeOffset; - public ValueItem(int bytesLength, int sizeOffset) { - super(bytesLength); - this.sizeOffset = sizeOffset; - - writeSize(); - } +public abstract class ValueItem extends BlockItem implements Value, + JSONConvert{ + private ReferenceItem mStringReference; + private final int sizeOffset; + public ValueItem(int bytesLength, int sizeOffset) { + super(bytesLength); + this.sizeOffset = sizeOffset; - void linkTableStrings(TableStringPool tableStringPool){ - if(getValueType() == ValueType.STRING){ - linkStringReference(tableStringPool); - } - } - public void onRemoved(){ - unLinkStringReference(); - } - protected void onDataChanged(){ - } - public void refresh(){ - writeSize(); - } + writeSize(); + } - byte getRes0(){ - return getBytesInternal()[this.sizeOffset + OFFSET_RES0]; - } - public byte getType(){ - return getBytesInternal()[this.sizeOffset + OFFSET_TYPE]; - } - public void setType(byte type){ - if(type == getType()){ - return; - } - byte[] bts = getBytesInternal(); - int offset = this.sizeOffset + OFFSET_TYPE; - byte old = bts[offset]; - bts[offset] = type; - onTypeChanged(old, type); - onDataChanged(); - } - public int getSize(){ - return 0xffff & getShort(getBytesInternal(), this.sizeOffset + OFFSET_SIZE); - } - public void setSize(int size){ - size = this.sizeOffset + size; - setBytesLength(size, false); - writeSize(); - } - private void writeSize(){ - int offset = this.sizeOffset; - int size = countBytes() - offset; - putShort(getBytesInternal(), offset + OFFSET_SIZE, (short) size); - } - protected void onDataLoaded(){ - if(getValueType() == ValueType.STRING){ - linkStringReference(); - }else { - unLinkStringReference(); - } - } - @Override - public ValueType getValueType(){ - return ValueType.valueOf(getType()); - } - @Override - public void setValueType(ValueType valueType){ - byte type = 0; - if(valueType!=null){ - type = valueType.getByte(); - } - setType(type); - } - @Override - public int getData(){ - return getInteger(getBytesInternal(), this.sizeOffset + OFFSET_DATA); - } - @Override - public void setData(int data){ - byte[] bts = getBytesInternal(); - int old = getInteger(bts, this.sizeOffset + OFFSET_DATA); - if(old == data){ - return; - } - unLinkStringReference(); - putInteger(bts, this.sizeOffset + OFFSET_DATA, data); - if(ValueType.STRING==getValueType()){ - linkStringReference(); - } - onDataChanged(); - } + void linkTableStrings(TableStringPool tableStringPool){ + if(getValueType() == ValueType.STRING){ + linkStringReference(tableStringPool); + } + } + public void onRemoved(){ + unLinkStringReference(); + } + protected void onDataChanged(){ + } + public void refresh(){ + writeSize(); + } + + byte getRes0(){ + return getBytesInternal()[this.sizeOffset + OFFSET_RES0]; + } + public byte getType(){ + return getBytesInternal()[this.sizeOffset + OFFSET_TYPE]; + } + public void setType(byte type){ + if(type == getType()){ + return; + } + byte[] bts = getBytesInternal(); + int offset = this.sizeOffset + OFFSET_TYPE; + byte old = bts[offset]; + bts[offset] = type; + onTypeChanged(old, type); + onDataChanged(); + } + public int getSize(){ + return 0xffff & getShort(getBytesInternal(), this.sizeOffset + OFFSET_SIZE); + } + public void setSize(int size){ + size = this.sizeOffset + size; + setBytesLength(size, false); + writeSize(); + } + private void writeSize(){ + int offset = this.sizeOffset; + int size = countBytes() - offset; + putShort(getBytesInternal(), offset + OFFSET_SIZE, (short) size); + } + protected void onDataLoaded(){ + if(getValueType() == ValueType.STRING){ + linkStringReference(); + }else { + unLinkStringReference(); + } + } + @Override + public ValueType getValueType(){ + return ValueType.valueOf(getType()); + } + @Override + public void setValueType(ValueType valueType){ + byte type = 0; + if(valueType!=null){ + type = valueType.getByte(); + } + setType(type); + } + @Override + public int getData(){ + return getInteger(getBytesInternal(), this.sizeOffset + OFFSET_DATA); + } + @Override + public void setData(int data){ + byte[] bts = getBytesInternal(); + int old = getInteger(bts, this.sizeOffset + OFFSET_DATA); + if(old == data){ + return; + } + unLinkStringReference(); + putInteger(bts, this.sizeOffset + OFFSET_DATA, data); + if(ValueType.STRING==getValueType()){ + linkStringReference(); + } + onDataChanged(); + } - public StringItem getDataAsPoolString(){ - if(getValueType()!=ValueType.STRING){ - return null; - } - StringPool stringPool = getStringPool(); - if(stringPool == null){ - return null; - } - return stringPool.get(getData()); - } - private void onTypeChanged(byte old, byte type){ - byte typeString = ValueType.STRING.getByte(); - if(old == typeString){ - unLinkStringReference(); - }else if(type == typeString){ - linkStringReference(); - } - } - private void linkStringReference(){ - StringPool stringPool = getStringPool(); - if(stringPool == null || stringPool.isStringLinkLocked()){ - return; - } - linkStringReference(stringPool); - } - private void linkStringReference(StringPool stringPool){ - StringItem tableString = stringPool.get(getData()); - if(tableString == null){ - unLinkStringReference(); - return; - } - ReferenceItem stringReference = mStringReference; - if(stringReference!=null){ - unLinkStringReference(); - } - stringReference = new ReferenceBlock<>(this, this.sizeOffset + OFFSET_DATA); - mStringReference = stringReference; - tableString.addReference(stringReference); - } - private void unLinkStringReference(){ - ReferenceItem stringReference = mStringReference; - if(stringReference==null){ - return; - } - mStringReference = null; - onUnlinkDataString(stringReference); - } - protected void onUnlinkDataString(ReferenceItem referenceItem){ - StringPool stringPool = getStringPool(); - if(stringPool == null){ - return; - } - stringPool.removeReference(referenceItem); - } - public StringPool getStringPool(){ - Block parent = getParent(); - while (parent!=null){ - if(parent instanceof MainChunk){ - return ((MainChunk) parent).getStringPool(); - } - parent=parent.getParent(); - } - return null; - } - @Override - public void onReadBytes(BlockReader reader) throws IOException { - int readSize = initializeBytes(reader); - super.onReadBytes(reader); - if(readSize<8){ - setBytesLength(this.sizeOffset + 8, false); - writeSize(); - } - } - private int initializeBytes(BlockReader reader) throws IOException { - int position = reader.getPosition(); - int offset = this.sizeOffset; - reader.offset(offset); - int readSize = reader.readUnsignedShort(); - int size = readSize; - if(size<8){ - if(reader.available()>=8){ - size = 8; - } - } - reader.seek(position); - setBytesLength(offset + size, false); - return readSize; - } - @Override - public String getValueAsString(){ - StringItem stringItem = getDataAsPoolString(); - if(stringItem!=null){ - String value = stringItem.getHtml(); - if(value == null){ - value = ""; - } - return value; - } - return null; - } - public void setValueAsString(String str){ - if(getValueType() == ValueType.STRING - && Objects.equals(str, getValueAsString())){ - return; - } - if(str == null){ - str = ""; - } - StringItem stringItem = getStringPool().getOrCreate(str); - setData(stringItem.getIndex()); - setValueType(ValueType.STRING); - } - public boolean getValueAsBoolean(){ - return getData()!=0; - } - public void setValueAsBoolean(boolean val){ - setValueType(ValueType.INT_BOOLEAN); - int data=val?0xffffffff:0; - setData(data); - } - public void setTypeAndData(ValueType valueType, int data){ - setData(data); - setValueType(valueType); - } - public void merge(ValueItem valueItem){ - if(valueItem == null || valueItem==this){ - return; - } - setSize(valueItem.getSize()); - ValueType coming = valueItem.getValueType(); - if(coming == ValueType.STRING){ - setValueAsString(valueItem.getValueAsString()); - }else { - setTypeAndData(coming, valueItem.getData()); - } - } - @Override - public JSONObject toJson() { - if(isNull()){ - return null; - } - JSONObject jsonObject = new JSONObject(); - ValueType valueType = getValueType(); - jsonObject.put(NAME_value_type, valueType.name()); - if(valueType==ValueType.STRING){ - jsonObject.put(NAME_data, getValueAsString()); - }else if(valueType==ValueType.INT_BOOLEAN){ - jsonObject.put(NAME_data, getValueAsBoolean()); - }else { - jsonObject.put(NAME_data, getData()); - } - return jsonObject; - } - @Override - public void fromJson(JSONObject json) { - ValueType valueType = ValueType.fromName(json.getString(NAME_value_type)); - if(valueType==ValueType.STRING){ - setValueAsString(json.optString(NAME_data, "")); - }else if(valueType==ValueType.INT_BOOLEAN){ - setValueAsBoolean(json.getBoolean(NAME_data)); - }else { - setValueType(valueType); - setData(json.getInt(NAME_data)); - } - } + public StringItem getDataAsPoolString(){ + if(getValueType()!=ValueType.STRING){ + return null; + } + StringPool stringPool = getStringPool(); + if(stringPool == null){ + return null; + } + return stringPool.get(getData()); + } + private void onTypeChanged(byte old, byte type){ + byte typeString = ValueType.STRING.getByte(); + if(old == typeString){ + unLinkStringReference(); + }else if(type == typeString){ + linkStringReference(); + } + } + private void linkStringReference(){ + StringPool stringPool = getStringPool(); + if(stringPool == null || stringPool.isStringLinkLocked()){ + return; + } + linkStringReference(stringPool); + } + private void linkStringReference(StringPool stringPool){ + StringItem tableString = stringPool.get(getData()); + if(tableString == null){ + unLinkStringReference(); + return; + } + ReferenceItem stringReference = mStringReference; + if(stringReference!=null){ + unLinkStringReference(); + } + stringReference = new ReferenceBlock<>(this, this.sizeOffset + OFFSET_DATA); + mStringReference = stringReference; + tableString.addReference(stringReference); + } + private void unLinkStringReference(){ + ReferenceItem stringReference = mStringReference; + if(stringReference==null){ + return; + } + mStringReference = null; + onUnlinkDataString(stringReference); + } + protected void onUnlinkDataString(ReferenceItem referenceItem){ + StringPool stringPool = getStringPool(); + if(stringPool == null){ + return; + } + stringPool.removeReference(referenceItem); + } + public StringPool getStringPool(){ + Block parent = getParent(); + while (parent!=null){ + if(parent instanceof MainChunk){ + return ((MainChunk) parent).getStringPool(); + } + parent=parent.getParent(); + } + return null; + } + @Override + public void onReadBytes(BlockReader reader) throws IOException { + int readSize = initializeBytes(reader); + super.onReadBytes(reader); + if(readSize<8){ + setBytesLength(this.sizeOffset + 8, false); + writeSize(); + } + } + private int initializeBytes(BlockReader reader) throws IOException { + int position = reader.getPosition(); + int offset = this.sizeOffset; + reader.offset(offset); + int readSize = reader.readUnsignedShort(); + int size = readSize; + if(size<8){ + if(reader.available()>=8){ + size = 8; + } + } + reader.seek(position); + setBytesLength(offset + size, false); + return readSize; + } + @Override + public String getValueAsString(){ + StringItem stringItem = getDataAsPoolString(); + if(stringItem!=null){ + String value = stringItem.getHtml(); + if(value == null){ + value = ""; + } + return value; + } + return null; + } + public void setValueAsString(String str){ + if(getValueType() == ValueType.STRING + && Objects.equals(str, getValueAsString())){ + return; + } + if(str == null){ + str = ""; + } + StringItem stringItem = getStringPool().getOrCreate(str); + setData(stringItem.getIndex()); + setValueType(ValueType.STRING); + } + public boolean getValueAsBoolean(){ + return getData()!=0; + } + public void setValueAsBoolean(boolean val){ + setValueType(ValueType.INT_BOOLEAN); + int data=val?0xffffffff:0; + setData(data); + } + public void setTypeAndData(ValueType valueType, int data){ + setData(data); + setValueType(valueType); + } + public void merge(ValueItem valueItem){ + if(valueItem == null || valueItem==this){ + return; + } + setSize(valueItem.getSize()); + ValueType coming = valueItem.getValueType(); + if(coming == ValueType.STRING){ + setValueAsString(valueItem.getValueAsString()); + }else { + setTypeAndData(coming, valueItem.getData()); + } + } + @Override + public JSONObject toJson() { + if(isNull()){ + return null; + } + JSONObject jsonObject = new JSONObject(); + ValueType valueType = getValueType(); + jsonObject.put(NAME_value_type, valueType.name()); + if(valueType==ValueType.STRING){ + jsonObject.put(NAME_data, getValueAsString()); + }else if(valueType==ValueType.INT_BOOLEAN){ + jsonObject.put(NAME_data, getValueAsBoolean()); + }else { + jsonObject.put(NAME_data, getData()); + } + return jsonObject; + } + @Override + public void fromJson(JSONObject json) { + ValueType valueType = ValueType.fromName(json.getString(NAME_value_type)); + if(valueType==ValueType.STRING){ + setValueAsString(json.optString(NAME_data, "")); + }else if(valueType==ValueType.INT_BOOLEAN){ + setValueAsBoolean(json.getBoolean(NAME_data)); + }else { + setValueType(valueType); + setData(json.getInt(NAME_data)); + } + } - @Override - public String toString(){ - StringBuilder builder = new StringBuilder(); - int size = getSize(); - if(size!=8){ - builder.append("size=").append(getSize()); - builder.append(", "); - } - builder.append("type="); - ValueType valueType=getValueType(); - if(valueType!=null){ - builder.append(valueType); - }else { - builder.append(String.format("0x%02x", (0xff & getType()))); - } - builder.append(", data="); - int data = getData(); - if(valueType==ValueType.STRING){ - StringItem tableString = getDataAsPoolString(); - if(tableString!=null){ - builder.append(tableString.getHtml()); - }else { - builder.append(String.format("0x%08x", data)); - } - }else { - builder.append(String.format("0x%08x", data)); - } - return builder.toString(); - } + @Override + public String toString(){ + StringBuilder builder = new StringBuilder(); + int size = getSize(); + if(size!=8){ + builder.append("size=").append(getSize()); + builder.append(", "); + } + builder.append("type="); + ValueType valueType=getValueType(); + if(valueType!=null){ + builder.append(valueType); + }else { + builder.append(HexUtil.toHex2(getType())); + } + builder.append(", data="); + int data = getData(); + if(valueType==ValueType.STRING){ + StringItem tableString = getDataAsPoolString(); + if(tableString!=null){ + builder.append(tableString.getHtml()); + }else { + builder.append(HexUtil.toHex8(data)); + } + }else { + builder.append(HexUtil.toHex8(data)); + } + return builder.toString(); + } - private static final int OFFSET_SIZE = 0; - private static final int OFFSET_RES0 = 2; - private static final int OFFSET_TYPE = 3; - private static final int OFFSET_DATA = 4; + private static final int OFFSET_SIZE = 0; + private static final int OFFSET_RES0 = 2; + private static final int OFFSET_TYPE = 3; + private static final int OFFSET_DATA = 4; - public static final String NAME_data = "data"; - public static final String NAME_value_type = "value_type"; - } + public static final String NAME_data = "data"; + public static final String NAME_value_type = "value_type"; +} diff --git a/src/main/java/com/reandroid/arsc/value/array/ArrayBagItem.java b/src/main/java/com/reandroid/arsc/value/array/ArrayBagItem.java index fdb9022..fa9cf2f 100644 --- a/src/main/java/com/reandroid/arsc/value/array/ArrayBagItem.java +++ b/src/main/java/com/reandroid/arsc/value/array/ArrayBagItem.java @@ -1,95 +1,96 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - package com.reandroid.arsc.value.array; +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.arsc.value.array; - import com.reandroid.arsc.decoder.ValueDecoder; - import com.reandroid.arsc.item.StringItem; - import com.reandroid.arsc.item.TableString; - import com.reandroid.arsc.value.ValueType; - import com.reandroid.arsc.value.bag.BagItem; - import com.reandroid.arsc.value.ResValueMap; +import com.reandroid.arsc.decoder.ValueDecoder; +import com.reandroid.arsc.item.StringItem; +import com.reandroid.arsc.item.TableString; +import com.reandroid.arsc.util.HexUtil; +import com.reandroid.arsc.value.ValueType; +import com.reandroid.arsc.value.bag.BagItem; +import com.reandroid.arsc.value.ResValueMap; - public class ArrayBagItem extends BagItem { - private ArrayBagItem(ResValueMap valueMap) { - super(valueMap); - } +public class ArrayBagItem extends BagItem { + private ArrayBagItem(ResValueMap valueMap) { + super(valueMap); + } - private ArrayBagItem(StringItem str) { - super(str); - } + private ArrayBagItem(StringItem str) { + super(str); + } - private ArrayBagItem(ValueType valueType, int value) { - super(valueType, value); - } + private ArrayBagItem(ValueType valueType, int value) { + super(valueType, value); + } - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(""); - if (hasStringValue()) { - builder.append(getStringValue()); - } else { - builder.append(String.format("0x%08x", getValue())); - } - builder.append(""); - return builder.toString(); - } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(""); + if (hasStringValue()) { + builder.append(getStringValue()); + } else { + builder.append(HexUtil.toHex8(getValue())); + } + builder.append(""); + return builder.toString(); + } - protected static ArrayBagItem create(ResValueMap valueMap) { - if (valueMap == null) { - return null; - } - return new ArrayBagItem(valueMap); - } + protected static ArrayBagItem create(ResValueMap valueMap) { + if (valueMap == null) { + return null; + } + return new ArrayBagItem(valueMap); + } - public static ArrayBagItem create(ValueType valueType, int value) { - if (valueType == null || valueType == ValueType.STRING) { - return null; - } - return new ArrayBagItem(valueType, value); - } + public static ArrayBagItem create(ValueType valueType, int value) { + if (valueType == null || valueType == ValueType.STRING) { + return null; + } + return new ArrayBagItem(valueType, value); + } - protected static ArrayBagItem copyOf(ResValueMap resValueMap) { - ValueType valueType = resValueMap.getValueType(); - if (valueType == ValueType.STRING) { - return new ArrayBagItem(resValueMap.getDataAsPoolString()); - } else { - return new ArrayBagItem(valueType, resValueMap.getData()); - } - } + protected static ArrayBagItem copyOf(ResValueMap resValueMap) { + ValueType valueType = resValueMap.getValueType(); + if (valueType == ValueType.STRING) { + return new ArrayBagItem(resValueMap.getDataAsPoolString()); + } else { + return new ArrayBagItem(valueType, resValueMap.getData()); + } + } - public static ArrayBagItem encoded(ValueDecoder.EncodeResult encodeResult) { - if (encodeResult == null) { - return null; - } - return create(encodeResult.valueType, encodeResult.value); - } + public static ArrayBagItem encoded(ValueDecoder.EncodeResult encodeResult) { + if (encodeResult == null) { + return null; + } + return create(encodeResult.valueType, encodeResult.value); + } - public static ArrayBagItem integer(int n) { - return create(ValueType.INT_DEC, n); - } + public static ArrayBagItem integer(int n) { + return create(ValueType.INT_DEC, n); + } - public static ArrayBagItem string(TableString str) { - if (str == null) { - return null; - } - return new ArrayBagItem(str); - } + public static ArrayBagItem string(TableString str) { + if (str == null) { + return null; + } + return new ArrayBagItem(str); + } - public static ArrayBagItem reference(int resourceId) { - return create(ValueType.REFERENCE, resourceId); - } - } + public static ArrayBagItem reference(int resourceId) { + return create(ValueType.REFERENCE, resourceId); + } +} diff --git a/src/main/java/com/reandroid/arsc/value/attribute/AttributeBagItem.java b/src/main/java/com/reandroid/arsc/value/attribute/AttributeBagItem.java index d6c675d..e5d305d 100755 --- a/src/main/java/com/reandroid/arsc/value/attribute/AttributeBagItem.java +++ b/src/main/java/com/reandroid/arsc/value/attribute/AttributeBagItem.java @@ -1,22 +1,23 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.reandroid.arsc.value.attribute; import com.reandroid.arsc.chunk.PackageBlock; import com.reandroid.arsc.group.EntryGroup; +import com.reandroid.arsc.util.HexUtil; import com.reandroid.arsc.value.Entry; import com.reandroid.arsc.value.ResValueMap; import com.reandroid.common.EntryStore; @@ -36,7 +37,7 @@ public class AttributeBagItem { public String getNameOrHex(EntryStore entryStore){ String name=getName(entryStore); if(name==null){ - name=String.format("@0x%08x", getBagItem().getName()); + name=HexUtil.toHex8("@0x", getBagItem().getName()); } return name; } @@ -162,7 +163,7 @@ public class AttributeBagItem { } ResValueMap item=getBagItem(); builder.append(getNameOrHex()); - builder.append("=").append(String.format("0x%x", item.getData())); + builder.append("=").append(HexUtil.toHex8(item.getData())); return builder.toString(); } @@ -214,6 +215,4 @@ public class AttributeBagItem { } return null; } - - } diff --git a/src/main/java/com/reandroid/arsc/value/plurals/PluralsBagItem.java b/src/main/java/com/reandroid/arsc/value/plurals/PluralsBagItem.java index a895c9c..34b5ba7 100644 --- a/src/main/java/com/reandroid/arsc/value/plurals/PluralsBagItem.java +++ b/src/main/java/com/reandroid/arsc/value/plurals/PluralsBagItem.java @@ -18,6 +18,7 @@ import com.reandroid.arsc.chunk.TableBlock; import com.reandroid.arsc.item.StringItem; import com.reandroid.arsc.item.TableString; + import com.reandroid.arsc.util.HexUtil; import com.reandroid.arsc.value.*; import com.reandroid.arsc.value.bag.BagItem; @@ -83,7 +84,7 @@ } private String formattedRefValue() { - return String.format("@0x%08x", getValue()); + return HexUtil.toHex8("@0x", getValue()); } @Override diff --git a/src/main/java/com/reandroid/arsc/value/style/StyleBagItem.java b/src/main/java/com/reandroid/arsc/value/style/StyleBagItem.java index 996533e..b6d7838 100644 --- a/src/main/java/com/reandroid/arsc/value/style/StyleBagItem.java +++ b/src/main/java/com/reandroid/arsc/value/style/StyleBagItem.java @@ -1,189 +1,190 @@ - /* - * Copyright (C) 2022 github.com/REAndroid - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - package com.reandroid.arsc.value.style; +/* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.arsc.value.style; - import com.reandroid.arsc.decoder.ValueDecoder; - import com.reandroid.arsc.item.StringItem; - import com.reandroid.arsc.item.TableString; - import com.reandroid.arsc.value.attribute.AttributeBag; - import com.reandroid.arsc.value.attribute.AttributeBagItem; - import com.reandroid.arsc.value.bag.BagItem; - import com.reandroid.arsc.value.Entry; - import com.reandroid.arsc.value.ResValueMap; - import com.reandroid.arsc.value.ValueType; - import com.reandroid.common.EntryStore; +import com.reandroid.arsc.decoder.ValueDecoder; +import com.reandroid.arsc.item.StringItem; +import com.reandroid.arsc.item.TableString; +import com.reandroid.arsc.util.HexUtil; +import com.reandroid.arsc.value.attribute.AttributeBag; +import com.reandroid.arsc.value.attribute.AttributeBagItem; +import com.reandroid.arsc.value.bag.BagItem; +import com.reandroid.arsc.value.Entry; +import com.reandroid.arsc.value.ResValueMap; +import com.reandroid.arsc.value.ValueType; +import com.reandroid.common.EntryStore; - public class StyleBagItem extends BagItem { - private StyleBagItem(ResValueMap bagItem) { - super(bagItem); - } +public class StyleBagItem extends BagItem { + private StyleBagItem(ResValueMap bagItem) { + super(bagItem); + } - private StyleBagItem(ValueType valueType, int data) { - super(valueType, data); - } + private StyleBagItem(ValueType valueType, int data) { + super(valueType, data); + } - private StyleBagItem(StringItem str) { - super(str); - } + private StyleBagItem(StringItem str) { + super(str); + } - public String getName() { - if (mBagItem == null) { - return null; - } - Entry block = mBagItem.getEntry(); - if (block == null) { - return null; - } - char prefix = 0; - return block.buildResourceName(mBagItem.getName(), prefix, false); - } - public Entry getAttributeEntry(EntryStore entryStore) { - if (mBagItem == null) { - return null; - } - return entryStore.getEntryGroup(mBagItem.getName()).pickOne(); - } + public String getName() { + if (mBagItem == null) { + return null; + } + Entry block = mBagItem.getEntry(); + if (block == null) { + return null; + } + char prefix = 0; + return block.buildResourceName(mBagItem.getName(), prefix, false); + } + public Entry getAttributeEntry(EntryStore entryStore) { + if (mBagItem == null) { + return null; + } + return entryStore.getEntryGroup(mBagItem.getName()).pickOne(); + } - public int getNameId() { - if (mBagItem == null) { - return 0; - } - return mBagItem.getName(); - } + public int getNameId() { + if (mBagItem == null) { + return 0; + } + return mBagItem.getName(); + } - public boolean hasAttributeValue() { - return getValueType() == ValueType.ATTRIBUTE; - } - public boolean hasIntValue() { - ValueType valueType = getValueType(); - return valueType == ValueType.INT_DEC || valueType == ValueType.INT_HEX; - } + public boolean hasAttributeValue() { + return getValueType() == ValueType.ATTRIBUTE; + } + public boolean hasIntValue() { + ValueType valueType = getValueType(); + return valueType == ValueType.INT_DEC || valueType == ValueType.INT_HEX; + } - public String getValueAsReference() { - ValueType valueType = getValueType(); - if (valueType != ValueType.REFERENCE && valueType != ValueType.ATTRIBUTE) { - throw new IllegalArgumentException("Not REF ValueType=" + valueType); - } - Entry entry = getBagItem().getEntry(); - if (entry == null) { - return null; - } - char prefix = '@'; - boolean includeType = true; - if (valueType == ValueType.ATTRIBUTE) { - prefix = '?'; - includeType = false; - } - int id = getValue(); - return entry.buildResourceName(id, prefix, includeType); - } - public String decodeAttributeValue(AttributeBag attr, EntryStore entryStore) { - if (!hasIntValue()) { - return null; - } - return attr.decodeAttributeValue(entryStore, getValue()); - } - public AttributeBagItem[] getFlagsOrEnum(AttributeBag attr) { - if (!hasIntValue()) { - return null; - } - return attr.searchValue(getValue()); - } + public String getValueAsReference() { + ValueType valueType = getValueType(); + if (valueType != ValueType.REFERENCE && valueType != ValueType.ATTRIBUTE) { + throw new IllegalArgumentException("Not REF ValueType=" + valueType); + } + Entry entry = getBagItem().getEntry(); + if (entry == null) { + return null; + } + char prefix = '@'; + boolean includeType = true; + if (valueType == ValueType.ATTRIBUTE) { + prefix = '?'; + includeType = false; + } + int id = getValue(); + return entry.buildResourceName(id, prefix, includeType); + } + public String decodeAttributeValue(AttributeBag attr, EntryStore entryStore) { + if (!hasIntValue()) { + return null; + } + return attr.decodeAttributeValue(entryStore, getValue()); + } + public AttributeBagItem[] getFlagsOrEnum(AttributeBag attr) { + if (!hasIntValue()) { + return null; + } + return attr.searchValue(getValue()); + } - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(""); - if (hasStringValue()) { - builder.append(getStringValue()); - } - String val = null; - if (hasReferenceValue() || hasAttributeValue()) { - val = getValueAsReference(); - } - if (val == null) { - val = String.format("0x%08x", getValue()); - } - builder.append(val); - builder.append(""); - return builder.toString(); - } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(""); + if (hasStringValue()) { + builder.append(getStringValue()); + } + String val = null; + if (hasReferenceValue() || hasAttributeValue()) { + val = getValueAsReference(); + } + if (val == null) { + val = HexUtil.toHex8(getValue()); + } + builder.append(val); + builder.append(""); + return builder.toString(); + } - protected static StyleBagItem create(ResValueMap resValueMap) { - if (resValueMap == null) { - return null; - } - return new StyleBagItem(resValueMap); - } + protected static StyleBagItem create(ResValueMap resValueMap) { + if (resValueMap == null) { + return null; + } + return new StyleBagItem(resValueMap); + } - public static StyleBagItem create(ValueType valueType, int value) { - if (valueType == null || valueType == ValueType.STRING) { - return null; - } - return new StyleBagItem(valueType, value); - } + public static StyleBagItem create(ValueType valueType, int value) { + if (valueType == null || valueType == ValueType.STRING) { + return null; + } + return new StyleBagItem(valueType, value); + } - protected static StyleBagItem copyOf(ResValueMap resValueMap) { - ValueType valueType = resValueMap.getValueType(); - if (valueType == ValueType.STRING) { - return new StyleBagItem(resValueMap.getDataAsPoolString()); - } else { - return new StyleBagItem(valueType, resValueMap.getData()); - } - } + protected static StyleBagItem copyOf(ResValueMap resValueMap) { + ValueType valueType = resValueMap.getValueType(); + if (valueType == ValueType.STRING) { + return new StyleBagItem(resValueMap.getDataAsPoolString()); + } else { + return new StyleBagItem(valueType, resValueMap.getData()); + } + } - public static StyleBagItem integer(int n) { - return new StyleBagItem(ValueType.INT_DEC, n); - } + public static StyleBagItem integer(int n) { + return new StyleBagItem(ValueType.INT_DEC, n); + } - public static StyleBagItem string(TableString str) { - if (str == null) { - return null; - } - return new StyleBagItem(str); - } + public static StyleBagItem string(TableString str) { + if (str == null) { + return null; + } + return new StyleBagItem(str); + } - public static StyleBagItem reference(int resourceId) { - return new StyleBagItem(ValueType.REFERENCE, resourceId); - } - public static StyleBagItem attribute(int resourceId) { - return new StyleBagItem(ValueType.ATTRIBUTE, resourceId); - } - public static StyleBagItem encoded(ValueDecoder.EncodeResult encodeResult) { - if (encodeResult == null) { - return null; - } - return create(encodeResult.valueType, encodeResult.value); - } - public static StyleBagItem color(String color) { - return encoded(ValueDecoder.encodeColor(color)); - } - public static StyleBagItem dimensionOrFraction(String str) { - return encoded(ValueDecoder.encodeDimensionOrFraction(str)); - } - public static StyleBagItem createFloat(float n) { - return new StyleBagItem(ValueType.FLOAT, Float.floatToIntBits(n)); - } - public static StyleBagItem enumOrFlag(AttributeBag attr, String valueString) { - return encoded(attr.encodeEnumOrFlagValue(valueString)); - } - } + public static StyleBagItem reference(int resourceId) { + return new StyleBagItem(ValueType.REFERENCE, resourceId); + } + public static StyleBagItem attribute(int resourceId) { + return new StyleBagItem(ValueType.ATTRIBUTE, resourceId); + } + public static StyleBagItem encoded(ValueDecoder.EncodeResult encodeResult) { + if (encodeResult == null) { + return null; + } + return create(encodeResult.valueType, encodeResult.value); + } + public static StyleBagItem color(String color) { + return encoded(ValueDecoder.encodeColor(color)); + } + public static StyleBagItem dimensionOrFraction(String str) { + return encoded(ValueDecoder.encodeDimensionOrFraction(str)); + } + public static StyleBagItem createFloat(float n) { + return new StyleBagItem(ValueType.FLOAT, Float.floatToIntBits(n)); + } + public static StyleBagItem enumOrFlag(AttributeBag attr, String valueString) { + return encoded(attr.encodeEnumOrFlagValue(valueString)); + } +}