mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-04-29 22:04:25 +02:00
V1.0.1
This commit is contained in:
parent
1763dfbc3c
commit
15e031fdeb
30
README.md
Normal file → Executable file
30
README.md
Normal file → Executable file
@ -7,22 +7,38 @@
|
|||||||
|
|
||||||
public static void example() throws IOException {
|
public static void example() throws IOException {
|
||||||
File inFile=new File("resources.arsc");
|
File inFile=new File("resources.arsc");
|
||||||
BlockReader blockReader=new BlockReader(inFile);
|
|
||||||
|
|
||||||
TableBlock tableBlock=new TableBlock();
|
TableBlock tableBlock=new TableBlock();
|
||||||
tableBlock.readBytes(blockReader);
|
tableBlock.readBytes(inFile);
|
||||||
|
|
||||||
// edit tableBlock as desired
|
//edit tableBlock as desired, for example to change the package:
|
||||||
|
PackageBlock packageBlock=tableBlock.getPackageArray().get(0);
|
||||||
|
packageBlock.setPackageName("com.new.package.name");
|
||||||
|
|
||||||
|
//refresh to recalculate offsets
|
||||||
tableBlock.refresh();
|
tableBlock.refresh();
|
||||||
|
|
||||||
|
//save the edited table
|
||||||
File outFile=new File("resources_out.arsc");
|
File outFile=new File("resources_out.arsc");
|
||||||
OutputStream outputStream=new FileOutputStream(outFile, false);
|
tableBlock.writeBytes(outFile);
|
||||||
|
}
|
||||||
|
|
||||||
tableBlock.writeBytes(outputStream);
|
public static void exampleManifest() throws IOException {
|
||||||
|
File inFile=new File("AndroidManifest.xml");
|
||||||
|
|
||||||
outputStream.flush();
|
AndroidManifestBlock manifestBlock=new AndroidManifestBlock();
|
||||||
outputStream.close();
|
manifestBlock.readBytes(file);
|
||||||
|
|
||||||
|
//edit AndroidManifest as desired, for example to change the package:
|
||||||
|
|
||||||
|
manifestBlock.setPackageName("com.new.package.name");
|
||||||
|
|
||||||
|
//refresh to recalculate offsets
|
||||||
|
manifestBlock.refresh();
|
||||||
|
|
||||||
|
//save the edited table
|
||||||
|
File outFile=new File("AndroidManifest_out.xml");
|
||||||
|
manifestBlock.writeBytes(outFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
12
build.gradle
Normal file → Executable file
12
build.gradle
Normal file → Executable file
@ -2,7 +2,7 @@
|
|||||||
apply plugin: 'java-library'
|
apply plugin: 'java-library'
|
||||||
|
|
||||||
group 'com.reandroid.lib.arsc'
|
group 'com.reandroid.lib.arsc'
|
||||||
version '1.0.0'
|
version '1.0.1'
|
||||||
|
|
||||||
java {
|
java {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
@ -18,12 +18,12 @@ if (JavaVersion.current().isJava8Compatible()) {
|
|||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
mavenLocal()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
processResources {
|
||||||
|
filesMatching('lib.properties') {
|
||||||
|
expand('version': version)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
processResources.inputs.property('version', version)
|
|
||||||
processResources.expand('version': version)
|
|
||||||
|
|
||||||
|
0
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file → Executable file
0
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file → Executable file
0
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file → Executable file
0
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file → Executable file
0
gradlew.bat
vendored
Normal file → Executable file
0
gradlew.bat
vendored
Normal file → Executable file
0
settings.gradle
Normal file → Executable file
0
settings.gradle
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/BuildInfo.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/BuildInfo.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/EntryBlockArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/EntryBlockArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/LibraryInfoArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/LibraryInfoArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/OffsetBlockArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/OffsetBlockArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/PackageArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/PackageArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/ResValueBagItemArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/ResValueBagItemArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/ResXmlAttributeArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/ResXmlAttributeArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/ResXmlChunkArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/ResXmlChunkArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/ResXmlIDArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/ResXmlIDArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/ResXmlStringArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/ResXmlStringArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/SpecBlockArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/SpecBlockArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/SpecStringArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/SpecStringArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/SpecTypePairArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/SpecTypePairArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/StringArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/StringArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/StyleArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/StyleArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/TableStringArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/TableStringArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/TypeBlockArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/TypeBlockArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/TypeStringArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/array/TypeStringArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/base/Block.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/base/Block.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/base/BlockArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/base/BlockArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/base/BlockArrayCreator.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/base/BlockArrayCreator.java
Normal file → Executable file
12
src/main/java/com/reandroid/lib/arsc/base/BlockContainer.java
Normal file → Executable file
12
src/main/java/com/reandroid/lib/arsc/base/BlockContainer.java
Normal file → Executable file
@ -9,6 +9,18 @@ public abstract class BlockContainer<T extends Block> extends Block{
|
|||||||
public BlockContainer(){
|
public BlockContainer(){
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected final BlockContainer getTopContainer(){
|
||||||
|
Block parent=this;
|
||||||
|
BlockContainer result=this;
|
||||||
|
while (parent!=null){
|
||||||
|
if(parent instanceof BlockContainer){
|
||||||
|
result=(BlockContainer)parent;
|
||||||
|
}
|
||||||
|
parent=parent.getParent();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
protected abstract void onRefreshed();
|
protected abstract void onRefreshed();
|
||||||
public final void refresh(){
|
public final void refresh(){
|
||||||
if(isNull()){
|
if(isNull()){
|
||||||
|
0
src/main/java/com/reandroid/lib/arsc/base/BlockCounter.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/base/BlockCounter.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/base/BlockCreator.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/base/BlockCreator.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/chunk/BaseChunk.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/chunk/BaseChunk.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/chunk/BaseTypeBlock.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/chunk/BaseTypeBlock.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/chunk/ChunkType.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/chunk/ChunkType.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/chunk/LibraryBlock.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/chunk/LibraryBlock.java
Normal file → Executable file
66
src/main/java/com/reandroid/lib/arsc/chunk/PackageBlock.java
Normal file → Executable file
66
src/main/java/com/reandroid/lib/arsc/chunk/PackageBlock.java
Normal file → Executable file
@ -4,7 +4,6 @@ import com.reandroid.lib.arsc.array.SpecTypePairArray;
|
|||||||
import com.reandroid.lib.arsc.base.Block;
|
import com.reandroid.lib.arsc.base.Block;
|
||||||
import com.reandroid.lib.arsc.container.PackageLastBlocks;
|
import com.reandroid.lib.arsc.container.PackageLastBlocks;
|
||||||
import com.reandroid.lib.arsc.container.SpecTypePair;
|
import com.reandroid.lib.arsc.container.SpecTypePair;
|
||||||
import com.reandroid.lib.arsc.decoder.ResourceNameProvider;
|
|
||||||
import com.reandroid.lib.arsc.group.EntryGroup;
|
import com.reandroid.lib.arsc.group.EntryGroup;
|
||||||
import com.reandroid.lib.arsc.item.IntegerItem;
|
import com.reandroid.lib.arsc.item.IntegerItem;
|
||||||
import com.reandroid.lib.arsc.item.PackageName;
|
import com.reandroid.lib.arsc.item.PackageName;
|
||||||
@ -12,15 +11,13 @@ import com.reandroid.lib.arsc.item.ReferenceItem;
|
|||||||
import com.reandroid.lib.arsc.pool.SpecStringPool;
|
import com.reandroid.lib.arsc.pool.SpecStringPool;
|
||||||
import com.reandroid.lib.arsc.pool.TableStringPool;
|
import com.reandroid.lib.arsc.pool.TableStringPool;
|
||||||
import com.reandroid.lib.arsc.pool.TypeStringPool;
|
import com.reandroid.lib.arsc.pool.TypeStringPool;
|
||||||
import com.reandroid.lib.arsc.value.BaseResValue;
|
|
||||||
import com.reandroid.lib.arsc.value.EntryBlock;
|
import com.reandroid.lib.arsc.value.EntryBlock;
|
||||||
import com.reandroid.lib.arsc.value.LibraryInfo;
|
import com.reandroid.lib.arsc.value.LibraryInfo;
|
||||||
import com.reandroid.lib.arsc.value.ResValueBag;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
|
||||||
public class PackageBlock extends BaseChunk implements ResourceNameProvider {
|
public class PackageBlock extends BaseChunk {
|
||||||
private final IntegerItem mPackageId;
|
private final IntegerItem mPackageId;
|
||||||
private final PackageName mPackageName;
|
private final PackageName mPackageName;
|
||||||
|
|
||||||
@ -270,67 +267,6 @@ public class PackageBlock extends BaseChunk implements ResourceNameProvider {
|
|||||||
refreshKeyStrings();
|
refreshKeyStrings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getResourceFullName(int resId, boolean includePackageName) {
|
|
||||||
EntryGroup entryGroup=getEntryGroup(resId);
|
|
||||||
if(entryGroup==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String type=entryGroup.getTypeName();
|
|
||||||
if(type==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String spec=entryGroup.getSpecName();
|
|
||||||
if(spec==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
StringBuilder builder=new StringBuilder();
|
|
||||||
builder.append('@');
|
|
||||||
if(includePackageName){
|
|
||||||
builder.append(getPackageName());
|
|
||||||
builder.append(':');
|
|
||||||
}
|
|
||||||
builder.append(type);
|
|
||||||
builder.append('/');
|
|
||||||
builder.append(spec);
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getResourceName(int resId, boolean includePackageName) {
|
|
||||||
EntryGroup entryGroup=getEntryGroup(resId);
|
|
||||||
if(entryGroup==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String spec=entryGroup.getSpecName();
|
|
||||||
if(spec==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
StringBuilder builder=new StringBuilder();
|
|
||||||
if(includePackageName){
|
|
||||||
builder.append(getPackageName());
|
|
||||||
builder.append(':');
|
|
||||||
}
|
|
||||||
builder.append(spec);
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public ResValueBag getAttributeBag(int resId){
|
|
||||||
EntryGroup entryGroup=getEntryGroup(resId);
|
|
||||||
if(entryGroup==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
EntryBlock entryBlock=entryGroup.pickOne();
|
|
||||||
if(entryBlock==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
BaseResValue resValue=entryBlock.getResValue();
|
|
||||||
if(resValue instanceof ResValueBag){
|
|
||||||
return (ResValueBag)resValue;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString(){
|
public String toString(){
|
||||||
StringBuilder builder=new StringBuilder();
|
StringBuilder builder=new StringBuilder();
|
||||||
|
0
src/main/java/com/reandroid/lib/arsc/chunk/SpecBlock.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/chunk/SpecBlock.java
Normal file → Executable file
96
src/main/java/com/reandroid/lib/arsc/chunk/TableBlock.java
Normal file → Executable file
96
src/main/java/com/reandroid/lib/arsc/chunk/TableBlock.java
Normal file → Executable file
@ -1,14 +1,16 @@
|
|||||||
package com.reandroid.lib.arsc.chunk;
|
package com.reandroid.lib.arsc.chunk;
|
||||||
|
|
||||||
import com.reandroid.lib.arsc.array.PackageArray;
|
import com.reandroid.lib.arsc.array.PackageArray;
|
||||||
import com.reandroid.lib.arsc.decoder.ResourceNameProvider;
|
import com.reandroid.lib.arsc.chunk.xml.ResXmlBlock;
|
||||||
|
import com.reandroid.lib.arsc.header.HeaderBlock;
|
||||||
|
import com.reandroid.lib.arsc.io.BlockReader;
|
||||||
import com.reandroid.lib.arsc.item.IntegerItem;
|
import com.reandroid.lib.arsc.item.IntegerItem;
|
||||||
import com.reandroid.lib.arsc.pool.TableStringPool;
|
import com.reandroid.lib.arsc.pool.TableStringPool;
|
||||||
import com.reandroid.lib.arsc.value.ResValueBag;
|
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
public class TableBlock extends BaseChunk implements ResourceNameProvider {
|
public class TableBlock extends BaseChunk {
|
||||||
private final IntegerItem mPackageCount;
|
private final IntegerItem mPackageCount;
|
||||||
private final TableStringPool mTableStringPool;
|
private final TableStringPool mTableStringPool;
|
||||||
private final PackageArray mPackageArray;
|
private final PackageArray mPackageArray;
|
||||||
@ -42,43 +44,34 @@ public class TableBlock extends BaseChunk implements ResourceNameProvider {
|
|||||||
protected void onChunkRefreshed() {
|
protected void onChunkRefreshed() {
|
||||||
refreshPackageCount();
|
refreshPackageCount();
|
||||||
}
|
}
|
||||||
@Override
|
|
||||||
public String getResourceFullName(int resId, boolean includePackageName) {
|
|
||||||
byte pkgId= (byte) ((resId>>24)&0xFF);
|
|
||||||
if(pkgId==0){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
PackageBlock packageBlock=getPackageBlockById(pkgId);
|
|
||||||
if(packageBlock!=null){
|
|
||||||
return packageBlock.getResourceFullName(resId, includePackageName);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getResourceName(int resId, boolean includePackageName) {
|
public int onWriteBytes(OutputStream stream) throws IOException{
|
||||||
byte pkgId= (byte) ((resId>>24)&0xFF);
|
int result=super.onWriteBytes(stream);
|
||||||
if(pkgId==0){
|
stream.flush();
|
||||||
return null;
|
stream.close();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
PackageBlock packageBlock=getPackageBlockById(pkgId);
|
public void readBytes(File file) throws IOException{
|
||||||
if(packageBlock!=null){
|
BlockReader reader=new BlockReader(file);
|
||||||
return packageBlock.getResourceName(resId, includePackageName);
|
super.readBytes(reader);
|
||||||
}
|
}
|
||||||
return null;
|
public void readBytes(InputStream inputStream) throws IOException{
|
||||||
|
BlockReader reader=new BlockReader(inputStream);
|
||||||
|
super.readBytes(reader);
|
||||||
}
|
}
|
||||||
@Override
|
public final int writeBytes(File file) throws IOException{
|
||||||
public ResValueBag getAttributeBag(int resId){
|
if(isNull()){
|
||||||
byte pkgId= (byte) ((resId>>24)&0xFF);
|
throw new IOException("Can NOT save null block");
|
||||||
if(pkgId==0){
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
PackageBlock packageBlock=getPackageBlockById(pkgId);
|
File dir=file.getParentFile();
|
||||||
if(packageBlock!=null){
|
if(dir!=null && !dir.exists()){
|
||||||
return packageBlock.getAttributeBag(resId);
|
dir.mkdirs();
|
||||||
}
|
}
|
||||||
return null;
|
OutputStream outputStream=new FileOutputStream(file);
|
||||||
|
return super.writeBytes(outputStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString(){
|
public String toString(){
|
||||||
StringBuilder builder=new StringBuilder();
|
StringBuilder builder=new StringBuilder();
|
||||||
@ -89,4 +82,43 @@ public class TableBlock extends BaseChunk implements ResourceNameProvider {
|
|||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean isResTableBlock(File file){
|
||||||
|
if(file==null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
InputStream inputStream=new FileInputStream(file);
|
||||||
|
return isResTableBlock(inputStream);
|
||||||
|
} catch (FileNotFoundException ignored) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static boolean isResTableBlock(InputStream inputStream){
|
||||||
|
try {
|
||||||
|
HeaderBlock headerBlock= BlockReader.readHeaderBlock(inputStream);
|
||||||
|
return isResTableBlock(headerBlock);
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static boolean isResTableBlock(BlockReader blockReader){
|
||||||
|
if(blockReader==null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
HeaderBlock headerBlock = blockReader.readHeaderBlock();
|
||||||
|
return isResTableBlock(headerBlock);
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static boolean isResTableBlock(HeaderBlock headerBlock){
|
||||||
|
if(headerBlock==null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ChunkType chunkType=headerBlock.getChunkType();
|
||||||
|
return chunkType==ChunkType.TABLE;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
0
src/main/java/com/reandroid/lib/arsc/chunk/TypeBlock.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/chunk/TypeBlock.java
Normal file → Executable file
@ -0,0 +1,166 @@
|
|||||||
|
package com.reandroid.lib.arsc.chunk.xml;
|
||||||
|
|
||||||
|
import com.reandroid.lib.arsc.item.ResXmlString;
|
||||||
|
import com.reandroid.lib.arsc.pool.ResXmlStringPool;
|
||||||
|
import com.reandroid.lib.arsc.value.ValueType;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AndroidManifestBlock extends ResXmlBlock{
|
||||||
|
public AndroidManifestBlock(){
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
public List<String> getPermissions(){
|
||||||
|
List<String> results=new ArrayList<>();
|
||||||
|
ResXmlElement manifestElement=getManifestElement();
|
||||||
|
if(manifestElement==null){
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
List<ResXmlElement> permissionList = manifestElement.searchElementsByTagName(TAG_uses_permission);
|
||||||
|
for(ResXmlElement permission:permissionList){
|
||||||
|
ResXmlAttribute nameAttr = permission.searchAttributeByName(ATTR_android_name);
|
||||||
|
if(nameAttr==null){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String val=nameAttr.getValueString();
|
||||||
|
if(val!=null){
|
||||||
|
results.add(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
public String getPackageName(){
|
||||||
|
return getManifestAttributeString(ATTR_PACKAGE);
|
||||||
|
}
|
||||||
|
public boolean setPackageName(String packageName){
|
||||||
|
return setManifestAttributeString(ATTR_PACKAGE, packageName);
|
||||||
|
}
|
||||||
|
public Integer getCompileSdkVersion(){
|
||||||
|
return getManifestAttributeInt(ATTR_compileSdkVersion);
|
||||||
|
}
|
||||||
|
public boolean setCompileSdkVersion(int val){
|
||||||
|
return setManifestAttributeInt(ATTR_compileSdkVersion, val);
|
||||||
|
}
|
||||||
|
public String getCompileSdkVersionCodename(){
|
||||||
|
return getManifestAttributeString(ATTR_compileSdkVersionCodename);
|
||||||
|
}
|
||||||
|
public boolean setCompileSdkVersionCodename(String val){
|
||||||
|
return setManifestAttributeString(ATTR_compileSdkVersionCodename, val);
|
||||||
|
}
|
||||||
|
public Integer getVersionCode(){
|
||||||
|
return getManifestAttributeInt(ATTR_versionCode);
|
||||||
|
}
|
||||||
|
public boolean setVersionCode(int val){
|
||||||
|
return setManifestAttributeInt(ATTR_versionCode, val);
|
||||||
|
}
|
||||||
|
public String getVersionName(){
|
||||||
|
return getManifestAttributeString(ATTR_versionName);
|
||||||
|
}
|
||||||
|
public boolean setVersionName(String packageName){
|
||||||
|
return setManifestAttributeString(ATTR_versionName, packageName);
|
||||||
|
}
|
||||||
|
private String getManifestAttributeString(String name){
|
||||||
|
ResXmlElement manifestElement=getManifestElement();
|
||||||
|
if(manifestElement==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ResXmlAttribute attribute= manifestElement.searchAttributeByName(name);
|
||||||
|
if(attribute==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int raw=attribute.getRawValue();
|
||||||
|
ResXmlStringPool pool = getStringPool();
|
||||||
|
ResXmlString resXmlString = pool.get(raw);
|
||||||
|
if(resXmlString==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return resXmlString.getHtml();
|
||||||
|
}
|
||||||
|
private boolean setManifestAttributeString(String name, String value){
|
||||||
|
ResXmlElement manifestElement=getManifestElement();
|
||||||
|
if(manifestElement==null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ResXmlAttribute attribute= manifestElement.searchAttributeByName(name);
|
||||||
|
if(attribute==null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
attribute.setValueType(ValueType.STRING);
|
||||||
|
ResXmlString resXmlString=attribute.setValueString(value);
|
||||||
|
return resXmlString!=null;
|
||||||
|
}
|
||||||
|
private boolean setManifestAttributeInt(String name, int value){
|
||||||
|
ResXmlElement manifestElement=getManifestElement();
|
||||||
|
if(manifestElement==null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ResXmlAttribute attribute= manifestElement.searchAttributeByName(name);
|
||||||
|
if(attribute==null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
attribute.setValueType(ValueType.INT_DEC);
|
||||||
|
attribute.setValueString(String.valueOf(value));
|
||||||
|
attribute.setRawValue(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
private Integer getManifestAttributeInt(String name){
|
||||||
|
ResXmlElement manifestElement=getManifestElement();
|
||||||
|
if(manifestElement==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ResXmlAttribute attribute= manifestElement.searchAttributeByName(name);
|
||||||
|
if(attribute==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return attribute.getRawValue();
|
||||||
|
}
|
||||||
|
private ResXmlElement getManifestElement(){
|
||||||
|
ResXmlElement manifestElement=getResXmlElement();
|
||||||
|
if(manifestElement==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if(!TAG_MANIFEST.equals(manifestElement.getTag())){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return manifestElement;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
StringBuilder builder=new StringBuilder();
|
||||||
|
builder.append(getClass().getSimpleName());
|
||||||
|
builder.append("{");
|
||||||
|
builder.append(ATTR_PACKAGE).append("=").append(getPackageName());
|
||||||
|
builder.append(", ").append(ATTR_versionCode).append("=").append(getVersionCode());
|
||||||
|
builder.append(", ").append(ATTR_versionName).append("=").append(getVersionName());
|
||||||
|
builder.append(", ").append(ATTR_compileSdkVersion).append("=").append(getCompileSdkVersion());
|
||||||
|
builder.append(", ").append(ATTR_compileSdkVersionCodename).append("=").append(getCompileSdkVersionCodename());
|
||||||
|
|
||||||
|
List<String> allPermissions=getPermissions();
|
||||||
|
builder.append(", PERMISSIONS[");
|
||||||
|
boolean appendOnce=false;
|
||||||
|
for(String permissions:allPermissions){
|
||||||
|
if(appendOnce){
|
||||||
|
builder.append(", ");
|
||||||
|
}
|
||||||
|
builder.append(permissions);
|
||||||
|
appendOnce=true;
|
||||||
|
}
|
||||||
|
builder.append("]");
|
||||||
|
builder.append("}");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
private static final String TAG_MANIFEST="manifest";
|
||||||
|
private static final String TAG_uses_permission="uses-permission";
|
||||||
|
|
||||||
|
private static final String ATTR_compileSdkVersion="compileSdkVersion";
|
||||||
|
private static final String ATTR_compileSdkVersionCodename="compileSdkVersionCodename";
|
||||||
|
private static final String ATTR_installLocation="installLocation";
|
||||||
|
private static final String ATTR_PACKAGE="package";
|
||||||
|
private static final String ATTR_platformBuildVersionCode="platformBuildVersionCode";
|
||||||
|
private static final String ATTR_platformBuildVersionName="platformBuildVersionName";
|
||||||
|
private static final String ATTR_versionCode="versionCode";
|
||||||
|
private static final String ATTR_versionName="versionName";
|
||||||
|
|
||||||
|
private static final String ATTR_android_name="name";
|
||||||
|
}
|
17
src/main/java/com/reandroid/lib/arsc/chunk/xml/BaseXmlChunk.java
Normal file → Executable file
17
src/main/java/com/reandroid/lib/arsc/chunk/xml/BaseXmlChunk.java
Normal file → Executable file
@ -57,6 +57,15 @@ public class BaseXmlChunk extends BaseChunk {
|
|||||||
public int getStringReference(){
|
public int getStringReference(){
|
||||||
return mStringReference.get();
|
return mStringReference.get();
|
||||||
}
|
}
|
||||||
|
public ResXmlString setString(String str){
|
||||||
|
ResXmlStringPool pool = getStringPool();
|
||||||
|
if(pool==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ResXmlString xmlString = pool.getOrCreate(str);
|
||||||
|
setStringReference(xmlString.getIndex());
|
||||||
|
return xmlString;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public ResXmlStringPool getStringPool(){
|
public ResXmlStringPool getStringPool(){
|
||||||
@ -82,6 +91,13 @@ public class BaseXmlChunk extends BaseChunk {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
ResXmlString getOrCreateResXmlString(String str){
|
||||||
|
ResXmlStringPool stringPool=getStringPool();
|
||||||
|
if(stringPool!=null){
|
||||||
|
return stringPool.getOrCreate(str);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
String getString(int ref){
|
String getString(int ref){
|
||||||
ResXmlString xmlString=getResXmlString(ref);
|
ResXmlString xmlString=getResXmlString(ref);
|
||||||
if(xmlString!=null){
|
if(xmlString!=null){
|
||||||
@ -96,6 +112,7 @@ public class BaseXmlChunk extends BaseChunk {
|
|||||||
public String getUri(){
|
public String getUri(){
|
||||||
return getString(getNamespaceReference());
|
return getString(getNamespaceReference());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResXmlElement getParentResXmlElement(){
|
public ResXmlElement getParentResXmlElement(){
|
||||||
Block parent=getParent();
|
Block parent=getParent();
|
||||||
while (parent!=null){
|
while (parent!=null){
|
||||||
|
92
src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlAttribute.java
Normal file → Executable file
92
src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlAttribute.java
Normal file → Executable file
@ -17,10 +17,10 @@ public class ResXmlAttribute extends FixedBlockContainer {
|
|||||||
private final IntegerItem mRawValue;
|
private final IntegerItem mRawValue;
|
||||||
public ResXmlAttribute() {
|
public ResXmlAttribute() {
|
||||||
super(7);
|
super(7);
|
||||||
mNamespaceReference =new IntegerItem();
|
mNamespaceReference =new IntegerItem(-1);
|
||||||
mNameReference =new IntegerItem();
|
mNameReference =new IntegerItem();
|
||||||
mValueStringReference =new IntegerItem();
|
mValueStringReference =new IntegerItem();
|
||||||
mNameType=new ShortItem();
|
mNameType=new ShortItem((short) 0x0008);
|
||||||
mReserved =new ByteItem();
|
mReserved =new ByteItem();
|
||||||
mValueTypeByte=new ByteItem();
|
mValueTypeByte=new ByteItem();
|
||||||
mRawValue=new IntegerItem();
|
mRawValue=new IntegerItem();
|
||||||
@ -75,6 +75,11 @@ public class ResXmlAttribute extends FixedBlockContainer {
|
|||||||
public ValueType getValueType(){
|
public ValueType getValueType(){
|
||||||
return ValueType.valueOf(getValueTypeByte());
|
return ValueType.valueOf(getValueTypeByte());
|
||||||
}
|
}
|
||||||
|
public void setValueType(ValueType valueType){
|
||||||
|
if(valueType!=null){
|
||||||
|
setValueTypeByte(valueType.getByte());
|
||||||
|
}
|
||||||
|
}
|
||||||
public String getFullName(){
|
public String getFullName(){
|
||||||
String name=getName();
|
String name=getName();
|
||||||
if(name==null){
|
if(name==null){
|
||||||
@ -100,12 +105,86 @@ public class ResXmlAttribute extends FixedBlockContainer {
|
|||||||
}
|
}
|
||||||
return startNamespace.getPrefix();
|
return startNamespace.getPrefix();
|
||||||
}
|
}
|
||||||
|
public ResXmlStartNamespace getStartNamespace(){
|
||||||
|
ResXmlElement xmlElement=getParentResXmlElement();
|
||||||
|
if(xmlElement==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return xmlElement.getStartNamespaceByUriRef(getNamespaceReference());
|
||||||
|
}
|
||||||
public String getValueString(){
|
public String getValueString(){
|
||||||
return getString(getValueStringReference());
|
return getString(getValueStringReference());
|
||||||
}
|
}
|
||||||
|
ResXmlString setValueString(String str){
|
||||||
|
ResXmlString resXmlString=getOrCreateResXmlString(str);
|
||||||
|
if(resXmlString==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int ref=resXmlString.getIndex();
|
||||||
|
setValueStringReference(ref);
|
||||||
|
if(getValueType()==ValueType.STRING){
|
||||||
|
setRawValue(ref);
|
||||||
|
}
|
||||||
|
return resXmlString;
|
||||||
|
}
|
||||||
public int getNameResourceID(){
|
public int getNameResourceID(){
|
||||||
return getResourceId(getNameReference());
|
return getResourceId(getNameReference());
|
||||||
}
|
}
|
||||||
|
public boolean setName(String name, int resourceId){
|
||||||
|
ResXmlStringPool stringPool=getStringPool();
|
||||||
|
if(stringPool==null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String old=getName();
|
||||||
|
if(resourceId==0){
|
||||||
|
if(name.equals(old)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ResXmlString resXmlString=stringPool.getOrCreate(name);
|
||||||
|
setNameReference(resXmlString.getIndex());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ResXmlIDMap xmlIDMap=getResXmlIDMap();
|
||||||
|
if(xmlIDMap==null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int oldId=getNameResourceID();
|
||||||
|
if(oldId==resourceId){
|
||||||
|
if(name.equals(old)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ResXmlID resXmlID=xmlIDMap.getByResId(resourceId);
|
||||||
|
if(resXmlID!=null){
|
||||||
|
int ref=resXmlID.getIndex();
|
||||||
|
ResXmlString idName=stringPool.get(ref);
|
||||||
|
if(idName != null){
|
||||||
|
if(name.equals(idName.getHtml())){
|
||||||
|
setNameReference(ref);
|
||||||
|
}else {
|
||||||
|
idName.set(name);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int stringsCount=stringPool.countStrings();
|
||||||
|
int idCount=xmlIDMap.getResXmlIDArray().childesCount();
|
||||||
|
if(idCount>stringsCount){
|
||||||
|
xmlIDMap.addResourceId(idCount, resourceId);;
|
||||||
|
stringPool.getStringsArray().ensureSize(idCount+1);
|
||||||
|
ResXmlString resXmlString=stringPool.get(idCount);
|
||||||
|
resXmlString.set(name);
|
||||||
|
setNameReference(idCount);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
xmlIDMap.addResourceId(stringsCount, resourceId);
|
||||||
|
stringPool.getStringsArray().ensureSize(stringsCount+1);
|
||||||
|
ResXmlString resXmlString=stringPool.get(stringsCount);
|
||||||
|
resXmlString.set(name);
|
||||||
|
setNameReference(stringsCount);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
private int getResourceId(int ref){
|
private int getResourceId(int ref){
|
||||||
if(ref<0){
|
if(ref<0){
|
||||||
return 0;
|
return 0;
|
||||||
@ -139,6 +218,13 @@ public class ResXmlAttribute extends FixedBlockContainer {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
private ResXmlString getOrCreateResXmlString(String str){
|
||||||
|
ResXmlStringPool stringPool=getStringPool();
|
||||||
|
if(stringPool!=null){
|
||||||
|
return stringPool.getOrCreate(str);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
private ResXmlStringPool getStringPool(){
|
private ResXmlStringPool getStringPool(){
|
||||||
ResXmlElement xmlElement=getParentResXmlElement();
|
ResXmlElement xmlElement=getParentResXmlElement();
|
||||||
if(xmlElement!=null){
|
if(xmlElement!=null){
|
||||||
@ -153,7 +239,7 @@ public class ResXmlAttribute extends FixedBlockContainer {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
private ResXmlElement getParentResXmlElement(){
|
public ResXmlElement getParentResXmlElement(){
|
||||||
Block parent=getParent();
|
Block parent=getParent();
|
||||||
while (parent!=null){
|
while (parent!=null){
|
||||||
if(parent instanceof ResXmlElement){
|
if(parent instanceof ResXmlElement){
|
||||||
|
146
src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlBlock.java
Normal file → Executable file
146
src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlBlock.java
Normal file → Executable file
@ -2,20 +2,94 @@ package com.reandroid.lib.arsc.chunk.xml;
|
|||||||
|
|
||||||
import com.reandroid.lib.arsc.chunk.ChunkType;
|
import com.reandroid.lib.arsc.chunk.ChunkType;
|
||||||
import com.reandroid.lib.arsc.chunk.BaseChunk;
|
import com.reandroid.lib.arsc.chunk.BaseChunk;
|
||||||
|
import com.reandroid.lib.arsc.container.SingleBlockContainer;
|
||||||
|
import com.reandroid.lib.arsc.header.HeaderBlock;
|
||||||
|
import com.reandroid.lib.arsc.io.BlockReader;
|
||||||
import com.reandroid.lib.arsc.pool.ResXmlStringPool;
|
import com.reandroid.lib.arsc.pool.ResXmlStringPool;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
public class ResXmlBlock extends BaseChunk {
|
public class ResXmlBlock extends BaseChunk {
|
||||||
private final ResXmlStringPool mResXmlStringPool;
|
private final ResXmlStringPool mResXmlStringPool;
|
||||||
private final ResXmlIDMap mResXmlIDMap;
|
private final ResXmlIDMap mResXmlIDMap;
|
||||||
private final ResXmlElement mResXmlElement;
|
private ResXmlElement mResXmlElement;
|
||||||
|
private final SingleBlockContainer<ResXmlElement> mResXmlElementContainer;
|
||||||
public ResXmlBlock() {
|
public ResXmlBlock() {
|
||||||
super(ChunkType.XML,3);
|
super(ChunkType.XML,3);
|
||||||
this.mResXmlStringPool=new ResXmlStringPool(true);
|
this.mResXmlStringPool=new ResXmlStringPool(true);
|
||||||
this.mResXmlIDMap=new ResXmlIDMap();
|
this.mResXmlIDMap=new ResXmlIDMap();
|
||||||
this.mResXmlElement=new ResXmlElement();
|
this.mResXmlElement=new ResXmlElement();
|
||||||
|
this.mResXmlElementContainer=new SingleBlockContainer<>();
|
||||||
|
this.mResXmlElementContainer.setItem(mResXmlElement);
|
||||||
addChild(mResXmlStringPool);
|
addChild(mResXmlStringPool);
|
||||||
addChild(mResXmlIDMap);
|
addChild(mResXmlIDMap);
|
||||||
addChild(mResXmlElement);
|
addChild(mResXmlElementContainer);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onReadBytes(BlockReader reader) throws IOException {
|
||||||
|
HeaderBlock headerBlock=reader.readHeaderBlock();
|
||||||
|
if(headerBlock==null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BlockReader chunkReader=reader.create(reader.getPosition(), headerBlock.getChunkSize());
|
||||||
|
ChunkType chunkType=headerBlock.getChunkType();
|
||||||
|
if(chunkType==ChunkType.XML){
|
||||||
|
getHeaderBlock().readBytes(chunkReader);
|
||||||
|
}else {
|
||||||
|
throw new IOException("Not ResXmlBlock: "+reader+", Header="+headerBlock);
|
||||||
|
}
|
||||||
|
while (chunkReader.isAvailable()){
|
||||||
|
boolean readOk=readNext(chunkReader);
|
||||||
|
if(!readOk){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reader.offset(headerBlock.getChunkSize());
|
||||||
|
chunkReader.close();
|
||||||
|
onChunkLoaded();
|
||||||
|
}
|
||||||
|
private boolean readNext(BlockReader reader) throws IOException {
|
||||||
|
if(!reader.isAvailable()){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int position=reader.getPosition();
|
||||||
|
HeaderBlock headerBlock=reader.readHeaderBlock();
|
||||||
|
if(headerBlock==null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ChunkType chunkType=headerBlock.getChunkType();
|
||||||
|
if(chunkType==ChunkType.STRING){
|
||||||
|
mResXmlStringPool.readBytes(reader);
|
||||||
|
}else if(chunkType==ChunkType.XML_RESOURCE_MAP){
|
||||||
|
mResXmlIDMap.readBytes(reader);
|
||||||
|
}else if(isElementChunk(chunkType)){
|
||||||
|
mResXmlElementContainer.readBytes(reader);
|
||||||
|
return reader.isAvailable();
|
||||||
|
}else {
|
||||||
|
throw new IOException("Unexpected chunk "+headerBlock);
|
||||||
|
}
|
||||||
|
return reader.isAvailable() && position!=reader.getPosition();
|
||||||
|
}
|
||||||
|
private boolean isElementChunk(ChunkType chunkType){
|
||||||
|
if(chunkType==ChunkType.XML_START_ELEMENT){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(chunkType==ChunkType.XML_END_ELEMENT){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(chunkType==ChunkType.XML_START_NAMESPACE){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(chunkType==ChunkType.XML_END_NAMESPACE){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(chunkType==ChunkType.XML_CDATA){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(chunkType==ChunkType.XML_LAST_CHUNK){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
public ResXmlStringPool getStringPool(){
|
public ResXmlStringPool getStringPool(){
|
||||||
return mResXmlStringPool;
|
return mResXmlStringPool;
|
||||||
@ -26,8 +100,76 @@ public class ResXmlBlock extends BaseChunk {
|
|||||||
public ResXmlElement getResXmlElement(){
|
public ResXmlElement getResXmlElement(){
|
||||||
return mResXmlElement;
|
return mResXmlElement;
|
||||||
}
|
}
|
||||||
|
public void setResXmlElement(ResXmlElement resXmlElement){
|
||||||
|
this.mResXmlElement=resXmlElement;
|
||||||
|
this.mResXmlElementContainer.setItem(resXmlElement);
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
protected void onChunkRefreshed() {
|
protected void onChunkRefreshed() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public int onWriteBytes(OutputStream stream) throws IOException{
|
||||||
|
int result=super.onWriteBytes(stream);
|
||||||
|
stream.flush();
|
||||||
|
stream.close();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public void readBytes(File file) throws IOException{
|
||||||
|
BlockReader reader=new BlockReader(file);
|
||||||
|
super.readBytes(reader);
|
||||||
|
}
|
||||||
|
public void readBytes(InputStream inputStream) throws IOException{
|
||||||
|
BlockReader reader=new BlockReader(inputStream);
|
||||||
|
super.readBytes(reader);
|
||||||
|
}
|
||||||
|
public final int writeBytes(File file) throws IOException{
|
||||||
|
if(isNull()){
|
||||||
|
throw new IOException("Can NOT save null block");
|
||||||
|
}
|
||||||
|
File dir=file.getParentFile();
|
||||||
|
if(dir!=null && !dir.exists()){
|
||||||
|
dir.mkdirs();
|
||||||
|
}
|
||||||
|
OutputStream outputStream=new FileOutputStream(file);
|
||||||
|
return super.writeBytes(outputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isResXmlBlock(File file){
|
||||||
|
if(file==null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
InputStream inputStream=new FileInputStream(file);
|
||||||
|
return isResXmlBlock(inputStream);
|
||||||
|
} catch (FileNotFoundException ignored) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static boolean isResXmlBlock(InputStream inputStream){
|
||||||
|
try {
|
||||||
|
HeaderBlock headerBlock=BlockReader.readHeaderBlock(inputStream);
|
||||||
|
return isResXmlBlock(headerBlock);
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static boolean isResXmlBlock(BlockReader blockReader){
|
||||||
|
if(blockReader==null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
HeaderBlock headerBlock = blockReader.readHeaderBlock();
|
||||||
|
return isResXmlBlock(headerBlock);
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static boolean isResXmlBlock(HeaderBlock headerBlock){
|
||||||
|
if(headerBlock==null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ChunkType chunkType=headerBlock.getChunkType();
|
||||||
|
return chunkType==ChunkType.XML;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
114
src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlElement.java
Normal file → Executable file
114
src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlElement.java
Normal file → Executable file
@ -7,6 +7,7 @@ import com.reandroid.lib.arsc.container.FixedBlockContainer;
|
|||||||
import com.reandroid.lib.arsc.container.SingleBlockContainer;
|
import com.reandroid.lib.arsc.container.SingleBlockContainer;
|
||||||
import com.reandroid.lib.arsc.header.HeaderBlock;
|
import com.reandroid.lib.arsc.header.HeaderBlock;
|
||||||
import com.reandroid.lib.arsc.io.BlockReader;
|
import com.reandroid.lib.arsc.io.BlockReader;
|
||||||
|
import com.reandroid.lib.arsc.item.ResXmlString;
|
||||||
import com.reandroid.lib.arsc.pool.ResXmlStringPool;
|
import com.reandroid.lib.arsc.pool.ResXmlStringPool;
|
||||||
|
|
||||||
|
|
||||||
@ -38,6 +39,42 @@ public class ResXmlElement extends FixedBlockContainer {
|
|||||||
addChild(4, mEndElementContainer);
|
addChild(4, mEndElementContainer);
|
||||||
addChild(5, mEndNamespaceList);
|
addChild(5, mEndNamespaceList);
|
||||||
}
|
}
|
||||||
|
public List<ResXmlElement> searchElementsByTagName(String name){
|
||||||
|
List<ResXmlElement> results=new ArrayList<>();
|
||||||
|
if(name==null){
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
for(ResXmlElement child:listElements()){
|
||||||
|
if(name.equals(child.getTag())||name.equals(child.getTagName())){
|
||||||
|
results.add(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
public ResXmlAttribute searchAttributeByName(String name){
|
||||||
|
ResXmlStartElement startElement=getStartElement();
|
||||||
|
if(startElement!=null){
|
||||||
|
return startElement.searchAttributeByName(name);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public void setTag(String tag){
|
||||||
|
ResXmlStringPool pool = getStringPool();
|
||||||
|
if(pool==null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ensureStartEndElement();
|
||||||
|
ResXmlStartElement start=getStartElement();
|
||||||
|
String prefix=null;
|
||||||
|
String name=tag;
|
||||||
|
int i=tag.lastIndexOf(':');
|
||||||
|
if(i>=0){
|
||||||
|
prefix=tag.substring(0,i);
|
||||||
|
i++;
|
||||||
|
name=tag.substring(i);
|
||||||
|
}
|
||||||
|
start.setName(name);
|
||||||
|
}
|
||||||
public String getTagName(){
|
public String getTagName(){
|
||||||
ResXmlStartElement startElement=getStartElement();
|
ResXmlStartElement startElement=getStartElement();
|
||||||
if(startElement!=null){
|
if(startElement!=null){
|
||||||
@ -45,6 +82,27 @@ public class ResXmlElement extends FixedBlockContainer {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
public String getTag(){
|
||||||
|
ResXmlStartElement startElement=getStartElement();
|
||||||
|
if(startElement!=null){
|
||||||
|
return startElement.getName();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public String getTagUri(){
|
||||||
|
ResXmlStartElement startElement=getStartElement();
|
||||||
|
if(startElement!=null){
|
||||||
|
return startElement.getUri();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public String getTagPrefix(){
|
||||||
|
ResXmlStartElement startElement=getStartElement();
|
||||||
|
if(startElement!=null){
|
||||||
|
return startElement.getPrefix();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
public Collection<ResXmlAttribute> listResXmlAttributes(){
|
public Collection<ResXmlAttribute> listResXmlAttributes(){
|
||||||
ResXmlStartElement startElement=getStartElement();
|
ResXmlStartElement startElement=getStartElement();
|
||||||
if(startElement!=null){
|
if(startElement!=null){
|
||||||
@ -182,6 +240,22 @@ public class ResXmlElement extends FixedBlockContainer {
|
|||||||
start.setResXmlEndElement(end);
|
start.setResXmlEndElement(end);
|
||||||
end.setResXmlStartElement(start);
|
end.setResXmlStartElement(start);
|
||||||
}
|
}
|
||||||
|
private void ensureStartEndElement(){
|
||||||
|
ResXmlStartElement start=getStartElement();
|
||||||
|
ResXmlEndElement end=getEndElement();
|
||||||
|
if(start!=null && end!=null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(start==null){
|
||||||
|
start=new ResXmlStartElement();
|
||||||
|
setStartElement(start);
|
||||||
|
}
|
||||||
|
if(end==null){
|
||||||
|
end=new ResXmlEndElement();
|
||||||
|
setEndElement(end);
|
||||||
|
}
|
||||||
|
linkStartEndElement();
|
||||||
|
}
|
||||||
private void linkStartEndNameSpaces(){
|
private void linkStartEndNameSpaces(){
|
||||||
if(!isNamespaceBalanced()){
|
if(!isNamespaceBalanced()){
|
||||||
return;
|
return;
|
||||||
@ -227,9 +301,9 @@ public class ResXmlElement extends FixedBlockContainer {
|
|||||||
unBalancedFinish(reader);
|
unBalancedFinish(reader);
|
||||||
}else {
|
}else {
|
||||||
readBytes(reader);
|
readBytes(reader);
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
linkStartEnd();
|
linkStartEnd();
|
||||||
onFinishedRead(reader, headerBlock);
|
onFinishedRead(reader, headerBlock);
|
||||||
}
|
}
|
||||||
@ -245,7 +319,14 @@ public class ResXmlElement extends FixedBlockContainer {
|
|||||||
|
|
||||||
}
|
}
|
||||||
private void onFinishedUnexpected(BlockReader reader) throws IOException{
|
private void onFinishedUnexpected(BlockReader reader) throws IOException{
|
||||||
throw new IOException("Unexpected finish reading: "+reader.toString());
|
StringBuilder builder=new StringBuilder();
|
||||||
|
builder.append("Unexpected finish reading: reader=").append(reader.toString());
|
||||||
|
HeaderBlock header = reader.readHeaderBlock();
|
||||||
|
if(header!=null){
|
||||||
|
builder.append(", next header=");
|
||||||
|
builder.append(header.toString());
|
||||||
|
}
|
||||||
|
throw new IOException(builder.toString());
|
||||||
}
|
}
|
||||||
private void onStartElement(BlockReader reader) throws IOException{
|
private void onStartElement(BlockReader reader) throws IOException{
|
||||||
if(hasStartElement()){
|
if(hasStartElement()){
|
||||||
@ -298,9 +379,25 @@ public class ResXmlElement extends FixedBlockContainer {
|
|||||||
throw new IOException("Unbalanced namespace: start="
|
throw new IOException("Unbalanced namespace: start="
|
||||||
+mStartNamespaceList.size()+", end="+mEndNamespaceList.size());
|
+mStartNamespaceList.size()+", end="+mEndNamespaceList.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isElementBalanced()){
|
if(!isElementBalanced()){
|
||||||
throw new IOException("Unbalanced element: hasStart="
|
// Should not happen unless corrupted file, auto corrected above
|
||||||
+hasStartElement()+", hasEnd="+hasEndElement());
|
StringBuilder builder=new StringBuilder();
|
||||||
|
builder.append("Unbalanced element: start=");
|
||||||
|
ResXmlStartElement startElement=getStartElement();
|
||||||
|
if(startElement!=null){
|
||||||
|
builder.append(startElement);
|
||||||
|
}else {
|
||||||
|
builder.append("null");
|
||||||
|
}
|
||||||
|
builder.append(", end=");
|
||||||
|
ResXmlEndElement endElement=getEndElement();
|
||||||
|
if(endElement!=null){
|
||||||
|
builder.append(endElement);
|
||||||
|
}else {
|
||||||
|
builder.append("null");
|
||||||
|
}
|
||||||
|
throw new IOException(builder.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
@ -324,4 +421,13 @@ public class ResXmlElement extends FixedBlockContainer {
|
|||||||
}
|
}
|
||||||
return "NULL";
|
return "NULL";
|
||||||
}
|
}
|
||||||
|
static ResXmlElement newResXmlElement(String tag){
|
||||||
|
ResXmlElement resXmlElement=new ResXmlElement();
|
||||||
|
ResXmlStartElement startElement=new ResXmlStartElement();
|
||||||
|
resXmlElement.setStartElement(startElement);
|
||||||
|
ResXmlEndElement endElement=new ResXmlEndElement();
|
||||||
|
resXmlElement.setEndElement(endElement);
|
||||||
|
resXmlElement.setTag(tag);
|
||||||
|
return resXmlElement;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
0
src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlEndElement.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlEndElement.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlEndNamespace.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlEndNamespace.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlIDMap.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlIDMap.java
Normal file → Executable file
15
src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlStartElement.java
Normal file → Executable file
15
src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlStartElement.java
Normal file → Executable file
@ -3,6 +3,7 @@ package com.reandroid.lib.arsc.chunk.xml;
|
|||||||
import com.reandroid.lib.arsc.chunk.ChunkType;
|
import com.reandroid.lib.arsc.chunk.ChunkType;
|
||||||
import com.reandroid.lib.arsc.array.ResXmlAttributeArray;
|
import com.reandroid.lib.arsc.array.ResXmlAttributeArray;
|
||||||
import com.reandroid.lib.arsc.item.IntegerItem;
|
import com.reandroid.lib.arsc.item.IntegerItem;
|
||||||
|
import com.reandroid.lib.arsc.item.ResXmlString;
|
||||||
import com.reandroid.lib.arsc.item.ShortItem;
|
import com.reandroid.lib.arsc.item.ShortItem;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -31,6 +32,17 @@ public class ResXmlStartElement extends BaseXmlChunk {
|
|||||||
addChild(mClassAttribute);
|
addChild(mClassAttribute);
|
||||||
addChild(mAttributeArray);
|
addChild(mAttributeArray);
|
||||||
}
|
}
|
||||||
|
public ResXmlAttribute searchAttributeByName(String name){
|
||||||
|
if(name==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for(ResXmlAttribute attribute:listResXmlAttributes()){
|
||||||
|
if(name.equals(attribute.getFullName()) || name.equals(attribute.getName())){
|
||||||
|
return attribute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
public String getTagName(){
|
public String getTagName(){
|
||||||
String prefix=getPrefix();
|
String prefix=getPrefix();
|
||||||
String name=getName();
|
String name=getName();
|
||||||
@ -39,6 +51,9 @@ public class ResXmlStartElement extends BaseXmlChunk {
|
|||||||
}
|
}
|
||||||
return prefix+":"+name;
|
return prefix+":"+name;
|
||||||
}
|
}
|
||||||
|
public void setName(String name){
|
||||||
|
setString(name);
|
||||||
|
}
|
||||||
public Collection<ResXmlAttribute> listResXmlAttributes(){
|
public Collection<ResXmlAttribute> listResXmlAttributes(){
|
||||||
return getResXmlAttributeArray().listItems();
|
return getResXmlAttributeArray().listItems();
|
||||||
}
|
}
|
||||||
|
0
src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlStartNamespace.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlStartNamespace.java
Normal file → Executable file
10
src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlText.java
Normal file → Executable file
10
src/main/java/com/reandroid/lib/arsc/chunk/xml/ResXmlText.java
Normal file → Executable file
@ -3,6 +3,7 @@ package com.reandroid.lib.arsc.chunk.xml;
|
|||||||
import com.reandroid.lib.arsc.chunk.ChunkType;
|
import com.reandroid.lib.arsc.chunk.ChunkType;
|
||||||
import com.reandroid.lib.arsc.item.IntegerItem;
|
import com.reandroid.lib.arsc.item.IntegerItem;
|
||||||
import com.reandroid.lib.arsc.item.ResXmlString;
|
import com.reandroid.lib.arsc.item.ResXmlString;
|
||||||
|
import com.reandroid.lib.arsc.pool.ResXmlStringPool;
|
||||||
|
|
||||||
public class ResXmlText extends BaseXmlChunk {
|
public class ResXmlText extends BaseXmlChunk {
|
||||||
private final IntegerItem mReserved;
|
private final IntegerItem mReserved;
|
||||||
@ -24,6 +25,15 @@ public class ResXmlText extends BaseXmlChunk {
|
|||||||
public void setTextReference(int ref){
|
public void setTextReference(int ref){
|
||||||
setNamespaceReference(ref);
|
setNamespaceReference(ref);
|
||||||
}
|
}
|
||||||
|
public void setText(String text){
|
||||||
|
ResXmlStringPool stringPool=getStringPool();
|
||||||
|
if(stringPool==null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ResXmlString resXmlString = stringPool.getOrCreate(text);
|
||||||
|
int ref=resXmlString.getIndex();
|
||||||
|
setTextReference(ref);
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public String toString(){
|
public String toString(){
|
||||||
String txt=getText();
|
String txt=getText();
|
||||||
|
0
src/main/java/com/reandroid/lib/arsc/container/BlockList.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/container/BlockList.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/container/ExpandableBlockContainer.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/container/ExpandableBlockContainer.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/container/FixedBlockContainer.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/container/FixedBlockContainer.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/container/PackageLastBlocks.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/container/PackageLastBlocks.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/container/ResValueContainer.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/container/ResValueContainer.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/container/SingleBlockContainer.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/container/SingleBlockContainer.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/container/SpecTypePair.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/container/SpecTypePair.java
Normal file → Executable file
@ -1,85 +0,0 @@
|
|||||||
package com.reandroid.lib.arsc.decoder;
|
|
||||||
|
|
||||||
import com.reandroid.lib.arsc.base.Block;
|
|
||||||
import com.reandroid.lib.arsc.value.ResValueBag;
|
|
||||||
import com.reandroid.lib.arsc.value.ResValueBagItem;
|
|
||||||
import com.reandroid.lib.arsc.value.ValueType;
|
|
||||||
|
|
||||||
public abstract class ResDecoder<InputBlock extends Block, Output> implements ResourceNameProvider{
|
|
||||||
private final ResourceNameStore resourceNameStore;
|
|
||||||
public ResDecoder(ResourceNameStore store){
|
|
||||||
this.resourceNameStore=store;
|
|
||||||
}
|
|
||||||
public String decodeAttribute(int attrResId, int rawValue){
|
|
||||||
ResValueBag valueBag=getAttributeBag(attrResId);
|
|
||||||
if(valueBag==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
ResValueBagItem[] bagItems=valueBag.getBagItems();
|
|
||||||
if(bagItems==null||bagItems.length==0){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
int len=bagItems.length;
|
|
||||||
ResValueBagItem firstAttrChild=bagItems[0];
|
|
||||||
if(len==1){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if(isFlagAttr(firstAttrChild)){
|
|
||||||
for(int i=1;i<len;i++){
|
|
||||||
ResValueBagItem bagItem=bagItems[i];
|
|
||||||
int data=bagItem.getData();
|
|
||||||
if(data!=rawValue){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int id=bagItem.getId();
|
|
||||||
return getResourceName(id, false);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
StringBuilder builder=new StringBuilder();
|
|
||||||
boolean appendOnce=false;
|
|
||||||
for(int i=1;i<len;i++){
|
|
||||||
ResValueBagItem bagItem=bagItems[i];
|
|
||||||
int data=bagItem.getData();
|
|
||||||
if((data&rawValue)==0){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int id=bagItem.getId();
|
|
||||||
String name=getResourceName(id, false);
|
|
||||||
if(appendOnce){
|
|
||||||
builder.append("|");
|
|
||||||
}
|
|
||||||
builder.append(name);
|
|
||||||
builder.append(data);
|
|
||||||
appendOnce=true;
|
|
||||||
}
|
|
||||||
if(!appendOnce){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
builder.append(":");
|
|
||||||
builder.append(rawValue);
|
|
||||||
builder.append(firstAttrChild.getValueType());
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
private boolean isFlagAttr(ResValueBagItem firstAttrChild){
|
|
||||||
ValueType valueType=firstAttrChild.getValueType();
|
|
||||||
return valueType==ValueType.FIRST_INT;
|
|
||||||
}
|
|
||||||
public ResourceNameStore getResourceNameStore() {
|
|
||||||
return resourceNameStore;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public String getResourceFullName(int resId, boolean includePackageName) {
|
|
||||||
return getResourceNameStore().getResourceFullName(resId, includePackageName);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public String getResourceName(int resId, boolean includePackageName) {
|
|
||||||
return getResourceNameStore().getResourceName(resId, includePackageName);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public ResValueBag getAttributeBag(int resId) {
|
|
||||||
return getResourceNameStore().getAttributeBag(resId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract Output decode(byte currentPackageId, InputBlock inputBlock);
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
package com.reandroid.lib.arsc.decoder;
|
|
||||||
|
|
||||||
import com.reandroid.lib.arsc.value.ResValueBag;
|
|
||||||
|
|
||||||
|
|
||||||
public interface ResourceNameProvider {
|
|
||||||
String getResourceFullName(int resId, boolean includePackageName);
|
|
||||||
String getResourceName(int resId, boolean includePackageName);
|
|
||||||
ResValueBag getAttributeBag(int resId);
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
package com.reandroid.lib.arsc.decoder;
|
|
||||||
|
|
||||||
import com.reandroid.lib.arsc.value.ResValueBag;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class ResourceNameStore implements ResourceNameProvider {
|
|
||||||
private final Set<ResourceNameProvider> resourceNameProviders;
|
|
||||||
public ResourceNameStore(){
|
|
||||||
this.resourceNameProviders=new HashSet<>();
|
|
||||||
}
|
|
||||||
public void addResourceNameProvider(ResourceNameProvider provider){
|
|
||||||
if(provider!=null){
|
|
||||||
resourceNameProviders.add(provider);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public Set<ResourceNameProvider> getResourceNameProviders(){
|
|
||||||
return resourceNameProviders;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public String getResourceFullName(int resId, boolean includePackageName) {
|
|
||||||
for(ResourceNameProvider provider:this.resourceNameProviders){
|
|
||||||
String name=provider.getResourceFullName(resId, includePackageName);
|
|
||||||
if(name!=null){
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getResourceName(int resId, boolean includePackageName) {
|
|
||||||
for(ResourceNameProvider provider:this.resourceNameProviders){
|
|
||||||
String name=provider.getResourceName(resId, includePackageName);
|
|
||||||
if(name!=null){
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public ResValueBag getAttributeBag(int resId) {
|
|
||||||
for(ResourceNameProvider provider:this.resourceNameProviders){
|
|
||||||
ResValueBag resValueBag=provider.getAttributeBag(resId);
|
|
||||||
if(resValueBag!=null){
|
|
||||||
return resValueBag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
496
src/main/java/com/reandroid/lib/arsc/decoder/ValueDecoder.java
Normal file → Executable file
496
src/main/java/com/reandroid/lib/arsc/decoder/ValueDecoder.java
Normal file → Executable file
@ -1,8 +1,181 @@
|
|||||||
package com.reandroid.lib.arsc.decoder;
|
package com.reandroid.lib.arsc.decoder;
|
||||||
|
|
||||||
import com.reandroid.lib.arsc.value.ValueType;
|
import com.reandroid.lib.arsc.chunk.PackageBlock;
|
||||||
|
import com.reandroid.lib.arsc.chunk.TableBlock;
|
||||||
|
import com.reandroid.lib.arsc.group.EntryGroup;
|
||||||
|
import com.reandroid.lib.arsc.item.TableString;
|
||||||
|
import com.reandroid.lib.arsc.pool.TableStringPool;
|
||||||
|
import com.reandroid.lib.arsc.value.*;
|
||||||
|
import com.reandroid.lib.arsc.value.attribute.AttributeBag;
|
||||||
|
import com.reandroid.lib.common.EntryStore;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
public class ValueDecoder {
|
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);
|
||||||
|
}
|
||||||
|
EntryBlock entryBlock=entryGroup.pickOne();
|
||||||
|
if(entryBlock==null){
|
||||||
|
return String.format("@0x%08x", resourceId);
|
||||||
|
}
|
||||||
|
String prefix=null;
|
||||||
|
if(currentPackage!=null){
|
||||||
|
String name=currentPackage.getPackageName();
|
||||||
|
String other=entryBlock.getPackageBlock().getPackageName();
|
||||||
|
if(!name.equals(other)){
|
||||||
|
prefix=other+":";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String name=entryGroup.getSpecName();
|
||||||
|
if(prefix!=null){
|
||||||
|
name=prefix+name;
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public static String decodeAttribute(EntryStore store, int attrResId, int rawValue){
|
||||||
|
AttributeBag attributeBag = getAttributeBag(store, attrResId);
|
||||||
|
if(attributeBag==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return attributeBag.decodeAttributeValue(store, rawValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String decodeEntryValue(EntryStore store, PackageBlock currentPackage, ValueType valueType, int data){
|
||||||
|
if(store==null || currentPackage==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if(valueType==ValueType.STRING){
|
||||||
|
return decodeIntEntryString(currentPackage, data);
|
||||||
|
}
|
||||||
|
boolean is_reference=false;
|
||||||
|
boolean is_attribute=false;
|
||||||
|
if(valueType==ValueType.REFERENCE){
|
||||||
|
if(data==0){
|
||||||
|
return "@null";
|
||||||
|
}
|
||||||
|
is_reference=true;
|
||||||
|
}
|
||||||
|
if(valueType==ValueType.ATTRIBUTE){
|
||||||
|
if(data==0){
|
||||||
|
return "?null";
|
||||||
|
}
|
||||||
|
is_attribute=true;
|
||||||
|
}
|
||||||
|
if(is_reference || is_attribute){
|
||||||
|
String ref=buildReferenceValue(store, valueType, currentPackage.getPackageName(), data);
|
||||||
|
if(ref!=null){
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
char atOrQues=is_reference?'@':'?';
|
||||||
|
ref=atOrQues+toHexResourceId(data);
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
return decode(valueType, data);
|
||||||
|
}
|
||||||
|
public static String decodeIntEntry(EntryStore store, EntryBlock entryBlock){
|
||||||
|
if(entryBlock==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
BaseResValue baseResValue = entryBlock.getResValue();
|
||||||
|
if(!(baseResValue instanceof ResValueInt)){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ResValueInt resValueInt=(ResValueInt)baseResValue;
|
||||||
|
return decodeIntEntry(store, resValueInt);
|
||||||
|
}
|
||||||
|
public static String decodeIntEntry(EntryStore store, ResValueInt resValueInt){
|
||||||
|
if(resValueInt==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
EntryBlock parentEntry=resValueInt.getEntryBlock();
|
||||||
|
if(parentEntry==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ValueType valueType=resValueInt.getValueType();
|
||||||
|
int data=resValueInt.getData();
|
||||||
|
return decodeIntEntry(store, parentEntry, valueType, data);
|
||||||
|
}
|
||||||
|
public static String decodeIntEntry(EntryStore store, ResValueBagItem bagItem){
|
||||||
|
if(bagItem==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
EntryBlock parentEntry=bagItem.getEntryBlock();
|
||||||
|
if(parentEntry==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ValueType valueType=bagItem.getValueType();
|
||||||
|
int data=bagItem.getData();
|
||||||
|
return decodeIntEntry(store, parentEntry, valueType, data);
|
||||||
|
}
|
||||||
|
public static String decodeIntEntry(EntryStore store, EntryBlock parentEntry, ValueType valueType, int data){
|
||||||
|
if(valueType==ValueType.NULL){
|
||||||
|
return "@empty";
|
||||||
|
}
|
||||||
|
if(valueType==ValueType.STRING){
|
||||||
|
return decodeIntEntryString(parentEntry, data);
|
||||||
|
}
|
||||||
|
boolean is_reference=false;
|
||||||
|
boolean is_attribute=false;
|
||||||
|
if(valueType==ValueType.REFERENCE){
|
||||||
|
if(data==0){
|
||||||
|
return "@null";
|
||||||
|
}
|
||||||
|
is_reference=true;
|
||||||
|
}
|
||||||
|
if(valueType==ValueType.ATTRIBUTE){
|
||||||
|
if(data==0){
|
||||||
|
return "?null";
|
||||||
|
}
|
||||||
|
is_attribute=true;
|
||||||
|
}
|
||||||
|
if(is_reference || is_attribute){
|
||||||
|
String ref=buildReferenceValue(store, parentEntry, valueType, data);
|
||||||
|
if(ref!=null){
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
char atOrQues=is_reference?'@':'?';
|
||||||
|
ref=atOrQues+toHexResourceId(data);
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
return decode(valueType, data);
|
||||||
|
}
|
||||||
|
public static String buildReferenceValue(EntryStore store, EntryBlock entryBlock){
|
||||||
|
if(entryBlock==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
BaseResValue baseResValue = entryBlock.getResValue();
|
||||||
|
if(!(baseResValue instanceof ResValueInt)){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ResValueInt resValueInt=(ResValueInt)baseResValue;
|
||||||
|
int resourceId=resValueInt.getData();
|
||||||
|
ValueType valueType=resValueInt.getValueType();
|
||||||
|
return buildReferenceValue(store, entryBlock, valueType, resourceId);
|
||||||
|
}
|
||||||
|
public static String decode(EntryStore entryStore, int currentPackageId, int nameResourceId, ValueType valueType, int rawVal){
|
||||||
|
String currPackageName=getPackageName(entryStore, currentPackageId);
|
||||||
|
String result=buildReferenceValue(entryStore, valueType, currPackageName, rawVal);
|
||||||
|
if(result!=null){
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if(valueType==ValueType.STRING){
|
||||||
|
// Should not happen the string could be in ResXmlBlock, but if you are lazy here it goes
|
||||||
|
return decodeString(entryStore, currentPackageId, rawVal);
|
||||||
|
}
|
||||||
|
if(valueType==ValueType.FIRST_INT||valueType==ValueType.INT_HEX){
|
||||||
|
result=decodeAttribute(entryStore, nameResourceId, rawVal);
|
||||||
|
if(result!=null){
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return decode(valueType, rawVal);
|
||||||
|
}
|
||||||
public static String decode(ValueType valueType, int data){
|
public static String decode(ValueType valueType, int data){
|
||||||
if(valueType==null){
|
if(valueType==null){
|
||||||
return null;
|
return null;
|
||||||
@ -30,6 +203,229 @@ public class ValueDecoder {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
public static String buildReference(String currentPackageName,
|
||||||
|
String referredPackageName,
|
||||||
|
char atOrQues,
|
||||||
|
String typeName,
|
||||||
|
String resourceName){
|
||||||
|
StringBuilder builder=new StringBuilder();
|
||||||
|
if(atOrQues!=0){
|
||||||
|
builder.append(atOrQues);
|
||||||
|
}
|
||||||
|
if(!isEqualString(currentPackageName, referredPackageName)){
|
||||||
|
if(!isEmpty(currentPackageName) && !isEmpty(referredPackageName)){
|
||||||
|
builder.append(referredPackageName);
|
||||||
|
if(!referredPackageName.endsWith(":")){
|
||||||
|
builder.append(':');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!isEmpty(typeName)){
|
||||||
|
builder.append(typeName);
|
||||||
|
builder.append('/');
|
||||||
|
}
|
||||||
|
builder.append(resourceName);
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String buildReferenceValue(EntryStore store, EntryBlock entryBlock, ValueType valueType, int resourceId){
|
||||||
|
if(entryBlock==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
EntryGroup value=searchEntryGroup(store, entryBlock, resourceId);
|
||||||
|
if(value==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return buildReferenceValue(valueType, entryBlock, value);
|
||||||
|
}
|
||||||
|
private static String buildReferenceValue(ValueType valueType, EntryBlock entryBlock, EntryGroup value){
|
||||||
|
char atOrQues;
|
||||||
|
if(valueType==ValueType.REFERENCE){
|
||||||
|
atOrQues='@';
|
||||||
|
}else if(valueType==ValueType.ATTRIBUTE){
|
||||||
|
atOrQues='?';
|
||||||
|
}else {
|
||||||
|
atOrQues=0;
|
||||||
|
}
|
||||||
|
String currentPackageName=getPackageName(entryBlock);
|
||||||
|
String referredPackageName=getPackageName(value);
|
||||||
|
String typeName=value.getTypeName();
|
||||||
|
String name=value.getSpecName();
|
||||||
|
return buildReference(currentPackageName, referredPackageName, atOrQues, typeName, name);
|
||||||
|
}
|
||||||
|
private static String buildReferenceValue(EntryStore entryStore, ValueType valueType, String currentPackageName, int resourceId){
|
||||||
|
char atOrQues;
|
||||||
|
if(valueType==ValueType.REFERENCE){
|
||||||
|
atOrQues='@';
|
||||||
|
}else if(valueType==ValueType.ATTRIBUTE){
|
||||||
|
atOrQues='?';
|
||||||
|
}else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
EntryGroup value=null;
|
||||||
|
if(entryStore!=null){
|
||||||
|
value=entryStore.getEntryGroup(resourceId);
|
||||||
|
}
|
||||||
|
if(value==null){
|
||||||
|
return atOrQues+toHexResourceId(resourceId);
|
||||||
|
}
|
||||||
|
String referredPackageName=getPackageName(value);
|
||||||
|
String typeName=value.getTypeName();
|
||||||
|
String name=value.getSpecName();
|
||||||
|
return buildReference(currentPackageName, referredPackageName, atOrQues, typeName, name);
|
||||||
|
}
|
||||||
|
private static String getPackageName(EntryStore entryStore, int packageOrResourceId){
|
||||||
|
if(entryStore==null || packageOrResourceId==0){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int pkgId=(packageOrResourceId>>24)&0xFF;
|
||||||
|
if(pkgId==0){
|
||||||
|
pkgId=packageOrResourceId;
|
||||||
|
}
|
||||||
|
Collection<PackageBlock> allPkg = entryStore.getPackageBlocks((byte) pkgId);
|
||||||
|
if(allPkg==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for(PackageBlock packageBlock:allPkg){
|
||||||
|
String name=packageBlock.getPackageName();
|
||||||
|
if(name!=null){
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
private static String getPackageName(EntryGroup entryGroup){
|
||||||
|
if(entryGroup==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return getPackageName(entryGroup.pickOne());
|
||||||
|
}
|
||||||
|
private static String getPackageName(EntryBlock entryBlock){
|
||||||
|
if(entryBlock==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
PackageBlock packageBlock=entryBlock.getPackageBlock();
|
||||||
|
if(packageBlock==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return packageBlock.getPackageName();
|
||||||
|
}
|
||||||
|
private static EntryGroup searchEntryGroup(EntryStore store, EntryBlock entryBlock, int resourceId){
|
||||||
|
EntryGroup entryGroup=searchEntryGroup(entryBlock, resourceId);
|
||||||
|
if(entryGroup!=null){
|
||||||
|
return entryGroup;
|
||||||
|
}
|
||||||
|
if(store==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return store.getEntryGroup(resourceId);
|
||||||
|
}
|
||||||
|
private static EntryGroup searchEntryGroup(EntryBlock entryBlock, int resourceId){
|
||||||
|
if(entryBlock==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
PackageBlock packageBlock=entryBlock.getPackageBlock();
|
||||||
|
if(packageBlock==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
TableBlock tableBlock=packageBlock.getTableBlock();
|
||||||
|
if(tableBlock==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for(PackageBlock pkg:tableBlock.listPackages()){
|
||||||
|
EntryGroup entryGroup=pkg.getEntryGroup(resourceId);
|
||||||
|
if(entryGroup!=null){
|
||||||
|
return entryGroup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
private static EntryGroup searchEntryGroup(EntryStore store, PackageBlock packageBlock, int resourceId){
|
||||||
|
if(packageBlock!=null){
|
||||||
|
TableBlock tableBlock=packageBlock.getTableBlock();
|
||||||
|
if(tableBlock!=null){
|
||||||
|
for(PackageBlock pkg:tableBlock.listPackages()){
|
||||||
|
EntryGroup entryGroup=pkg.getEntryGroup(resourceId);
|
||||||
|
if(entryGroup!=null){
|
||||||
|
return entryGroup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(store!=null){
|
||||||
|
return store.getEntryGroup(resourceId);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
private static String decodeIntEntryString(EntryBlock entryBlock, int data){
|
||||||
|
if(entryBlock==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
PackageBlock packageBlock=entryBlock.getPackageBlock();
|
||||||
|
if(packageBlock==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
TableBlock tableBlock=packageBlock.getTableBlock();
|
||||||
|
if(tableBlock==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
TableStringPool pool = tableBlock.getTableStringPool();
|
||||||
|
TableString tableString=pool.get(data);
|
||||||
|
if(tableString==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return tableString.getHtml();
|
||||||
|
}
|
||||||
|
private static String decodeString(EntryStore entryStore, int packageOrResourceId, int stringRef){
|
||||||
|
if(entryStore==null||packageOrResourceId==0){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int pkgId=(packageOrResourceId>>24)&0xFF;
|
||||||
|
if(pkgId==0){
|
||||||
|
pkgId=packageOrResourceId;
|
||||||
|
}
|
||||||
|
Collection<PackageBlock> allPkg = entryStore.getPackageBlocks((byte) pkgId);
|
||||||
|
if(allPkg==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
TableString tableString=null;
|
||||||
|
for(PackageBlock packageBlock:allPkg){
|
||||||
|
TableBlock tableBlock=packageBlock.getTableBlock();
|
||||||
|
if(tableBlock==null){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
TableString ts=tableBlock.getTableStringPool().get(stringRef);
|
||||||
|
if(ts==null){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(tableString==null){
|
||||||
|
tableString=ts;
|
||||||
|
}else {
|
||||||
|
// Duplicate result, could be from split apks
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(tableString!=null){
|
||||||
|
return tableString.getHtml();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
private static String decodeIntEntryString(PackageBlock packageBlock, int data){
|
||||||
|
if(packageBlock==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
TableBlock tableBlock=packageBlock.getTableBlock();
|
||||||
|
if(tableBlock==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
TableStringPool pool = tableBlock.getTableStringPool();
|
||||||
|
TableString tableString=pool.get(data);
|
||||||
|
if(tableString==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return tableString.getHtml();
|
||||||
|
}
|
||||||
|
|
||||||
private static String decodeHex(int rawVal){
|
private static String decodeHex(int rawVal){
|
||||||
return String.format("0x%x", rawVal);
|
return String.format("0x%x", rawVal);
|
||||||
}
|
}
|
||||||
@ -99,6 +495,104 @@ public class ValueDecoder {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
private static String getResourceName(EntryStore store, EntryBlock entryBlock, int resourceId){
|
||||||
|
if(entryBlock!=null){
|
||||||
|
EntryGroup group=searchEntryGroup(entryBlock, resourceId);
|
||||||
|
if(group!=null){
|
||||||
|
String name=group.getSpecName();
|
||||||
|
if(name!=null){
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(store==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Collection<EntryGroup> foundGroups = store.getEntryGroups(resourceId);
|
||||||
|
return pickResourceName(foundGroups);
|
||||||
|
}
|
||||||
|
private static String pickResourceName(Collection<EntryGroup> groups){
|
||||||
|
if(groups==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for(EntryGroup entryGroup:groups){
|
||||||
|
String name=entryGroup.getSpecName();
|
||||||
|
if(name!=null){
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
private static AttributeBag getAttributeBag(EntryStore store, int resourceId){
|
||||||
|
ResValueBag resValueBag=getAttributeValueBag(store, resourceId);
|
||||||
|
if(resValueBag==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return AttributeBag.create(resValueBag);
|
||||||
|
}
|
||||||
|
private static ResValueBag getAttributeValueBag(EntryStore store, int resourceId){
|
||||||
|
if(store==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Collection<EntryGroup> foundGroups = store.getEntryGroups(resourceId);
|
||||||
|
ResValueBag best=null;
|
||||||
|
for(EntryGroup group:foundGroups){
|
||||||
|
ResValueBag valueBag= getAttributeValueBag(group);
|
||||||
|
best=chooseBest(best, valueBag);
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
private static ResValueBag getAttributeValueBag(EntryGroup entryGroup){
|
||||||
|
if(entryGroup==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ResValueBag best=null;
|
||||||
|
Iterator<EntryBlock> iterator=entryGroup.iterator(true);
|
||||||
|
while (iterator.hasNext()){
|
||||||
|
EntryBlock entryBlock=iterator.next();
|
||||||
|
ResValueBag valueBag= getAttributeValueBag(entryBlock);
|
||||||
|
best=chooseBest(best, valueBag);
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
private static ResValueBag getAttributeValueBag(EntryBlock entryBlock){
|
||||||
|
if(entryBlock==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
BaseResValue baseResValue = entryBlock.getResValue();
|
||||||
|
if(baseResValue instanceof ResValueBag){
|
||||||
|
return (ResValueBag) baseResValue;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
private static ResValueBag chooseBest(ResValueBag valueBag1, ResValueBag valueBag2){
|
||||||
|
if(valueBag1==null){
|
||||||
|
return valueBag2;
|
||||||
|
}
|
||||||
|
if(valueBag2==null){
|
||||||
|
return valueBag1;
|
||||||
|
}
|
||||||
|
if(valueBag2.getCount()>valueBag1.getCount()){
|
||||||
|
return valueBag2;
|
||||||
|
}
|
||||||
|
return valueBag1;
|
||||||
|
}
|
||||||
|
private static String toHexResourceId(int resourceId){
|
||||||
|
return String.format("0x%08x", resourceId);
|
||||||
|
}
|
||||||
|
private static boolean isEqualString(String str1, String str2){
|
||||||
|
if(isEmpty(str1)){
|
||||||
|
return isEmpty(str2);
|
||||||
|
}
|
||||||
|
return str1.equals(str2);
|
||||||
|
}
|
||||||
|
private static boolean isEmpty(String str){
|
||||||
|
if(str==null){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
str=str.trim();
|
||||||
|
return str.length()==0;
|
||||||
|
}
|
||||||
|
|
||||||
private static final String[] DIMENSION_UNIT_STRS = new String[] { "px", "dip", "sp", "pt", "in", "mm" };
|
private static final String[] DIMENSION_UNIT_STRS = new String[] { "px", "dip", "sp", "pt", "in", "mm" };
|
||||||
private static final float MANTISSA_MULT = 1.0f / (1 << 8);
|
private static final float MANTISSA_MULT = 1.0f / (1 << 8);
|
||||||
|
@ -1,139 +0,0 @@
|
|||||||
package com.reandroid.lib.arsc.decoder.xml;
|
|
||||||
|
|
||||||
import com.reandroid.lib.arsc.chunk.xml.ResXmlAttribute;
|
|
||||||
import com.reandroid.lib.arsc.chunk.xml.ResXmlBlock;
|
|
||||||
import com.reandroid.lib.arsc.chunk.xml.ResXmlElement;
|
|
||||||
import com.reandroid.lib.arsc.chunk.xml.ResXmlText;
|
|
||||||
import com.reandroid.lib.arsc.decoder.ResDecoder;
|
|
||||||
import com.reandroid.lib.arsc.decoder.ResourceNameStore;
|
|
||||||
import com.reandroid.lib.arsc.decoder.ValueDecoder;
|
|
||||||
import com.reandroid.lib.arsc.value.ValueType;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ResXmlDecoder extends ResDecoder<ResXmlBlock, String> {
|
|
||||||
private byte mCurrentPackageId;
|
|
||||||
public ResXmlDecoder(ResourceNameStore store){
|
|
||||||
super(store);
|
|
||||||
}
|
|
||||||
private String decodeToString(ResXmlBlock resXmlBlock){
|
|
||||||
StringBuilder builder=new StringBuilder();
|
|
||||||
builder.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
|
||||||
builder.append("\n");
|
|
||||||
String body=decodeToString(resXmlBlock.getResXmlElement());
|
|
||||||
builder.append(body);
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
private String decodeToString(ResXmlElement resXmlElement){
|
|
||||||
if(resXmlElement==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
StringBuilder builder=new StringBuilder();
|
|
||||||
for(int i=0;i<resXmlElement.getDepth();i++){
|
|
||||||
builder.append(' ');
|
|
||||||
}
|
|
||||||
builder.append('<');
|
|
||||||
String tagName=resXmlElement.getTagName();
|
|
||||||
builder.append(tagName);
|
|
||||||
for(ResXmlAttribute attribute:resXmlElement.listResXmlAttributes()){
|
|
||||||
builder.append(' ');
|
|
||||||
String name=decodeAttributeFullName(attribute);
|
|
||||||
builder.append(name);
|
|
||||||
builder.append("=\"");
|
|
||||||
String value=decodeAttributeValue(attribute);
|
|
||||||
builder.append(value);
|
|
||||||
builder.append("\"");
|
|
||||||
}
|
|
||||||
boolean useEndTag=false;
|
|
||||||
ResXmlText resXmlText=resXmlElement.getResXmlText();
|
|
||||||
String text=null;
|
|
||||||
if(resXmlText!=null){
|
|
||||||
useEndTag=true;
|
|
||||||
text=resXmlText.getText();
|
|
||||||
}
|
|
||||||
List<ResXmlElement> childElements=resXmlElement.listElements();
|
|
||||||
if(!useEndTag){
|
|
||||||
useEndTag=childElements.size()>0;
|
|
||||||
}
|
|
||||||
if(!useEndTag){
|
|
||||||
builder.append("/>");
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
builder.append(">");
|
|
||||||
if(text!=null){
|
|
||||||
builder.append(text);
|
|
||||||
}
|
|
||||||
for(ResXmlElement child:childElements){
|
|
||||||
builder.append("\n");
|
|
||||||
String txtChild=decodeToString(child);
|
|
||||||
builder.append(txtChild);
|
|
||||||
}
|
|
||||||
if(childElements.size()>0){
|
|
||||||
builder.append("\n");
|
|
||||||
for(int i=0;i<resXmlElement.getDepth();i++){
|
|
||||||
builder.append(' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
builder.append("</");
|
|
||||||
builder.append(tagName);
|
|
||||||
builder.append(">");
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
private String decodeAttributeValue(ResXmlAttribute attribute){
|
|
||||||
ValueType valueType=attribute.getValueType();
|
|
||||||
if(valueType==ValueType.FIRST_INT || valueType==ValueType.INT_HEX){
|
|
||||||
int nameId=attribute.getNameResourceID();
|
|
||||||
String val=decodeAttribute(nameId, attribute.getRawValue());
|
|
||||||
if(val!=null){
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(valueType==ValueType.REFERENCE){
|
|
||||||
int id=attribute.getRawValue();
|
|
||||||
byte pkgId= (byte) ((id>>24)&0xFF);
|
|
||||||
return getResourceFullName(id, pkgId!=getCurrentPackageId());
|
|
||||||
}
|
|
||||||
if(valueType==ValueType.STRING){
|
|
||||||
return attribute.getValueString();
|
|
||||||
}
|
|
||||||
String val= ValueDecoder.decode(valueType, attribute.getRawValue());
|
|
||||||
if(val!=null){
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
return attribute.getRawValue()+"["+valueType+"]";
|
|
||||||
}
|
|
||||||
private String decodeAttributeFullName(ResXmlAttribute attribute){
|
|
||||||
StringBuilder builder=new StringBuilder();
|
|
||||||
String prefix=getRealAttributeNamePrefix(attribute);
|
|
||||||
String name=getRealAttributeName(attribute);
|
|
||||||
if(prefix!=null&&!name.contains(":")){
|
|
||||||
builder.append(prefix);
|
|
||||||
builder.append(':');
|
|
||||||
}
|
|
||||||
builder.append(name);
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
private String getRealAttributeNamePrefix(ResXmlAttribute attribute){
|
|
||||||
/* TODO readjust wrong/stripped attribute name prefix prefix; */
|
|
||||||
return attribute.getNamePrefix();
|
|
||||||
}
|
|
||||||
private String getRealAttributeName(ResXmlAttribute attribute){
|
|
||||||
int nameId=attribute.getNameResourceID();
|
|
||||||
ResourceNameStore store=getResourceNameStore();
|
|
||||||
byte pkgId= (byte) ((nameId>>24)&0xFF);
|
|
||||||
String name=store.getResourceName(nameId, getCurrentPackageId()!=pkgId);
|
|
||||||
if(name!=null){
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
return attribute.getName();
|
|
||||||
}
|
|
||||||
private byte getCurrentPackageId(){
|
|
||||||
return mCurrentPackageId;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public String decode(byte currentPackageId, ResXmlBlock resXmlBlock) {
|
|
||||||
this.mCurrentPackageId=currentPackageId;
|
|
||||||
return decodeToString(resXmlBlock);
|
|
||||||
}
|
|
||||||
}
|
|
0
src/main/java/com/reandroid/lib/arsc/group/EntryGroup.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/group/EntryGroup.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/group/ItemGroup.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/group/ItemGroup.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/group/StringGroup.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/group/StringGroup.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/header/HeaderBlock.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/header/HeaderBlock.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/io/BlockLoad.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/io/BlockLoad.java
Normal file → Executable file
11
src/main/java/com/reandroid/lib/arsc/io/BlockReader.java
Normal file → Executable file
11
src/main/java/com/reandroid/lib/arsc/io/BlockReader.java
Normal file → Executable file
@ -324,4 +324,15 @@ public class BlockReader extends InputStream {
|
|||||||
System.arraycopy(arr2, 0, result, arr1.length, len);
|
System.arraycopy(arr2, 0, result, arr1.length, len);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
public static HeaderBlock readHeaderBlock(File file) throws IOException{
|
||||||
|
InputStream inputStream=new FileInputStream(file);
|
||||||
|
return readHeaderBlock(inputStream);
|
||||||
|
}
|
||||||
|
public static HeaderBlock readHeaderBlock(InputStream inputStream) throws IOException{
|
||||||
|
byte[] buffer=new byte[8];
|
||||||
|
inputStream.read(buffer);
|
||||||
|
inputStream.close();
|
||||||
|
BlockReader reader=new BlockReader(buffer);
|
||||||
|
return reader.readHeaderBlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
0
src/main/java/com/reandroid/lib/arsc/item/BlockItem.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/BlockItem.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/ByteArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/ByteArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/ByteItem.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/ByteItem.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/IntegerArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/IntegerArray.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/IntegerItem.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/IntegerItem.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/PackageName.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/PackageName.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/ReferenceItem.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/ReferenceItem.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/ResXmlID.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/ResXmlID.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/ResXmlString.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/ResXmlString.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/ShortItem.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/ShortItem.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/SpecString.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/SpecString.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/StringItem.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/StringItem.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/StyleItem.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/StyleItem.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/TableString.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/TableString.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/TypeString.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/item/TypeString.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/model/StyleSpanInfo.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/model/StyleSpanInfo.java
Normal file → Executable file
11
src/main/java/com/reandroid/lib/arsc/pool/BaseStringPool.java
Normal file → Executable file
11
src/main/java/com/reandroid/lib/arsc/pool/BaseStringPool.java
Normal file → Executable file
@ -9,6 +9,7 @@ import com.reandroid.lib.arsc.group.StringGroup;
|
|||||||
import com.reandroid.lib.arsc.io.BlockLoad;
|
import com.reandroid.lib.arsc.io.BlockLoad;
|
||||||
import com.reandroid.lib.arsc.io.BlockReader;
|
import com.reandroid.lib.arsc.io.BlockReader;
|
||||||
import com.reandroid.lib.arsc.item.*;
|
import com.reandroid.lib.arsc.item.*;
|
||||||
|
import com.reandroid.lib.arsc.pool.builder.StyleBuilder;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@ -63,6 +64,16 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
|
|||||||
mUniqueMap=new HashMap<>();
|
mUniqueMap=new HashMap<>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
public void recreateStyles(){
|
||||||
|
StyleArray styleArray = getStyleArray();
|
||||||
|
//styleArray.clearChildes();
|
||||||
|
StringArray<T> stringArray=getStringsArray();
|
||||||
|
for(T stringItem:stringArray.listItems()){
|
||||||
|
if(StyleBuilder.hasStyle(stringItem)){
|
||||||
|
StyleBuilder.buildStyle(stringItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
public List<T> removeUnusedStrings(){
|
public List<T> removeUnusedStrings(){
|
||||||
return getStringsArray().removeUnusedStrings();
|
return getStringsArray().removeUnusedStrings();
|
||||||
}
|
}
|
||||||
|
0
src/main/java/com/reandroid/lib/arsc/pool/PoolType.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/pool/PoolType.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/pool/ResXmlStringPool.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/pool/ResXmlStringPool.java
Normal file → Executable file
3
src/main/java/com/reandroid/lib/arsc/pool/SpecStringPool.java
Normal file → Executable file
3
src/main/java/com/reandroid/lib/arsc/pool/SpecStringPool.java
Normal file → Executable file
@ -15,4 +15,7 @@ public class SpecStringPool extends BaseStringPool<SpecString> {
|
|||||||
StringArray<SpecString> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
|
StringArray<SpecString> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
|
||||||
return new SpecStringArray(offsets, itemCount, itemStart, is_utf8);
|
return new SpecStringArray(offsets, itemCount, itemStart, is_utf8);
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public void recreateStyles(){
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
0
src/main/java/com/reandroid/lib/arsc/pool/TableStringPool.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/pool/TableStringPool.java
Normal file → Executable file
3
src/main/java/com/reandroid/lib/arsc/pool/TypeStringPool.java
Normal file → Executable file
3
src/main/java/com/reandroid/lib/arsc/pool/TypeStringPool.java
Normal file → Executable file
@ -17,4 +17,7 @@ public class TypeStringPool extends BaseStringPool<TypeString> {
|
|||||||
StringArray<TypeString> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
|
StringArray<TypeString> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
|
||||||
return new TypeStringArray(offsets, itemCount, itemStart, is_utf8);
|
return new TypeStringArray(offsets, itemCount, itemStart, is_utf8);
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public void recreateStyles(){
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
16
src/main/java/com/reandroid/lib/arsc/pool/builder/SpannedText.java
Executable file
16
src/main/java/com/reandroid/lib/arsc/pool/builder/SpannedText.java
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
package com.reandroid.lib.arsc.pool.builder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SpannedText {
|
||||||
|
private String mLeftText;
|
||||||
|
private String mTag;
|
||||||
|
private String mText;
|
||||||
|
private String mRightText;
|
||||||
|
private List<SpannedText> mChildes;
|
||||||
|
public SpannedText(){
|
||||||
|
}
|
||||||
|
public void parse(int start, String text){
|
||||||
|
int i=text.indexOf('<', start);
|
||||||
|
}
|
||||||
|
}
|
29
src/main/java/com/reandroid/lib/arsc/pool/builder/StyleBuilder.java
Executable file
29
src/main/java/com/reandroid/lib/arsc/pool/builder/StyleBuilder.java
Executable file
@ -0,0 +1,29 @@
|
|||||||
|
package com.reandroid.lib.arsc.pool.builder;
|
||||||
|
|
||||||
|
import com.reandroid.lib.arsc.item.StringItem;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class StyleBuilder {
|
||||||
|
public static void buildStyle(StringItem stringItem){
|
||||||
|
System.out.println(stringItem.toString());
|
||||||
|
}
|
||||||
|
public static boolean hasStyle(StringItem stringItem){
|
||||||
|
if(stringItem==null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return hasStyle(stringItem.getHtml());
|
||||||
|
}
|
||||||
|
public static boolean hasStyle(String text){
|
||||||
|
if(text==null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int i=text.indexOf('<');
|
||||||
|
if(i<0){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
i=text.indexOf('>');
|
||||||
|
return i>1;
|
||||||
|
}
|
||||||
|
private static final Pattern PATTERN_STYLE=Pattern.compile("");
|
||||||
|
}
|
151
src/main/java/com/reandroid/lib/arsc/util/FrameworkTable.java
Normal file → Executable file
151
src/main/java/com/reandroid/lib/arsc/util/FrameworkTable.java
Normal file → Executable file
@ -1,9 +1,11 @@
|
|||||||
package com.reandroid.lib.arsc.util;
|
package com.reandroid.lib.arsc.util;
|
||||||
|
|
||||||
|
import com.reandroid.lib.arsc.chunk.ChunkType;
|
||||||
import com.reandroid.lib.arsc.chunk.PackageBlock;
|
import com.reandroid.lib.arsc.chunk.PackageBlock;
|
||||||
import com.reandroid.lib.arsc.chunk.TableBlock;
|
import com.reandroid.lib.arsc.chunk.TableBlock;
|
||||||
import com.reandroid.lib.arsc.chunk.TypeBlock;
|
import com.reandroid.lib.arsc.chunk.TypeBlock;
|
||||||
import com.reandroid.lib.arsc.group.EntryGroup;
|
import com.reandroid.lib.arsc.group.EntryGroup;
|
||||||
|
import com.reandroid.lib.arsc.header.HeaderBlock;
|
||||||
import com.reandroid.lib.arsc.io.BlockReader;
|
import com.reandroid.lib.arsc.io.BlockReader;
|
||||||
import com.reandroid.lib.arsc.item.ReferenceItem;
|
import com.reandroid.lib.arsc.item.ReferenceItem;
|
||||||
import com.reandroid.lib.arsc.item.TableString;
|
import com.reandroid.lib.arsc.item.TableString;
|
||||||
@ -15,9 +17,42 @@ import java.util.*;
|
|||||||
|
|
||||||
public class FrameworkTable extends TableBlock {
|
public class FrameworkTable extends TableBlock {
|
||||||
|
|
||||||
|
private String mFrameworkTitle;
|
||||||
|
private String mFrameworkName;
|
||||||
|
private String mFrameworkVersion;
|
||||||
public FrameworkTable(){
|
public FrameworkTable(){
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
public String getFrameworkTitle(){
|
||||||
|
if(mFrameworkTitle==null){
|
||||||
|
mFrameworkTitle=loadProperty(PROP_TITLE);
|
||||||
|
}
|
||||||
|
return mFrameworkTitle;
|
||||||
|
}
|
||||||
|
public String getFrameworkName(){
|
||||||
|
if(mFrameworkName==null){
|
||||||
|
mFrameworkName=loadProperty(PROP_NAME);
|
||||||
|
}
|
||||||
|
return mFrameworkName;
|
||||||
|
}
|
||||||
|
public String getFrameworkVersion(){
|
||||||
|
if(mFrameworkVersion==null){
|
||||||
|
mFrameworkVersion=loadProperty(PROP_VERSION);
|
||||||
|
}
|
||||||
|
return mFrameworkVersion;
|
||||||
|
}
|
||||||
|
private void setFrameworkTitle(String value){
|
||||||
|
mFrameworkTitle=null;
|
||||||
|
writeProperty(PROP_TITLE, value);
|
||||||
|
}
|
||||||
|
public void setFrameworkName(String value){
|
||||||
|
mFrameworkName=null;
|
||||||
|
writeProperty(PROP_NAME, value);
|
||||||
|
}
|
||||||
|
public void setFrameworkVersion(String value){
|
||||||
|
mFrameworkVersion=null;
|
||||||
|
writeProperty(PROP_VERSION, value);
|
||||||
|
}
|
||||||
public int writeTable(File resourcesArscFile) throws IOException{
|
public int writeTable(File resourcesArscFile) throws IOException{
|
||||||
File dir=resourcesArscFile.getParentFile();
|
File dir=resourcesArscFile.getParentFile();
|
||||||
if(dir!=null && !dir.exists()){
|
if(dir!=null && !dir.exists()){
|
||||||
@ -49,7 +84,7 @@ public class FrameworkTable extends TableBlock {
|
|||||||
super.onReadBytes(reader);
|
super.onReadBytes(reader);
|
||||||
reader.close();
|
reader.close();
|
||||||
}
|
}
|
||||||
public void optimize(){
|
public void optimize(String frameworkName, String frameworkVersion){
|
||||||
Map<Integer, EntryGroup> groupMap=scanAllEntryGroups();
|
Map<Integer, EntryGroup> groupMap=scanAllEntryGroups();
|
||||||
for(EntryGroup group:groupMap.values()){
|
for(EntryGroup group:groupMap.values()){
|
||||||
List<EntryBlock> entryBlockList=getEntriesToRemove(group);
|
List<EntryBlock> entryBlockList=getEntriesToRemove(group);
|
||||||
@ -60,6 +95,9 @@ public class FrameworkTable extends TableBlock {
|
|||||||
pkg.refresh();
|
pkg.refresh();
|
||||||
}
|
}
|
||||||
optimizeTableString();
|
optimizeTableString();
|
||||||
|
setFrameworkTitle(TITLE_STRING);
|
||||||
|
setFrameworkName(frameworkName);
|
||||||
|
setFrameworkVersion(frameworkVersion);
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
private void optimizeTableString(){
|
private void optimizeTableString(){
|
||||||
@ -75,13 +113,14 @@ public class FrameworkTable extends TableBlock {
|
|||||||
}
|
}
|
||||||
private void shrinkTableString(){
|
private void shrinkTableString(){
|
||||||
TableStringPool tableStringPool=getTableStringPool();
|
TableStringPool tableStringPool=getTableStringPool();
|
||||||
TableString zero=tableStringPool.get(0);
|
tableStringPool.getStringsArray().ensureSize(1);
|
||||||
zero.set("Framework string table");
|
TableString title=tableStringPool.get(0);
|
||||||
|
title.set(PROP_TITLE+":"+TITLE_STRING);
|
||||||
for(TableString tableString:tableStringPool.getStringsArray().listItems()){
|
for(TableString tableString:tableStringPool.getStringsArray().listItems()){
|
||||||
if(tableString==zero){
|
if(tableString==title){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
shrinkTableString(zero, tableString);
|
shrinkTableString(title, tableString);
|
||||||
}
|
}
|
||||||
tableStringPool.refresh();
|
tableStringPool.refresh();
|
||||||
}
|
}
|
||||||
@ -141,4 +180,106 @@ public class FrameworkTable extends TableBlock {
|
|||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
private TableString writeProperty(String name, String value){
|
||||||
|
if(!name.endsWith(":")){
|
||||||
|
name=name+":";
|
||||||
|
}
|
||||||
|
if(value==null){
|
||||||
|
value="";
|
||||||
|
}
|
||||||
|
if(!value.startsWith(name)){
|
||||||
|
value=name+value;
|
||||||
|
}
|
||||||
|
TableString tableString=loadPropertyString(name);
|
||||||
|
if(tableString!=null){
|
||||||
|
tableString.set(value);
|
||||||
|
}else {
|
||||||
|
TableStringPool tableStringPool=getTableStringPool();
|
||||||
|
tableString=tableStringPool.getOrCreate(value);
|
||||||
|
}
|
||||||
|
return tableString;
|
||||||
|
}
|
||||||
|
private String loadProperty(String name){
|
||||||
|
if(name==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if(!name.endsWith(":")){
|
||||||
|
name=name+":";
|
||||||
|
}
|
||||||
|
TableString tableString=loadPropertyString(name);
|
||||||
|
if(tableString==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String str=tableString.get().trim();
|
||||||
|
return str.substring(name.length());
|
||||||
|
}
|
||||||
|
private TableString loadPropertyString(String name){
|
||||||
|
if(name==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if(!name.endsWith(":")){
|
||||||
|
name=name+":";
|
||||||
|
}
|
||||||
|
TableStringPool tableStringPool=getTableStringPool();
|
||||||
|
int max=PROP_COUNT;
|
||||||
|
for(int i=0;i<max;i++){
|
||||||
|
TableString tableString=tableStringPool.get(i);
|
||||||
|
if(tableString==null){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String str=tableString.get();
|
||||||
|
if(str==null){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
str=str.trim();
|
||||||
|
if(str.startsWith(name)){
|
||||||
|
return tableString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
HeaderBlock headerBlock=getHeaderBlock();
|
||||||
|
if(headerBlock.getChunkType()!= ChunkType.TABLE){
|
||||||
|
return super.toString();
|
||||||
|
}
|
||||||
|
StringBuilder builder=new StringBuilder();
|
||||||
|
builder.append(getClass().getSimpleName());
|
||||||
|
builder.append(": SIZE=").append(headerBlock.getChunkSize());
|
||||||
|
String str=getFrameworkTitle();
|
||||||
|
builder.append("\n");
|
||||||
|
if(str==null){
|
||||||
|
builder.append(PROP_TITLE).append(":null");
|
||||||
|
}else {
|
||||||
|
builder.append(str);
|
||||||
|
}
|
||||||
|
str=getFrameworkName();
|
||||||
|
builder.append("\n ").append(PROP_NAME).append(":");
|
||||||
|
if(str==null){
|
||||||
|
builder.append("null");
|
||||||
|
}else {
|
||||||
|
builder.append(str);
|
||||||
|
}
|
||||||
|
str=getFrameworkVersion();
|
||||||
|
builder.append("\n ").append(PROP_VERSION).append(":");
|
||||||
|
if(str==null){
|
||||||
|
builder.append("null");
|
||||||
|
}else {
|
||||||
|
builder.append(str);
|
||||||
|
}
|
||||||
|
Collection<PackageBlock> allPkg = listPackages();
|
||||||
|
builder.append("\n PACKAGES=").append(allPkg.size());
|
||||||
|
for(PackageBlock packageBlock:allPkg){
|
||||||
|
builder.append("\n ");
|
||||||
|
builder.append(String.format("0x%02x", packageBlock.getPackageId()));
|
||||||
|
builder.append(":").append(packageBlock.getPackageName());
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
private static final String TITLE_STRING="Framework table";
|
||||||
|
private static final String PROP_TITLE="TITLE";
|
||||||
|
private static final String PROP_NAME="NAME";
|
||||||
|
private static final String PROP_VERSION="VERSION";
|
||||||
|
private static final int PROP_COUNT=10;
|
||||||
}
|
}
|
||||||
|
0
src/main/java/com/reandroid/lib/arsc/value/BaseResValue.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/value/BaseResValue.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/value/BaseResValueItem.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/value/BaseResValueItem.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/value/EntryBlock.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/value/EntryBlock.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/value/LibraryInfo.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/value/LibraryInfo.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/value/ResConfig.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/value/ResConfig.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/value/ResConfigHelper.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/value/ResConfigHelper.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/value/ResValueBag.java
Normal file → Executable file
0
src/main/java/com/reandroid/lib/arsc/value/ResValueBag.java
Normal file → Executable file
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user