mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-05-19 14:27:04 +02:00
V1.0.7
This commit is contained in:
parent
9d8421b0c7
commit
8bac03ca9b
@ -2,7 +2,7 @@
|
||||
apply plugin: 'java-library'
|
||||
|
||||
group 'com.reandroid.lib.arsc'
|
||||
version '1.0.6'
|
||||
version '1.0.7'
|
||||
|
||||
java {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
|
129
src/main/java/com/reandroid/lib/apk/ApkBundle.java
Normal file
129
src/main/java/com/reandroid/lib/apk/ApkBundle.java
Normal file
@ -0,0 +1,129 @@
|
||||
package com.reandroid.lib.apk;
|
||||
|
||||
import com.reandroid.archive.APKArchive;
|
||||
import com.reandroid.lib.arsc.chunk.TableBlock;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public class ApkBundle {
|
||||
private final Map<String, ApkModule> mModulesMap;
|
||||
private APKLogger apkLogger;
|
||||
public ApkBundle(){
|
||||
this.mModulesMap=new HashMap<>();
|
||||
}
|
||||
|
||||
public ApkModule mergeModules() throws IOException {
|
||||
List<ApkModule> moduleList=getApkModuleList();
|
||||
if(moduleList.size()==0){
|
||||
throw new FileNotFoundException("Nothing to merge, empty modules");
|
||||
}
|
||||
ApkModule result=new ApkModule("merged", new APKArchive());
|
||||
result.setAPKLogger(apkLogger);
|
||||
ApkModule base=getBaseModule();
|
||||
if(base==null){
|
||||
base=getLargestTableModule();
|
||||
}
|
||||
result.merge(base);
|
||||
for(ApkModule module:moduleList){
|
||||
if(module==base){
|
||||
continue;
|
||||
}
|
||||
result.merge(module);
|
||||
}
|
||||
if(result.hasTableBlock()){
|
||||
TableBlock tableBlock=result.getTableBlock();
|
||||
tableBlock.sortPackages();
|
||||
tableBlock.refresh();
|
||||
}
|
||||
result.sortApkFiles();
|
||||
return result;
|
||||
}
|
||||
private ApkModule getLargestTableModule() throws IOException {
|
||||
ApkModule apkModule=null;
|
||||
int chunkSize=0;
|
||||
for(ApkModule module:getApkModuleList()){
|
||||
if(!module.hasTableBlock()){
|
||||
continue;
|
||||
}
|
||||
TableBlock tableBlock=module.getTableBlock();
|
||||
int size=tableBlock.getHeaderBlock().getChunkSize();
|
||||
if(apkModule==null || size>chunkSize){
|
||||
chunkSize=size;
|
||||
apkModule=module;
|
||||
}
|
||||
}
|
||||
return apkModule;
|
||||
}
|
||||
public ApkModule getBaseModule(){
|
||||
for(ApkModule module:getApkModuleList()){
|
||||
if(module.isBaseModule()){
|
||||
return module;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public List<ApkModule> getApkModuleList(){
|
||||
return new ArrayList<>(mModulesMap.values());
|
||||
}
|
||||
public void loadApkDirectory(File dir) throws IOException {
|
||||
if(!dir.isDirectory()){
|
||||
throw new FileNotFoundException("No such directory: "+dir);
|
||||
}
|
||||
List<File> apkList=ApkUtil.listFiles(dir, ".apk");
|
||||
if(apkList.size()==0){
|
||||
throw new FileNotFoundException("No '*.apk' files in directory: "+dir);
|
||||
}
|
||||
logMessage("Found apk files: "+apkList.size());
|
||||
for(File file:apkList){
|
||||
logVerbose("Loading: "+file.getName());
|
||||
String name=ApkUtil.toModuleName(file);
|
||||
ApkModule module=ApkModule.loadApkFile(file, name);
|
||||
module.setAPKLogger(apkLogger);
|
||||
addModule(module);
|
||||
}
|
||||
}
|
||||
public void addModule(ApkModule apkModule){
|
||||
String name=apkModule.getModuleName();
|
||||
mModulesMap.remove(name);
|
||||
mModulesMap.put(name, apkModule);
|
||||
}
|
||||
public boolean containsApkModule(String moduleName){
|
||||
return mModulesMap.containsKey(moduleName);
|
||||
}
|
||||
public ApkModule removeApkModule(String moduleName){
|
||||
return mModulesMap.remove(moduleName);
|
||||
}
|
||||
public ApkModule getApkModule(String moduleName){
|
||||
return mModulesMap.get(moduleName);
|
||||
}
|
||||
public List<String> listModuleNames(){
|
||||
return new ArrayList<>(mModulesMap.keySet());
|
||||
}
|
||||
public int countModules(){
|
||||
return mModulesMap.size();
|
||||
}
|
||||
public Collection<ApkModule> getModules(){
|
||||
return mModulesMap.values();
|
||||
}
|
||||
public void setAPKLogger(APKLogger logger) {
|
||||
this.apkLogger = logger;
|
||||
}
|
||||
private void logMessage(String msg) {
|
||||
if(apkLogger!=null){
|
||||
apkLogger.logMessage(msg);
|
||||
}
|
||||
}
|
||||
private void logError(String msg, Throwable tr) {
|
||||
if(apkLogger!=null){
|
||||
apkLogger.logError(msg, tr);
|
||||
}
|
||||
}
|
||||
private void logVerbose(String msg) {
|
||||
if(apkLogger!=null){
|
||||
apkLogger.logVerbose(msg);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package com.reandroid.lib.apk;
|
||||
|
||||
import com.reandroid.archive.*;
|
||||
import com.reandroid.lib.arsc.array.PackageArray;
|
||||
import com.reandroid.lib.arsc.chunk.BaseChunk;
|
||||
import com.reandroid.lib.arsc.chunk.PackageBlock;
|
||||
import com.reandroid.lib.arsc.chunk.TableBlock;
|
||||
import com.reandroid.lib.arsc.chunk.xml.AndroidManifestBlock;
|
||||
@ -30,6 +31,16 @@ public class ApkModule {
|
||||
this.mUncompressedFiles=new UncompressedFiles();
|
||||
this.mUncompressedFiles.addPath(apkArchive);
|
||||
}
|
||||
public List<DexFileInputSource> listDexFiles(){
|
||||
List<DexFileInputSource> results=new ArrayList<>();
|
||||
for(InputSource source:getApkArchive().listInputSources()){
|
||||
if(DexFileInputSource.isDexName(source.getAlias())){
|
||||
results.add(new DexFileInputSource(source.getAlias(), source));
|
||||
}
|
||||
}
|
||||
DexFileInputSource.sort(results);
|
||||
return results;
|
||||
}
|
||||
public boolean isBaseModule(){
|
||||
if(!hasAndroidManifestBlock()){
|
||||
return false;
|
||||
@ -223,6 +234,9 @@ public class ApkModule {
|
||||
tableBlock=((SplitJsonTableInputSource)inputSource).getTableBlock();
|
||||
}else if(inputSource instanceof SingleJsonTableInputSource){
|
||||
tableBlock=((SingleJsonTableInputSource)inputSource).getTableBlock();
|
||||
}else if(inputSource instanceof BlockInputSource){
|
||||
BaseChunk block = ((BlockInputSource<?>) inputSource).getBlock();
|
||||
tableBlock=(TableBlock) block;
|
||||
}else {
|
||||
InputStream inputStream = inputSource.openStream();
|
||||
if(loadDefaultFramework){
|
||||
@ -246,6 +260,78 @@ public class ApkModule {
|
||||
this.loadDefaultFramework = loadDefaultFramework;
|
||||
}
|
||||
|
||||
public void merge(ApkModule module) throws IOException {
|
||||
if(module==null||module==this){
|
||||
return;
|
||||
}
|
||||
logMessage("Merging: "+module.getModuleName());
|
||||
mergeDexFiles(module);
|
||||
mergeTable(module);
|
||||
mergeFiles(module);
|
||||
getUncompressedFiles().merge(module.getUncompressedFiles());
|
||||
}
|
||||
private void mergeTable(ApkModule module) throws IOException {
|
||||
if(!module.hasTableBlock()){
|
||||
return;
|
||||
}
|
||||
logMessage("Merging resource table: "+module.getModuleName());
|
||||
TableBlock exist;
|
||||
if(!hasTableBlock()){
|
||||
exist=new TableBlock();
|
||||
BlockInputSource<TableBlock> inputSource=new BlockInputSource<>(TableBlock.FILE_NAME, exist);
|
||||
getApkArchive().add(inputSource);
|
||||
}else{
|
||||
exist=getTableBlock();
|
||||
}
|
||||
TableBlock coming=module.getTableBlock();
|
||||
exist.merge(coming);
|
||||
}
|
||||
private void mergeFiles(ApkModule module) throws IOException {
|
||||
APKArchive archiveExist = getApkArchive();
|
||||
APKArchive archiveComing = module.getApkArchive();
|
||||
Map<String, InputSource> comingAlias=ApkUtil.toAliasMap(archiveComing.listInputSources());
|
||||
Map<String, InputSource> existAlias=ApkUtil.toAliasMap(archiveExist.listInputSources());
|
||||
UncompressedFiles uf=getUncompressedFiles();
|
||||
for(InputSource inputSource:comingAlias.values()){
|
||||
if(existAlias.containsKey(inputSource.getAlias())||existAlias.containsKey(inputSource.getName())){
|
||||
continue;
|
||||
}
|
||||
if(DexFileInputSource.isDexName(inputSource.getName())){
|
||||
continue;
|
||||
}
|
||||
logVerbose("Added: "+inputSource.getAlias());
|
||||
archiveExist.add(inputSource);
|
||||
uf.addPath(inputSource);
|
||||
}
|
||||
}
|
||||
private void mergeDexFiles(ApkModule module){
|
||||
List<DexFileInputSource> existList=listDexFiles();
|
||||
List<DexFileInputSource> comingList=module.listDexFiles();
|
||||
APKArchive archive=getApkArchive();
|
||||
int index=0;
|
||||
if(existList.size()>0){
|
||||
index=existList.get(existList.size()-1).getDexNumber();
|
||||
if(index==0){
|
||||
index=2;
|
||||
}else {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
for(DexFileInputSource source:comingList){
|
||||
String name=DexFileInputSource.getDexName(index);
|
||||
DexFileInputSource add=new DexFileInputSource(name, source.getInputSource());
|
||||
archive.add(add);
|
||||
logMessage("Added ["+module.getModuleName()+"] "
|
||||
+source.getAlias()+" -> "+name);
|
||||
index++;
|
||||
if(index==1){
|
||||
index=2;
|
||||
}
|
||||
}
|
||||
}
|
||||
void sortApkFiles(){
|
||||
sortApkFiles(new ArrayList<>(getApkArchive().listInputSources()));
|
||||
}
|
||||
public void setAPKLogger(APKLogger logger) {
|
||||
this.apkLogger = logger;
|
||||
}
|
||||
@ -264,6 +350,10 @@ public class ApkModule {
|
||||
apkLogger.logVerbose(msg);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String toString(){
|
||||
return getModuleName();
|
||||
}
|
||||
public static ApkModule loadApkFile(File apkFile) throws IOException {
|
||||
return loadApkFile(apkFile, ApkUtil.DEF_MODULE_NAME);
|
||||
}
|
||||
@ -271,4 +361,39 @@ public class ApkModule {
|
||||
APKArchive archive=APKArchive.loadZippedApk(apkFile);
|
||||
return new ApkModule(moduleName, archive);
|
||||
}
|
||||
private static void sortApkFiles(List<InputSource> sourceList){
|
||||
Comparator<InputSource> cmp=new Comparator<InputSource>() {
|
||||
@Override
|
||||
public int compare(InputSource in1, InputSource in2) {
|
||||
return getSortName(in1).compareTo(getSortName(in2));
|
||||
}
|
||||
};
|
||||
sourceList.sort(cmp);
|
||||
int i=0;
|
||||
for(InputSource inputSource:sourceList){
|
||||
inputSource.setSort(i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
private static String getSortName(InputSource inputSource){
|
||||
String name=inputSource.getAlias();
|
||||
StringBuilder builder=new StringBuilder();
|
||||
if(name.equals(AndroidManifestBlock.FILE_NAME)){
|
||||
builder.append("0 ");
|
||||
}else if(name.equals(TableBlock.FILE_NAME)){
|
||||
builder.append("1 ");
|
||||
}else if(name.startsWith("classes")){
|
||||
builder.append("2 ");
|
||||
}else if(name.startsWith("res/")){
|
||||
builder.append("3 ");
|
||||
}else if(name.startsWith("lib/")){
|
||||
builder.append("4 ");
|
||||
}else if(name.startsWith("assets/")){
|
||||
builder.append("5 ");
|
||||
}else {
|
||||
builder.append("6 ");
|
||||
}
|
||||
builder.append(name.toLowerCase());
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
package com.reandroid.lib.apk;
|
||||
|
||||
import com.reandroid.archive.InputSource;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
public class ApkUtil {
|
||||
public static String replaceRootDir(String path, String dirName){
|
||||
@ -106,6 +107,21 @@ public class ApkUtil {
|
||||
}
|
||||
return results;
|
||||
}
|
||||
public static String toModuleName(File file){
|
||||
String name=file.getName();
|
||||
int i=name.lastIndexOf('.');
|
||||
if(i>0){
|
||||
name=name.substring(0,i);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
public static Map<String, InputSource> toAliasMap(Collection<InputSource> sourceList){
|
||||
Map<String, InputSource> results=new HashMap<>();
|
||||
for(InputSource inputSource:sourceList){
|
||||
results.put(inputSource.getAlias(), inputSource);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
public static final String JSON_FILE_EXTENSION=".json";
|
||||
public static final String RES_JSON_NAME="res-json";
|
||||
public static final String ROOT_NAME="root";
|
||||
|
51
src/main/java/com/reandroid/lib/apk/DexFileInputSource.java
Normal file
51
src/main/java/com/reandroid/lib/apk/DexFileInputSource.java
Normal file
@ -0,0 +1,51 @@
|
||||
package com.reandroid.lib.apk;
|
||||
|
||||
import com.reandroid.archive.InputSource;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class DexFileInputSource extends RenamedInputSource<InputSource> implements Comparable<DexFileInputSource>{
|
||||
public DexFileInputSource(String name, InputSource inputSource){
|
||||
super(name, inputSource);
|
||||
}
|
||||
public int getDexNumber(){
|
||||
return getDexNumber(getAlias());
|
||||
}
|
||||
@Override
|
||||
public int compareTo(DexFileInputSource source) {
|
||||
return Integer.compare(getDexNumber(), source.getDexNumber());
|
||||
}
|
||||
public static void sort(List<DexFileInputSource> sourceList){
|
||||
sourceList.sort(new Comparator<DexFileInputSource>() {
|
||||
@Override
|
||||
public int compare(DexFileInputSource s1, DexFileInputSource s2) {
|
||||
return s1.compareTo(s2);
|
||||
}
|
||||
});
|
||||
}
|
||||
public static boolean isDexName(String name){
|
||||
return getDexNumber(name)>=0;
|
||||
}
|
||||
static String getDexName(int i){
|
||||
if(i==0){
|
||||
return "classes.dex";
|
||||
}
|
||||
return "classes"+i+".dex";
|
||||
}
|
||||
static int getDexNumber(String name){
|
||||
Matcher matcher=PATTERN.matcher(name);
|
||||
if(!matcher.find()){
|
||||
return -1;
|
||||
}
|
||||
String num=matcher.group(1);
|
||||
if(num.length()==0){
|
||||
return 0;
|
||||
}
|
||||
return Integer.parseInt(num);
|
||||
}
|
||||
private static final Pattern PATTERN=Pattern.compile("^classes([0-9]*)\\.dex$");
|
||||
|
||||
}
|
40
src/main/java/com/reandroid/lib/apk/RenamedInputSource.java
Normal file
40
src/main/java/com/reandroid/lib/apk/RenamedInputSource.java
Normal file
@ -0,0 +1,40 @@
|
||||
package com.reandroid.lib.apk;
|
||||
|
||||
import com.reandroid.archive.InputSource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class RenamedInputSource<T extends InputSource> extends InputSource {
|
||||
private final T inputSource;
|
||||
public RenamedInputSource(String name, T input){
|
||||
super(name);
|
||||
this.inputSource=input;
|
||||
super.setMethod(input.getMethod());
|
||||
super.setSort(input.getSort());
|
||||
}
|
||||
public T getInputSource() {
|
||||
return inputSource;
|
||||
}
|
||||
@Override
|
||||
public void close(InputStream inputStream) throws IOException {
|
||||
getInputSource().close(inputStream);
|
||||
}
|
||||
@Override
|
||||
public long getLength() throws IOException {
|
||||
return getInputSource().getLength();
|
||||
}
|
||||
@Override
|
||||
public long getCrc() throws IOException {
|
||||
return getInputSource().getCrc();
|
||||
}
|
||||
@Override
|
||||
public long write(OutputStream outputStream) throws IOException {
|
||||
return getInputSource().write(outputStream);
|
||||
}
|
||||
@Override
|
||||
public InputStream openStream() throws IOException {
|
||||
return getInputSource().openStream();
|
||||
}
|
||||
}
|
@ -30,6 +30,7 @@ public class TableBlockJsonBuilder {
|
||||
for(File pkgDir:pkgDirList){
|
||||
scanPackageDirectory(tableBlock, pkgDir);
|
||||
}
|
||||
tableBlock.sortPackages();
|
||||
tableBlock.refresh();
|
||||
return tableBlock;
|
||||
}
|
||||
|
@ -159,6 +159,17 @@ public class UncompressedFiles implements JSONConvert<JSONObject> {
|
||||
}
|
||||
}
|
||||
}
|
||||
public void merge(UncompressedFiles uf){
|
||||
if(uf==null||uf==this){
|
||||
return;
|
||||
}
|
||||
for(String path: uf.mPathList){
|
||||
addPath(path);
|
||||
}
|
||||
for(String ext:uf.mExtensionList){
|
||||
addExtension(ext);
|
||||
}
|
||||
}
|
||||
public void fromJson(File jsonFile) throws IOException {
|
||||
if(!jsonFile.isFile()){
|
||||
return;
|
||||
|
@ -1,12 +1,18 @@
|
||||
package com.reandroid.lib.arsc.array;
|
||||
|
||||
import com.reandroid.lib.arsc.chunk.TypeBlock;
|
||||
import com.reandroid.lib.arsc.item.IntegerArray;
|
||||
import com.reandroid.lib.arsc.item.IntegerItem;
|
||||
import com.reandroid.lib.arsc.value.BaseResValue;
|
||||
import com.reandroid.lib.arsc.value.EntryBlock;
|
||||
import com.reandroid.lib.arsc.value.ResValueInt;
|
||||
import com.reandroid.lib.arsc.value.ValueType;
|
||||
import com.reandroid.lib.json.JSONConvert;
|
||||
import com.reandroid.lib.json.JSONArray;
|
||||
import com.reandroid.lib.json.JSONObject;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
|
||||
public class EntryBlockArray extends OffsetBlockArray<EntryBlock> implements JSONConvert<JSONArray> {
|
||||
public EntryBlockArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart){
|
||||
@ -56,7 +62,6 @@ public class EntryBlockArray extends OffsetBlockArray<EntryBlock> implements JSO
|
||||
}
|
||||
return jsonArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJson(JSONArray json) {
|
||||
clearChildes();
|
||||
@ -74,6 +79,34 @@ public class EntryBlockArray extends OffsetBlockArray<EntryBlock> implements JSO
|
||||
}
|
||||
refreshCountAndStart();
|
||||
}
|
||||
public void merge(EntryBlockArray entryBlockArray){
|
||||
if(entryBlockArray==null||entryBlockArray==this||entryBlockArray.isEmpty()){
|
||||
return;
|
||||
}
|
||||
ensureSize(entryBlockArray.childesCount());
|
||||
Iterator<EntryBlock> itr=entryBlockArray.iterator(true);
|
||||
while (itr.hasNext()){
|
||||
EntryBlock comingBlock=itr.next();
|
||||
EntryBlock existingBlock=get(comingBlock.getIndex());
|
||||
if(shouldMerge(existingBlock, comingBlock)){
|
||||
existingBlock.merge(comingBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
private boolean shouldMerge(EntryBlock exist, EntryBlock coming){
|
||||
if(exist.isNull()){
|
||||
return true;
|
||||
}
|
||||
if(coming.isNull()){
|
||||
return false;
|
||||
}
|
||||
BaseResValue resVal = coming.getResValue();
|
||||
if(resVal instanceof ResValueInt){
|
||||
ValueType valueType=((ResValueInt)resVal).getValueType();
|
||||
return valueType!=ValueType.INT_BOOLEAN;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public String toString(){
|
||||
return getClass().getSimpleName()+": size="+childesCount();
|
||||
|
@ -15,6 +15,25 @@ public class LibraryInfoArray extends BlockArray<LibraryInfo> implements JSONCon
|
||||
public LibraryInfoArray(IntegerItem infoCount){
|
||||
this.mInfoCount=infoCount;
|
||||
}
|
||||
public LibraryInfo getOrCreate(int pkgId){
|
||||
LibraryInfo info=getById(pkgId);
|
||||
if(info!=null){
|
||||
return info;
|
||||
}
|
||||
int index=childesCount();
|
||||
ensureSize(index+1);
|
||||
info=get(index);
|
||||
info.setPackageId(pkgId);
|
||||
return info;
|
||||
}
|
||||
public LibraryInfo getById(int pkgId){
|
||||
for(LibraryInfo info:listItems()){
|
||||
if(pkgId==info.getPackageId()){
|
||||
return info;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public LibraryInfo newInstance() {
|
||||
return new LibraryInfo();
|
||||
@ -61,4 +80,13 @@ public class LibraryInfoArray extends BlockArray<LibraryInfo> implements JSONCon
|
||||
libraryInfo.fromJson(jsonObject);
|
||||
}
|
||||
}
|
||||
public void merge(LibraryInfoArray infoArray){
|
||||
if(infoArray==null||infoArray==this||infoArray.childesCount()==0){
|
||||
return;
|
||||
}
|
||||
for(LibraryInfo info:infoArray.listItems()){
|
||||
LibraryInfo exist=getOrCreate(info.getPackageId());
|
||||
exist.merge(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,14 +11,22 @@ import com.reandroid.lib.json.JSONArray;
|
||||
import com.reandroid.lib.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class PackageArray extends BlockArray<PackageBlock> implements BlockLoad, JSONConvert<JSONArray> {
|
||||
public class PackageArray extends BlockArray<PackageBlock>
|
||||
implements BlockLoad, JSONConvert<JSONArray>, Comparator<PackageBlock> {
|
||||
private final IntegerItem mPackageCount;
|
||||
public PackageArray(IntegerItem packageCount){
|
||||
this.mPackageCount=packageCount;
|
||||
mPackageCount.setBlockLoad(this);
|
||||
}
|
||||
public void sort(){
|
||||
for(PackageBlock packageBlock:listItems()){
|
||||
packageBlock.sortTypes();
|
||||
}
|
||||
sort(this);
|
||||
}
|
||||
public PackageBlock getOrCreate(byte pkgId){
|
||||
PackageBlock packageBlock=getPackageBlockById(pkgId);
|
||||
if(packageBlock!=null){
|
||||
@ -88,4 +96,17 @@ public class PackageArray extends BlockArray<PackageBlock> implements BlockLoad,
|
||||
packageBlock.fromJson(jsonObject);
|
||||
}
|
||||
}
|
||||
public void merge(PackageArray packageArray){
|
||||
if(packageArray==null||packageArray==this){
|
||||
return;
|
||||
}
|
||||
for(PackageBlock packageBlock:packageArray.listItems()){
|
||||
PackageBlock exist=getOrCreate((byte) packageBlock.getId());
|
||||
exist.merge(packageBlock);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public int compare(PackageBlock p1, PackageBlock p2) {
|
||||
return p1.compareTo(p2);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.reandroid.lib.arsc.array;
|
||||
|
||||
import com.reandroid.lib.arsc.base.BlockArray;
|
||||
import com.reandroid.lib.arsc.value.ResValueBag;
|
||||
import com.reandroid.lib.arsc.value.ResValueBagItem;
|
||||
import com.reandroid.lib.json.JSONConvert;
|
||||
import com.reandroid.lib.json.JSONArray;
|
||||
@ -22,6 +23,13 @@ public class ResValueBagItemArray extends BlockArray<ResValueBagItem> implements
|
||||
@Override
|
||||
protected void onRefreshed() {
|
||||
|
||||
}
|
||||
@Override
|
||||
public void clearChildes(){
|
||||
for(ResValueBagItem bagItem:listItems()){
|
||||
bagItem.onRemoved();
|
||||
}
|
||||
super.clearChildes();
|
||||
}
|
||||
@Override
|
||||
public JSONArray toJson() {
|
||||
@ -47,4 +55,17 @@ public class ResValueBagItemArray extends BlockArray<ResValueBagItem> implements
|
||||
get(i).fromJson(json.getJSONObject(i));
|
||||
}
|
||||
}
|
||||
public void merge(ResValueBagItemArray bagItemArray){
|
||||
if(bagItemArray==null||bagItemArray==this){
|
||||
return;
|
||||
}
|
||||
clearChildes();
|
||||
int count=bagItemArray.childesCount();
|
||||
ensureSize(count);
|
||||
for(int i=0;i<count;i++){
|
||||
ResValueBagItem coming=bagItemArray.get(i);
|
||||
ResValueBagItem exist=get(i);
|
||||
exist.merge(coming);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.reandroid.lib.arsc.array;
|
||||
|
||||
import com.reandroid.lib.arsc.base.BlockArray;
|
||||
import com.reandroid.lib.arsc.chunk.PackageBlock;
|
||||
import com.reandroid.lib.arsc.chunk.TypeBlock;
|
||||
import com.reandroid.lib.arsc.container.SpecTypePair;
|
||||
import com.reandroid.lib.arsc.value.EntryBlock;
|
||||
@ -226,6 +227,18 @@ public class SpecTypePairArray extends BlockArray<SpecTypePair>
|
||||
specTypePair.fromJson(jsonObject);
|
||||
}
|
||||
}
|
||||
public void merge(SpecTypePairArray pairArray){
|
||||
if(pairArray==null || pairArray==this){
|
||||
return;
|
||||
}
|
||||
for(SpecTypePair typePair:pairArray.listItems()){
|
||||
if(typePair.isEmpty()){
|
||||
continue;
|
||||
}
|
||||
SpecTypePair exist=getOrCreate(typePair.getTypeId());
|
||||
exist.merge(typePair);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public int compare(SpecTypePair typePair1, SpecTypePair typePair2) {
|
||||
return typePair1.compareTo(typePair2);
|
||||
|
@ -58,16 +58,27 @@ public class StyleArray extends OffsetBlockArray<StyleItem> implements JSONConve
|
||||
public JSONArray toJson() {
|
||||
if(childesCount()==0){
|
||||
return null;
|
||||
}
|
||||
int i=0;
|
||||
for(StyleItem styleItem:listItems()){
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public void fromJson(JSONArray json) {
|
||||
|
||||
}
|
||||
public void merge(StyleArray styleArray){
|
||||
if(styleArray==null||styleArray==this){
|
||||
return;
|
||||
}
|
||||
if(childesCount()!=0){
|
||||
return;
|
||||
}
|
||||
int count=styleArray.childesCount();
|
||||
ensureSize(count);
|
||||
for(int i=0;i<count;i++){
|
||||
StyleItem exist=get(i);
|
||||
StyleItem coming=styleArray.get(i);
|
||||
exist.merge(coming);
|
||||
}
|
||||
}
|
||||
private static final byte END_BYTE= (byte) 0xFF;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import com.reandroid.lib.arsc.base.Block;
|
||||
import com.reandroid.lib.arsc.base.BlockArray;
|
||||
import com.reandroid.lib.arsc.chunk.SpecBlock;
|
||||
import com.reandroid.lib.arsc.chunk.TypeBlock;
|
||||
import com.reandroid.lib.arsc.container.SpecTypePair;
|
||||
import com.reandroid.lib.arsc.header.HeaderBlock;
|
||||
import com.reandroid.lib.arsc.io.BlockReader;
|
||||
import com.reandroid.lib.arsc.item.TypeString;
|
||||
@ -277,6 +278,15 @@ public class TypeBlockArray extends BlockArray<TypeBlock>
|
||||
typeBlock.fromJson(jsonObject);
|
||||
}
|
||||
}
|
||||
public void merge(TypeBlockArray typeBlockArray){
|
||||
if(typeBlockArray==null||typeBlockArray==this){
|
||||
return;
|
||||
}
|
||||
for(TypeBlock typeBlock:typeBlockArray.listItems()){
|
||||
TypeBlock block=getOrCreate(typeBlock.getResConfig());
|
||||
block.merge(typeBlock);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public int compare(TypeBlock typeBlock1, TypeBlock typeBlock2) {
|
||||
return typeBlock1.compareTo(typeBlock2);
|
||||
|
@ -50,10 +50,15 @@ public class LibraryBlock extends BaseChunk {
|
||||
mLibCount.set(count);
|
||||
mLibraryInfoArray.setChildesCount(count);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onChunkRefreshed() {
|
||||
mLibCount.set(mLibraryInfoArray.childesCount());
|
||||
}
|
||||
|
||||
public void merge(LibraryBlock libraryBlock){
|
||||
if(libraryBlock==null||libraryBlock==this){
|
||||
return;
|
||||
}
|
||||
getLibraryInfoArray().merge(libraryBlock.getLibraryInfoArray());
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.reandroid.lib.arsc.chunk;
|
||||
|
||||
import com.reandroid.lib.arsc.array.LibraryInfoArray;
|
||||
import com.reandroid.lib.arsc.array.PackageArray;
|
||||
import com.reandroid.lib.arsc.array.SpecTypePairArray;
|
||||
import com.reandroid.lib.arsc.base.Block;
|
||||
import com.reandroid.lib.arsc.container.PackageLastBlocks;
|
||||
@ -24,7 +25,8 @@ import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public class PackageBlock extends BaseChunk implements BlockLoad, JSONConvert<JSONObject> {
|
||||
public class PackageBlock extends BaseChunk
|
||||
implements BlockLoad, JSONConvert<JSONObject>, Comparable<PackageBlock> {
|
||||
private final IntegerItem mPackageId;
|
||||
private final PackageName mPackageName;
|
||||
|
||||
@ -136,7 +138,7 @@ public class PackageBlock extends BaseChunk implements BlockLoad, JSONConvert<JS
|
||||
return mSpecTypePairArray;
|
||||
}
|
||||
public Collection<LibraryInfo> listLibraryInfo(){
|
||||
return mLibraryBlock.listLibraryInfo();
|
||||
return getLibraryBlock().listLibraryInfo();
|
||||
}
|
||||
|
||||
public void addLibrary(LibraryBlock libraryBlock){
|
||||
@ -148,7 +150,10 @@ public class PackageBlock extends BaseChunk implements BlockLoad, JSONConvert<JS
|
||||
}
|
||||
}
|
||||
public void addLibraryInfo(LibraryInfo info){
|
||||
mLibraryBlock.addLibraryInfo(info);
|
||||
getLibraryBlock().addLibraryInfo(info);
|
||||
}
|
||||
private LibraryBlock getLibraryBlock(){
|
||||
return mLibraryBlock;
|
||||
}
|
||||
public Set<Integer> listResourceIds(){
|
||||
return mEntriesGroup.keySet();
|
||||
@ -291,6 +296,22 @@ public class PackageBlock extends BaseChunk implements BlockLoad, JSONConvert<JS
|
||||
LibraryInfoArray libraryInfoArray = mLibraryBlock.getLibraryInfoArray();
|
||||
libraryInfoArray.fromJson(json.optJSONArray(NAME_libraries));
|
||||
}
|
||||
public void merge(PackageBlock packageBlock){
|
||||
if(packageBlock==null||packageBlock==this){
|
||||
return;
|
||||
}
|
||||
if(getId()!=packageBlock.getId()){
|
||||
throw new IllegalArgumentException("Can not merge different id packages: "
|
||||
+getId()+"!="+packageBlock.getId());
|
||||
}
|
||||
setName(packageBlock.getName());
|
||||
getLibraryBlock().merge(packageBlock.getLibraryBlock());
|
||||
getSpecTypePairArray().merge(packageBlock.getSpecTypePairArray());
|
||||
}
|
||||
@Override
|
||||
public int compareTo(PackageBlock pkg) {
|
||||
return Integer.compare(getId(), pkg.getId());
|
||||
}
|
||||
@Override
|
||||
public String toString(){
|
||||
StringBuilder builder=new StringBuilder();
|
||||
|
@ -30,6 +30,9 @@ public class TableBlock extends BaseChunk implements JSONConvert<JSONObject> {
|
||||
addChild(mTableStringPool);
|
||||
addChild(mPackageArray);
|
||||
}
|
||||
public void sortPackages(){
|
||||
getPackageArray().sort();
|
||||
}
|
||||
public Collection<PackageBlock> listPackages(){
|
||||
return getPackageArray().listItems();
|
||||
}
|
||||
@ -138,6 +141,16 @@ public class TableBlock extends BaseChunk implements JSONConvert<JSONObject> {
|
||||
getPackageArray().fromJson(json.getJSONArray(NAME_packages));
|
||||
refresh();
|
||||
}
|
||||
public void merge(TableBlock tableBlock){
|
||||
if(tableBlock==null||tableBlock==this){
|
||||
return;
|
||||
}
|
||||
if(getPackageArray().childesCount()==0){
|
||||
getTableStringPool().merge(tableBlock.getTableStringPool());
|
||||
}
|
||||
getPackageArray().merge(tableBlock.getPackageArray());
|
||||
refresh();
|
||||
}
|
||||
public static TableBlock loadWithAndroidFramework(InputStream inputStream) throws IOException{
|
||||
TableBlock tableBlock=load(inputStream);
|
||||
tableBlock.addFramework(Frameworks.getAndroid());
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.reandroid.lib.arsc.chunk;
|
||||
|
||||
import com.reandroid.lib.arsc.array.EntryBlockArray;
|
||||
import com.reandroid.lib.arsc.array.TypeBlockArray;
|
||||
import com.reandroid.lib.arsc.base.Block;
|
||||
import com.reandroid.lib.arsc.container.SpecTypePair;
|
||||
import com.reandroid.lib.arsc.item.IntegerArray;
|
||||
@ -138,6 +139,17 @@ public class TypeBlock extends BaseTypeBlock
|
||||
getEntryBlockArray().fromJson(json.getJSONArray("entries"));
|
||||
getResConfig().fromJson(json.getJSONObject("config"));
|
||||
}
|
||||
public void merge(TypeBlock typeBlock){
|
||||
if(typeBlock==null||typeBlock==this){
|
||||
return;
|
||||
}
|
||||
if(getTypeId() != typeBlock.getTypeId()){
|
||||
throw new IllegalArgumentException("Can not merge different id types: "
|
||||
+getTypeId()+"!="+typeBlock.getTypeId());
|
||||
}
|
||||
setTypeName(typeBlock.getTypeName());
|
||||
getEntryBlockArray().merge(typeBlock.getEntryBlockArray());
|
||||
}
|
||||
@Override
|
||||
public int compareTo(TypeBlock typeBlock) {
|
||||
int id1=getTypeId();
|
||||
|
@ -18,9 +18,14 @@ public class AndroidManifestBlock extends ResXmlBlock{
|
||||
public ResXmlElement getMainActivity(){
|
||||
for(ResXmlElement activity:listActivities()){
|
||||
for(ResXmlElement intentFilter:activity.listElements(TAG_intent_filter)){
|
||||
ResXmlAttribute attribute = intentFilter.searchAttributeByResourceId(ID_name);
|
||||
if(VALUE_android_intent_action_MAIN.equals(attribute.getValueAsString())){
|
||||
return activity;
|
||||
for(ResXmlElement action:intentFilter.listElements(TAG_action)){
|
||||
ResXmlAttribute attribute = action.searchAttributeByResourceId(ID_name);
|
||||
if(attribute==null){
|
||||
continue;
|
||||
}
|
||||
if(VALUE_android_intent_action_MAIN.equals(attribute.getValueAsString())){
|
||||
return activity;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -294,6 +299,8 @@ public class AndroidManifestBlock extends ResXmlBlock{
|
||||
public static final String NAME_versionCode = "versionCode";
|
||||
public static final String NAME_versionName = "versionName";
|
||||
public static final String NAME_name = "name";
|
||||
public static final String NAME_extractNativeLibs = "extractNativeLibs";
|
||||
public static final String NAME_isSplitRequired = "isSplitRequired";
|
||||
|
||||
public static final int ID_name = 0x01010003;
|
||||
public static final int ID_compileSdkVersion = 0x01010572;
|
||||
@ -302,6 +309,8 @@ public class AndroidManifestBlock extends ResXmlBlock{
|
||||
public static final int ID_host = 0x01010028;
|
||||
public static final int ID_configChanges = 0x0101001f;
|
||||
public static final int ID_screenOrientation = 0x0101001e;
|
||||
public static final int ID_extractNativeLibs = 0x010104ea;
|
||||
public static final int ID_isSplitRequired = 0x01010591;
|
||||
|
||||
public static final String VALUE_android_intent_action_MAIN = "android.intent.action.MAIN";
|
||||
|
||||
|
@ -159,6 +159,16 @@ public class SpecTypePair extends BlockContainer<Block>
|
||||
getSpecBlock().setTypeId((byte) json.getInt("id"));
|
||||
getTypeBlockArray().fromJson(json.getJSONArray("types"));
|
||||
}
|
||||
public void merge(SpecTypePair typePair){
|
||||
if(typePair==null||typePair==this){
|
||||
return;
|
||||
}
|
||||
if(getTypeId() != typePair.getTypeId()){
|
||||
throw new IllegalArgumentException("Can not merge different id types: "
|
||||
+getTypeId()+"!="+typePair.getTypeId());
|
||||
}
|
||||
getTypeBlockArray().merge(typePair.getTypeBlockArray());
|
||||
}
|
||||
@Override
|
||||
public int compareTo(SpecTypePair specTypePair) {
|
||||
return Integer.compare(getTypeId(), specTypePair.getTypeId());
|
||||
|
@ -5,6 +5,23 @@ public class ByteItem extends BlockItem {
|
||||
public ByteItem() {
|
||||
super(1);
|
||||
}
|
||||
public boolean getBit(int index){
|
||||
return ((get()>>index) & 0x1) == 1;
|
||||
}
|
||||
public void putBit(int index, boolean bit){
|
||||
int val=get();
|
||||
int left=val>>index;
|
||||
if(bit){
|
||||
left=left|0x1;
|
||||
}else {
|
||||
left=left & 0xFE;
|
||||
}
|
||||
left=left<<index;
|
||||
index=8-index;
|
||||
int right=(0xFF>>index) & val;
|
||||
val=left|right;
|
||||
set((byte) val);
|
||||
}
|
||||
public void set(byte b){
|
||||
getBytesInternal()[0]=b;
|
||||
}
|
||||
|
@ -307,6 +307,14 @@ public class StyleItem extends IntegerArray implements JSONConvert<JSONObject> {
|
||||
addSpanInfo(spanInfo.getTag(), spanInfo.getFirst(), spanInfo.getLast());
|
||||
}
|
||||
}
|
||||
public void merge(StyleItem styleItem){
|
||||
if(styleItem==null||styleItem==this){
|
||||
return;
|
||||
}
|
||||
for(int[] info:styleItem.getIntSpanInfoList()){
|
||||
addStylePiece(info[0], info[1], info[2]);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String toString(){
|
||||
return "Spans count = "+getSpanInfoList().size();
|
||||
|
@ -15,4 +15,22 @@ public class TableStringPool extends BaseStringPool<TableString> {
|
||||
StringArray<TableString> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
|
||||
return new TableStringArray(offsets, itemCount, itemStart, is_utf8);
|
||||
}
|
||||
public void merge(TableStringPool stringPool){
|
||||
if(stringPool==null||stringPool==this){
|
||||
return;
|
||||
}
|
||||
StringArray<TableString> existArray = getStringsArray();
|
||||
if(existArray.childesCount()!=0){
|
||||
return;
|
||||
}
|
||||
StringArray<TableString> comingArray = stringPool.getStringsArray();
|
||||
int count=comingArray.childesCount();
|
||||
existArray.ensureSize(count);
|
||||
for(int i=0;i<count;i++){
|
||||
TableString exist = existArray.get(i);
|
||||
TableString coming = comingArray.get(i);
|
||||
exist.set(coming.get());
|
||||
}
|
||||
getStyleArray().merge(stringPool.getStyleArray());
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,9 @@ public abstract class BaseResValue extends BlockItem implements JSONConvert<JSON
|
||||
super(bytesLength);
|
||||
}
|
||||
|
||||
protected void onRemoved(){
|
||||
}
|
||||
|
||||
public EntryBlock getEntryBlock(){
|
||||
Block parent=getParent();
|
||||
while(parent!=null){
|
||||
|
@ -1,8 +1,10 @@
|
||||
package com.reandroid.lib.arsc.value;
|
||||
|
||||
import com.reandroid.lib.arsc.array.EntryBlockArray;
|
||||
import com.reandroid.lib.arsc.base.Block;
|
||||
import com.reandroid.lib.arsc.base.BlockCounter;
|
||||
import com.reandroid.lib.arsc.chunk.PackageBlock;
|
||||
import com.reandroid.lib.arsc.chunk.SpecBlock;
|
||||
import com.reandroid.lib.arsc.chunk.TableBlock;
|
||||
import com.reandroid.lib.arsc.chunk.TypeBlock;
|
||||
import com.reandroid.lib.arsc.group.EntryGroup;
|
||||
@ -17,6 +19,7 @@ import com.reandroid.lib.json.JSONObject;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class EntryBlock extends Block implements JSONConvert<JSONObject> {
|
||||
@ -228,41 +231,23 @@ public class EntryBlock extends Block implements JSONConvert<JSONObject> {
|
||||
removeSpecReferences();
|
||||
}
|
||||
public void setEntryTypeBag(boolean b){
|
||||
int val=mFlagEntryType.get();
|
||||
if(b){
|
||||
val=val|0x1;
|
||||
}else {
|
||||
val=val&0xFE;
|
||||
}
|
||||
mFlagEntryType.set((byte) val);
|
||||
mFlagEntryType.putBit(0, b);
|
||||
refreshHeaderSize();
|
||||
}
|
||||
public boolean isEntryTypeBag(){
|
||||
return ((mFlagEntryType.get() & 0x1) != 0);
|
||||
return mFlagEntryType.getBit(0);
|
||||
}
|
||||
public void setEntryTypeShared(boolean b){
|
||||
int val=mFlagEntryType.get();
|
||||
if(b){
|
||||
val=val|0x2;
|
||||
}else {
|
||||
val=val&0xFD;
|
||||
}
|
||||
mFlagEntryType.set((byte) val);
|
||||
mFlagEntryType.putBit(1, b);
|
||||
}
|
||||
public boolean isEntryTypeShared(){
|
||||
return (mFlagEntryType.get() & 0x2) !=0;
|
||||
return mFlagEntryType.getBit(1);
|
||||
}
|
||||
public void setEntryTypePublic(boolean b){
|
||||
int val=mFlagEntryType.get();
|
||||
if(b){
|
||||
val=val|0x4;
|
||||
}else {
|
||||
val=val&0xFB;
|
||||
}
|
||||
mFlagEntryType.set((byte) val);
|
||||
mFlagEntryType.putBit(2, b);
|
||||
}
|
||||
public boolean isEntryTypePublic(){
|
||||
return (mFlagEntryType.get() & 0x4) !=0;
|
||||
return mFlagEntryType.getBit(2);
|
||||
}
|
||||
private void setByteFlagsB(byte b){
|
||||
mByteFlagsB.set(b);
|
||||
@ -310,6 +295,7 @@ public class EntryBlock extends Block implements JSONConvert<JSONObject> {
|
||||
if(mResValue!=null){
|
||||
mResValue.setIndex(-1);
|
||||
mResValue.setParent(null);
|
||||
mResValue.onRemoved();
|
||||
}
|
||||
if(resValue!=null){
|
||||
setNull(false);
|
||||
@ -685,6 +671,41 @@ public class EntryBlock extends Block implements JSONConvert<JSONObject> {
|
||||
baseResValue.fromJson(json.getJSONObject(NAME_value));
|
||||
mResValue.onDataLoaded();
|
||||
}
|
||||
public void merge(EntryBlock entryBlock){
|
||||
if(entryBlock==null||entryBlock==this||entryBlock.isNull()){
|
||||
return;
|
||||
}
|
||||
String name=entryBlock.getName();
|
||||
if(name==null){
|
||||
name="";
|
||||
}
|
||||
if(!entryBlock.isEntryTypeBag()){
|
||||
ResValueInt comingValue = (ResValueInt) entryBlock.getResValue();
|
||||
ResValueInt exist = getOrCreateResValueInt();
|
||||
setResValue(exist);
|
||||
exist.merge(comingValue);
|
||||
}else {
|
||||
ResValueBag comingValue = (ResValueBag) entryBlock.getResValue();
|
||||
ResValueBag exist=getOrCreateResValueBag();
|
||||
setResValue(exist);
|
||||
exist.merge(comingValue);
|
||||
}
|
||||
SpecString spec = getPackageBlock()
|
||||
.getSpecStringPool().getOrCreate(name);
|
||||
setSpecReference(spec.getIndex());
|
||||
}
|
||||
private ResValueBag getOrCreateResValueBag(){
|
||||
if(mResValue instanceof ResValueBag){
|
||||
return (ResValueBag) mResValue;
|
||||
}
|
||||
return new ResValueBag();
|
||||
}
|
||||
private ResValueInt getOrCreateResValueInt(){
|
||||
if(mResValue instanceof ResValueInt){
|
||||
return (ResValueInt) mResValue;
|
||||
}
|
||||
return new ResValueInt();
|
||||
}
|
||||
@Override
|
||||
public String toString(){
|
||||
StringBuilder builder=new StringBuilder();
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.reandroid.lib.arsc.value;
|
||||
|
||||
import com.reandroid.lib.arsc.array.LibraryInfoArray;
|
||||
import com.reandroid.lib.arsc.base.Block;
|
||||
import com.reandroid.lib.arsc.base.BlockCounter;
|
||||
import com.reandroid.lib.arsc.io.BlockReader;
|
||||
@ -88,6 +89,16 @@ public class LibraryInfo extends Block implements JSONConvert<JSONObject> {
|
||||
setPackageId(json.getInt("id"));
|
||||
setPackageName(json.getString("name"));
|
||||
}
|
||||
public void merge(LibraryInfo info){
|
||||
if(info==null||info==this){
|
||||
return;
|
||||
}
|
||||
if(getPackageId()!=info.getPackageId()){
|
||||
throw new IllegalArgumentException("Can not add different id libraries: "
|
||||
+getPackageId()+"!="+info.getPackageId());
|
||||
}
|
||||
setPackageName(info.getPackageName());
|
||||
}
|
||||
@Override
|
||||
public String toString(){
|
||||
StringBuilder builder=new StringBuilder();
|
||||
|
@ -113,7 +113,6 @@ public class ResValueBag extends BaseResValue {
|
||||
if(isNull()){
|
||||
return 0;
|
||||
}
|
||||
refreshCount();
|
||||
int result;
|
||||
result=mParentId.writeBytes(writer);
|
||||
result+=mCount.writeBytes(writer);
|
||||
@ -150,6 +149,14 @@ public class ResValueBag extends BaseResValue {
|
||||
getResValueBagItemArray().fromJson(json.getJSONArray(NAME_items));
|
||||
refreshCount();
|
||||
}
|
||||
public void merge(ResValueBag resValueBag){
|
||||
if(resValueBag==null||resValueBag==this){
|
||||
return;
|
||||
}
|
||||
setParentId(resValueBag.getParentId());
|
||||
getResValueBagItemArray().merge(resValueBag.getResValueBagItemArray());
|
||||
refreshCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
|
@ -11,6 +11,10 @@ public class ResValueBagItem extends BaseResValueItem{
|
||||
super(BYTES_COUNT);
|
||||
setHeaderSize(BYTES_SIZE);
|
||||
}
|
||||
@Override
|
||||
public void onRemoved(){
|
||||
removeTableReference();
|
||||
}
|
||||
public String getValueAsString(){
|
||||
return getTableString(getData()).getHtml();
|
||||
}
|
||||
@ -186,6 +190,19 @@ public class ResValueBagItem extends BaseResValueItem{
|
||||
setData(json.getInt(NAME_data));
|
||||
}
|
||||
}
|
||||
public void merge(ResValueBagItem bagItem){
|
||||
if(bagItem==null||bagItem==this){
|
||||
return;
|
||||
}
|
||||
setId(bagItem.getId());
|
||||
ValueType valueType=bagItem.getValueType();
|
||||
if(valueType==ValueType.STRING){
|
||||
setValueAsString(bagItem.getValueAsString());
|
||||
}else {
|
||||
setType(valueType);
|
||||
setData(bagItem.getData());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.reandroid.lib.arsc.value;
|
||||
|
||||
import com.reandroid.lib.arsc.decoder.ValueDecoder;
|
||||
import com.reandroid.lib.arsc.item.SpecString;
|
||||
import com.reandroid.lib.arsc.item.TableString;
|
||||
import com.reandroid.lib.json.JSONObject;
|
||||
|
||||
@ -9,6 +10,9 @@ public class ResValueInt extends BaseResValueItem {
|
||||
super(BYTES_COUNT);
|
||||
setHeaderSize(BYTES_SIZE);
|
||||
}
|
||||
protected void onRemoved(){
|
||||
removeTableReference();
|
||||
}
|
||||
public String getValueAsString(){
|
||||
return getString(getData());
|
||||
}
|
||||
@ -116,6 +120,18 @@ public class ResValueInt extends BaseResValueItem {
|
||||
setData(json.getInt(NAME_data));
|
||||
}
|
||||
}
|
||||
public void merge(ResValueInt resValueInt){
|
||||
if(resValueInt==null||resValueInt==this){
|
||||
return;
|
||||
}
|
||||
ValueType valueType=resValueInt.getValueType();
|
||||
if(valueType==ValueType.STRING){
|
||||
setValueAsString(resValueInt.getValueAsString());
|
||||
}else {
|
||||
setType(valueType);
|
||||
setData(resValueInt.getData());
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String toString(){
|
||||
StringBuilder builder=new StringBuilder();
|
||||
|
Loading…
x
Reference in New Issue
Block a user