V1.0.3 (to/from json convert)

This commit is contained in:
REAndroid 2022-11-30 11:11:23 -05:00
parent 8cbbc2fdad
commit 625baa03f1
51 changed files with 2201 additions and 177 deletions

View File

@ -23,6 +23,7 @@ repositories {
dependencies {
compile(files("$rootProject.projectDir/libs/ArchiveUtil.jar"))
compile(files("$rootProject.projectDir/libs/json.jar"))
}
processResources {

Binary file not shown.

BIN
libs/json.jar Executable file

Binary file not shown.

View File

@ -0,0 +1,10 @@
package com.reandroid.lib.apk;
import com.reandroid.archive.InputSource;
public class ApkEntry {
private InputSource mInputSource;
public ApkEntry(InputSource inputSource){
this.mInputSource=inputSource;
}
}

View File

@ -0,0 +1,170 @@
package com.reandroid.lib.apk;
import com.reandroid.archive.APKArchive;
import com.reandroid.archive.InputSource;
import com.reandroid.lib.arsc.array.PackageArray;
import com.reandroid.lib.arsc.chunk.PackageBlock;
import com.reandroid.lib.arsc.chunk.TableBlock;
import com.reandroid.lib.arsc.chunk.xml.AndroidManifestBlock;
import com.reandroid.lib.arsc.group.StringGroup;
import com.reandroid.lib.arsc.item.TableString;
import com.reandroid.lib.arsc.pool.TableStringPool;
import com.reandroid.lib.arsc.value.EntryBlock;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
public class ApkModule {
private final APKArchive apkArchive;
private boolean loadDefaultFramework = true;
private TableBlock mTableBlock;
private AndroidManifestBlock mManifestBlock;
private ApkModule(APKArchive apkArchive){
this.apkArchive=apkArchive;
}
public void writeTo(File file) throws IOException {
APKArchive archive=getApkArchive();
archive.writeApk(file);
}
public void removeDir(String dirName){
getApkArchive().removeDir(dirName);
}
public void setResourcesRootDir(String dirName) throws IOException {
List<ResFile> resFileList = listResFiles();
Set<String> existPaths=new HashSet<>();
List<InputSource> sourceList = getApkArchive().listInputSources();
for(InputSource inputSource:sourceList){
existPaths.add(inputSource.getAlias());
}
for(ResFile resFile:resFileList){
String path=resFile.getFilePath();
String pathNew=ApkUtil.replaceRootDir(path, dirName);
if(existPaths.contains(pathNew)){
continue;
}
existPaths.remove(path);
existPaths.add(pathNew);
resFile.setFilePath(pathNew);
}
TableStringPool stringPool= getTableBlock().getTableStringPool();
stringPool.refreshUniqueIdMap();
}
public List<ResFile> listResFiles() throws IOException {
List<ResFile> results=new ArrayList<>();
TableBlock tableBlock=getTableBlock();
TableStringPool stringPool= tableBlock.getTableStringPool();
for(InputSource inputSource:getApkArchive().listInputSources()){
String name=inputSource.getAlias();
StringGroup<TableString> groupTableString = stringPool.get(name);
if(groupTableString==null){
continue;
}
for(TableString tableString:groupTableString.listItems()){
List<EntryBlock> entryBlockList = tableString.listReferencedEntries();
ResFile resFile=new ResFile(inputSource, entryBlockList);
results.add(resFile);
}
}
return results;
}
public String getPackageName() throws IOException {
if(hasAndroidManifestBlock()){
return getAndroidManifestBlock().getPackageName();
}
if(!hasTableBlock()){
return null;
}
TableBlock tableBlock=getTableBlock();
PackageArray pkgArray = tableBlock.getPackageArray();
PackageBlock pkg = pkgArray.get(0);
if(pkg==null){
return null;
}
return pkg.getPackageName();
}
public void setPackageName(String name) throws IOException {
String old=getPackageName();
if(hasAndroidManifestBlock()){
getAndroidManifestBlock().setPackageName(name);
}
if(!hasTableBlock()){
return;
}
TableBlock tableBlock=getTableBlock();
PackageArray pkgArray = tableBlock.getPackageArray();
for(PackageBlock pkg:pkgArray.listItems()){
if(pkgArray.childesCount()==1){
pkg.setPackageName(name);
continue;
}
String pkgName=pkg.getPackageName();
if(pkgName.startsWith(old)){
pkgName=pkgName.replace(old, name);
pkg.setPackageName(pkgName);
}
}
}
public boolean hasAndroidManifestBlock(){
return mManifestBlock!=null
|| getApkArchive().getInputSource(AndroidManifestBlock.FILE_NAME)!=null;
}
public AndroidManifestBlock getAndroidManifestBlock() throws IOException {
if(mManifestBlock!=null){
return mManifestBlock;
}
APKArchive archive=getApkArchive();
InputSource inputSource = archive.getInputSource(AndroidManifestBlock.FILE_NAME);
if(inputSource==null){
throw new IOException("Entry not found: "+AndroidManifestBlock.FILE_NAME);
}
InputStream inputStream = inputSource.openStream();
AndroidManifestBlock manifestBlock=AndroidManifestBlock.load(inputStream);
inputStream.close();
BlockInputSource<AndroidManifestBlock> blockInputSource=new BlockInputSource<>(inputSource.getName(),manifestBlock);
blockInputSource.setSort(inputSource.getSort());
blockInputSource.setMethod(inputSource.getMethod());
archive.add(blockInputSource);
mManifestBlock=manifestBlock;
return mManifestBlock;
}
public boolean hasTableBlock(){
return mTableBlock!=null
|| getApkArchive().getInputSource(TableBlock.FILE_NAME)!=null;
}
public TableBlock getTableBlock() throws IOException {
if(mTableBlock!=null){
return mTableBlock;
}
APKArchive archive=getApkArchive();
InputSource inputSource = archive.getInputSource(TableBlock.FILE_NAME);
if(inputSource==null){
throw new IOException("Entry not found: "+TableBlock.FILE_NAME);
}
TableBlock tableBlock;
InputStream inputStream = inputSource.openStream();
if(loadDefaultFramework){
tableBlock=TableBlock.loadWithAndroidFramework(inputStream);
}else {
tableBlock=TableBlock.load(inputStream);
}
inputStream.close();
mTableBlock=tableBlock;
BlockInputSource<TableBlock> blockInputSource=new BlockInputSource<>(inputSource.getName(),tableBlock);
blockInputSource.setMethod(inputSource.getMethod());
blockInputSource.setSort(inputSource.getSort());
archive.add(blockInputSource);
return mTableBlock;
}
public APKArchive getApkArchive() {
return apkArchive;
}
public void setLoadDefaultFramework(boolean loadDefaultFramework) {
this.loadDefaultFramework = loadDefaultFramework;
}
public static ApkModule loadApkFile(File apkFile) throws IOException {
APKArchive archive=APKArchive.loadZippedApk(apkFile);
return new ApkModule(archive);
}
}

View File

@ -0,0 +1,15 @@
package com.reandroid.lib.apk;
public class ApkUtil {
public static String replaceRootDir(String path, String dirName){
int i=path.indexOf('/')+1;
path=path.substring(i);
if(dirName != null && dirName.length()>0){
if(!dirName.endsWith("/")){
dirName=dirName+"/";
}
path=dirName+path;
}
return path;
}
}

View File

@ -0,0 +1,24 @@
package com.reandroid.lib.apk;
import com.reandroid.archive.InputSource;
import com.reandroid.lib.arsc.chunk.BaseChunk;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
public class BlockInputSource<T extends BaseChunk> extends InputSource {
private final T mBlock;
public BlockInputSource(String name, T block) {
super(name);
this.mBlock=block;
}
public T getBlock() {
return mBlock;
}
@Override
public InputStream openStream(){
T block=getBlock();
block.refresh();
return new ByteArrayInputStream(block.getBytes());
}
}

View File

@ -0,0 +1,33 @@
package com.reandroid.lib.apk;
import com.reandroid.archive.InputSource;
import com.reandroid.lib.arsc.value.EntryBlock;
import java.util.List;
public class ResFile {
private final List<EntryBlock> entryBlockList;
private final InputSource inputSource;
public ResFile(InputSource inputSource, List<EntryBlock> entryBlockList){
this.inputSource=inputSource;
this.entryBlockList=entryBlockList;
}
public String getFilePath(){
return getInputSource().getAlias();
}
public void setFilePath(String filePath){
getInputSource().setAlias(filePath);
for(EntryBlock entryBlock:entryBlockList){
entryBlock.getValueAsTableString().set(filePath);
}
}
public InputSource getInputSource() {
return inputSource;
}
@Override
public String toString(){
return getFilePath();
}
public static final String DIR_NAME="res";
}

View File

@ -3,9 +3,12 @@ package com.reandroid.lib.arsc.array;
import com.reandroid.lib.arsc.item.IntegerArray;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.value.EntryBlock;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONArray;
import org.json.JSONObject;
public class EntryBlockArray extends OffsetBlockArray<EntryBlock> {
public class EntryBlockArray extends OffsetBlockArray<EntryBlock> implements JsonItem<JSONArray> {
public EntryBlockArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart){
super(offsets, itemCount, itemStart);
}
@ -38,4 +41,42 @@ public class EntryBlockArray extends OffsetBlockArray<EntryBlock> {
return new EntryBlock[len];
}
@Override
public JSONArray toJson() {
JSONArray jsonArray=new JSONArray();
int index=0;
for(EntryBlock entryBlock:listItems()){
JSONObject childObject = entryBlock.toJson();
if(childObject==null){
continue;
}
childObject.put(NAME_id, entryBlock.getIndex());
jsonArray.put(index, childObject);
index++;
}
return jsonArray;
}
@Override
public void fromJson(JSONArray json) {
clearChildes();
int length=json.length();
ensureSize(length);
for(int i=0;i<length;i++){
JSONObject jsonObject= json.getJSONObject(i);
if(jsonObject==null){
continue;
}
int id=jsonObject.getInt(NAME_id);
ensureSize(id+1);
EntryBlock entryBlock=get(id);
entryBlock.fromJson(jsonObject);
}
refreshCountAndStart();
}
@Override
public String toString(){
return toJson().toString(4);
}
private static final String NAME_id="id";
}

View File

@ -1,13 +1,17 @@
package com.reandroid.lib.arsc.array;
import com.reandroid.lib.arsc.base.BlockArray;
import com.reandroid.lib.arsc.container.SpecTypePair;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.value.LibraryInfo;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;
public class LibraryInfoArray extends BlockArray<LibraryInfo> {
public class LibraryInfoArray extends BlockArray<LibraryInfo> implements JsonItem<JSONArray> {
private final IntegerItem mInfoCount;
public LibraryInfoArray(IntegerItem infoCount){
this.mInfoCount=infoCount;
@ -30,4 +34,32 @@ public class LibraryInfoArray extends BlockArray<LibraryInfo> {
setChildesCount(mInfoCount.get());
super.onReadBytes(reader);
}
@Override
public JSONArray toJson() {
JSONArray jsonArray=new JSONArray();
int i=0;
for(LibraryInfo libraryInfo:listItems()){
JSONObject jsonObject= libraryInfo.toJson();
if(jsonObject==null){
continue;
}
jsonArray.put(i, jsonObject);
i++;
}
return jsonArray;
}
@Override
public void fromJson(JSONArray json) {
clearChildes();
if(json==null){
return;
}
int length= json.length();
ensureSize(length);
for (int i=0;i<length;i++){
JSONObject jsonObject=json.getJSONObject(i);
LibraryInfo libraryInfo=get(i);
libraryInfo.fromJson(jsonObject);
}
}
}

View File

@ -3,14 +3,18 @@ package com.reandroid.lib.arsc.array;
import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.base.BlockArray;
import com.reandroid.lib.arsc.chunk.PackageBlock;
import com.reandroid.lib.arsc.container.SpecTypePair;
import com.reandroid.lib.arsc.io.BlockLoad;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;
import java.util.Iterator;
public class PackageArray extends BlockArray<PackageBlock> implements BlockLoad {
public class PackageArray extends BlockArray<PackageBlock> implements BlockLoad, JsonItem<JSONArray> {
private final IntegerItem mPackageCount;
public PackageArray(IntegerItem packageCount){
this.mPackageCount=packageCount;
@ -60,4 +64,29 @@ public class PackageArray extends BlockArray<PackageBlock> implements BlockLoad
setChildesCount(mPackageCount.get());
}
}
@Override
public JSONArray toJson() {
JSONArray jsonArray=new JSONArray();
int i=0;
for(PackageBlock packageBlock:listItems()){
JSONObject jsonObject= packageBlock.toJson();
if(jsonObject==null){
continue;
}
jsonArray.put(i, jsonObject);
i++;
}
return jsonArray;
}
@Override
public void fromJson(JSONArray json) {
int length= json.length();
clearChildes();
ensureSize(length);
for (int i=0;i<length;i++){
JSONObject jsonObject=json.getJSONObject(i);
PackageBlock packageBlock=get(i);
packageBlock.fromJson(jsonObject);
}
}
}

View File

@ -2,8 +2,10 @@ package com.reandroid.lib.arsc.array;
import com.reandroid.lib.arsc.base.BlockArray;
import com.reandroid.lib.arsc.value.ResValueBagItem;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONArray;
public class ResValueBagItemArray extends BlockArray<ResValueBagItem> {
public class ResValueBagItemArray extends BlockArray<ResValueBagItem> implements JsonItem<JSONArray> {
public ResValueBagItemArray(){
super();
}
@ -21,4 +23,28 @@ public class ResValueBagItemArray extends BlockArray<ResValueBagItem> {
protected void onRefreshed() {
}
@Override
public JSONArray toJson() {
JSONArray jsonArray=new JSONArray();
if(isNull()){
return jsonArray;
}
ResValueBagItem[] childes = getChildes();
for(int i=0;i<childes.length;i++){
jsonArray.put(i, childes[i].toJson());
}
return jsonArray;
}
@Override
public void fromJson(JSONArray json){
clearChildes();
if(json==null){
return;
}
int count=json.length();
ensureSize(count);
for(int i=0;i<count;i++){
get(i).fromJson(json.getJSONObject(i));
}
}
}

View File

@ -7,6 +7,9 @@ import com.reandroid.lib.arsc.header.HeaderBlock;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.chunk.xml.ResXmlAttribute;
import com.reandroid.lib.arsc.item.ShortItem;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
@ -14,7 +17,8 @@ import java.util.Collection;
import java.util.Comparator;
import java.util.List;
public class ResXmlAttributeArray extends BlockArray<ResXmlAttribute> implements Comparator<ResXmlAttribute> {
public class ResXmlAttributeArray extends BlockArray<ResXmlAttribute>
implements Comparator<ResXmlAttribute>, JsonItem<JSONArray> {
private final HeaderBlock mHeaderBlock;
private final ShortItem mAttributeStart;
private final ShortItem mAttributeCount;
@ -70,4 +74,27 @@ public class ResXmlAttributeArray extends BlockArray<ResXmlAttribute> implements
public int compare(ResXmlAttribute attr1, ResXmlAttribute attr2) {
return attr1.compareTo(attr2);
}
@Override
public JSONArray toJson() {
JSONArray jsonArray=new JSONArray();
int i=0;
for(ResXmlAttribute attr:listItems()){
JSONObject jsonObject = attr.toJson();
jsonArray.put(i, jsonObject);
i++;
}
return jsonArray;
}
@Override
public void fromJson(JSONArray json) {
clearChildes();
int length= json.length();
ensureSize(length);
for(int i=0;i<length;i++){
ResXmlAttribute attribute=get(i);
JSONObject jsonObject= json.getJSONObject(i);
attribute.fromJson(jsonObject);
}
}
}

View File

@ -4,12 +4,15 @@ import com.reandroid.lib.arsc.base.BlockArray;
import com.reandroid.lib.arsc.header.HeaderBlock;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.ResXmlID;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class ResXmlIDArray extends BlockArray<ResXmlID> {
public class ResXmlIDArray extends BlockArray<ResXmlID> implements JsonItem<JSONArray> {
private final HeaderBlock mHeaderBlock;
private final Map<Integer, ResXmlID> mResIdMap;
private boolean mUpdated;
@ -86,4 +89,23 @@ public class ResXmlIDArray extends BlockArray<ResXmlID> {
count=count/4;
return count;
}
@Override
public JSONArray toJson() {
if(childesCount()==0){
return null;
}
JSONArray jsonArray=new JSONArray();
int i=0;
for(ResXmlID xmlID:listItems()){
JSONObject jsonObject=xmlID.toJson();
jsonArray.put(i,jsonObject);
i++;
}
return jsonArray;
}
@Override
public void fromJson(JSONArray json) {
//TODO
throw new IllegalArgumentException("Not implemented yet");
}
}

View File

@ -4,10 +4,13 @@ import com.reandroid.lib.arsc.base.BlockArray;
import com.reandroid.lib.arsc.chunk.TypeBlock;
import com.reandroid.lib.arsc.container.SpecTypePair;
import com.reandroid.lib.arsc.value.EntryBlock;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.*;
public class SpecTypePairArray extends BlockArray<SpecTypePair> {
public class SpecTypePairArray extends BlockArray<SpecTypePair> implements JsonItem<JSONArray> {
public SpecTypePairArray(){
super();
}
@ -140,4 +143,29 @@ public class SpecTypePairArray extends BlockArray<SpecTypePair> {
}
return results;
}
@Override
public JSONArray toJson() {
JSONArray jsonArray=new JSONArray();
int i=0;
for(SpecTypePair specTypePair:listItems()){
JSONObject jsonObject= specTypePair.toJson();
if(jsonObject==null){
continue;
}
jsonArray.put(i, jsonObject);
i++;
}
return jsonArray;
}
@Override
public void fromJson(JSONArray json) {
int length= json.length();
clearChildes();
ensureSize(length);
for (int i=0;i<length;i++){
JSONObject jsonObject=json.getJSONObject(i);
SpecTypePair specTypePair=get(i);
specTypePair.fromJson(jsonObject);
}
}
}

View File

@ -3,11 +3,14 @@ package com.reandroid.lib.arsc.array;
import com.reandroid.lib.arsc.item.IntegerArray;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.item.StringItem;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public abstract class StringArray<T extends StringItem> extends OffsetBlockArray<T>{
public abstract class StringArray<T extends StringItem> extends OffsetBlockArray<T> implements JsonItem<JSONArray> {
private boolean mUtf8;
public StringArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
@ -50,5 +53,48 @@ public abstract class StringArray<T extends StringItem> extends OffsetBlockArray
protected void refreshChildes(){
// Not required
}
@Override
public JSONArray toJson() {
return toJson(true);
}
public JSONArray toJson(boolean styledOnly) {
if(childesCount()==0){
return null;
}
JSONArray jsonArray=new JSONArray();
int i=0;
for(T item:listItems()){
if(item.isNull()){
continue;
}
if(styledOnly && !item.hasStyle()){
continue;
}
JSONObject jsonObject= item.toJson();
if(jsonObject==null){
continue;
}
jsonArray.put(i, jsonObject);
i++;
}
if(i==0){
return null;
}
return jsonArray;
}
@Override
public void fromJson(JSONArray json) {
clearChildes();
if(json==null){
return;
}
int length = json.length();
ensureSize(length);
for(int i=0; i<length;i++){
T item=get(i);
JSONObject jsonObject = json.getJSONObject(i);
item.fromJson(jsonObject);
}
}
}

View File

@ -5,10 +5,12 @@ import com.reandroid.lib.arsc.item.ByteArray;
import com.reandroid.lib.arsc.item.IntegerArray;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.item.StyleItem;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONArray;
import java.io.IOException;
public class StyleArray extends OffsetBlockArray<StyleItem> {
public class StyleArray extends OffsetBlockArray<StyleItem> implements JsonItem<JSONArray> {
public StyleArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart) {
super(offsets, itemCount, itemStart);
setEndBytes(END_BYTE);
@ -51,5 +53,21 @@ public class StyleArray extends OffsetBlockArray<StyleItem> {
public StyleItem[] newInstance(int len) {
return new StyleItem[len];
}
@Override
public JSONArray toJson() {
if(childesCount()==0){
return null;
}
int i=0;
for(StyleItem styleItem:listItems()){
}
return null;
}
@Override
public void fromJson(JSONArray json) {
}
private static final byte END_BYTE= (byte) 0xFF;
}

View File

@ -3,6 +3,7 @@ package com.reandroid.lib.arsc.array;
import com.reandroid.lib.arsc.item.IntegerArray;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.item.TableString;
import org.json.JSONArray;
public class TableStringArray extends StringArray<TableString> {
public TableStringArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {

View File

@ -10,13 +10,16 @@ import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.TypeString;
import com.reandroid.lib.arsc.value.EntryBlock;
import com.reandroid.lib.arsc.value.ResConfig;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;
public class TypeBlockArray extends BlockArray<TypeBlock> {
public class TypeBlockArray extends BlockArray<TypeBlock> implements JsonItem<JSONArray> {
private byte mTypeId;
public TypeBlockArray(){
super();
@ -232,4 +235,29 @@ public class TypeBlockArray extends BlockArray<TypeBlock> {
}
return null;
}
@Override
public JSONArray toJson() {
JSONArray jsonArray=new JSONArray();
int i=0;
for(TypeBlock typeBlock:listItems()){
JSONObject jsonObject= typeBlock.toJson();
if(jsonObject==null){
continue;
}
jsonArray.put(i, jsonObject);
i++;
}
return jsonArray;
}
@Override
public void fromJson(JSONArray json) {
int length= json.length();
clearChildes();
ensureSize(length);
for (int i=0;i<length;i++){
JSONObject jsonObject=json.getJSONObject(i);
TypeBlock typeBlock=get(i);
typeBlock.fromJson(jsonObject);
}
}
}

View File

@ -33,6 +33,15 @@ abstract class BaseTypeBlock extends BaseChunk {
public void setTypeId(byte id){
mTypeId.set(id);
}
public void setTypeName(String name){
TypeStringPool typeStringPool=getTypeStringPool();
byte id=getTypeId();
TypeString typeString=typeStringPool.getById(id);
if(typeString==null){
typeString=typeStringPool.getOrCreate(id, name);
}
typeString.set(name);
}
public void setEntryCount(int count){
if(count == mEntryCount.get()){
return;

View File

@ -18,18 +18,14 @@ public class LibraryBlock extends BaseChunk {
addToHeader(mLibCount);
addChild(mLibraryInfoArray);
}
public LibraryInfo[] getAllInfo(){
return mLibraryInfoArray.getChildes();
public LibraryInfoArray getLibraryInfoArray(){
return mLibraryInfoArray;
}
public void addLibraryInfo(LibraryBlock libraryBlock){
if(libraryBlock==null){
return;
}
LibraryInfo[] allInfo=libraryBlock.getAllInfo();
if (allInfo==null){
return;
}
for(LibraryInfo info:allInfo){
for(LibraryInfo info:libraryBlock.getLibraryInfoArray().listItems()){
addLibraryInfo(info);
}
}
@ -37,11 +33,11 @@ public class LibraryBlock extends BaseChunk {
if(info==null){
return;
}
mLibraryInfoArray.add(info);
getLibraryInfoArray().add(info);
mLibCount.set(mLibraryInfoArray.childesCount());
}
public Collection<LibraryInfo> listLibraryInfo(){
return mLibraryInfoArray.listItems();
return getLibraryInfoArray().listItems();
}
@Override
public boolean isNull(){

View File

@ -1,5 +1,6 @@
package com.reandroid.lib.arsc.chunk;
import com.reandroid.lib.arsc.array.LibraryInfoArray;
import com.reandroid.lib.arsc.array.SpecTypePairArray;
import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.container.PackageLastBlocks;
@ -14,11 +15,13 @@ import com.reandroid.lib.arsc.pool.TableStringPool;
import com.reandroid.lib.arsc.pool.TypeStringPool;
import com.reandroid.lib.arsc.value.EntryBlock;
import com.reandroid.lib.arsc.value.LibraryInfo;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONObject;
import java.util.*;
public class PackageBlock extends BaseChunk {
public class PackageBlock extends BaseChunk implements JsonItem<JSONObject> {
private final IntegerItem mPackageId;
private final PackageName mPackageName;
@ -157,11 +160,7 @@ public class PackageBlock extends BaseChunk {
if(libraryBlock==null){
return;
}
LibraryInfo[] allInfo=libraryBlock.getAllInfo();
if (allInfo==null){
return;
}
for(LibraryInfo info:allInfo){
for(LibraryInfo info:libraryBlock.getLibraryInfoArray().listItems()){
addLibraryInfo(info);
}
}
@ -268,6 +267,26 @@ public class PackageBlock extends BaseChunk {
refreshKeyStrings();
}
@Override
public JSONObject toJson() {
JSONObject jsonObject=new JSONObject();
jsonObject.put(NAME_id, getId());
jsonObject.put(NAME_name, getName());
jsonObject.put(NAME_specs, getSpecTypePairArray().toJson());
LibraryInfoArray libraryInfoArray = mLibraryBlock.getLibraryInfoArray();
if(libraryInfoArray.childesCount()>0){
jsonObject.put(NAME_libraries,libraryInfoArray.toJson());
}
return jsonObject;
}
@Override
public void fromJson(JSONObject json) {
setId(json.getInt(NAME_id));
setName(json.getString(NAME_name));
getSpecTypePairArray().fromJson(json.getJSONArray(NAME_specs));
LibraryInfoArray libraryInfoArray = mLibraryBlock.getLibraryInfoArray();
libraryInfoArray.fromJson(json.optJSONArray(NAME_libraries));
}
@Override
public String toString(){
StringBuilder builder=new StringBuilder();
@ -283,4 +302,9 @@ public class PackageBlock extends BaseChunk {
}
return builder.toString();
}
private static final String NAME_id="id";
private static final String NAME_name="name";
private static final String NAME_specs="specs";
private static final String NAME_libraries="libraries";
}

View File

@ -7,10 +7,12 @@ import com.reandroid.lib.arsc.io.BlockLoad;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.IntegerArray;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONObject;
import java.io.IOException;
public class SpecBlock extends BaseTypeBlock implements BlockLoad {
public class SpecBlock extends BaseTypeBlock implements BlockLoad , JsonItem<JSONObject> {
private final IntegerArray mOffsets;
public SpecBlock() {
super(ChunkType.SPEC, 1);
@ -51,4 +53,16 @@ public class SpecBlock extends BaseTypeBlock implements BlockLoad {
}
return builder.toString();
}
@Override
public JSONObject toJson() {
JSONObject jsonObject=new JSONObject();
jsonObject.put("id", getTypeId());
return jsonObject;
}
@Override
public void fromJson(JSONObject json) {
setTypeId((byte) json.getInt("id"));
}
}

View File

@ -8,13 +8,16 @@ import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.pool.TableStringPool;
import com.reandroid.lib.common.Frameworks;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
public class TableBlock extends BaseChunk {
public class TableBlock extends BaseChunk implements JsonItem<JSONObject> {
private final IntegerItem mPackageCount;
private final TableStringPool mTableStringPool;
private final PackageArray mPackageArray;
@ -116,10 +119,33 @@ public class TableBlock extends BaseChunk {
}
mFrameWorks.add(tableBlock);
}
@Override
public JSONObject toJson() {
JSONObject jsonObject=new JSONObject();
jsonObject.put(NAME_packages, getPackageArray().toJson());
JSONArray jsonArray = getTableStringPool().toJson();
if(jsonArray!=null){
jsonObject.put(NAME_styled_strings, jsonArray);
}
return jsonObject;
}
@Override
public void fromJson(JSONObject json) {
JSONArray jsonArray= json.optJSONArray(NAME_styled_strings);
if(jsonArray!=null){
getTableStringPool().fromJson(jsonArray);
}
getPackageArray().fromJson(json.getJSONArray(NAME_packages));
refresh();
}
public static TableBlock loadWithAndroidFramework(InputStream inputStream) throws IOException{
TableBlock tableBlock=load(inputStream);
tableBlock.addFramework(Frameworks.getAndroid());
return tableBlock;
}
public static TableBlock load(InputStream inputStream) throws IOException{
TableBlock tableBlock=new TableBlock();
tableBlock.readBytes(inputStream);
tableBlock.addFramework(Frameworks.getAndroid());
return tableBlock;
}
@ -164,4 +190,6 @@ public class TableBlock extends BaseChunk {
}
public static final String FILE_NAME="resources.arsc";
private static final String NAME_packages="packages";
private static final String NAME_styled_strings="styled_strings";
}

View File

@ -5,14 +5,17 @@ import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.container.SpecTypePair;
import com.reandroid.lib.arsc.item.IntegerArray;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.item.TypeString;
import com.reandroid.lib.arsc.value.EntryBlock;
import com.reandroid.lib.arsc.value.ResConfig;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class TypeBlock extends BaseTypeBlock {
public class TypeBlock extends BaseTypeBlock implements JsonItem<JSONObject> {
private final IntegerItem mEntriesStart;
private final ResConfig mResConfig;
private final IntegerArray mEntryOffsets;
@ -113,6 +116,28 @@ public class TypeBlock extends BaseTypeBlock {
super.onPreRefreshRefresh();
}
@Override
public JSONObject toJson() {
JSONObject jsonObject=new JSONObject();
jsonObject.put("id", getTypeId());
TypeString typeString=getTypeString();
if(typeString!=null){
jsonObject.put("name", typeString.get());
}
jsonObject.put("config", getResConfig().toJson());
jsonObject.put("entries", getEntryBlockArray().toJson());
return jsonObject;
}
@Override
public void fromJson(JSONObject json) {
setTypeId((byte) json.getInt("id"));
String name= json.optString("name");
if(name!=null){
setTypeName(name);
}
getEntryBlockArray().fromJson(json.getJSONArray("entries"));
getResConfig().fromJson(json.getJSONObject("config"));
}
@Override
public String toString(){
StringBuilder builder=new StringBuilder();
builder.append(getResConfig().toString());

View File

@ -4,6 +4,10 @@ import com.reandroid.lib.arsc.item.ResXmlString;
import com.reandroid.lib.arsc.pool.ResXmlStringPool;
import com.reandroid.lib.arsc.value.ValueType;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
@ -219,6 +223,14 @@ public class AndroidManifestBlock extends ResXmlBlock{
builder.append("}");
return builder.toString();
}
public static AndroidManifestBlock load(File file) throws IOException {
return load(new FileInputStream(file));
}
public static AndroidManifestBlock load(InputStream inputStream) throws IOException {
AndroidManifestBlock manifestBlock=new AndroidManifestBlock();
manifestBlock.readBytes(inputStream);
return manifestBlock;
}
public static final String TAG_manifest ="manifest";
public static final String TAG_uses_permission="uses-permission";
public static final String TAG_application ="application";

View File

@ -6,8 +6,11 @@ import com.reandroid.lib.arsc.container.FixedBlockContainer;
import com.reandroid.lib.arsc.item.*;
import com.reandroid.lib.arsc.pool.ResXmlStringPool;
import com.reandroid.lib.arsc.value.ValueType;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONObject;
public class ResXmlAttribute extends FixedBlockContainer implements Comparable<ResXmlAttribute>{
public class ResXmlAttribute extends FixedBlockContainer
implements Comparable<ResXmlAttribute>, JsonItem<JSONObject> {
private final IntegerItem mNamespaceReference;
private final IntegerItem mNameReference;
private final IntegerItem mValueStringReference;
@ -105,6 +108,17 @@ public class ResXmlAttribute extends FixedBlockContainer implements Comparable<R
}
return startNamespace.getPrefix();
}
public String getNamespace(){
ResXmlElement xmlElement=getParentResXmlElement();
if(xmlElement==null){
return null;
}
ResXmlStartNamespace startNamespace=xmlElement.getStartNamespaceByUriRef(getNamespaceReference());
if(startNamespace==null){
return null;
}
return startNamespace.getUri();
}
public ResXmlStartNamespace getStartNamespace(){
ResXmlElement xmlElement=getParentResXmlElement();
if(xmlElement==null){
@ -344,6 +358,43 @@ public class ResXmlAttribute extends FixedBlockContainer implements Comparable<R
return getCompareName().compareTo(other.getCompareName());
}
@Override
public JSONObject toJson() {
JSONObject jsonObject=new JSONObject();
jsonObject.put(NAME_name, getName());
jsonObject.put(NAME_id, getNameResourceID());
jsonObject.put(NAME_namespace_uri, getNamespace());
jsonObject.put(NAME_namespace_prefix, getNamePrefix());
ValueType valueType=getValueType();
jsonObject.put(NAME_value_type, valueType.name());
if(valueType==ValueType.STRING){
jsonObject.put(NAME_data, getValueAsString());
}else if(valueType==ValueType.INT_BOOLEAN){
jsonObject.put(NAME_data, getValueAsBoolean());
}else {
jsonObject.put(NAME_data, getRawValue());
}
return jsonObject;
}
@Override
public void fromJson(JSONObject json) {
String name = json.getString(NAME_name);
int id = json.optInt(NAME_id);
setName(name, id);
String uri= json.optString(NAME_namespace_uri);
String prefix= json.optString(NAME_namespace_prefix);
ResXmlStartNamespace ns = getParentResXmlElement().getOrCreateNamespace(uri, prefix);
setNamespaceReference(ns.getUriReference());
ValueType valueType=ValueType.fromName(json.getString(NAME_value_type));
if(valueType==ValueType.STRING){
setValueAsString(json.getString(NAME_data));
}else if(valueType==ValueType.INT_BOOLEAN){
setValueAsBoolean(json.getBoolean(NAME_data));
}else {
setValueType(valueType);
setRawValue(json.getInt(NAME_data));
}
}
@Override
public String toString(){
String fullName=getFullName();
@ -372,4 +423,10 @@ public class ResXmlAttribute extends FixedBlockContainer implements Comparable<R
builder.append("}");
return builder.toString();
}
private static final String NAME_id="id";
private static final String NAME_value_type="value_type";
private static final String NAME_name="name";
private static final String NAME_namespace_uri ="namespace_uri";
private static final String NAME_namespace_prefix ="namespace_name";
private static final String NAME_data="data";
}

View File

@ -6,10 +6,13 @@ 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.json.JsonItem;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.*;
public class ResXmlBlock extends BaseChunk {
public class ResXmlBlock extends BaseChunk implements JsonItem<JSONObject> {
private final ResXmlStringPool mResXmlStringPool;
private final ResXmlIDMap mResXmlIDMap;
private ResXmlElement mResXmlElement;
@ -129,6 +132,26 @@ public class ResXmlBlock extends BaseChunk {
outputStream.close();
return length;
}
@Override
public JSONObject toJson() {
JSONObject jsonObject=new JSONObject();
jsonObject.put(NAME_element, getResXmlElement().toJson());
JSONArray pool =getStringPool().toJson();
if(pool!=null){
jsonObject.put(NAME_styled_strings, getResXmlElement().toJson());
}
JSONArray idArray = getResXmlIDMap().getResXmlIDArray().toJson();
if(idArray!=null){
jsonObject.put("resource_ids", idArray);
}
return jsonObject;
}
@Override
public void fromJson(JSONObject json) {
// TODO
throw new IllegalArgumentException("Not implemented yet");
}
public static boolean isResXmlBlock(File file){
if(file==null){
@ -167,4 +190,6 @@ public class ResXmlBlock extends BaseChunk {
ChunkType chunkType=headerBlock.getChunkType();
return chunkType==ChunkType.XML;
}
private static final String NAME_element ="element";
private static final String NAME_styled_strings="styled_strings";
}

View File

@ -9,6 +9,9 @@ import com.reandroid.lib.arsc.header.HeaderBlock;
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.json.JsonItem;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;
@ -16,7 +19,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class ResXmlElement extends FixedBlockContainer {
public class ResXmlElement extends FixedBlockContainer implements JsonItem<JSONObject> {
private final BlockList<ResXmlStartNamespace> mStartNamespaceList;
private final SingleBlockContainer<ResXmlStartElement> mStartElementContainer;
private final BlockList<ResXmlElement> mBody;
@ -492,6 +495,55 @@ public class ResXmlElement extends FixedBlockContainer {
}
}
@Override
public JSONObject toJson() {
JSONObject jsonObject=new JSONObject();
ResXmlStartElement start = getStartElement();
jsonObject.put(NAME_line, start.getLineNumber());
int i=0;
JSONArray nsList=new JSONArray();
for(ResXmlStartNamespace namespace:getStartNamespaceList()){
JSONObject ns=new JSONObject();
ns.put(NAME_namespace_uri, namespace.getUri());
ns.put(NAME_namespace_prefix, namespace.getPrefix());
nsList.put(i, ns);
i++;
}
if(i>0){
jsonObject.put(NAME_namespaces, nsList);
}
jsonObject.put(NAME_name, start.getName());
String uri=start.getUri();
if(uri!=null){
jsonObject.put(NAME_namespace_uri, uri);
jsonObject.put(NAME_namespace_prefix, start.getPrefix());
}
JSONArray attrArray=start.getResXmlAttributeArray().toJson();
jsonObject.put(NAME_attributes, attrArray);
i=0;
JSONArray childes=new JSONArray();
for(ResXmlElement element:listElements()){
childes.put(i, element.toJson());
i++;
}
if(i>0){
jsonObject.put(NAME_childes, childes);
}
return jsonObject;
}
@Override
public void fromJson(JSONObject json) {
ResXmlStartElement start = getStartElement();
start.setLineNumber(json.getInt(NAME_line));
String uri= json.optString(NAME_namespace_uri);
String prefix= json.optString(NAME_namespace_prefix);
if(uri!=null && prefix!=null){
ResXmlStartNamespace ns = getOrCreateNamespace(uri, prefix);
start.setNamespaceReference(ns.getUriReference());
}
JSONArray attributes = json.getJSONArray(NAME_attributes);
start.getResXmlAttributeArray().fromJson(attributes);
}
@Override
public String toString(){
ResXmlStartElement start = getStartElement();
if(start!=null){
@ -524,4 +576,12 @@ public class ResXmlElement extends FixedBlockContainer {
public static final String NS_ANDROID_URI = "http://schemas.android.com/apk/res/android";
public static final String NS_ANDROID_PREFIX = "android";
private static final String NAME_name = "name";
private static final String NAME_namespaces = "namespaces";
private static final String NAME_namespace_uri = "namespace_uri";
private static final String NAME_namespace_prefix = "namespace_name";
private static final String NAME_line = "line";
private static final String NAME_attributes = "attributes";
private static final String NAME_childes = "childes";
}

View File

@ -74,6 +74,19 @@ public class ResXmlStartElement extends BaseXmlChunk {
public ResXmlAttributeArray getResXmlAttributeArray(){
return mAttributeArray;
}
public String getUri(){
int uriRef=getNamespaceReference();
if(uriRef<0){
return null;
}
ResXmlElement parentElement=getParentResXmlElement();
ResXmlStartNamespace startNamespace=parentElement.getStartNamespaceByUriRef(uriRef);
if(startNamespace!=null){
return startNamespace.getUri();
}
return null;
}
public String getPrefix(){
int uriRef=getNamespaceReference();
if(uriRef<0){

View File

@ -12,6 +12,8 @@ import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.TypeString;
import com.reandroid.lib.arsc.value.EntryBlock;
import com.reandroid.lib.arsc.value.ResConfig;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
@ -19,7 +21,7 @@ import java.util.Collection;
import java.util.Iterator;
import java.util.List;
public class SpecTypePair extends BlockContainer<Block> {
public class SpecTypePair extends BlockContainer<Block> implements JsonItem<JSONObject> {
private final Block[] mChildes;
private final SpecBlock mSpecBlock;
private final TypeBlockArray mTypeBlockArray;
@ -140,4 +142,17 @@ public class SpecTypePair extends BlockContainer<Block> {
public TypeString getTypeString(){
return getTypeBlockArray().getTypeString();
}
@Override
public JSONObject toJson() {
JSONObject jsonObject=new JSONObject();
jsonObject.put("id", getSpecBlock().getTypeId());
jsonObject.put("types", getTypeBlockArray().toJson());
return jsonObject;
}
@Override
public void fromJson(JSONObject json) {
getSpecBlock().setTypeId((byte) json.getInt("id"));
getTypeBlockArray().fromJson(json.getJSONArray("types"));
}
}

View File

@ -28,13 +28,28 @@ public class EntryGroup extends ItemGroup<EntryBlock> {
if(specStringPool==null){
return false;
}
String oldName=getSpecName();
if(name.equals(oldName)){
return false;
if(isAllSameSpec()){
String oldName=getSpecName();
if(name.equals(oldName)){
return false;
}
}
SpecString specString=specStringPool.getOrCreate(name);
return renameSpec(specString.getIndex());
}
private boolean isAllSameSpec(){
EntryBlock first=null;
for(EntryBlock entryBlock:listItems()){
if(first==null){
first=entryBlock;
continue;
}
if(first.getSpecReference()!=entryBlock.getSpecReference()){
return false;
}
}
return true;
}
public boolean renameSpec(int specReference){
EntryBlock[] items=getItems();
if(items==null){

View File

@ -1,10 +1,16 @@
package com.reandroid.lib.arsc.item;
import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.chunk.xml.ResXmlBlock;
import com.reandroid.lib.arsc.pool.ResXmlStringPool;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class ResXmlID extends IntegerItem {
public class ResXmlID extends IntegerItem implements JsonItem<JSONObject> {
private final List<ReferenceItem> mReferencedList;
public ResXmlID(int resId){
super(resId);
@ -47,6 +53,29 @@ public class ResXmlID extends IntegerItem {
public void onIndexChanged(int oldIndex, int newIndex){
reUpdateReferences(newIndex);
}
private ResXmlStringPool getXmlStringPool(){
Block parent=this;
while (parent!=null){
if(parent instanceof ResXmlBlock){
return ((ResXmlBlock)parent).getStringPool();
}
parent=parent.getParent();
}
return null;
}
@Override
public JSONObject toJson() {
JSONObject jsonObject=new JSONObject();
jsonObject.put("id", get());
jsonObject.put("name", getXmlStringPool().get(getIndex()).getHtml());
return jsonObject;
}
@Override
public void fromJson(JSONObject json) {
//TODO
throw new IllegalArgumentException("Not implemented yet");
}
@Override
public String toString(){
return getIndex()+": "+String.format("0x%08x", get());

View File

@ -3,6 +3,8 @@ package com.reandroid.lib.arsc.item;
import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.pool.BaseStringPool;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONObject;
import java.io.IOException;
@ -15,7 +17,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class StringItem extends BlockItem {
public class StringItem extends BlockItem implements JsonItem<JSONObject> {
private String mCache;
private boolean mUtf8;
private final List<ReferenceItem> mReferencedList;
@ -166,27 +168,54 @@ public class StringItem extends BlockItem {
return new String(allStringBytes, offLen[0], offLen[1], StandardCharsets.UTF_16LE);
}
}
public boolean hasStyle(){
StyleItem styleItem=getStyle();
if(styleItem==null){
return false;
}
return !styleItem.isNull();
}
public StyleItem getStyle(){
BaseStringPool stringPool=getStringPool();
BaseStringPool<?> stringPool=getStringPool();
if(stringPool==null){
return null;
}
int index=getIndex();
return stringPool.getStyle(index);
}
private BaseStringPool getStringPool(){
private BaseStringPool<?> getStringPool(){
Block parent=getParent();
while (parent!=null){
if(parent instanceof BaseStringPool){
return (BaseStringPool)parent;
return (BaseStringPool<?>)parent;
}
parent=parent.getParent();
}
return null;
}
@Override
public JSONObject toJson() {
if(isNull()){
return null;
}
JSONObject jsonObject=new JSONObject();
jsonObject.put(NAME_string, get());
StyleItem styleItem=getStyle();
if(styleItem!=null){
JSONObject styleJson=styleItem.toJson();
if(styleJson!=null){
jsonObject.put(NAME_style, styleJson);
}
}
return jsonObject;
}
@Override
public void fromJson(JSONObject json) {
String str = json.getString(NAME_string);
set(str);
throw new IllegalArgumentException("Not implemented");
}
@Override
public String toString(){
String str=get();
if(str==null){
@ -332,4 +361,7 @@ public class StringItem extends BlockItem {
private final CharsetDecoder UTF16LE_DECODER = StandardCharsets.UTF_16LE.newDecoder();
private final CharsetDecoder UTF8_DECODER = StandardCharsets.UTF_8.newDecoder();
private static final String NAME_string="string";
private static final String NAME_style="style";
}

View File

@ -4,16 +4,19 @@ import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.model.StyleSpanInfo;
import com.reandroid.lib.arsc.pool.BaseStringPool;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;
public class StyleItem extends IntegerArray{
private List<int[]> mStyleList;
public class StyleItem extends IntegerArray implements JsonItem<JSONObject> {
private List<StyleSpanInfo> mSpanInfoList;
public StyleItem() {
super();
mStyleList=createStyleList();
}
private void setEndValue(int negOne){
super.put(size()-1, negOne);
@ -22,54 +25,67 @@ public class StyleItem extends IntegerArray{
return super.get(size()-1);
}
final Integer getStringRef(int index){
int i=index*STYLE_PIECE_COUNT+STRING_REF;
int i=index * INTEGERS_COUNT + INDEX_STRING_REF;
return super.get(i);
}
final void setStringRef(int index, int val){
int i=index*STYLE_PIECE_COUNT+STRING_REF;
int i=index * INTEGERS_COUNT + INDEX_STRING_REF;
super.put(i, val);
}
final Integer getFirstChar(int index){
int i=index*STYLE_PIECE_COUNT+CHAR_FIRST;
int i=index * INTEGERS_COUNT + INDEX_CHAR_FIRST;
return super.get(i);
}
final void setFirstChar(int index, int val){
int i=index*STYLE_PIECE_COUNT+CHAR_FIRST;
int i=index * INTEGERS_COUNT + INDEX_CHAR_FIRST;
super.put(i, val);
}
final Integer getLastChar(int index){
int i=index*STYLE_PIECE_COUNT+CHAR_LAST;
int i=index * INTEGERS_COUNT + INDEX_CHAR_LAST;
return super.get(i);
}
final void setLastChar(int index, int val){
int i=index*STYLE_PIECE_COUNT+CHAR_LAST;
int i=index * INTEGERS_COUNT + INDEX_CHAR_LAST;
super.put(i, val);
}
public void addStylePiece(String tag, int firstChar, int lastChar){
BaseStringPool<?> stringPool = getStringPool();
if(stringPool==null){
throw new IllegalArgumentException("Null string pool, must be added to parent StyleArray first");
}
StringItem stringItem=stringPool.getOrCreate(tag);
addStylePiece(stringItem.getIndex(), firstChar, lastChar);
}
public void addStylePiece(int refString, int firstChar, int lastChar){
int index=getStylePieceCount();
setStylePieceCount(index+1);
setStylePiece(index, refString, firstChar, lastChar);
}
final void setStylePiece(int index, int refString, int firstChar, int lastChar){
int i=index*STYLE_PIECE_COUNT;
super.put(i+STRING_REF, refString);
super.put(i+CHAR_FIRST, firstChar);
super.put(i+CHAR_LAST, lastChar);
int i=index * INTEGERS_COUNT;
super.put(i+ INDEX_STRING_REF, refString);
super.put(i+ INDEX_CHAR_FIRST, firstChar);
super.put(i+ INDEX_CHAR_LAST, lastChar);
}
final int[] getStylePiece(int index){
if(index<0||index>= getStylePieceCount()){
return null;
}
int[] result=new int[STYLE_PIECE_COUNT];
int i=index*STYLE_PIECE_COUNT;
result[STRING_REF]=super.get(i);
result[CHAR_FIRST]=super.get(i+CHAR_FIRST);
result[CHAR_LAST]=super.get(i+CHAR_LAST);
int[] result=new int[INTEGERS_COUNT];
int i=index * INTEGERS_COUNT;
result[INDEX_STRING_REF]=super.get(i);
result[INDEX_CHAR_FIRST]=super.get(i+ INDEX_CHAR_FIRST);
result[INDEX_CHAR_LAST]=super.get(i+ INDEX_CHAR_LAST);
return result;
}
final void setStylePiece(int index, int[] three){
if(three==null || three.length<STYLE_PIECE_COUNT){
if(three==null || three.length< INTEGERS_COUNT){
return;
}
int i=index*STYLE_PIECE_COUNT;
super.put(i+STRING_REF, three[STRING_REF]);
super.put(i+CHAR_FIRST, three[CHAR_FIRST]);
super.put(i+CHAR_LAST, three[CHAR_LAST]);
int i = index * INTEGERS_COUNT;
super.put(i + INDEX_STRING_REF, three[INDEX_STRING_REF]);
super.put(i + INDEX_CHAR_FIRST, three[INDEX_CHAR_FIRST]);
super.put(i + INDEX_CHAR_LAST, three[INDEX_CHAR_LAST]);
}
final void ensureStylePieceCount(int count){
if(count<0){
@ -84,23 +100,23 @@ public class StyleItem extends IntegerArray{
if(sz<0){
sz=0;
}
return sz/STYLE_PIECE_COUNT;
return sz/ INTEGERS_COUNT;
}
final void setStylePieceCount(int count){
if(count<0){
count=0;
}
int cur= getStylePieceCount();
int cur = getStylePieceCount();
if(count==cur){
return;
}
int max=count*STYLE_PIECE_COUNT+1;
int max=count * INTEGERS_COUNT + 1;
if(size()==0 || count==0){
super.setSize(max);
setEndValue(END_VALUE);
return;
}
List<int[]> copy=new ArrayList<>(mStyleList);
List<int[]> copy=new ArrayList<>(getIntSpanInfoList());
Integer end= getEndValue();
if(end==null){
end=END_VALUE;
@ -117,42 +133,54 @@ public class StyleItem extends IntegerArray{
}
setEndValue(end);
}
final List<int[]> getStyleList(){
return mStyleList;
private List<int[]> getIntSpanInfoList(){
return new AbstractList<int[]>() {
@Override
public int[] get(int i) {
return StyleItem.this.getStylePiece(i);
}
@Override
public int size() {
return StyleItem.this.getStylePieceCount();
}
};
}
private List<int[]> createStyleList(){
List<int[]> results=new ArrayList<>();
int max=getStylePieceCount();
for(int i=0;i<max;i++){
results.add(getStylePiece(i));
final List<StyleSpanInfo> getSpanInfoList(){
if(mSpanInfoList!=null){
return mSpanInfoList;
}
return results;
mSpanInfoList = new AbstractList<StyleSpanInfo>() {
@Override
public StyleSpanInfo get(int i) {
int ref=getStringRef(i);
return new StyleSpanInfo(
getStringFromPool(ref),
getFirstChar(i),
getLastChar(i));
}
@Override
public int size() {
return getStylePieceCount();
}
};
return mSpanInfoList;
}
final List<StyleSpanInfo> getSpanInfo(){
BaseStringPool stringPool= getStringPool();
private String getStringFromPool(int ref){
BaseStringPool<?> stringPool = getStringPool();
if(stringPool==null){
return null;
}
List<int[]> allPiece=getStyleList();
List<StyleSpanInfo> results=new ArrayList<>();
for(int[] piece:allPiece){
StringItem stringItem=stringPool.get(piece[STRING_REF]);
if(stringItem==null){
return null;
}
StyleSpanInfo info=new StyleSpanInfo(stringItem.get(), piece[CHAR_FIRST], piece[CHAR_LAST]);
results.add(info);
}
if(results.size()==0){
StringItem stringItem = stringPool.get(ref);
if(stringItem==null){
return null;
}
return results;
return stringItem.get();
}
private BaseStringPool getStringPool(){
private BaseStringPool<?> getStringPool(){
Block parent=getParent();
while (parent!=null){
if(parent instanceof BaseStringPool){
return (BaseStringPool)parent;
return (BaseStringPool<?>)parent;
}
parent=parent.getParent();
}
@ -163,8 +191,8 @@ public class StyleItem extends IntegerArray{
if(str==null){
return null;
}
List<StyleSpanInfo> allInfo=getSpanInfo();
if(allInfo==null){
List<StyleSpanInfo> spanInfoList = getSpanInfoList();
if(spanInfoList.size()==0){
return str;
}
StringBuilder builder=new StringBuilder();
@ -173,9 +201,9 @@ public class StyleItem extends IntegerArray{
for(int i=0;i<max;i++){
char ch=allChars[i];
boolean lastAppend=false;
for(StyleSpanInfo info:allInfo){
boolean isLast=(info.LAST==i);
if(info.FIRST==i || isLast){
for(StyleSpanInfo info:spanInfoList){
boolean isLast=(info.getLast()==i);
if(info.getFirst()==i || isLast){
if(isLast && !lastAppend){
builder.append(ch);
lastAppend=true;
@ -195,7 +223,6 @@ public class StyleItem extends IntegerArray{
}
@Override
public void onBytesChanged() {
mStyleList=createStyleList();
}
@Override
public void setNull(boolean is_null){
@ -216,11 +243,57 @@ public class StyleItem extends IntegerArray{
reader.readFully(bts);
onBytesChanged();
}
private static final int STRING_REF=0;
private static final int CHAR_FIRST=1;
private static final int CHAR_LAST=2;
public void addSpanInfo(String tag, int first, int last){
int index=getStylePieceCount();
setStylePieceCount(index+1);
BaseStringPool<?> stringPool = getStringPool();
if(stringPool==null){
throw new IllegalArgumentException("Null string pool, must be added to parent StyleArray first");
}
StringItem stringItem=stringPool.getOrCreate(tag);
setStylePiece(index, stringItem.getIndex(), first, last);
}
@Override
public JSONObject toJson() {
if(isNull()){
return null;
}
JSONObject jsonObject=new JSONObject();
JSONArray jsonArray=new JSONArray();
int i=0;
for(StyleSpanInfo spanInfo:getSpanInfoList()){
JSONObject jsonObjectSpan=spanInfo.toJson();
jsonArray.put(i, jsonObjectSpan);
i++;
}
jsonObject.put(NAME_spans, jsonArray);
return jsonObject;
}
@Override
public void fromJson(JSONObject json) {
setNull(true);
if(json==null){
return;
}
JSONArray jsonArray= json.getJSONArray(NAME_spans);
int length = jsonArray.length();
for(int i=0;i<length;i++){
JSONObject jsonObject=jsonArray.getJSONObject(i);
StyleSpanInfo spanInfo=new StyleSpanInfo(null, 0, 0);
spanInfo.fromJson(jsonObject);
addSpanInfo(spanInfo.getTag(), spanInfo.getFirst(), spanInfo.getLast());
}
}
@Override
public String toString(){
return "Spans count = "+getSpanInfoList().size();
}
private static final int INDEX_STRING_REF = 0;
private static final int INDEX_CHAR_FIRST = 1;
private static final int INDEX_CHAR_LAST = 2;
private static final int STYLE_PIECE_COUNT=3;
private static final int INTEGERS_COUNT = 3;
private static final int END_VALUE=0xFFFFFFFF;
private static final String NAME_spans="spans";
}

View File

@ -1,11 +1,29 @@
package com.reandroid.lib.arsc.item;
import com.reandroid.lib.arsc.value.EntryBlock;
import com.reandroid.lib.arsc.value.ResValueReference;
import java.util.ArrayList;
import java.util.List;
public class TableString extends StringItem {
public TableString(boolean utf8) {
super(utf8);
}
public List<EntryBlock> listReferencedEntries(){
List<EntryBlock> results=new ArrayList<>();
for(ReferenceItem ref:getReferencedList()){
if(!(ref instanceof ResValueReference)){
continue;
}
EntryBlock entryBlock=((ResValueReference)ref).getEntryBlock();
if(entryBlock==null){
continue;
}
results.add(entryBlock);
}
return results;
}
@Override
public String toString(){
List<ReferenceItem> refList = getReferencedList();

View File

@ -1,44 +1,84 @@
package com.reandroid.lib.arsc.model;
public class StyleSpanInfo {
public final String TAG;
public final int FIRST;
public final int LAST;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONObject;
public class StyleSpanInfo implements JsonItem<JSONObject> {
private String mTag;
private int mFirst;
private int mLast;
public StyleSpanInfo(String tag, int first, int last){
this.TAG=tag;
this.FIRST=first;
this.LAST=last;
this.mTag = tag;
this.mFirst = first;
this.mLast = last;
}
public int getFirst() {
return mFirst;
}
public void setFirst(int first) {
this.mFirst = first;
}
public int getLast() {
return mLast;
}
public void setLast(int last) {
this.mLast = last;
}
public String getTag() {
return mTag;
}
public void setTag(String tag) {
this.mTag = tag;
}
public String getStartTag(){
int i=TAG.indexOf(';');
int i= mTag.indexOf(';');
StringBuilder builder=new StringBuilder();
builder.append('<');
if(i<0){
builder.append(TAG);
builder.append(mTag);
}else {
builder.append(TAG, 0, i);
builder.append(mTag, 0, i);
builder.append(' ');
builder.append(TAG.substring(i+1));
builder.append(mTag.substring(i+1));
}
builder.append('>');
return builder.toString();
}
public String getEndTag(){
int i=TAG.indexOf(';');
int i= mTag.indexOf(';');
StringBuilder builder=new StringBuilder();
builder.append('<');
builder.append('/');
if(i<0){
builder.append(TAG);
builder.append(mTag);
}else {
builder.append(TAG, 0, i);
builder.append(mTag, 0, i);
}
builder.append('>');
return builder.toString();
}
@Override
public String toString(){
return TAG+" ("+FIRST+", "+LAST+")";
public JSONObject toJson() {
JSONObject jsonObject=new JSONObject();
jsonObject.put(NAME_tag, mTag);
jsonObject.put(NAME_first, mFirst);
jsonObject.put(NAME_last, mLast);
return jsonObject;
}
@Override
public void fromJson(JSONObject json) {
setTag(json.getString(NAME_tag));
setFirst(json.getInt(NAME_first));
setLast(json.getInt(NAME_last));
}
@Override
public String toString(){
return mTag +" ("+ mFirst +", "+ mLast +")";
}
private static final String NAME_tag="tag";
private static final String NAME_first="first";
private static final String NAME_last="last";
}

View File

@ -10,12 +10,14 @@ import com.reandroid.lib.arsc.io.BlockLoad;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.*;
import com.reandroid.lib.arsc.pool.builder.StyleBuilder;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONArray;
import java.io.IOException;
import java.util.*;
public abstract class BaseStringPool<T extends StringItem> extends BaseChunk implements BlockLoad {
public abstract class BaseStringPool<T extends StringItem> extends BaseChunk implements BlockLoad, JsonItem<JSONArray> {
private final IntegerItem mCountStrings;
private final IntegerItem mCountStyles;
private final ShortItem mFlagUtf8;
@ -64,6 +66,10 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
mUniqueMap=new HashMap<>();
}
// call this after modifying string values
public void refreshUniqueIdMap(){
reUpdateUniqueMap();
}
public void recreateStyles(){
StyleArray styleArray = getStyleArray();
//styleArray.clearChildes();
@ -249,6 +255,16 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
mArrayStrings.setUtf8(isUtf8Flag());
}
}
@Override
public JSONArray toJson() {
return getStringsArray().toJson();
}
@Override
public void fromJson(JSONArray json) {
getStringsArray().fromJson(json);
refreshUniqueIdMap();
refresh();
}
private static final short UTF8_FLAG_VALUE=0x0100;
private static final short FLAG_UTF8 = 0x0100;

View File

@ -6,6 +6,7 @@ import com.reandroid.lib.arsc.item.IntegerArray;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.item.ReferenceItem;
import com.reandroid.lib.arsc.item.TableString;
import org.json.JSONArray;
public class TableStringPool extends BaseStringPool<TableString> {
public TableStringPool(boolean is_utf8) {

View File

@ -3,8 +3,10 @@ package com.reandroid.lib.arsc.value;
import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.item.BlockItem;
import com.reandroid.lib.arsc.item.ReferenceItem;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONObject;
public abstract class BaseResValue extends BlockItem {
public abstract class BaseResValue extends BlockItem implements JsonItem<JSONObject> {
BaseResValue(int bytesLength){
super(bytesLength);
}
@ -95,4 +97,10 @@ public abstract class BaseResValue extends BlockItem {
byte getByte(int offset){
return getBytesInternal()[offset];
}
static final String NAME_data = "data";
static final String NAME_value_type="value_type";
static final String NAME_id="id";
static final String NAME_parent="parent";
static final String NAME_items="items";
}

View File

@ -46,7 +46,7 @@ public abstract class BaseResValueItem extends BaseResValue implements ResValueI
return null;
}
if(mReferenceItem==null){
mReferenceItem=createReferenceItem();
mReferenceItem=new ResValueReference(this);
}
return mReferenceItem;
}
@ -62,23 +62,6 @@ public abstract class BaseResValueItem extends BaseResValue implements ResValueI
mReferenceItem=null;
return entryBlock.removeTableReference(ref);
}
private ReferenceItem createReferenceItem(){
return new ReferenceItem() {
@Override
public void set(int val) {
if(getValueType()==ValueType.STRING){
BaseResValueItem.this.setData(val);
}
}
@Override
public int get() {
if(getValueType()==ValueType.STRING){
return BaseResValueItem.this.getData();
}
return -1;
}
};
}
public ValueType getValueType(){
return ValueType.valueOf(getType());

View File

@ -10,6 +10,8 @@ import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.*;
import com.reandroid.lib.arsc.pool.SpecStringPool;
import com.reandroid.lib.arsc.pool.TableStringPool;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONObject;
import java.io.IOException;
@ -17,7 +19,7 @@ import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
public class EntryBlock extends Block{
public class EntryBlock extends Block implements JsonItem<JSONObject> {
private ShortItem mHeaderSize;
private ShortItem mFlags;
private IntegerItem mSpecReference;
@ -84,7 +86,18 @@ public class EntryBlock extends Block{
resValueInt.setData(tableString.getIndex());
return resValueInt;
}
public boolean getValueAsBoolean(){
int data = ((ResValueInt)getResValue()).getData();
return data!=0;
}
public String getValueAsString(){
TableString tableString= getValueAsTableString();
if(tableString==null){
return null;
}
return tableString.getHtml();
}
public TableString getValueAsTableString(){
TableStringPool stringPool=getTableStringPool();
if(stringPool==null){
return null;
@ -98,7 +111,7 @@ public class EntryBlock extends Block{
if(tableString==null){
return null;
}
return tableString.getHtml();
return tableString;
}
private TableStringPool getTableStringPool(){
PackageBlock pkg=getPackageBlock();
@ -298,6 +311,11 @@ public class EntryBlock extends Block{
}
return specString.get();
}
private void setName(String name){
PackageBlock packageBlock=getPackageBlock();
EntryGroup entryGroup = packageBlock.getEntryGroup(getResourceId());
entryGroup.renameSpec(name);
}
public String getTypeName(){
TypeString typeString=getTypeString();
if(typeString==null){
@ -479,6 +497,12 @@ public class EntryBlock extends Block{
private boolean isFlagsComplex(){
return ((mFlags.get() & FLAG_COMPLEX_MASK) != 0);
}
public boolean isArray(){
return ((mFlags.get() & FLAG_COMPLEX_MASK) != 0);
}
public void setIsArray(boolean is_array){
setFlagComplex(is_array);
}
@Override
public void setNull(boolean is_null){
if(is_null){
@ -596,6 +620,35 @@ public class EntryBlock extends Block{
updateSpecRef();
}
@Override
public JSONObject toJson() {
if(isNull()){
return null;
}
JSONObject jsonObject=new JSONObject();
jsonObject.put(NAME_name, getSpecString().get());
jsonObject.put(NAME_is_array, isArray());
jsonObject.put(NAME_value, getResValue().toJson());
return jsonObject;
}
@Override
public void fromJson(JSONObject json) {
if(json==null){
setNull(true);
return;
}
setName(json.getString(NAME_name));
setNull(false);
BaseResValue baseResValue;
if(json.getBoolean(NAME_is_array)){
baseResValue=new ResValueInt();
}else {
baseResValue=new ResValueBag();
}
setResValue(baseResValue);
baseResValue.fromJson(json.getJSONObject(NAME_value));
}
@Override
public String toString(){
StringBuilder builder=new StringBuilder();
builder.append(getClass().getSimpleName());
@ -654,4 +707,8 @@ public class EntryBlock extends Block{
private final static short HEADER_COMPLEX=0x0010;
private final static short HEADER_INT=0x0008;
private static final String NAME_name="name";
private static final String NAME_is_array="is_array";
private static final String NAME_value="value";
}

View File

@ -5,11 +5,13 @@ import com.reandroid.lib.arsc.base.BlockCounter;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.item.PackageName;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONObject;
import java.io.IOException;
import java.io.OutputStream;
public class LibraryInfo extends Block {
public class LibraryInfo extends Block implements JsonItem<JSONObject> {
private final IntegerItem mPackageId;
private final PackageName mPackageName;
@ -74,6 +76,18 @@ public class LibraryInfo extends Block {
mPackageName.readBytes(reader);
}
@Override
public JSONObject toJson() {
JSONObject jsonObject=new JSONObject();
jsonObject.put("id", getPackageId());
jsonObject.put("name", getPackageName());
return jsonObject;
}
@Override
public void fromJson(JSONObject json) {
setPackageId(json.getInt("id"));
setPackageName(json.getString("name"));
}
@Override
public String toString(){
StringBuilder builder=new StringBuilder();

View File

@ -6,12 +6,13 @@ import com.reandroid.lib.arsc.io.BlockLoad;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.ByteArray;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.json.JsonItem;
import org.json.JSONObject;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
public class ResConfig extends FixedBlockContainer implements BlockLoad {
public class ResConfig extends FixedBlockContainer implements BlockLoad, JsonItem<JSONObject> {
private final IntegerItem configSize;
private final ByteArray mValuesContainer;
@ -156,7 +157,17 @@ public class ResConfig extends FixedBlockContainer implements BlockLoad {
}
return mValuesContainer.get(OFFSET_languageIn1);
}
public char[] getLanguage(){
public String getLanguage(){
return ResConfigHelper.decodeLanguage(getLanguageChars());
}
public void setLanguage(String language){
char[] chs=new char[2];
if(language!=null){
chs=language.toCharArray();
}
setLanguage(chs);
}
public char[] getLanguageChars(){
byte b0=getLanguageIn0();
byte b1=getLanguageIn1();
return unpackLanguageOrRegion(b0, b1, 'a');
@ -201,7 +212,10 @@ public class ResConfig extends FixedBlockContainer implements BlockLoad {
}
return mValuesContainer.get(OFFSET_countryIn1);
}
public char[] getRegion(){
public String getRegion(){
return ResConfigHelper.decodeRegion(getRegionChars());
}
public char[] getRegionChars(){
byte b0=getCountryIn0();
byte b1=getCountryIn1();
return unpackLanguageOrRegion(b0, b1, '0');
@ -225,12 +239,18 @@ public class ResConfig extends FixedBlockContainer implements BlockLoad {
}
mValuesContainer.put(OFFSET_orientation, b);
}
public byte getOrientation(){
public byte getOrientationByte(){
if(getConfigSize()<SIZE_16){
return 0;
}
return mValuesContainer.get(OFFSET_orientation);
}
public Orientation getOrientation(){
return Orientation.fromValue(getOrientationByte());
}
public void setOrientation(Orientation orientation){
setOrientation(orientation.getByteValue());
}
public void setTouchscreen(byte b){
if(getConfigSize()<SIZE_16){
if(b==0){
@ -240,12 +260,18 @@ public class ResConfig extends FixedBlockContainer implements BlockLoad {
}
mValuesContainer.put(OFFSET_touchscreen, b);
}
public byte getTouchscreen(){
public byte getTouchscreenByte(){
if(getConfigSize()<SIZE_16){
return 0;
}
return mValuesContainer.get(OFFSET_touchscreen);
}
public Touchscreen getTouchscreen(){
return Touchscreen.fromValue(getTouchscreenByte());
}
public void setTouchscreen(Touchscreen touchscreen){
setTouchscreen(touchscreen.getByteValue());
}
public void setDensity(short sh){
if(getConfigSize()<SIZE_16){
if(sh==0){
@ -255,12 +281,18 @@ public class ResConfig extends FixedBlockContainer implements BlockLoad {
}
mValuesContainer.putShort(OFFSET_density, sh);
}
public short getDensity(){
public short getDensityValue(){
if(getConfigSize()<SIZE_16){
return 0;
}
return mValuesContainer.getShort(OFFSET_density);
}
public String getDensity(){
return ResConfigHelper.decodeDensity(getDensityValue());
}
public void setDensity(String density){
setDensity(ResConfigHelper.encodeDensity(density));
}
public void setKeyboard(byte b){
if(getConfigSize()<SIZE_28){
if(b==0){
@ -270,12 +302,18 @@ public class ResConfig extends FixedBlockContainer implements BlockLoad {
}
mValuesContainer.put(OFFSET_keyboard, b);
}
public byte getKeyboard(){
public byte getKeyboardByte(){
if(getConfigSize()<SIZE_28){
return 0;
}
return mValuesContainer.get(OFFSET_keyboard);
}
public Keyboard getKeyboard(){
return Keyboard.fromValue(getKeyboardByte());
}
public void setKeyboard(Keyboard keyboard){
setKeyboard(keyboard.getByteValue());
}
public void setNavigation(byte b){
if(getConfigSize()<SIZE_28){
if(b==0){
@ -285,12 +323,18 @@ public class ResConfig extends FixedBlockContainer implements BlockLoad {
}
mValuesContainer.put(OFFSET_navigation, b);
}
public byte getNavigation(){
public byte getNavigationByte(){
if(getConfigSize()<SIZE_28){
return 0;
}
return mValuesContainer.get(OFFSET_navigation);
}
public Navigation getNavigation(){
return Navigation.fromValue(getNavigationByte());
}
public void setNavigation(Navigation navigation){
setNavigation(navigation.getByteValue());
}
public void setInputFlags(byte b){
if(getConfigSize()<SIZE_28){
if(b==0){
@ -300,12 +344,18 @@ public class ResConfig extends FixedBlockContainer implements BlockLoad {
}
mValuesContainer.put(OFFSET_inputFlags, b);
}
public byte getInputFlags(){
public byte getInputFlagsValue(){
if(getConfigSize()<SIZE_28){
return 0;
}
return mValuesContainer.get(OFFSET_inputFlags);
}
public String getInputFlags(){
return ResConfigHelper.decodeInputFlags(getInputFlagsValue());
}
public void setInputFlags(String inputFlags){
setInputFlags(ResConfigHelper.encodeInputFlags(inputFlags));
}
public void setInputPad0(byte b){
if(getConfigSize()<SIZE_28){
if(b==0){
@ -394,12 +444,18 @@ public class ResConfig extends FixedBlockContainer implements BlockLoad {
}
mValuesContainer.put(OFFSET_screenLayout, b);
}
public byte getScreenLayout(){
public byte getScreenLayoutValue(){
if(getConfigSize()<SIZE_32){
return 0;
}
return mValuesContainer.get(OFFSET_screenLayout);
}
public String getScreenLayout(){
return ResConfigHelper.decodeScreenLayout(getScreenLayoutValue());
}
public void setScreenLayout(String screenLayout){
setScreenLayout(ResConfigHelper.encodeScreenLayout(screenLayout));
}
public void setUiMode(byte b){
if(getConfigSize()<SIZE_32){
if(b==0){
@ -409,12 +465,18 @@ public class ResConfig extends FixedBlockContainer implements BlockLoad {
}
mValuesContainer.put(OFFSET_uiMode, b);
}
public byte getUiMode(){
public byte getUiModeValue(){
if(getConfigSize()<SIZE_32){
return 0;
}
return mValuesContainer.get(OFFSET_uiMode);
}
public String getUiMode(){
return ResConfigHelper.decodeUiMode(getUiModeValue());
}
public void setUiMode(String uiMode){
setUiMode(ResConfigHelper.encodeUiMode(uiMode));
}
public void setSmallestScreenWidthDp(short sh){
if(getConfigSize()<SIZE_32){
if(sh==0){
@ -562,6 +624,119 @@ public class ResConfig extends FixedBlockContainer implements BlockLoad {
return isNull(mValuesContainer.getBytes());
}
@Override
public JSONObject toJson() {
JSONObject jsonObject=new JSONObject();
if(isDefault()){
return jsonObject;
}
int val=getMcc();
if(val!=0){
jsonObject.put(NAME_mcc, val);
}
val=getMnc();
if(val!=0){
jsonObject.put(NAME_mnc, val);
}
String str=getLanguage();
if(str!=null){
jsonObject.put(NAME_language, str);
}
str=getRegion();
if(str!=null){
jsonObject.put(NAME_region, str);
}
Orientation orientation=getOrientation();
if(orientation!=Orientation.ANY){
jsonObject.put(NAME_orientation, orientation.toString());
}
Touchscreen touchscreen=getTouchscreen();
if(touchscreen!=Touchscreen.NONE){
jsonObject.put(NAME_touchscreen, touchscreen.toString());
}
str = getDensity();
if(str!=null){
jsonObject.put(NAME_density, str);
}
Keyboard keyboard = getKeyboard();
if(keyboard!=Keyboard.NONE){
jsonObject.put(NAME_keyboard, keyboard.toString());
}
Navigation navigation = getNavigation();
if(navigation!=Navigation.NONE){
jsonObject.put(NAME_navigation, navigation.toString());
}
str = getInputFlags();
if(str!=null){
jsonObject.put(NAME_inputFlags, str);
}
val = getScreenWidth();
if(val!=0){
jsonObject.put(NAME_screenWidth, val);
}
val = getScreenHeight();
if(val!=0){
jsonObject.put(NAME_screenHeight, val);
}
val = getSdkVersion();
if(val!=0){
jsonObject.put(NAME_sdkVersion, val);
}
val = getMinorVersion();
if(val!=0){
jsonObject.put(NAME_minorVersion, val);
}
str = getScreenLayout();
if(str!=null){
jsonObject.put(NAME_screenLayout, str);
}
str = getUiMode();
if(str!=null){
jsonObject.put(NAME_uiMode, str);
}
val = getSmallestScreenWidthDp();
if(val!=0){
jsonObject.put(NAME_smallestScreenWidthDp, val);
}
val = getScreenWidthDp();
if(val!=0){
jsonObject.put(NAME_screenWidthDp, val);
}
val = getScreenHeightDp();
if(val!=0){
jsonObject.put(NAME_screenHeightDp, val);
}
return jsonObject;
}
@Override
public void fromJson(JSONObject json) {
if(json.isEmpty()){
mValuesContainer.fill((byte) 0);
return;
}
trimToSize(SIZE_64);
setMcc((short) json.optInt(NAME_mcc));
setMnc((short) json.optInt(NAME_mnc));
setLanguage(json.optString(NAME_language));
setOrientation(Orientation.fromName(json.optString(NAME_orientation)));
setTouchscreen(Touchscreen.fromName(json.optString(NAME_touchscreen)));
setDensity(json.optString(NAME_density));
setKeyboard(Keyboard.fromName(json.optString(NAME_keyboard)));
setNavigation(Navigation.fromName(json.optString(NAME_navigation)));
setInputFlags(json.optString(NAME_inputFlags));
setScreenWidth((short) json.optInt(NAME_screenWidth));
setScreenHeight((short) json.optInt(NAME_screenHeight));
setSdkVersion((short) json.optInt(NAME_sdkVersion));
setMinorVersion((short) json.optInt(NAME_minorVersion));
setScreenLayout(json.optString(NAME_screenLayout));
setUiMode(json.optString(NAME_uiMode));
setSmallestScreenWidthDp((short) json.optInt(NAME_smallestScreenWidthDp));
setScreenWidthDp((short) json.optInt(NAME_screenWidthDp));
setScreenHeightDp((short) json.optInt(NAME_screenHeightDp));
trimToSize(SIZE_48);
}
@Override
public int hashCode(){
byte[] bts = ByteArray.trimTrailZeros(mValuesContainer.getBytes());
return Arrays.hashCode(bts);
@ -706,6 +881,161 @@ public class ResConfig extends FixedBlockContainer implements BlockLoad {
System.arraycopy(bts, 0, result, 0, max);
return result;
}
public enum Orientation{
ANY((byte) 0),
PORT((byte) 0x1),
LAND((byte) 0x2),
SQUARE((byte) 0x3);
private final byte mByteValue;
Orientation(byte b) {
this.mByteValue=b;
}
public byte getByteValue() {
return mByteValue;
}
@Override
public String toString(){
return name().toLowerCase();
}
public static Orientation fromValue(byte b){
for(Orientation orientation:values()){
if(b==orientation.getByteValue()){
return orientation;
}
}
return ANY;
}
public static Orientation fromName(String name){
if(name==null){
return ANY;
}
name=name.trim().toUpperCase();
for(Orientation orientation:values()){
if(name.equals(orientation.name())){
return orientation;
}
}
return ANY;
}
}
public enum Touchscreen{
NONE((byte) 0x0),
NOTOUCH((byte) 0x1),
STYLUS((byte) 0x2),
FINGER((byte) 0x3);
private final byte mByteValue;
Touchscreen(byte b) {
this.mByteValue=b;
}
public byte getByteValue() {
return mByteValue;
}
@Override
public String toString(){
return name().toLowerCase();
}
public static Touchscreen fromValue(byte b){
for(Touchscreen touchscreen:values()){
if(b==touchscreen.getByteValue()){
return touchscreen;
}
}
return NONE;
}
public static Touchscreen fromName(String name){
if(name==null){
return NONE;
}
name=name.trim().toUpperCase();
for(Touchscreen touchscreen:values()){
if(name.equals(touchscreen.name())){
return touchscreen;
}
}
return NONE;
}
}
public enum Keyboard{
NONE((byte) 0x0),
NOKEYS((byte) 0x1),
QWERTY((byte) 0x2),
KEY12((byte) 0x3);
private final byte mByteValue;
Keyboard(byte b) {
this.mByteValue=b;
}
public byte getByteValue() {
return mByteValue;
}
@Override
public String toString(){
if(this==KEY12){
return "12key";
}
return name().toLowerCase();
}
public static Keyboard fromValue(byte b){
for(Keyboard keyboard:values()){
if(b==keyboard.getByteValue()){
return keyboard;
}
}
return NOKEYS;
}
public static Keyboard fromName(String name){
if(name==null){
return NOKEYS;
}
name=name.trim().toUpperCase();
if(name.equals("12KEY")){
return KEY12;
}
for(Keyboard keyboard:values()){
if(name.equals(keyboard.name())){
return keyboard;
}
}
return NOKEYS;
}
}
public enum Navigation{
NONE((byte) 0),
NONAV((byte) 0x1),
DPAD((byte) 0x2),
TRACKBALL((byte) 0x3),
WHEEL((byte) 0x4);
private final byte mByteValue;
Navigation(byte b) {
this.mByteValue=b;
}
public byte getByteValue() {
return mByteValue;
}
@Override
public String toString(){
return name().toLowerCase();
}
public static Navigation fromValue(byte b){
for(Navigation navigation:values()){
if(b==navigation.getByteValue()){
return navigation;
}
}
return NONE;
}
public static Navigation fromName(String name){
if(name==null){
return NONE;
}
name=name.trim().toUpperCase();
for(Navigation navigation:values()){
if(name.equals(navigation.name())){
return navigation;
}
}
return NONE;
}
}
public static final int SIZE_16 = 16;
public static final int SIZE_28 = 28;
@ -753,4 +1083,34 @@ public class ResConfig extends FixedBlockContainer implements BlockLoad {
private static final int LEN_localeScript = 4;
private static final int LEN_localeVariant = 8;
private static final String NAME_mcc = "mcc";
private static final String NAME_mnc = "mnc";
private static final String NAME_language = "language";
private static final String NAME_region = "region";
private static final String NAME_orientation = "orientation";
private static final String NAME_touchscreen = "touchscreen";
private static final String NAME_density = "density";
//SIZE=16
private static final String NAME_keyboard = "keyboard";
private static final String NAME_navigation = "navigation";
private static final String NAME_inputFlags = "inputFlags";
private static final String NAME_inputPad0 = "inputPad0";
private static final String NAME_screenWidth = "screenWidth";
private static final String NAME_screenHeight = "screenHeight";
private static final String NAME_sdkVersion = "sdkVersion";
private static final String NAME_minorVersion = "minorVersion";
//SIZE=28
private static final String NAME_screenLayout = "screenLayout";
private static final String NAME_uiMode = "uiMode";
private static final String NAME_smallestScreenWidthDp = "smallestScreenWidthDp";
//SIZE=32 = "";
private static final String NAME_screenWidthDp = "screenWidthDp";
private static final String NAME_screenHeightDp = "screenHeightDp";
//SIZE=36
private static final String NAME_localeScript = "localeScript";
private static final String NAME_localeVariant = "localeVariant";
private static final String NAME_screenLayout2 = "screenLayout2";
private static final String NAME_colorMode = "colorMode";
}

View File

@ -11,6 +11,7 @@ public class ResConfigHelper {
ResConfig result=new ResConfig();
result.setConfigSize(ResConfig.SIZE_64);
parseQualifiers(result, qualifiers);
result.refresh();
return result;
}
static String toQualifier(ResConfig resConfig){
@ -137,9 +138,29 @@ public class ResConfigHelper {
char[] chs=country.toCharArray();
resConfig.setRegion(chs);
}
public static String decodeLanguage(char[] language){
StringBuilder builder=new StringBuilder();
if(language[0]!=0){
builder.append(language[0]).append(language[1]);
}
if(builder.length()==0){
return null;
}
return builder.toString();
}
public static String decodeRegion(char[] region){
StringBuilder builder=new StringBuilder();
if(region[0]!=0){
builder.append(region[0]).append(region[1]);
}
if(builder.length()==0){
return null;
}
return builder.toString();
}
public static String decodeLocale(ResConfig resConfig){
char[] region=resConfig.getRegion();
char[] language=resConfig.getLanguage();
char[] region=resConfig.getRegionChars();
char[] language=resConfig.getLanguageChars();
StringBuilder builder=new StringBuilder();
if(language[0]!=0){
builder.append(language[0]).append(language[1]);
@ -159,8 +180,8 @@ public class ResConfigHelper {
StringBuilder builder = new StringBuilder();
char[] localeVariant=resConfig.getLocaleVariant();
char[] localeScript=resConfig.getLocaleScript();
char[] region=resConfig.getRegion();
char[] language=resConfig.getLanguage();
char[] region=resConfig.getRegionChars();
char[] language=resConfig.getLanguageChars();
if (localeVariant == null && localeScript == null && (region[0] != '\00' || language[0] != '\00') &&
region.length != 3) {
builder.append("-").append(language);
@ -217,7 +238,7 @@ public class ResConfigHelper {
}
private static String decodeNavigation(ResConfig resConfig){
StringBuilder ret=new StringBuilder();
switch (resConfig.getNavigation()) {
switch (resConfig.getNavigationByte()) {
case NAVIGATION_NONAV:
ret.append("-nonav");
break;
@ -265,9 +286,45 @@ public class ResConfigHelper {
}
resConfig.setInputFlags((byte)inputFlags);
}
public static byte encodeInputFlags(String inputFlags){
if(inputFlags==null){
return 0;
}
String[] split=inputFlags.split("-");
int result=0;
for(int i=0;i<split.length;i++){
String s=split[i];
if(s==null){
continue;
}
int val;
switch (s) {
case "keysexposed":
val = (KEYSHIDDEN_NO);
break;
case "keyshidden":
val = (KEYSHIDDEN_YES);
break;
case "keyssoft":
val = (KEYSHIDDEN_SOFT);
break;
case "navexposed":
val = (NAVHIDDEN_NO);
break;
case "navhidden":
val = (NAVHIDDEN_YES);
break;
default:
continue;
}
result=(result | val);
split[i]=null;
}
return (byte)result;
}
private static String decodeInputFlags(ResConfig resConfig){
StringBuilder ret=new StringBuilder();
int inputFlags=resConfig.getInputFlags();
int inputFlags=resConfig.getInputFlagsValue();
switch (inputFlags & MASK_KEYSHIDDEN) {
case KEYSHIDDEN_NO:
ret.append("-keysexposed");
@ -289,6 +346,32 @@ public class ResConfigHelper {
}
return ret.toString();
}
public static String decodeInputFlags(byte inputFlags){
StringBuilder builder=new StringBuilder();
switch (inputFlags & MASK_KEYSHIDDEN) {
case KEYSHIDDEN_NO:
builder.append("-keysexposed");
break;
case KEYSHIDDEN_YES:
builder.append("-keyshidden");
break;
case KEYSHIDDEN_SOFT:
builder.append("-keyssoft");
break;
}
switch (inputFlags & MASK_NAVHIDDEN) {
case NAVHIDDEN_NO:
builder.append("-navexposed");
break;
case NAVHIDDEN_YES:
builder.append("-navhidden");
break;
}
if(builder.length()==0){
return null;
}
return builder.toString();
}
private static void encodeKeyboard(ResConfig resConfig, String[] split){
byte keyboard=0;
for(int i=0;i<split.length;i++){
@ -316,7 +399,7 @@ public class ResConfigHelper {
}
private static String decodeKeyboard(ResConfig resConfig){
StringBuilder ret=new StringBuilder();
switch (resConfig.getKeyboard()) {
switch (resConfig.getKeyboardByte()) {
case KEYBOARD_NOKEYS:
ret.append("-nokeys");
break;
@ -329,6 +412,39 @@ public class ResConfigHelper {
}
return ret.toString();
}
public static short encodeDensity(String densityName){
short density=0;
if(densityName==null){
return density;
}
Matcher matcher=PATTERN_DENSITY.matcher(densityName);
if(!matcher.find()){
return density;
}
String d=matcher.group("A");
if("l".equals(d)){
density = DENSITY_LOW;
}else if("m".equals(d)){
density = DENSITY_MEDIUM;
}else if("h".equals(d)){
density = DENSITY_HIGH;
}else if("tv".equals(d)){
density = DENSITY_TV;
}else if("xh".equals(d)){
density = DENSITY_XHIGH;
}else if("xxh".equals(d)){
density = DENSITY_XXHIGH;
}else if("xxxh".equals(d)){
density = DENSITY_XXXHIGH;
}else if("any".equals(d)){
density = DENSITY_ANY;
}else if("no".equals(d)){
density = DENSITY_NONE;
}else if(isDecimal(d)){
density = (short) Integer.parseInt(d);
}
return density;
}
private static void encodeDensity(ResConfig resConfig, String[] split){
int density=0;
for(int i=0;i<split.length;i++){
@ -371,7 +487,7 @@ public class ResConfigHelper {
}
private static String decodeDensity(ResConfig resConfig){
StringBuilder ret=new StringBuilder();
int density=resConfig.getDensity();
int density=resConfig.getDensityValue();
switch (density) {
case DENSITY_DEFAULT:
break;
@ -407,6 +523,32 @@ public class ResConfigHelper {
}
return ret.toString();
}
public static String decodeDensity(short density){
switch (density) {
case DENSITY_DEFAULT:
return null;
case DENSITY_LOW:
return "ldpi";
case DENSITY_MEDIUM:
return "mdpi";
case DENSITY_HIGH:
return "hdpi";
case DENSITY_TV:
return "tvdpi";
case DENSITY_XHIGH:
return "xhdpi";
case DENSITY_XXHIGH:
return "xxhdpi";
case DENSITY_XXXHIGH:
return "xxxhdpi";
case DENSITY_ANY:
return "anydpi";
case DENSITY_NONE:
return "nodpi";
default:
return density+"dpi";
}
}
private static void encodeTouchscreen(ResConfig resConfig, String[] split){
byte touchscreen=0;
for(int i=0;i<split.length;i++){
@ -434,7 +576,7 @@ public class ResConfigHelper {
}
private static String decodeTouchscreen(ResConfig resConfig){
StringBuilder ret=new StringBuilder();
byte touchscreen=resConfig.getTouchscreen();
byte touchscreen=resConfig.getTouchscreenByte();
switch (touchscreen) {
case TOUCHSCREEN_NOTOUCH:
ret.append("-notouch");
@ -514,9 +656,129 @@ public class ResConfigHelper {
}
resConfig.setUiMode((byte)uiMode);
}
public static byte encodeUiMode(String uiMode){
if(uiMode==null){
return 0;
}
String[] split=uiMode.split("-");
int result=0;
for(int i=0;i<split.length;i++){
String s=split[i];
if(s==null){
continue;
}
int val;
switch (s) {
case "car":
val = (UI_MODE_TYPE_CAR);
break;
case "desk":
val = (UI_MODE_TYPE_DESK);
break;
case "television":
val = (UI_MODE_TYPE_TELEVISION);
break;
case "smallui":
val = (UI_MODE_TYPE_SMALLUI);
break;
case "mediumui":
val = (UI_MODE_TYPE_MEDIUMUI);
break;
case "largeui":
val = (UI_MODE_TYPE_LARGEUI);
break;
case "godzillaui":
val = (UI_MODE_TYPE_GODZILLAUI);
break;
case "hugeui":
val = (UI_MODE_TYPE_HUGEUI);
break;
case "appliance":
val = (UI_MODE_TYPE_APPLIANCE);
break;
case "watch":
val = (UI_MODE_TYPE_WATCH);
break;
case "vrheadset":
val = (UI_MODE_TYPE_VR_HEADSET);
break;
default:
continue;
}
result=(result | val);
split[i]=null;
}
for(int i=0;i<split.length;i++){
String s=split[i];
if(s==null){
continue;
}
int val;
if("night".equals(s)){
val = (UI_MODE_NIGHT_YES);
}else if("notnight".equals(s)){
val = (UI_MODE_NIGHT_NO);
}else {
continue;
}
result=(result | val);
split[i]=null;
}
return (byte)result;
}
public static String decodeUiMode(byte uiMode){
StringBuilder ret=new StringBuilder();
switch (uiMode & MASK_UI_MODE_TYPE) {
case UI_MODE_TYPE_CAR:
ret.append("-car");
break;
case UI_MODE_TYPE_DESK:
ret.append("-desk");
break;
case UI_MODE_TYPE_TELEVISION:
ret.append("-television");
break;
case UI_MODE_TYPE_SMALLUI:
ret.append("-smallui");
break;
case UI_MODE_TYPE_MEDIUMUI:
ret.append("-mediumui");
break;
case UI_MODE_TYPE_LARGEUI:
ret.append("-largeui");
break;
case UI_MODE_TYPE_GODZILLAUI:
ret.append("-godzillaui");
break;
case UI_MODE_TYPE_HUGEUI:
ret.append("-hugeui");
break;
case UI_MODE_TYPE_APPLIANCE:
ret.append("-appliance");
break;
case UI_MODE_TYPE_WATCH:
ret.append("-watch");
break;
case UI_MODE_TYPE_VR_HEADSET:
ret.append("-vrheadset");
break;
}
switch (uiMode & MASK_UI_MODE_NIGHT) {
case UI_MODE_NIGHT_YES:
ret.append("-night");
break;
case UI_MODE_NIGHT_NO:
ret.append("-notnight");
break;
}
if(ret.length()==0){
return null;
}
return ret.toString();
}
private static String decodeUiMode(ResConfig resConfig){
StringBuilder ret=new StringBuilder();
byte uiMode=resConfig.getUiMode();
byte uiMode=resConfig.getUiModeValue();
switch (uiMode & MASK_UI_MODE_TYPE) {
case UI_MODE_TYPE_CAR:
ret.append("-car");
@ -583,7 +845,7 @@ public class ResConfigHelper {
}
private static String decodeOrientation(ResConfig resConfig){
StringBuilder ret=new StringBuilder();
byte orientation=resConfig.getOrientation();
byte orientation=resConfig.getOrientationByte();
switch (orientation) {
case ORIENTATION_PORT:
ret.append("-port");
@ -597,6 +859,17 @@ public class ResConfigHelper {
}
return ret.toString();
}
public static String decodeOrientation(byte orientation){
switch (orientation) {
case ORIENTATION_PORT:
return "port";
case ORIENTATION_LAND:
return "land";
case ORIENTATION_SQUARE:
return "square";
}
return null;
}
private static void encodeScreenLayout(ResConfig resConfig, String[] split){
int screenLayout=0;
for(int i=0;i<split.length;i++){
@ -638,9 +911,54 @@ public class ResConfigHelper {
}
resConfig.setScreenLayout((byte) screenLayout);
}
public static byte encodeScreenLayout(String screenLayout){
if(screenLayout==null){
return 0;
}
String[] split=screenLayout.split("-");
int result=0;
for(int i=0;i<split.length;i++){
String s=split[i];
if(s==null){
continue;
}
int val;
switch (s) {
case "ldrtl":
val = (SCREENLAYOUT_LAYOUTDIR_RTL);
break;
case "ldltr":
val = (SCREENLAYOUT_LAYOUTDIR_LTR);
break;
case "small":
val = (SCREENSIZE_SMALL);
break;
case "normal":
val = (SCREENSIZE_NORMAL);
break;
case "large":
val = (SCREENSIZE_LARGE);
break;
case "xlarge":
val = (SCREENSIZE_XLARGE);
break;
case "long":
val = (SCREENLONG_YES);
break;
case "notlong":
val = (SCREENLONG_NO);
break;
default:
continue;
}
result = (result | val);
split[i]=null;
}
return (byte) result;
}
private static String decodeScreenLayout(ResConfig resConfig){
StringBuilder ret=new StringBuilder();
byte screenLayout=resConfig.getScreenLayout();
byte screenLayout=resConfig.getScreenLayoutValue();
switch (screenLayout & MASK_LAYOUTDIR) {
case SCREENLAYOUT_LAYOUTDIR_RTL:
ret.append("-ldrtl");
@ -672,6 +990,42 @@ public class ResConfigHelper {
}
return ret.toString();
}
public static String decodeScreenLayout(byte screenLayout){
StringBuilder ret=new StringBuilder();
switch (screenLayout & MASK_LAYOUTDIR) {
case SCREENLAYOUT_LAYOUTDIR_RTL:
ret.append("-ldrtl");
break;
case SCREENLAYOUT_LAYOUTDIR_LTR:
ret.append("-ldltr");
}
switch (screenLayout & MASK_SCREENSIZE) {
case SCREENSIZE_SMALL:
ret.append("-small");
break;
case SCREENSIZE_NORMAL:
ret.append("-normal");
break;
case SCREENSIZE_LARGE:
ret.append("-large");
break;
case SCREENSIZE_XLARGE:
ret.append("-xlarge");
break;
}
switch (screenLayout & MASK_SCREENLONG) {
case SCREENLONG_YES:
ret.append("-long");
break;
case SCREENLONG_NO:
ret.append("-notlong");
break;
}
if(ret.length()==0){
return null;
}
return ret.toString();
}
private static void encodeScreenLayout2(ResConfig resConfig, String[] split){
int screenLayout2=0;
for(int i=0;i<split.length;i++){

View File

@ -6,6 +6,8 @@ import com.reandroid.lib.arsc.base.BlockCounter;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.item.ReferenceItem;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;
import java.io.OutputStream;
@ -127,9 +129,28 @@ public class ResValueBag extends BaseResValue {
mResValueBagItemArray.setChildesCount(mCount.get());
mResValueBagItemArray.readBytes(reader);
}
@Override
public JSONObject toJson() {
if(isNull()){
return null;
}
JSONObject jsonObject=new JSONObject();
jsonObject.put(NAME_parent, getParentId());
jsonObject.put(NAME_items, getResValueBagItemArray().toJson());
return jsonObject;
}
@Override
public void fromJson(JSONObject json) {
setParentId(json.getInt(NAME_parent));
getResValueBagItemArray().fromJson(json.getJSONArray(NAME_items));
refreshCount();
}
@Override
public String toString(){
if(getParent()!=null){
return toJson().toString(4);
}
StringBuilder builder=new StringBuilder();
builder.append(getClass().getSimpleName());
builder.append(": parent=");
@ -139,6 +160,4 @@ public class ResValueBag extends BaseResValue {
return builder.toString();
}
private final static short HEADER_COMPLEX=0x0010;
}

View File

@ -2,6 +2,8 @@ package com.reandroid.lib.arsc.value;
import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.item.ReferenceItem;
import com.reandroid.lib.arsc.item.TableString;
import org.json.JSONObject;
public class ResValueBagItem extends BaseResValueItem{
@ -9,6 +11,22 @@ public class ResValueBagItem extends BaseResValueItem{
super(BYTES_COUNT);
setHeaderSize(BYTES_SIZE);
}
public String getValueAsString(){
return getTableString(getData()).getHtml();
}
public void setValueAsString(String str){
setType(ValueType.STRING);
TableString tableString=getTableStringPool().getOrCreate(str);
setData(tableString.getIndex());
}
public boolean getValueAsBoolean(){
return getData()!=0;
}
public void setValueAsBoolean(boolean val){
setType(ValueType.INT_BOOLEAN);
int data=val?0xffffffff:0;
setData(data);
}
public ResValueBag getParentBag(){
Block parent=getParent();
@ -128,6 +146,37 @@ public class ResValueBagItem extends BaseResValueItem{
setShort(OFFSET_DATA+2, val);
afterDataValueChanged();
}
@Override
public JSONObject toJson() {
if(isNull()){
return null;
}
JSONObject jsonObject=new JSONObject();
ValueType valueType=getValueType();
jsonObject.put(NAME_value_type, valueType.name());
jsonObject.put(NAME_id, getId());
if(valueType==ValueType.STRING){
jsonObject.put(NAME_data, getValueAsString());
}else if(valueType==ValueType.INT_BOOLEAN){
jsonObject.put(NAME_data, getValueAsBoolean());
}else {
jsonObject.put(NAME_data, getData());
}
return jsonObject;
}
@Override
public void fromJson(JSONObject json) {
ValueType valueType=ValueType.fromName(json.getString(NAME_value_type));
setType(valueType);
setId(json.getInt(NAME_id));
if(valueType==ValueType.STRING){
setValueAsString(json.getString(NAME_data));
}else if(valueType==ValueType.INT_BOOLEAN){
setValueAsBoolean(json.getBoolean(NAME_data));
}else {
setData(json.getInt(NAME_data));
}
}
@Override
public String toString(){

View File

@ -1,15 +1,30 @@
package com.reandroid.lib.arsc.value;
import com.reandroid.lib.arsc.decoder.ValueDecoder;
import com.reandroid.lib.arsc.io.BlockReader;
import java.io.IOException;
import com.reandroid.lib.arsc.item.TableString;
import org.json.JSONObject;
public class ResValueInt extends BaseResValueItem {
public ResValueInt() {
super(BYTES_COUNT);
setHeaderSize(BYTES_SIZE);
}
public String getValueAsString(){
return getString(getData());
}
public void setValueAsString(String str){
setType(ValueType.STRING);
TableString tableString=getTableStringPool().getOrCreate(str);
setData(tableString.getIndex());
}
public void setValueAsBoolean(boolean val){
setType(ValueType.INT_BOOLEAN);
int data=val?0xffffffff:0;
setData(data);
}
public boolean getValueAsBoolean(){
return getData()!=0;
}
@Override
public void setHeaderSize(short size) {
setShort(OFFSET_SIZE, size);
@ -58,11 +73,34 @@ public class ResValueInt extends BaseResValueItem {
addTableReference(getTableStringReference());
}
}
@Override
public void onReadBytes(BlockReader reader) throws IOException {
super.onReadBytes(reader);
public JSONObject toJson() {
if(isNull()){
return null;
}
JSONObject jsonObject=new JSONObject();
ValueType valueType=getValueType();
jsonObject.put(NAME_value_type, valueType.name());
if(valueType==ValueType.STRING){
jsonObject.put(NAME_data, getValueAsString());
}else if(valueType==ValueType.INT_BOOLEAN){
jsonObject.put(NAME_data, getValueAsBoolean());
}else {
jsonObject.put(NAME_data, getData());
}
return jsonObject;
}
@Override
public void fromJson(JSONObject json) {
ValueType valueType=ValueType.fromName(json.getString(NAME_value_type));
if(valueType==ValueType.STRING){
setValueAsString(json.getString(NAME_data));
}else if(valueType==ValueType.INT_BOOLEAN){
setValueAsBoolean(json.getBoolean(NAME_data));
}else {
setType(valueType);
setData(json.getInt(NAME_data));
}
}
@Override
public String toString(){
@ -97,6 +135,6 @@ public class ResValueInt extends BaseResValueItem {
private static final int OFFSET_DATA=4;
private static final int BYTES_COUNT=8;
private static final short BYTES_SIZE=0x08;
}

View File

@ -0,0 +1,21 @@
package com.reandroid.lib.arsc.value;
import com.reandroid.lib.arsc.item.ReferenceItem;
public class ResValueReference implements ReferenceItem {
private final BaseResValueItem resValueItem;
public ResValueReference(BaseResValueItem resValueItem){
this.resValueItem=resValueItem;
}
public EntryBlock getEntryBlock(){
return resValueItem.getEntryBlock();
}
@Override
public void set(int val) {
resValueItem.setData(val);
}
@Override
public int get() {
return resValueItem.getData();
}
}

View File

@ -0,0 +1,6 @@
package com.reandroid.lib.json;
public interface JsonItem<T> {
public T toJson();
public void fromJson(T json);
}

View File

@ -0,0 +1,62 @@
package com.reandroid.lib.json;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.*;
import java.nio.charset.StandardCharsets;
public class JsonUtil {
public static void writeJSONObject(JsonItem<JSONObject> jsonItem, File file) throws IOException{
writeJSONObject(jsonItem, file, INDENT_FACTOR);
}
public static void writeJSONObject(JsonItem<JSONObject> jsonItem, File file, int indentFactor) throws IOException{
File dir=file.getParentFile();
if(dir!=null && !dir.exists()){
dir.mkdirs();
}
FileOutputStream outputStream=new FileOutputStream(file);
writeJSONObject(jsonItem, outputStream, indentFactor);
}
public static void writeJSONObject(JsonItem<JSONObject> jsonItem, OutputStream outputStream) throws IOException{
writeJSONObject(jsonItem, outputStream, INDENT_FACTOR);
}
public static void writeJSONObject(JsonItem<JSONObject> jsonItem, OutputStream outputStream, int indentFactor) throws IOException{
Writer writer=new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
writer= writeJSONObject(jsonItem, writer, indentFactor);
writer.flush();
writer.close();
}
public static Writer writeJSONObject(JsonItem<JSONObject> jsonItem, Writer writer, int indentFactor){
JSONObject jsonObject=jsonItem.toJson();
return jsonObject.write(writer, indentFactor, 0);
}
public static void writeJSONArray(JsonItem<JSONArray> jsonItem, File file) throws IOException{
writeJSONArray(jsonItem, file, INDENT_FACTOR);
}
public static void writeJSONArray(JsonItem<JSONArray> jsonItem, File file, int indentFactor) throws IOException{
File dir=file.getParentFile();
if(dir!=null && !dir.exists()){
dir.mkdirs();
}
FileOutputStream outputStream=new FileOutputStream(file);
writeJSONArray(jsonItem, outputStream, indentFactor);
}
public static void writeJSONArray(JsonItem<JSONArray> jsonItem, OutputStream outputStream) throws IOException{
writeJSONArray(jsonItem, outputStream, INDENT_FACTOR);
}
public static void writeJSONArray(JsonItem<JSONArray> jsonItem, OutputStream outputStream, int indentFactor) throws IOException{
Writer writer=new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
writer= writeJSONArray(jsonItem, writer, indentFactor);
writer.flush();
writer.close();
}
public static Writer writeJSONArray(JsonItem<JSONArray> jsonItem, Writer writer, int indentFactor){
JSONArray jsonArray=jsonItem.toJson();
return jsonArray.write(writer, indentFactor, 0);
}
private static final int INDENT_FACTOR=4;
}