better hex conversion

This commit is contained in:
REAndroid 2023-05-04 15:01:57 +02:00
parent 1b240b2281
commit f5ec1381a4
40 changed files with 1459 additions and 1320 deletions

View File

@ -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){

View File

@ -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{

View File

@ -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());

View File

@ -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<OUTPUT> extends BagDecoder<OUTPUT>{
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);
}

View File

@ -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<ResourceIds.Table.Package> packageIdSet = new HashSet<>();
private PackageBlock currentPackage;
private final Set<FrameworkTable> frameworkTables = new HashSet<>();
private APKLogger apkLogger;
private boolean mForceCreateNamespaces = true;
private Set<String> mFrameworkPackageNames;
private final ResNameMap<Entry> 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<ResourceIds.Table.Package> packageIdSet = new HashSet<>();
private PackageBlock currentPackage;
private final Set<FrameworkTable> frameworkTables = new HashSet<>();
private APKLogger apkLogger;
private boolean mForceCreateNamespaces = true;
private Set<String> mFrameworkPackageNames;
private final ResNameMap<Entry> 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<Entry> 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<String> getFrameworkPackageNames(){
if(mFrameworkPackageNames!=null){
return mFrameworkPackageNames;
}
Set<String> 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<Entry> 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<String> getFrameworkPackageNames(){
if(mFrameworkPackageNames!=null){
return mFrameworkPackageNames;
}
Set<String> 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;
}
}
}

View File

@ -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);
}
}

View File

@ -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());

View File

@ -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());

View File

@ -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();

View File

@ -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();
}

View File

@ -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<SignatureId>{
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<SignatureId>{
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) {

View File

@ -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<T extends InputStream> 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();
}
}

View File

@ -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){

View File

@ -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<PackageHeader>
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();

View File

@ -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<SpecHeader> implements JSONConvert<JSONObject> {
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<Integer> 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<SpecHeader> implements JSONConvert<JSONObject> {
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<Integer> 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";
}

View File

@ -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+"\"";

View File

@ -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<Block>
@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){

View File

@ -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){

View File

@ -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){

View File

@ -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);
}
}

View File

@ -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());

View File

@ -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(){

View File

@ -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() {

View File

@ -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

View File

@ -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();
}

View File

@ -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() {

View File

@ -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<SpecFlagsArray> {
public SpecFlag(SpecFlagsArray specFlagsArray, int offset) {
@ -58,7 +59,7 @@ public class SpecFlag extends IndirectItem<SpecFlagsArray> {
}
int val = getInteger();
if(val != 0){
return String.format("0x%08x", val);
return HexUtil.toHex8(val);
}
return "";
}

View File

@ -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();
}
}

View File

@ -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 {

View File

@ -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;
}
}

View File

@ -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<JSONObject> {
@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){

View File

@ -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();

View File

@ -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<JSONObject> {
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){

View File

@ -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();
}

View File

@ -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<JSONObjec
return getInteger(0);
}
public void setStagedResId(int id){
putInteger(0, id);
putInteger(0, id);
}
public int getFinalizedResId(){
return getInteger(4);
@ -32,8 +48,8 @@ public class StagedAliasEntry extends ByteArray implements JSONConvert<JSONObjec
}
@Override
public String toString(){
return "stagedResId="+String.format("0x%08x",getStagedResId())
+", finalizedResId="+String.format("0x%08x",getFinalizedResId());
return "stagedResId=" + HexUtil.toHex8(getStagedResId())
+", finalizedResId=" + HexUtil.toHex8(getFinalizedResId());
}
@Override
public JSONObject toJson() {

View File

@ -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;
@ -24,308 +24,309 @@ import com.reandroid.arsc.item.ReferenceItem;
import com.reandroid.arsc.item.StringItem;
import com.reandroid.arsc.pool.StringPool;
import com.reandroid.arsc.pool.TableStringPool;
import com.reandroid.arsc.util.HexUtil;
import com.reandroid.json.JSONConvert;
import com.reandroid.json.JSONObject;
import java.io.IOException;
import java.util.Objects;
public abstract class ValueItem extends BlockItem implements Value,
JSONConvert<JSONObject>{
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<JSONObject>{
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";
}

View File

@ -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("<item>");
if (hasStringValue()) {
builder.append(getStringValue());
} else {
builder.append(String.format("0x%08x", getValue()));
}
builder.append("</item>");
return builder.toString();
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("<item>");
if (hasStringValue()) {
builder.append(getStringValue());
} else {
builder.append(HexUtil.toHex8(getValue()));
}
builder.append("</item>");
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);
}
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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("<item name=\"");
String name = getName();
if (name == null) {
name = String.format("@0x%08x", getNameId());
}
builder.append(name);
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("</item>");
return builder.toString();
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("<item name=\"");
String name = getName();
if (name == null) {
name = HexUtil.toHex8("@0x", getNameId());
}
builder.append(name);
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("</item>");
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));
}
}