make custom header for each chunk

This commit is contained in:
REAndroid 2023-01-15 13:40:43 -05:00
parent 4c9fabc425
commit 9e02964884
32 changed files with 920 additions and 395 deletions

View File

@ -15,35 +15,28 @@
*/ */
package com.reandroid.lib.arsc.chunk; package com.reandroid.lib.arsc.chunk;
import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.container.ExpandableBlockContainer; import com.reandroid.lib.arsc.container.ExpandableBlockContainer;
import com.reandroid.lib.arsc.header.HeaderBlock; import com.reandroid.lib.arsc.header.HeaderBlock;
import com.reandroid.lib.arsc.io.BlockReader; import com.reandroid.lib.arsc.io.BlockReader;
import java.io.IOException; import java.io.IOException;
public abstract class BaseChunk extends ExpandableBlockContainer { public abstract class BaseChunk<T extends HeaderBlock> extends ExpandableBlockContainer {
private final HeaderBlock mHeaderBlock; private final T mHeaderBlock;
protected BaseChunk(short chunkType, int initialChildesCount) { protected BaseChunk(T headerBlock, int initialChildesCount) {
super(initialChildesCount+1); super(initialChildesCount+1);
mHeaderBlock=new HeaderBlock(chunkType); this.mHeaderBlock = headerBlock;
addChild(mHeaderBlock); addChild(headerBlock);
}
protected BaseChunk(ChunkType chunkType, int initialChildesCount) {
this(chunkType.ID, initialChildesCount);
}
protected void addToHeader(Block block){
mHeaderBlock.addChild(block);
} }
void setHeaderLoaded(HeaderBlock.HeaderLoaded headerLoaded){ void setHeaderLoaded(HeaderBlock.HeaderLoaded headerLoaded){
mHeaderBlock.setHeaderLoaded(headerLoaded); getHeaderBlock().setHeaderLoaded(headerLoaded);
} }
public HeaderBlock getHeaderBlock(){ public final T getHeaderBlock(){
return mHeaderBlock; return mHeaderBlock;
} }
@Override @Override
protected final void onRefreshed() { protected final void onRefreshed() {
mHeaderBlock.refreshHeader(); getHeaderBlock().refreshHeader();
onChunkRefreshed(); onChunkRefreshed();
} }
protected abstract void onChunkRefreshed(); protected abstract void onChunkRefreshed();
@ -73,7 +66,7 @@ public abstract class BaseChunk extends ExpandableBlockContainer {
StringBuilder builder=new StringBuilder(); StringBuilder builder=new StringBuilder();
builder.append(getClass().getSimpleName()); builder.append(getClass().getSimpleName());
builder.append(": "); builder.append(": ");
builder.append(mHeaderBlock.toString()); builder.append(getHeaderBlock());
return builder.toString(); return builder.toString();
} }
} }

View File

@ -16,21 +16,20 @@
package com.reandroid.lib.arsc.chunk; package com.reandroid.lib.arsc.chunk;
import com.reandroid.lib.arsc.array.LibraryInfoArray; import com.reandroid.lib.arsc.array.LibraryInfoArray;
import com.reandroid.lib.arsc.header.LibraryHeader;
import com.reandroid.lib.arsc.item.IntegerItem; import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.value.LibraryInfo; import com.reandroid.lib.arsc.value.LibraryInfo;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
public class LibraryBlock extends BaseChunk { public class LibraryBlock extends BaseChunk<LibraryHeader> {
private final IntegerItem mLibCount;
private final LibraryInfoArray mLibraryInfoArray; private final LibraryInfoArray mLibraryInfoArray;
public LibraryBlock() { public LibraryBlock() {
super(ChunkType.LIBRARY,1); super(new LibraryHeader(),1);
this.mLibCount=new IntegerItem(); LibraryHeader header = getHeaderBlock();
this.mLibraryInfoArray=new LibraryInfoArray(mLibCount); this.mLibraryInfoArray = new LibraryInfoArray(header.getCount());
addToHeader(mLibCount);
addChild(mLibraryInfoArray); addChild(mLibraryInfoArray);
} }
public LibraryInfoArray getLibraryInfoArray(){ public LibraryInfoArray getLibraryInfoArray(){
@ -49,7 +48,7 @@ public class LibraryBlock extends BaseChunk {
return; return;
} }
getLibraryInfoArray().add(info); getLibraryInfoArray().add(info);
mLibCount.set(mLibraryInfoArray.childesCount()); getHeaderBlock().getCount().set(mLibraryInfoArray.childesCount());
} }
public Collection<LibraryInfo> listLibraryInfo(){ public Collection<LibraryInfo> listLibraryInfo(){
return getLibraryInfoArray().listItems(); return getLibraryInfoArray().listItems();
@ -62,12 +61,12 @@ public class LibraryBlock extends BaseChunk {
return mLibraryInfoArray.childesCount(); return mLibraryInfoArray.childesCount();
} }
public void setLibraryCount(int count){ public void setLibraryCount(int count){
mLibCount.set(count); getHeaderBlock().getCount().set(count);
mLibraryInfoArray.setChildesCount(count); mLibraryInfoArray.setChildesCount(count);
} }
@Override @Override
protected void onChunkRefreshed() { protected void onChunkRefreshed() {
mLibCount.set(mLibraryInfoArray.childesCount()); getHeaderBlock().getCount().set(mLibraryInfoArray.childesCount());
} }
public void merge(LibraryBlock libraryBlock){ public void merge(LibraryBlock libraryBlock){

View File

@ -17,6 +17,7 @@
import com.reandroid.lib.arsc.base.Block; import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.header.HeaderBlock; import com.reandroid.lib.arsc.header.HeaderBlock;
import com.reandroid.lib.arsc.header.OverlayableHeader;
import com.reandroid.lib.arsc.io.BlockLoad; import com.reandroid.lib.arsc.io.BlockLoad;
import com.reandroid.lib.arsc.io.BlockReader; import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.ByteArray; import com.reandroid.lib.arsc.item.ByteArray;
@ -29,9 +30,7 @@
* We didn't test this class with resource table, if someone found a resource/apk please * We didn't test this class with resource table, if someone found a resource/apk please
* create issue on https://github.com/REAndroid/ARSCLib * create issue on https://github.com/REAndroid/ARSCLib
* */ * */
public class Overlayable extends BaseChunk implements BlockLoad { public class Overlayable extends BaseChunk<OverlayableHeader> implements BlockLoad {
private final FixedLengthString name;
private final FixedLengthString actor;
/** /**
* @link body * @link body
* As on AOSP there is only a description of header struct but no mention about * As on AOSP there is only a description of header struct but no mention about
@ -39,33 +38,29 @@
* */ * */
private final ByteArray body; private final ByteArray body;
public Overlayable() { public Overlayable() {
super(ChunkType.OVERLAYABLE, 1); super(new OverlayableHeader(), 1);
this.name = new FixedLengthString(512);
this.actor = new FixedLengthString(512);
this.body = new ByteArray(); this.body = new ByteArray();
addToHeader(this.name);
addToHeader(this.actor);
addChild(this.body); addChild(this.body);
this.actor.setBlockLoad(this); getHeaderBlock().getActor().setBlockLoad(this);
} }
public ByteArray getBody() { public ByteArray getBody() {
return body; return body;
} }
public String getName(){ public String getName(){
return this.name.get(); return getHeaderBlock().getName().get();
} }
public void setName(String str){ public void setName(String str){
this.name.set(str); getHeaderBlock().getName().set(str);
} }
public String getActor(){ public String getActor(){
return this.actor.get(); return getHeaderBlock().getActor().get();
} }
public void setActor(String str){ public void setActor(String str){
this.actor.set(str); getHeaderBlock().getActor().set(str);
} }
@Override @Override
public void onBlockLoaded(BlockReader reader, Block sender) throws IOException { public void onBlockLoaded(BlockReader reader, Block sender) throws IOException {
if(sender==this.actor){ if(sender==getHeaderBlock().getActor()){
HeaderBlock header = getHeaderBlock(); HeaderBlock header = getHeaderBlock();
int bodySize=header.getChunkSize()-header.getHeaderSize(); int bodySize=header.getChunkSize()-header.getHeaderSize();
this.body.setSize(bodySize); this.body.setSize(bodySize);

View File

@ -16,6 +16,7 @@
package com.reandroid.lib.arsc.chunk; package com.reandroid.lib.arsc.chunk;
import com.reandroid.lib.arsc.base.Block; import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.header.OverlayablePolicyHeader;
import com.reandroid.lib.arsc.io.BlockLoad; import com.reandroid.lib.arsc.io.BlockLoad;
import com.reandroid.lib.arsc.io.BlockReader; import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.IntegerArray; import com.reandroid.lib.arsc.item.IntegerArray;
@ -29,22 +30,15 @@
* We didn't test this class with resource table, if someone found a resource/apk please * We didn't test this class with resource table, if someone found a resource/apk please
* create issue on https://github.com/REAndroid/ARSCLib * create issue on https://github.com/REAndroid/ARSCLib
* */ * */
public class OverlayablePolicy extends BaseChunk implements BlockLoad { public class OverlayablePolicy extends BaseChunk<OverlayablePolicyHeader> implements BlockLoad {
private final IntegerItem flags;
private final IntegerItem entryCount;
private final IntegerArray tableRefArray; private final IntegerArray tableRefArray;
public OverlayablePolicy(){ public OverlayablePolicy(){
super(ChunkType.OVERLAYABLE_POLICY, 1); super(new OverlayablePolicyHeader(), 1);
this.flags = new IntegerItem();
this.entryCount = new IntegerItem();
this.tableRefArray = new IntegerArray(); this.tableRefArray = new IntegerArray();
addToHeader(this.flags);
addToHeader(this.entryCount);
addChild(this.tableRefArray); addChild(this.tableRefArray);
this.entryCount.setBlockLoad(this); getHeaderBlock().getEntryCount().setBlockLoad(this);
} }
@Override @Override
public boolean isNull() { public boolean isNull() {
@ -61,10 +55,10 @@
return tableRefArray; return tableRefArray;
} }
public int getFlags() { public int getFlags() {
return flags.get(); return getHeaderBlock().getFlags().get();
} }
public void setFlags(int flags){ public void setFlags(int flags){
this.flags.set(flags); getHeaderBlock().getFlags().set(flags);
} }
public void setFlags(PolicyFlag[] policyFlags){ public void setFlags(PolicyFlag[] policyFlags){
setFlags(PolicyFlag.sum(policyFlags)); setFlags(PolicyFlag.sum(policyFlags));
@ -78,11 +72,12 @@
} }
@Override @Override
protected void onChunkRefreshed() { protected void onChunkRefreshed() {
this.entryCount.set(getTableRefArray().size()); getHeaderBlock().getEntryCount().set(getTableRefArray().size());
} }
@Override @Override
public void onBlockLoaded(BlockReader reader, Block sender) throws IOException { public void onBlockLoaded(BlockReader reader, Block sender) throws IOException {
if(sender==this.entryCount){ IntegerItem entryCount = getHeaderBlock().getEntryCount();
if(sender==entryCount){
this.tableRefArray.setSize(entryCount.get()); this.tableRefArray.setSize(entryCount.get());
} }
} }

View File

@ -24,6 +24,7 @@ package com.reandroid.lib.arsc.chunk;
import com.reandroid.lib.arsc.container.SingleBlockContainer; import com.reandroid.lib.arsc.container.SingleBlockContainer;
import com.reandroid.lib.arsc.container.SpecTypePair; import com.reandroid.lib.arsc.container.SpecTypePair;
import com.reandroid.lib.arsc.group.EntryGroup; import com.reandroid.lib.arsc.group.EntryGroup;
import com.reandroid.lib.arsc.header.PackageHeader;
import com.reandroid.lib.arsc.io.BlockLoad; import com.reandroid.lib.arsc.io.BlockLoad;
import com.reandroid.lib.arsc.io.BlockReader; import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.FixedLengthString; import com.reandroid.lib.arsc.item.FixedLengthString;
@ -42,17 +43,8 @@ package com.reandroid.lib.arsc.chunk;
import java.util.*; import java.util.*;
public class PackageBlock extends BaseChunk public class PackageBlock extends BaseChunk<PackageHeader>
implements BlockLoad, JSONConvert<JSONObject>, Comparable<PackageBlock> { implements JSONConvert<JSONObject>, Comparable<PackageBlock> {
private final IntegerItem mPackageId;
private final FixedLengthString mPackageName;
private final IntegerItem mTypeStringPoolOffset;
private final IntegerItem mTypeStringPoolCount;
private final IntegerItem mSpecStringPoolOffset;
private final IntegerItem mSpecStringPoolCount;
private final SingleBlockContainer<IntegerItem> mTypeIdOffsetContainer;
private final IntegerItem mTypeIdOffset;
private final TypeStringPool mTypeStringPool; private final TypeStringPool mTypeStringPool;
private final SpecStringPool mSpecStringPool; private final SpecStringPool mSpecStringPool;
@ -62,42 +54,19 @@ package com.reandroid.lib.arsc.chunk;
private final Map<Integer, EntryGroup> mEntriesGroup; private final Map<Integer, EntryGroup> mEntriesGroup;
public PackageBlock() { public PackageBlock() {
super(ChunkType.PACKAGE, 3); super(new PackageHeader(), 3);
this.mPackageId=new IntegerItem(); PackageHeader header = getHeaderBlock();
this.mPackageName = new FixedLengthString(256);
this.mTypeStringPoolOffset = new IntegerItem(); this.mTypeStringPool=new TypeStringPool(false, header.getTypeIdOffset());
this.mTypeStringPoolCount = new IntegerItem();
this.mSpecStringPoolOffset = new IntegerItem();
this.mSpecStringPoolCount = new IntegerItem();
this.mTypeIdOffsetContainer = new SingleBlockContainer<>();
this.mTypeIdOffset = new IntegerItem();
this.mTypeIdOffsetContainer.setItem(mTypeIdOffset);
this.mTypeStringPool=new TypeStringPool(false, mTypeIdOffset);
this.mSpecStringPool=new SpecStringPool(true); this.mSpecStringPool=new SpecStringPool(true);
this.mBody = new PackageBody(); this.mBody = new PackageBody();
this.mEntriesGroup=new HashMap<>(); this.mEntriesGroup=new HashMap<>();
mPackageId.setBlockLoad(this);
addToHeader(mPackageId);
addToHeader(mPackageName);
addToHeader(mTypeStringPoolOffset);
addToHeader(mTypeStringPoolCount);
addToHeader(mSpecStringPoolOffset);
addToHeader(mSpecStringPoolCount);
addToHeader(mTypeIdOffsetContainer);
addChild(mTypeStringPool); addChild(mTypeStringPool);
addChild(mSpecStringPool); addChild(mSpecStringPool);
addChild(mBody); addChild(mBody);
} }
public BlockList<UnknownChunk> getUnknownChunkList(){ public BlockList<UnknownChunk> getUnknownChunkList(){
return mBody.getUnknownChunkList(); return mBody.getUnknownChunkList();
@ -125,16 +94,7 @@ package com.reandroid.lib.arsc.chunk;
public void sortTypes(){ public void sortTypes(){
getSpecTypePairArray().sort(); getSpecTypePairArray().sort();
} }
@Override
public void onBlockLoaded(BlockReader reader, Block sender) throws IOException {
if(sender==mPackageId){
int headerSize=getHeaderBlock().getHeaderSize();
if(headerSize<288){
mTypeIdOffset.set(0);
mTypeIdOffsetContainer.setItem(null);
}
}
}
public void removeEmpty(){ public void removeEmpty(){
getSpecTypePairArray().removeEmptyPairs(); getSpecTypePairArray().removeEmptyPairs();
} }
@ -142,19 +102,19 @@ package com.reandroid.lib.arsc.chunk;
return getSpecTypePairArray().isEmpty(); return getSpecTypePairArray().isEmpty();
} }
public int getId(){ public int getId(){
return mPackageId.get(); return getHeaderBlock().getPackageId().get();
} }
public void setId(byte id){ public void setId(byte id){
setId(0xff & id); setId(0xff & id);
} }
public void setId(int id){ public void setId(int id){
mPackageId.set(id); getHeaderBlock().getPackageId().set(id);
} }
public String getName(){ public String getName(){
return mPackageName.get(); return getHeaderBlock().getPackageName().get();
} }
public void setName(String name){ public void setName(String name){
mPackageName.set(name); getHeaderBlock().getPackageName().set(name);
} }
public TableBlock getTableBlock(){ public TableBlock getTableBlock(){
Block parent=getParent(); Block parent=getParent();
@ -296,24 +256,24 @@ package com.reandroid.lib.arsc.chunk;
private void refreshTypeStringPoolOffset(){ private void refreshTypeStringPoolOffset(){
int pos=countUpTo(mTypeStringPool); int pos=countUpTo(mTypeStringPool);
mTypeStringPoolOffset.set(pos); getHeaderBlock().getTypeStringPoolOffset().set(pos);
} }
private void refreshTypeStringPoolCount(){ private void refreshTypeStringPoolCount(){
mTypeStringPoolCount.set(mTypeStringPool.countStrings()); getHeaderBlock().getTypeStringPoolCount().set(mTypeStringPool.countStrings());
} }
private void refreshSpecStringPoolOffset(){ private void refreshSpecStringPoolOffset(){
int pos=countUpTo(mSpecStringPool); int pos=countUpTo(mSpecStringPool);
mSpecStringPoolOffset.set(pos); getHeaderBlock().getSpecStringPoolOffset().set(pos);
} }
private void refreshSpecStringCount(){ private void refreshSpecStringCount(){
mSpecStringPoolCount.set(mSpecStringPool.countStrings()); getHeaderBlock().getSpecStringPoolCount().set(mSpecStringPool.countStrings());
} }
private void refreshTypeIdOffset(){ private void refreshTypeIdOffset(){
// TODO: find solution // TODO: find solution
//int largest=getSpecTypePairArray().getHighestTypeId(); //int largest=getSpecTypePairArray().getHighestTypeId();
//int count=getTypeStringPool().countStrings(); //int count=getTypeStringPool().countStrings();
//mTypeIdOffset.set(count-largest); //getHeaderBlock().getTypeIdOffset().set(count-largest);
mTypeIdOffset.set(0); getHeaderBlock().getTypeIdOffset().set(0);
} }
public void onEntryAdded(EntryBlock entryBlock){ public void onEntryAdded(EntryBlock entryBlock){
updateEntry(entryBlock); updateEntry(entryBlock);

View File

@ -18,27 +18,19 @@
import com.reandroid.lib.arsc.array.TypeBlockArray; import com.reandroid.lib.arsc.array.TypeBlockArray;
import com.reandroid.lib.arsc.base.Block; import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.container.SpecTypePair; import com.reandroid.lib.arsc.container.SpecTypePair;
import com.reandroid.lib.arsc.header.SpecHeader;
import com.reandroid.lib.arsc.item.*; import com.reandroid.lib.arsc.item.*;
import com.reandroid.lib.json.JSONConvert; import com.reandroid.lib.json.JSONConvert;
import com.reandroid.lib.json.JSONObject; import com.reandroid.lib.json.JSONObject;
import java.util.List; import java.util.List;
public class SpecBlock extends BaseChunk implements JSONConvert<JSONObject> { public class SpecBlock extends BaseChunk<SpecHeader> implements JSONConvert<JSONObject> {
private final SpecFlagsArray specFlagsArray; private final SpecFlagsArray specFlagsArray;
private final ByteItem mTypeId;
public SpecBlock() { public SpecBlock() {
super(ChunkType.SPEC, 1); super(new SpecHeader(), 1);
this.mTypeId=new ByteItem(); SpecHeader header = getHeaderBlock();
ByteItem res0 = new ByteItem(); this.specFlagsArray = new SpecFlagsArray(header.getEntryCount());
ShortItem res1 = new ShortItem();
IntegerItem entryCount = new IntegerItem();
this.specFlagsArray = new SpecFlagsArray(entryCount);
addToHeader(mTypeId);
addToHeader(res0);
addToHeader(res1);
addToHeader(entryCount);
addChild(specFlagsArray); addChild(specFlagsArray);
} }
public SpecFlagsArray getSpecFlagsArray(){ public SpecFlagsArray getSpecFlagsArray(){
@ -48,16 +40,16 @@
return specFlagsArray.toList(); return specFlagsArray.toList();
} }
public byte getTypeId(){ public byte getTypeId(){
return mTypeId.get(); return getHeaderBlock().getId().get();
} }
public int getTypeIdInt(){ public int getTypeIdInt(){
return (0xff & mTypeId.get()); return getHeaderBlock().getId().unsignedInt();
} }
public void setTypeId(int id){ public void setTypeId(int id){
setTypeId((byte) (0xff & id)); setTypeId((byte) (0xff & id));
} }
public void setTypeId(byte id){ public void setTypeId(byte id){
mTypeId.set(id); getHeaderBlock().getId().set(id);
} }
public TypeBlockArray getTypeBlockArray(){ public TypeBlockArray getTypeBlockArray(){
SpecTypePair specTypePair=getSpecTypePair(); SpecTypePair specTypePair=getSpecTypePair();

View File

@ -16,18 +16,19 @@
package com.reandroid.lib.arsc.chunk; package com.reandroid.lib.arsc.chunk;
import com.reandroid.lib.arsc.array.StagedAliasEntryArray; import com.reandroid.lib.arsc.array.StagedAliasEntryArray;
import com.reandroid.lib.arsc.header.StagedAliasHeader;
import com.reandroid.lib.arsc.item.IntegerItem; import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.value.StagedAliasEntry; import com.reandroid.lib.arsc.value.StagedAliasEntry;
import java.util.Collection; import java.util.Collection;
public class StagedAlias extends BaseChunk{ public class StagedAlias extends BaseChunk<StagedAliasHeader>{
private final StagedAliasEntryArray stagedAliasEntryArray; private final StagedAliasEntryArray stagedAliasEntryArray;
public StagedAlias() { public StagedAlias() {
super(ChunkType.STAGED_ALIAS, 1); super(new StagedAliasHeader(), 1);
IntegerItem count = new IntegerItem(); StagedAliasHeader header = getHeaderBlock();
addToHeader(count);
stagedAliasEntryArray = new StagedAliasEntryArray(count); stagedAliasEntryArray = new StagedAliasEntryArray(header.getCount());
addChild(stagedAliasEntryArray); addChild(stagedAliasEntryArray);
} }
public void merge(StagedAlias stagedAlias){ public void merge(StagedAlias stagedAlias){

View File

@ -19,6 +19,7 @@ import com.reandroid.lib.arsc.BuildInfo;
import com.reandroid.lib.arsc.array.PackageArray; import com.reandroid.lib.arsc.array.PackageArray;
import com.reandroid.lib.arsc.group.EntryGroup; import com.reandroid.lib.arsc.group.EntryGroup;
import com.reandroid.lib.arsc.header.HeaderBlock; import com.reandroid.lib.arsc.header.HeaderBlock;
import com.reandroid.lib.arsc.header.TableHeader;
import com.reandroid.lib.arsc.io.BlockReader; import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.IntegerItem; import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.pool.TableStringPool; import com.reandroid.lib.arsc.pool.TableStringPool;
@ -33,17 +34,15 @@ import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
public class TableBlock extends BaseChunk implements JSONConvert<JSONObject> { public class TableBlock extends BaseChunk<TableHeader> implements JSONConvert<JSONObject> {
private final IntegerItem mPackageCount;
private final TableStringPool mTableStringPool; private final TableStringPool mTableStringPool;
private final PackageArray mPackageArray; private final PackageArray mPackageArray;
private final Set<TableBlock> mFrameWorks=new HashSet<>(); private final Set<TableBlock> mFrameWorks=new HashSet<>();
public TableBlock() { public TableBlock() {
super(ChunkType.TABLE, 2); super(new TableHeader(), 2);
this.mPackageCount=new IntegerItem(); TableHeader header = getHeaderBlock();
this.mTableStringPool=new TableStringPool(true); this.mTableStringPool=new TableStringPool(true);
this.mPackageArray=new PackageArray(mPackageCount); this.mPackageArray=new PackageArray(header.getPackageCount());
addToHeader(mPackageCount);
addChild(mTableStringPool); addChild(mTableStringPool);
addChild(mPackageArray); addChild(mPackageArray);
} }
@ -68,7 +67,7 @@ public class TableBlock extends BaseChunk implements JSONConvert<JSONObject> {
private void refreshPackageCount(){ private void refreshPackageCount(){
int count = getPackageArray().childesCount(); int count = getPackageArray().childesCount();
mPackageCount.set(count); getHeaderBlock().getPackageCount().set(count);
} }
@Override @Override
protected void onChunkRefreshed() { protected void onChunkRefreshed() {

View File

@ -19,6 +19,7 @@ import com.reandroid.lib.arsc.array.EntryBlockArray;
import com.reandroid.lib.arsc.array.TypeBlockArray; import com.reandroid.lib.arsc.array.TypeBlockArray;
import com.reandroid.lib.arsc.base.Block; import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.container.SpecTypePair; import com.reandroid.lib.arsc.container.SpecTypePair;
import com.reandroid.lib.arsc.header.TypeHeader;
import com.reandroid.lib.arsc.io.BlockLoad; import com.reandroid.lib.arsc.io.BlockLoad;
import com.reandroid.lib.arsc.io.BlockReader; import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.*; import com.reandroid.lib.arsc.item.*;
@ -34,34 +35,20 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
public class TypeBlock extends BaseChunk public class TypeBlock extends BaseChunk<TypeHeader>
implements BlockLoad, JSONConvert<JSONObject>, Comparable<TypeBlock> { implements BlockLoad, JSONConvert<JSONObject>, Comparable<TypeBlock> {
private final ByteItem mTypeId;
private final ByteItem mTypeFlags;
private final IntegerItem mEntryCount;
private final ResConfig mResConfig;
private final EntryBlockArray mEntryArray; private final EntryBlockArray mEntryArray;
private TypeString mTypeString; private TypeString mTypeString;
public TypeBlock() { public TypeBlock() {
super(ChunkType.TYPE, 2); super(new TypeHeader(), 2);
this.mTypeId=new ByteItem(); TypeHeader header = getHeaderBlock();
this.mTypeFlags=new ByteItem();
ShortItem reserved = new ShortItem();
this.mEntryCount=new IntegerItem();
IntegerItem entriesStart = new IntegerItem();
this.mResConfig =new ResConfig();
IntegerArray entryOffsets = new IntegerArray(); IntegerArray entryOffsets = new IntegerArray();
this.mEntryArray = new EntryBlockArray(entryOffsets, mEntryCount, entriesStart); this.mEntryArray = new EntryBlockArray(entryOffsets,
header.getCount(), header.getEntriesStart());
mTypeFlags.setBlockLoad(this); header.getFlags().setBlockLoad(this);
addToHeader(mTypeId);
addToHeader(mTypeFlags);
addToHeader(reserved);
addToHeader(mEntryCount);
addToHeader(entriesStart);
addToHeader(mResConfig);
addChild(entryOffsets); addChild(entryOffsets);
addChild(mEntryArray); addChild(mEntryArray);
@ -99,16 +86,16 @@ public class TypeBlock extends BaseChunk
return mTypeString; return mTypeString;
} }
public byte getTypeId(){ public byte getTypeId(){
return mTypeId.get(); return getHeaderBlock().getId().get();
} }
public int getTypeIdInt(){ public int getTypeIdInt(){
return (0xff & mTypeId.get()); return getHeaderBlock().getId().unsignedInt();
} }
public void setTypeId(int id){ public void setTypeId(int id){
setTypeId((byte) (0xff & id)); setTypeId((byte) (0xff & id));
} }
public void setTypeId(byte id){ public void setTypeId(byte id){
mTypeId.set(id); getHeaderBlock().getId().set(id);
} }
public void setTypeName(String name){ public void setTypeName(String name){
TypeStringPool typeStringPool=getTypeStringPool(); TypeStringPool typeStringPool=getTypeStringPool();
@ -127,10 +114,11 @@ public class TypeBlock extends BaseChunk
return null; return null;
} }
public void setEntryCount(int count){ public void setEntryCount(int count){
if(count == mEntryCount.get()){ IntegerItem entryCount = getHeaderBlock().getCount();
if(count == entryCount.get()){
return; return;
} }
mEntryCount.set(count); entryCount.set(count);
onSetEntryCount(count); onSetEntryCount(count);
} }
public boolean isEmpty(){ public boolean isEmpty(){
@ -182,7 +170,7 @@ public class TypeBlock extends BaseChunk
return getEntryBlockArray().getEntry(entryId); return getEntryBlockArray().getEntry(entryId);
} }
public ResConfig getResConfig(){ public ResConfig getResConfig(){
return mResConfig; return getHeaderBlock().getConfig();
} }
public EntryBlockArray getEntryBlockArray(){ public EntryBlockArray getEntryBlockArray(){
return mEntryArray; return mEntryArray;
@ -212,7 +200,7 @@ public class TypeBlock extends BaseChunk
} }
@Override @Override
protected void onPreRefreshRefresh(){ protected void onPreRefreshRefresh(){
mResConfig.refresh(); getHeaderBlock().getConfig().refresh();
super.onPreRefreshRefresh(); super.onPreRefreshRefresh();
} }
/* /*
@ -280,8 +268,8 @@ public class TypeBlock extends BaseChunk
} }
@Override @Override
public void onBlockLoaded(BlockReader reader, Block sender) throws IOException { public void onBlockLoaded(BlockReader reader, Block sender) throws IOException {
if(sender==mTypeFlags){ if(sender==getHeaderBlock().getFlags()){
if(mTypeFlags.get()==0x1){ if(getHeaderBlock().getFlags().unsignedInt()==0x1){
//ResTable_sparseTypeEntry ? //ResTable_sparseTypeEntry ?
} }
} }

View File

@ -24,10 +24,10 @@ package com.reandroid.lib.arsc.chunk;
* This class can load any valid chunk, aimed to * This class can load any valid chunk, aimed to
* handle any future android changes * handle any future android changes
* */ * */
public class UnknownChunk extends BaseChunk implements HeaderBlock.HeaderLoaded { public class UnknownChunk extends BaseChunk<HeaderBlock> implements HeaderBlock.HeaderLoaded {
private final ByteArray body; private final ByteArray body;
public UnknownChunk() { public UnknownChunk() {
super(INITIAL_CHUNK_TYPE, 1); super(new HeaderBlock(INITIAL_CHUNK_TYPE), 1);
this.body = new ByteArray(); this.body = new ByteArray();
addChild(body); addChild(body);
setHeaderLoaded(this); setHeaderLoaded(this);

View File

@ -18,6 +18,7 @@ package com.reandroid.lib.arsc.chunk.xml;
import com.reandroid.lib.arsc.chunk.ChunkType; import com.reandroid.lib.arsc.chunk.ChunkType;
import com.reandroid.lib.arsc.base.Block; import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.chunk.BaseChunk; import com.reandroid.lib.arsc.chunk.BaseChunk;
import com.reandroid.lib.arsc.header.XmlNodeHeader;
import com.reandroid.lib.arsc.item.IntegerItem; import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.item.ResXmlString; import com.reandroid.lib.arsc.item.ResXmlString;
import com.reandroid.lib.arsc.pool.ResXmlStringPool; import com.reandroid.lib.arsc.pool.ResXmlStringPool;
@ -26,30 +27,23 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
public class BaseXmlChunk extends BaseChunk { public class BaseXmlChunk extends BaseChunk<XmlNodeHeader> {
private final IntegerItem mLineNumber;
private final IntegerItem mCommentReference;
private final IntegerItem mNamespaceReference; private final IntegerItem mNamespaceReference;
private final IntegerItem mStringReference; private final IntegerItem mStringReference;
BaseXmlChunk(ChunkType chunkType, int initialChildesCount) { BaseXmlChunk(ChunkType chunkType, int initialChildesCount) {
super(chunkType, initialChildesCount+2); super(new XmlNodeHeader(chunkType), initialChildesCount+2);
this.mLineNumber=new IntegerItem();
this.mCommentReference =new IntegerItem(-1);
this.mNamespaceReference=new IntegerItem(-1); this.mNamespaceReference=new IntegerItem(-1);
this.mStringReference=new IntegerItem(-1); this.mStringReference=new IntegerItem(-1);
addToHeader(mLineNumber);
addToHeader(mCommentReference);
addChild(mNamespaceReference); addChild(mNamespaceReference);
addChild(mStringReference); addChild(mStringReference);
} }
Set<ResXmlString> clearStringReferences(){ Set<ResXmlString> clearStringReferences(){
Set<ResXmlString> results=new HashSet<>(); Set<ResXmlString> results=new HashSet<>();
ResXmlString xmlString; ResXmlString xmlString;
xmlString=unLinkStringReference(mCommentReference); xmlString=unLinkStringReference(getHeaderBlock().getCommentReference());
if(xmlString!=null){ if(xmlString!=null){
results.add(xmlString); results.add(xmlString);
} }
@ -64,7 +58,7 @@ import java.util.Set;
return results; return results;
} }
void linkStringReferences(){ void linkStringReferences(){
linkStringReference(mCommentReference); linkStringReference(getHeaderBlock().getCommentReference());
linkStringReference(mNamespaceReference); linkStringReference(mNamespaceReference);
linkStringReference(mStringReference); linkStringReference(mStringReference);
} }
@ -82,18 +76,19 @@ import java.util.Set;
return xmlString; return xmlString;
} }
public void setLineNumber(int val){ public void setLineNumber(int val){
mLineNumber.set(val); getHeaderBlock().getLineNumber().set(val);
} }
public int getLineNumber(){ public int getLineNumber(){
return mLineNumber.get(); return getHeaderBlock().getLineNumber().get();
} }
public void setCommentReference(int val){ public void setCommentReference(int val){
unLinkStringReference(mCommentReference); IntegerItem comment=getHeaderBlock().getCommentReference();
mCommentReference.set(val); unLinkStringReference(comment);
linkStringReference(mCommentReference); getHeaderBlock().getCommentReference().set(val);
linkStringReference(comment);
} }
public int getCommentReference(){ public int getCommentReference(){
return mCommentReference.get(); return getHeaderBlock().getCommentReference().get();
} }
public void setNamespaceReference(int val){ public void setNamespaceReference(int val){
unLinkStringReference(mNamespaceReference); unLinkStringReference(mNamespaceReference);

View File

@ -36,13 +36,13 @@ package com.reandroid.lib.arsc.chunk.xml;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
public class ResXmlBlock extends BaseChunk implements JSONConvert<JSONObject> { public class ResXmlBlock extends BaseChunk<HeaderBlock> implements JSONConvert<JSONObject> {
private final ResXmlStringPool mResXmlStringPool; private final ResXmlStringPool mResXmlStringPool;
private final ResXmlIDMap mResXmlIDMap; private final ResXmlIDMap mResXmlIDMap;
private ResXmlElement mResXmlElement; private ResXmlElement mResXmlElement;
private final SingleBlockContainer<ResXmlElement> mResXmlElementContainer; private final SingleBlockContainer<ResXmlElement> mResXmlElementContainer;
public ResXmlBlock() { public ResXmlBlock() {
super(ChunkType.XML,3); super(new HeaderBlock(ChunkType.XML),3);
this.mResXmlStringPool=new ResXmlStringPool(true); this.mResXmlStringPool=new ResXmlStringPool(true);
this.mResXmlIDMap=new ResXmlIDMap(); this.mResXmlIDMap=new ResXmlIDMap();
this.mResXmlElement=new ResXmlElement(); this.mResXmlElement=new ResXmlElement();

View File

@ -19,6 +19,7 @@ import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.chunk.ChunkType; import com.reandroid.lib.arsc.chunk.ChunkType;
import com.reandroid.lib.arsc.array.ResXmlIDArray; import com.reandroid.lib.arsc.array.ResXmlIDArray;
import com.reandroid.lib.arsc.chunk.BaseChunk; import com.reandroid.lib.arsc.chunk.BaseChunk;
import com.reandroid.lib.arsc.header.HeaderBlock;
import com.reandroid.lib.arsc.io.BlockReader; import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.ResXmlID; import com.reandroid.lib.arsc.item.ResXmlID;
import com.reandroid.lib.arsc.pool.ResXmlStringPool; import com.reandroid.lib.arsc.pool.ResXmlStringPool;
@ -26,10 +27,10 @@ import com.reandroid.lib.arsc.pool.ResXmlStringPool;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
public class ResXmlIDMap extends BaseChunk { public class ResXmlIDMap extends BaseChunk<HeaderBlock> {
private final ResXmlIDArray mResXmlIDArray; private final ResXmlIDArray mResXmlIDArray;
public ResXmlIDMap() { public ResXmlIDMap() {
super(ChunkType.XML_RESOURCE_MAP, 1); super(new HeaderBlock(ChunkType.XML_RESOURCE_MAP), 1);
this.mResXmlIDArray=new ResXmlIDArray(getHeaderBlock()); this.mResXmlIDArray=new ResXmlIDArray(getHeaderBlock());
addChild(mResXmlIDArray); addChild(mResXmlIDArray);
} }

View File

@ -26,11 +26,9 @@ import com.reandroid.lib.arsc.item.BlockItem;
import com.reandroid.lib.arsc.item.ByteArray; import com.reandroid.lib.arsc.item.ByteArray;
import com.reandroid.lib.arsc.item.IntegerItem; import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.item.ShortItem; import com.reandroid.lib.arsc.item.ShortItem;
import com.reandroid.lib.arsc.util.HexBytesWriter;
import java.io.File; import java.io.*;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List; import java.util.List;
public class HeaderBlock extends ExpandableBlockContainer implements BlockLoad { public class HeaderBlock extends ExpandableBlockContainer implements BlockLoad {
@ -52,6 +50,9 @@ import java.util.List;
this.mHeaderSize.setBlockLoad(this); this.mHeaderSize.setBlockLoad(this);
this.mChunkSize.setBlockLoad(this); this.mChunkSize.setBlockLoad(this);
} }
public HeaderBlock(ChunkType chunkType){
this(chunkType.ID);
}
public ByteArray getExtraBytes() { public ByteArray getExtraBytes() {
return extraBytes; return extraBytes;
} }
@ -199,7 +200,12 @@ import java.util.List;
headerLoaded.onChunkSizeLoaded(headerSize, chunkSize); headerLoaded.onChunkSizeLoaded(headerSize, chunkSize);
} }
} }
/**
* Prints bytes in hex for debug/testing
* */
public String toHex(){
return HexBytesWriter.toHex(getBytes());
}
@Override @Override
public String toString(){ public String toString(){
short t = getType(); short t = getType();

View File

@ -16,11 +16,26 @@
package com.reandroid.lib.arsc.header; package com.reandroid.lib.arsc.header;
import com.reandroid.lib.arsc.chunk.ChunkType; import com.reandroid.lib.arsc.chunk.ChunkType;
import com.reandroid.lib.arsc.item.IntegerItem;
/**No importance of this class, to be removed latter*/ public class LibraryHeader extends HeaderBlock{
@Deprecated private final IntegerItem count;
public class AnyHeader extends HeaderBlock{ public LibraryHeader() {
public AnyHeader() { super(ChunkType.LIBRARY.ID);
super(ChunkType.NULL.ID); this.count = new IntegerItem();
addChild(this.count);
}
public IntegerItem getCount() {
return count;
}
@Override
public String toString(){
if(getChunkType()!=ChunkType.LIBRARY){
return super.toString();
}
return getClass().getSimpleName()
+" {count="+getCount() + '}';
} }
} }

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reandroid.lib.arsc.header;
import com.reandroid.lib.arsc.chunk.ChunkType;
import com.reandroid.lib.arsc.item.FixedLengthString;
public class OverlayableHeader extends HeaderBlock{
private final FixedLengthString name;
private final FixedLengthString actor;
public OverlayableHeader() {
super(ChunkType.OVERLAYABLE.ID);
this.name = new FixedLengthString(512);
this.actor = new FixedLengthString(512);
addChild(this.name);
addChild(this.actor);
}
public FixedLengthString getName() {
return name;
}
public FixedLengthString getActor() {
return actor;
}
@Override
public String toString(){
if(getChunkType()!=ChunkType.OVERLAYABLE){
return super.toString();
}
return getClass().getSimpleName()
+" {count="+getName()
+", actor=" + getActor() + '}';
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reandroid.lib.arsc.header;
import com.reandroid.lib.arsc.chunk.ChunkType;
import com.reandroid.lib.arsc.item.IntegerItem;
public class OverlayablePolicyHeader extends HeaderBlock{
private final IntegerItem flags;
private final IntegerItem entryCount;
public OverlayablePolicyHeader() {
super(ChunkType.OVERLAYABLE_POLICY.ID);
this.flags = new IntegerItem();
this.entryCount = new IntegerItem();
addChild(this.flags);
addChild(this.entryCount);
}
public IntegerItem getFlags() {
return flags;
}
public IntegerItem getEntryCount() {
return entryCount;
}
@Override
public String toString(){
if(getChunkType()!=ChunkType.OVERLAYABLE_POLICY){
return super.toString();
}
return getClass().getSimpleName()
+" {flags="+getFlags().toHex()
+", entryCount=" + getEntryCount() + '}';
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reandroid.lib.arsc.header;
import com.reandroid.lib.arsc.chunk.ChunkType;
import com.reandroid.lib.arsc.container.SingleBlockContainer;
import com.reandroid.lib.arsc.item.FixedLengthString;
import com.reandroid.lib.arsc.item.IntegerItem;
public class PackageHeader extends HeaderBlock{
private final IntegerItem packageId;
private final FixedLengthString packageName;
private final IntegerItem typeStringPoolOffset;
private final IntegerItem typeStringPoolCount;
private final IntegerItem specStringPoolOffset;
private final IntegerItem specStringPoolCount;
private final SingleBlockContainer<IntegerItem> typeIdOffsetContainer;
private final IntegerItem typeIdOffset;
public PackageHeader() {
super(ChunkType.PACKAGE.ID);
this.packageId = new IntegerItem();
this.packageName = new FixedLengthString(256);
this.typeStringPoolOffset = new IntegerItem();
this.typeStringPoolCount = new IntegerItem();
this.specStringPoolOffset = new IntegerItem();
this.specStringPoolCount = new IntegerItem();
this.typeIdOffsetContainer = new SingleBlockContainer<>();
this.typeIdOffset = new IntegerItem();
this.typeIdOffsetContainer.setItem(typeIdOffset);
addChild(this.packageId);
addChild(this.packageName);
addChild(this.typeStringPoolOffset);
addChild(this.typeStringPoolCount);
addChild(this.specStringPoolOffset);
addChild(this.specStringPoolCount);
addChild(this.typeIdOffsetContainer);
}
public IntegerItem getPackageId() {
return packageId;
}
public FixedLengthString getPackageName() {
return packageName;
}
public IntegerItem getTypeStringPoolOffset() {
return typeStringPoolOffset;
}
public IntegerItem getTypeStringPoolCount() {
return typeStringPoolCount;
}
public IntegerItem getSpecStringPoolOffset() {
return specStringPoolOffset;
}
public IntegerItem getSpecStringPoolCount() {
return specStringPoolCount;
}
public IntegerItem getTypeIdOffset() {
return typeIdOffset;
}
@Override
void onHeaderSizeLoaded(int size){
super.onHeaderSizeLoaded(size);
if(size<288){
typeIdOffset.set(0);
typeIdOffsetContainer.setItem(null);
}
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reandroid.lib.arsc.header;
import com.reandroid.lib.arsc.chunk.ChunkType;
import com.reandroid.lib.arsc.item.ByteItem;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.item.ShortItem;
public class SpecHeader extends HeaderBlock{
private final ByteItem id;
private final IntegerItem entryCount;
public SpecHeader() {
super(ChunkType.SPEC.ID);
this.id = new ByteItem();
ByteItem res0 = new ByteItem();
ShortItem res1 = new ShortItem();
this.entryCount = new IntegerItem();
addChild(id);
addChild(res0);
addChild(res1);
addChild(entryCount);
}
public ByteItem getId() {
return id;
}
public IntegerItem getEntryCount() {
return entryCount;
}
@Override
public String toString(){
if(getChunkType() != ChunkType.SPEC){
return super.toString();
}
return getClass().getSimpleName()
+" {id="+getId().toHex()
+", entryCount=" + getEntryCount() + '}';
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reandroid.lib.arsc.header;
import com.reandroid.lib.arsc.chunk.ChunkType;
import com.reandroid.lib.arsc.item.IntegerItem;
public class StagedAliasHeader extends HeaderBlock{
private final IntegerItem count;
public StagedAliasHeader() {
super(ChunkType.STAGED_ALIAS.ID);
this.count = new IntegerItem();
addChild(count);
}
public IntegerItem getCount() {
return count;
}
@Override
public String toString(){
if(getChunkType()!=ChunkType.STAGED_ALIAS){
return super.toString();
}
return getClass().getSimpleName()
+" {count="+getCount()+ '}';
}
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reandroid.lib.arsc.header;
import com.reandroid.lib.arsc.chunk.ChunkType;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.item.ShortItem;
public class StringPoolHeader extends HeaderBlock{
private final IntegerItem countStrings;
private final IntegerItem countStyles;
private final ShortItem flagUtf8;
private final ShortItem flagSorted;
private final IntegerItem startStrings;
private final IntegerItem startStyles;
public StringPoolHeader() {
super(ChunkType.STRING.ID);
this.countStrings = new IntegerItem();
this.countStyles = new IntegerItem();
this.flagUtf8 = new ShortItem();
this.flagSorted = new ShortItem();
this.startStrings = new IntegerItem();
this.startStyles = new IntegerItem();
addChild(countStrings);
addChild(countStyles);
addChild(flagUtf8);
addChild(flagSorted);
addChild(startStrings);
addChild(startStyles);
}
public IntegerItem getCountStrings() {
return countStrings;
}
public IntegerItem getCountStyles() {
return countStyles;
}
public ShortItem getFlagUtf8() {
return flagUtf8;
}
public ShortItem getFlagSorted() {
return flagSorted;
}
public IntegerItem getStartStrings() {
return startStrings;
}
public IntegerItem getStartStyles() {
return startStyles;
}
@Override
public String toString(){
if(getChunkType()!=ChunkType.STRING){
return super.toString();
}
return getClass().getSimpleName()
+" {strings="+getCountStrings()
+", styles="+getCountStyles()
+", utf8="+getFlagUtf8().toHex()
+", sorted="+getFlagSorted().toHex()
+", offset-strings="+getStartStrings().get()
+", offset-styles="+getStartStyles().get() + '}';
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reandroid.lib.arsc.header;
import com.reandroid.lib.arsc.chunk.ChunkType;
import com.reandroid.lib.arsc.item.IntegerItem;
public class TableHeader extends HeaderBlock{
private final IntegerItem packageCount;
public TableHeader() {
super(ChunkType.TABLE.ID);
this.packageCount = new IntegerItem();
addChild(packageCount);
}
public IntegerItem getPackageCount() {
return packageCount;
}
@Override
public String toString(){
if(getChunkType()!=ChunkType.TABLE){
return super.toString();
}
return getClass().getSimpleName()
+" {packageCount=" + getPackageCount() + '}';
}
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reandroid.lib.arsc.header;
import com.reandroid.lib.arsc.chunk.ChunkType;
import com.reandroid.lib.arsc.item.ByteItem;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.item.ShortItem;
import com.reandroid.lib.arsc.value.ResConfig;
public class TypeHeader extends HeaderBlock{
private final ByteItem id;
private final ByteItem flags;
private final IntegerItem count;
private final IntegerItem entriesStart;
private final ResConfig config;
public TypeHeader() {
super(ChunkType.TYPE.ID);
this.id = new ByteItem();
this.flags = new ByteItem();
ShortItem reserved = new ShortItem();
this.count = new IntegerItem();
this.entriesStart = new IntegerItem();
this.config = new ResConfig();
addChild(id);
addChild(flags);
addChild(reserved);
addChild(count);
addChild(entriesStart);
addChild(config);
}
public ByteItem getId() {
return id;
}
public ByteItem getFlags() {
return flags;
}
public IntegerItem getCount() {
return count;
}
public IntegerItem getEntriesStart() {
return entriesStart;
}
public ResConfig getConfig() {
return config;
}
@Override
public String toString(){
if(getChunkType()!=ChunkType.TYPE){
return super.toString();
}
return getClass().getSimpleName()
+" {id="+getId().toHex()
+", flags=" + getFlags().toHex()
+", count=" + getCount()
+", entriesStart=" + getEntriesStart()
+", config=" + getConfig()
+", flags=" + getFlags().toHex() + '}';
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reandroid.lib.arsc.header;
import com.reandroid.lib.arsc.chunk.ChunkType;
import com.reandroid.lib.arsc.item.IntegerItem;
public class XmlNodeHeader extends HeaderBlock{
private final IntegerItem lineNumber;
private final IntegerItem commentReference;
private final ChunkType chunkType;
public XmlNodeHeader(ChunkType chunkType) {
super(chunkType.ID);
this.chunkType = chunkType;
this.lineNumber = new IntegerItem();
this.commentReference = new IntegerItem(-1);
addChild(lineNumber);
addChild(commentReference);
}
public IntegerItem getLineNumber() {
return lineNumber;
}
public IntegerItem getCommentReference() {
return commentReference;
}
@Override
public String toString(){
if(getChunkType() != chunkType){
return super.toString();
}
return getClass().getSimpleName()
+" {lineNumber="+getLineNumber()
+", commentReference=" + getCommentReference() + '}';
}
}

View File

@ -43,6 +43,12 @@ public class ByteItem extends BlockItem {
public byte get(){ public byte get(){
return getBytesInternal()[0]; return getBytesInternal()[0];
} }
public int unsignedInt(){
return 0xff & get();
}
public String toHex(){
return String.format("0x%02x", unsignedInt());
}
@Override @Override
public String toString(){ public String toString(){
return String.valueOf(get()); return String.valueOf(get());

View File

@ -41,6 +41,9 @@ public class IntegerItem extends BlockItem implements ReferenceItem{
public int get(){ public int get(){
return mCache; return mCache;
} }
public String toHex(){
return String.format("0x%08x", get());
}
@Override @Override
protected void onBytesChanged() { protected void onBytesChanged() {
// To save cpu usage, better to calculate once only when bytes changed // To save cpu usage, better to calculate once only when bytes changed

View File

@ -40,6 +40,9 @@ public class ShortItem extends BlockItem {
public int unsignedInt(){ public int unsignedInt(){
return 0xffff & get(); return 0xffff & get();
} }
public String toHex(){
return String.format("0x%04x", unsignedInt());
}
@Override @Override
protected void onBytesChanged() { protected void onBytesChanged() {
// To save cpu usage, better to calculate once only when bytes changed // To save cpu usage, better to calculate once only when bytes changed

View File

@ -15,72 +15,58 @@
*/ */
package com.reandroid.lib.arsc.pool; package com.reandroid.lib.arsc.pool;
import com.reandroid.lib.arsc.chunk.ChunkType; import com.reandroid.lib.arsc.array.StringArray;
import com.reandroid.lib.arsc.array.StringArray; import com.reandroid.lib.arsc.array.StyleArray;
import com.reandroid.lib.arsc.array.StyleArray; import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.base.Block; import com.reandroid.lib.arsc.chunk.BaseChunk;
import com.reandroid.lib.arsc.chunk.BaseChunk; import com.reandroid.lib.arsc.group.StringGroup;
import com.reandroid.lib.arsc.group.StringGroup; import com.reandroid.lib.arsc.header.StringPoolHeader;
import com.reandroid.lib.arsc.io.BlockLoad; import com.reandroid.lib.arsc.io.BlockLoad;
import com.reandroid.lib.arsc.io.BlockReader; import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.*; import com.reandroid.lib.arsc.item.*;
import com.reandroid.lib.arsc.model.StyleSpanInfo; import com.reandroid.lib.json.JSONArray;
import com.reandroid.lib.json.JSONConvert; import com.reandroid.lib.json.JSONConvert;
import com.reandroid.lib.json.JSONArray;
import com.reandroid.lib.json.JSONObject;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
public abstract class BaseStringPool<T extends StringItem> extends BaseChunk implements BlockLoad, JSONConvert<JSONArray>, Comparator<String> { public abstract class BaseStringPool<T extends StringItem> extends BaseChunk<StringPoolHeader> implements BlockLoad, JSONConvert<JSONArray>, Comparator<String> {
private final IntegerItem mCountStrings;
private final IntegerItem mCountStyles;
private final ShortItem mFlagUtf8;
private final ShortItem mFlagSorted;
private final IntegerItem mStartStrings;
private final IntegerItem mStartStyles;
private final IntegerArray mOffsetStrings;
private final IntegerArray mOffsetStyles;
private final StringArray<T> mArrayStrings; private final StringArray<T> mArrayStrings;
private final StyleArray mArrayStyles; private final StyleArray mArrayStyles;
private final Map<String, StringGroup<T>> mUniqueMap; private final Map<String, StringGroup<T>> mUniqueMap;
BaseStringPool(boolean is_utf8){ BaseStringPool(boolean is_utf8){
super(ChunkType.STRING, 4); super(new StringPoolHeader(), 4);
this.mCountStrings=new IntegerItem(); //header IntegerArray offsetStrings = new IntegerArray();
this.mCountStyles=new IntegerItem(); //header IntegerArray offsetStyles = new IntegerArray();
this.mFlagUtf8 =new ShortItem(); //header
this.mFlagSorted=new ShortItem(); //header
this.mStartStrings=new IntegerItem(); //header
this.mStartStyles=new IntegerItem(); //header
this.mOffsetStrings=new IntegerArray();//1 StringPoolHeader header = getHeaderBlock();
this.mOffsetStyles=new IntegerArray(); //2
this.mArrayStrings=newInstance(mOffsetStrings, mCountStrings, mStartStrings, is_utf8); //3
this.mArrayStyles=new StyleArray(mOffsetStyles, mCountStyles, mStartStyles); //4
addToHeader(mCountStrings); this.mArrayStrings = newInstance(
addToHeader(mCountStyles); offsetStrings,
addToHeader(mFlagUtf8); header.getCountStrings(),
addToHeader(mFlagSorted); header.getStartStrings(),
addToHeader(mStartStrings); is_utf8);
addToHeader(mStartStyles);
addChild(mOffsetStrings); this.mArrayStyles = new StyleArray(
addChild(mOffsetStyles); offsetStyles,
header.getCountStyles(),
header.getStartStyles());
addChild(offsetStrings);
addChild(offsetStyles);
addChild(mArrayStrings); addChild(mArrayStrings);
addChild(mArrayStyles); addChild(mArrayStyles);
setUtf8(is_utf8, false); setUtf8(is_utf8, false);
mFlagUtf8.setBlockLoad(this); header.getFlagUtf8().setBlockLoad(this);
mUniqueMap=new HashMap<>();
mUniqueMap = new HashMap<>();
} }
public List<String> toStringList(){ public List<String> toStringList(){
return getStringsArray().toStringList(); return getStringsArray().toStringList();
@ -137,13 +123,12 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
// call this after modifying string values // call this after modifying string values
public void refreshUniqueIdMap(){ public void refreshUniqueIdMap(){
mUniqueMap.clear(); mUniqueMap.clear();
T[] allChildes=getStrings(); T[] stringsArray = getStrings();
if(allChildes==null){ if(stringsArray==null){
return; return;
} }
int max=allChildes.length; for(int i=0;i<stringsArray.length;i++){
for(int i=0;i<max;i++){ T item=stringsArray[i];
T item=allChildes[i];
if(item==null){ if(item==null){
continue; continue;
} }
@ -237,7 +222,7 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
private T createNewString(String str){ private T createNewString(String str){
T item=mArrayStrings.createNext(); T item=mArrayStrings.createNext();
item.set(str); item.set(str);
mCountStrings.set(mArrayStrings.childesCount()); getHeaderBlock().getCountStrings().set(mArrayStrings.childesCount());
return item; return item;
} }
public final StyleItem getStyle(int index){ public final StyleItem getStyle(int index){
@ -249,35 +234,30 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
public final int countStyles(){ public final int countStyles(){
return mArrayStyles.childesCount(); return mArrayStyles.childesCount();
} }
public final T[] getStrings(){ public final T[] getStrings(){
return mArrayStrings.getChildes(); return mArrayStrings.getChildes();
} }
public final StyleItem[] getStyles(){ public final StyleItem[] getStyles(){
return mArrayStyles.getChildes(); return mArrayStyles.getChildes();
} }
private void setUtf8Flag(short flag){
mFlagUtf8.set(flag);
}
public void setUtf8(boolean is_utf8){ public void setUtf8(boolean is_utf8){
setUtf8(is_utf8, true); setUtf8(is_utf8, true);
} }
private void setSortedFlag(short flag){
mFlagSorted.set(flag);
}
public final void setSorted(boolean sorted){ public final void setSorted(boolean sorted){
ShortItem flagSorted = getHeaderBlock().getFlagSorted();
if(sorted){ if(sorted){
setSortedFlag(FLAG_SORTED); flagSorted.set(FLAG_SORTED);
}else { }else {
setSortedFlag((short)0); flagSorted.set((short)0);
} }
} }
private void setUtf8(boolean is_utf8, boolean updateAll){ private void setUtf8(boolean is_utf8, boolean updateAll){
boolean old= isUtf8Flag(); ShortItem flagUtf8 = getHeaderBlock().getFlagUtf8();
boolean old = isUtf8Flag();
if(is_utf8){ if(is_utf8){
setUtf8Flag(UTF8_FLAG_VALUE); flagUtf8.set(UTF8_FLAG_VALUE);
}else { }else {
setUtf8Flag((short) 0); flagUtf8.set((short) 0);
} }
if(!updateAll || old == isUtf8Flag()){ if(!updateAll || old == isUtf8Flag()){
return; return;
@ -285,13 +265,8 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
mArrayStrings.setUtf8(is_utf8); mArrayStrings.setUtf8(is_utf8);
} }
private boolean isUtf8Flag(){ private boolean isUtf8Flag(){
return (mFlagUtf8.get() & FLAG_UTF8) !=0; return (getHeaderBlock().getFlagUtf8().get() & FLAG_UTF8) !=0;
} }
private boolean isSortedFlag(){
return (mFlagSorted.get() & FLAG_SORTED) !=0;
}
abstract StringArray<T> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8); abstract StringArray<T> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8);
@Override @Override
protected void onChunkRefreshed() { protected void onChunkRefreshed() {
@ -305,7 +280,7 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
@Override @Override
public void onBlockLoaded(BlockReader reader, Block sender) throws IOException { public void onBlockLoaded(BlockReader reader, Block sender) throws IOException {
if(sender== mFlagUtf8){ if(sender == getHeaderBlock().getFlagUtf8()){
mArrayStrings.setUtf8(isUtf8Flag()); mArrayStrings.setUtf8(isUtf8Flag());
} }
} }
@ -319,112 +294,15 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
if(json==null){ if(json==null){
return; return;
} }
loadStyledStrings(json); JsonStringPoolHelper<T> helper=new JsonStringPoolHelper<>(this);
helper.loadStyledStrings(json);
refresh(); refresh();
} }
public void loadStyledStrings(JSONArray jsonArray) {
//Styled strings should be at first rows of string pool thus we clear all before adding
getStringsArray().clearChildes();
getStyleArray().clearChildes();
List<StyledString> styledStringList = StyledString.fromJson(jsonArray);
loadText(styledStringList);
Map<String, Integer> tagIndexMap = loadStyleTags(styledStringList);
loadStyles(styledStringList, tagIndexMap);
refreshUniqueIdMap();
}
private void loadText(List<StyledString> styledStringList) {
StringArray<T> stringsArray = getStringsArray();
int size=styledStringList.size();
stringsArray.ensureSize(size);
for(int i=0;i<size;i++){
StyledString styledString=styledStringList.get(i);
T item=stringsArray.get(i);
item.set(styledString.text);
}
}
private Map<String, Integer> loadStyleTags(List<StyledString> styledStringList) {
Map<String, Integer> indexMap=new HashMap<>();
List<String> tagList=new ArrayList<>(getStyleTags(styledStringList));
tagList.sort(this);
StringArray<T> stringsArray = getStringsArray();
int tagsSize = tagList.size();
int initialSize = stringsArray.childesCount();
stringsArray.ensureSize(initialSize + tagsSize);
for(int i=0;i<tagsSize;i++){
String tag = tagList.get(i);
T item = stringsArray.get(initialSize + i);
item.set(tag);
indexMap.put(tag, item.getIndex());
}
return indexMap;
}
private void loadStyles(List<StyledString> styledStringList, Map<String, Integer> tagIndexMap){
StyleArray styleArray = getStyleArray();
int size=styledStringList.size();
styleArray.ensureSize(size);
for(int i=0;i<size;i++){
StyledString ss = styledStringList.get(i);
StyleItem styleItem = styleArray.get(i);
for(StyleSpanInfo spanInfo:ss.spanInfoList){
int tagIndex=tagIndexMap.get(spanInfo.getTag());
styleItem.addStylePiece(tagIndex, spanInfo.getFirst(), spanInfo.getLast());
}
}
}
private static Set<String> getStyleTags(List<StyledString> styledStringList){
Set<String> results=new HashSet<>();
for(StyledString ss:styledStringList){
for(StyleSpanInfo spanInfo:ss.spanInfoList){
results.add(spanInfo.getTag());
}
}
return results;
}
@Override @Override
public int compare(String s1, String s2) { public int compare(String s1, String s2) {
return s1.compareTo(s2); return s1.compareTo(s2);
} }
private static class StyledString{
final String text;
final List<StyleSpanInfo> spanInfoList;
StyledString(String text, List<StyleSpanInfo> spanInfoList){
this.text=text;
this.spanInfoList=spanInfoList;
}
@Override
public String toString(){
return text;
}
static List<StyledString> fromJson(JSONArray jsonArray){
int length = jsonArray.length();
List<StyledString> results=new ArrayList<>();
for(int i=0;i<length;i++){
StyledString styledString=fromJson(jsonArray.getJSONObject(i));
results.add(styledString);
}
return results;
}
static StyledString fromJson(JSONObject jsonObject){
String text= jsonObject.getString(StringItem.NAME_string);
JSONObject style=jsonObject.getJSONObject(StringItem.NAME_style);
JSONArray spansArray=style.getJSONArray(StyleItem.NAME_spans);
List<StyleSpanInfo> spanInfoList = toSpanInfoList(spansArray);
return new StyledString(text, spanInfoList);
}
private static List<StyleSpanInfo> toSpanInfoList(JSONArray jsonArray){
int length = jsonArray.length();
List<StyleSpanInfo> results=new ArrayList<>(length);
for(int i=0;i<length;i++){
JSONObject jsonObject = jsonArray.getJSONObject(i);
StyleSpanInfo spanInfo=new StyleSpanInfo(null, 0,0);
spanInfo.fromJson(jsonObject);
results.add(spanInfo);
}
return results;
}
}
private static final short UTF8_FLAG_VALUE=0x0100; private static final short UTF8_FLAG_VALUE=0x0100;
private static final short FLAG_UTF8 = 0x0100; private static final short FLAG_UTF8 = 0x0100;

View File

@ -0,0 +1,117 @@
package com.reandroid.lib.arsc.pool;
import com.reandroid.lib.arsc.array.StringArray;
import com.reandroid.lib.arsc.array.StyleArray;
import com.reandroid.lib.arsc.item.StringItem;
import com.reandroid.lib.arsc.item.StyleItem;
import com.reandroid.lib.arsc.model.StyleSpanInfo;
import com.reandroid.lib.json.JSONArray;
import com.reandroid.lib.json.JSONObject;
import java.util.*;
class JsonStringPoolHelper<T extends StringItem> {
private final BaseStringPool<T> stringPool;
JsonStringPoolHelper(BaseStringPool<T> stringPool){
this.stringPool=stringPool;
}
void loadStyledStrings(JSONArray jsonArray) {
//Styled strings should be at first rows of string pool thus we clear all before adding
stringPool.getStringsArray().clearChildes();
stringPool.getStyleArray().clearChildes();
List<StyledString> styledStringList = StyledString.fromJson(jsonArray);
loadText(styledStringList);
Map<String, Integer> tagIndexMap = loadStyleTags(styledStringList);
loadStyles(styledStringList, tagIndexMap);
stringPool.refreshUniqueIdMap();
}
private void loadText(List<StyledString> styledStringList) {
StringArray<T> stringsArray = stringPool.getStringsArray();
int size=styledStringList.size();
stringsArray.ensureSize(size);
for(int i=0;i<size;i++){
StyledString styledString=styledStringList.get(i);
T item=stringsArray.get(i);
item.set(styledString.text);
}
}
private Map<String, Integer> loadStyleTags(List<StyledString> styledStringList) {
Map<String, Integer> indexMap=new HashMap<>();
List<String> tagList=new ArrayList<>(getStyleTags(styledStringList));
tagList.sort(stringPool);
StringArray<T> stringsArray = stringPool.getStringsArray();
int tagsSize = tagList.size();
int initialSize = stringsArray.childesCount();
stringsArray.ensureSize(initialSize + tagsSize);
for(int i=0;i<tagsSize;i++){
String tag = tagList.get(i);
T item = stringsArray.get(initialSize + i);
item.set(tag);
indexMap.put(tag, item.getIndex());
}
return indexMap;
}
private void loadStyles(List<StyledString> styledStringList, Map<String, Integer> tagIndexMap){
StyleArray styleArray = stringPool.getStyleArray();
int size=styledStringList.size();
styleArray.ensureSize(size);
for(int i=0;i<size;i++){
StyledString ss = styledStringList.get(i);
StyleItem styleItem = styleArray.get(i);
for(StyleSpanInfo spanInfo:ss.spanInfoList){
int tagIndex=tagIndexMap.get(spanInfo.getTag());
styleItem.addStylePiece(tagIndex, spanInfo.getFirst(), spanInfo.getLast());
}
}
}
private static Set<String> getStyleTags(List<StyledString> styledStringList){
Set<String> results=new HashSet<>();
for(StyledString ss:styledStringList){
for(StyleSpanInfo spanInfo:ss.spanInfoList){
results.add(spanInfo.getTag());
}
}
return results;
}
private static class StyledString{
final String text;
final List<StyleSpanInfo> spanInfoList;
StyledString(String text, List<StyleSpanInfo> spanInfoList){
this.text=text;
this.spanInfoList=spanInfoList;
}
@Override
public String toString(){
return text;
}
static List<StyledString> fromJson(JSONArray jsonArray){
int length = jsonArray.length();
List<StyledString> results=new ArrayList<>();
for(int i=0;i<length;i++){
StyledString styledString=fromJson(jsonArray.getJSONObject(i));
results.add(styledString);
}
return results;
}
static StyledString fromJson(JSONObject jsonObject){
String text= jsonObject.getString(StringItem.NAME_string);
JSONObject style=jsonObject.getJSONObject(StringItem.NAME_style);
JSONArray spansArray=style.getJSONArray(StyleItem.NAME_spans);
List<StyleSpanInfo> spanInfoList = toSpanInfoList(spansArray);
return new StyledString(text, spanInfoList);
}
private static List<StyleSpanInfo> toSpanInfoList(JSONArray jsonArray){
int length = jsonArray.length();
List<StyleSpanInfo> results=new ArrayList<>(length);
for(int i=0;i<length;i++){
JSONObject jsonObject = jsonArray.getJSONObject(i);
StyleSpanInfo spanInfo=new StyleSpanInfo(null, 0,0);
spanInfo.fromJson(jsonObject);
results.add(spanInfo);
}
return results;
}
}
}

View File

@ -1,23 +0,0 @@
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reandroid.lib.arsc.pool;
public enum PoolType {
TABLE,
SPEC,
TYPE,
XML
}

View File

@ -20,6 +20,7 @@ import com.reandroid.lib.arsc.array.TableStringArray;
import com.reandroid.lib.arsc.chunk.ChunkType; import com.reandroid.lib.arsc.chunk.ChunkType;
import com.reandroid.lib.arsc.chunk.UnknownChunk; import com.reandroid.lib.arsc.chunk.UnknownChunk;
import com.reandroid.lib.arsc.header.HeaderBlock; import com.reandroid.lib.arsc.header.HeaderBlock;
import com.reandroid.lib.arsc.header.StringPoolHeader;
import com.reandroid.lib.arsc.io.BlockReader; import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.IntegerArray; import com.reandroid.lib.arsc.item.IntegerArray;
import com.reandroid.lib.arsc.item.IntegerItem; import com.reandroid.lib.arsc.item.IntegerItem;

View File

@ -0,0 +1,86 @@
package com.reandroid.lib.arsc.util;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
public class HexBytesWriter {
private final byte[] byteArray;
private final int width;
private final int columns;
private final int indent;
public HexBytesWriter(byte[] byteArray, int width, int columns, int indent){
this.byteArray = byteArray;
this.width = (width <= 0) ? DEFAULT_WIDTH : width;
this.columns = (columns <= 0) ? width : columns;
this.indent = indent;
}
public HexBytesWriter(byte[] byteArray, int width){
this(byteArray, width, DEFAULT_COLUMNS, DEFAULT_INDENT);
}
public HexBytesWriter(byte[] byteArray){
this(byteArray, DEFAULT_WIDTH, DEFAULT_COLUMNS, DEFAULT_INDENT);
}
public void write(Writer writer) throws IOException{
if(byteArray==null){
return;
}
write(writer, 0, byteArray.length);
}
public void write(Writer writer, int offset, int length) throws IOException {
byte[] byteArray = this.byteArray;
if(byteArray==null){
return;
}
int width = this.width;
int columns = this.columns;
int x = 0;
boolean newLineAppended = false;
for(int i=0; i < length; i++){
if((i%width)==0){
if(i!=0){
writeNewLine(writer);
newLineAppended=true;
}
writeIndent(writer);
x=0;
}else if(x%columns==0){
writer.write(' ');
}
if(!newLineAppended && i!=0){
writer.write(' ');
}
x++;
newLineAppended=false;
writeHex(writer, byteArray[offset+i]);
}
}
private void writeHex(Writer writer, byte b) throws IOException {
String hex = String.format("%02x", (0xff & b)).toUpperCase();
writer.write(hex);
}
private void writeIndent(Writer writer) throws IOException {
for(int i=0;i<this.indent;i++){
writer.write(' ');
}
}
private void writeNewLine(Writer writer) throws IOException {
writer.write('\n');
}
public static String toHex(byte[] byteArray){
StringWriter writer=new StringWriter();
HexBytesWriter hexBytesWriter = new HexBytesWriter(byteArray);
try {
hexBytesWriter.write(writer);
writer.flush();
writer.close();
} catch (IOException ignored) {
}
return writer.toString();
}
private static final int DEFAULT_WIDTH = 16;
private static final int DEFAULT_COLUMNS = 4;
private static final int DEFAULT_INDENT = 0;
}