mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-05-01 06:34:26 +02:00
make custom header for each chunk
This commit is contained in:
parent
4c9fabc425
commit
9e02964884
@ -15,35 +15,28 @@
|
||||
*/
|
||||
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.header.HeaderBlock;
|
||||
import com.reandroid.lib.arsc.io.BlockReader;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public abstract class BaseChunk extends ExpandableBlockContainer {
|
||||
private final HeaderBlock mHeaderBlock;
|
||||
protected BaseChunk(short chunkType, int initialChildesCount) {
|
||||
public abstract class BaseChunk<T extends HeaderBlock> extends ExpandableBlockContainer {
|
||||
private final T mHeaderBlock;
|
||||
protected BaseChunk(T headerBlock, int initialChildesCount) {
|
||||
super(initialChildesCount+1);
|
||||
mHeaderBlock=new HeaderBlock(chunkType);
|
||||
addChild(mHeaderBlock);
|
||||
}
|
||||
protected BaseChunk(ChunkType chunkType, int initialChildesCount) {
|
||||
this(chunkType.ID, initialChildesCount);
|
||||
}
|
||||
protected void addToHeader(Block block){
|
||||
mHeaderBlock.addChild(block);
|
||||
this.mHeaderBlock = headerBlock;
|
||||
addChild(headerBlock);
|
||||
}
|
||||
void setHeaderLoaded(HeaderBlock.HeaderLoaded headerLoaded){
|
||||
mHeaderBlock.setHeaderLoaded(headerLoaded);
|
||||
getHeaderBlock().setHeaderLoaded(headerLoaded);
|
||||
}
|
||||
public HeaderBlock getHeaderBlock(){
|
||||
public final T getHeaderBlock(){
|
||||
return mHeaderBlock;
|
||||
}
|
||||
@Override
|
||||
protected final void onRefreshed() {
|
||||
mHeaderBlock.refreshHeader();
|
||||
getHeaderBlock().refreshHeader();
|
||||
onChunkRefreshed();
|
||||
}
|
||||
protected abstract void onChunkRefreshed();
|
||||
@ -73,7 +66,7 @@ public abstract class BaseChunk extends ExpandableBlockContainer {
|
||||
StringBuilder builder=new StringBuilder();
|
||||
builder.append(getClass().getSimpleName());
|
||||
builder.append(": ");
|
||||
builder.append(mHeaderBlock.toString());
|
||||
builder.append(getHeaderBlock());
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
@ -16,21 +16,20 @@
|
||||
package com.reandroid.lib.arsc.chunk;
|
||||
|
||||
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.value.LibraryInfo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class LibraryBlock extends BaseChunk {
|
||||
private final IntegerItem mLibCount;
|
||||
public class LibraryBlock extends BaseChunk<LibraryHeader> {
|
||||
private final LibraryInfoArray mLibraryInfoArray;
|
||||
public LibraryBlock() {
|
||||
super(ChunkType.LIBRARY,1);
|
||||
this.mLibCount=new IntegerItem();
|
||||
this.mLibraryInfoArray=new LibraryInfoArray(mLibCount);
|
||||
super(new LibraryHeader(),1);
|
||||
LibraryHeader header = getHeaderBlock();
|
||||
this.mLibraryInfoArray = new LibraryInfoArray(header.getCount());
|
||||
|
||||
addToHeader(mLibCount);
|
||||
addChild(mLibraryInfoArray);
|
||||
}
|
||||
public LibraryInfoArray getLibraryInfoArray(){
|
||||
@ -49,7 +48,7 @@ public class LibraryBlock extends BaseChunk {
|
||||
return;
|
||||
}
|
||||
getLibraryInfoArray().add(info);
|
||||
mLibCount.set(mLibraryInfoArray.childesCount());
|
||||
getHeaderBlock().getCount().set(mLibraryInfoArray.childesCount());
|
||||
}
|
||||
public Collection<LibraryInfo> listLibraryInfo(){
|
||||
return getLibraryInfoArray().listItems();
|
||||
@ -62,12 +61,12 @@ public class LibraryBlock extends BaseChunk {
|
||||
return mLibraryInfoArray.childesCount();
|
||||
}
|
||||
public void setLibraryCount(int count){
|
||||
mLibCount.set(count);
|
||||
getHeaderBlock().getCount().set(count);
|
||||
mLibraryInfoArray.setChildesCount(count);
|
||||
}
|
||||
@Override
|
||||
protected void onChunkRefreshed() {
|
||||
mLibCount.set(mLibraryInfoArray.childesCount());
|
||||
getHeaderBlock().getCount().set(mLibraryInfoArray.childesCount());
|
||||
}
|
||||
|
||||
public void merge(LibraryBlock libraryBlock){
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
import com.reandroid.lib.arsc.base.Block;
|
||||
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.BlockReader;
|
||||
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
|
||||
* create issue on https://github.com/REAndroid/ARSCLib
|
||||
* */
|
||||
public class Overlayable extends BaseChunk implements BlockLoad {
|
||||
private final FixedLengthString name;
|
||||
private final FixedLengthString actor;
|
||||
public class Overlayable extends BaseChunk<OverlayableHeader> implements BlockLoad {
|
||||
/**
|
||||
* @link body
|
||||
* As on AOSP there is only a description of header struct but no mention about
|
||||
@ -39,33 +38,29 @@
|
||||
* */
|
||||
private final ByteArray body;
|
||||
public Overlayable() {
|
||||
super(ChunkType.OVERLAYABLE, 1);
|
||||
this.name = new FixedLengthString(512);
|
||||
this.actor = new FixedLengthString(512);
|
||||
super(new OverlayableHeader(), 1);
|
||||
this.body = new ByteArray();
|
||||
addToHeader(this.name);
|
||||
addToHeader(this.actor);
|
||||
addChild(this.body);
|
||||
this.actor.setBlockLoad(this);
|
||||
getHeaderBlock().getActor().setBlockLoad(this);
|
||||
}
|
||||
public ByteArray getBody() {
|
||||
return body;
|
||||
}
|
||||
public String getName(){
|
||||
return this.name.get();
|
||||
return getHeaderBlock().getName().get();
|
||||
}
|
||||
public void setName(String str){
|
||||
this.name.set(str);
|
||||
getHeaderBlock().getName().set(str);
|
||||
}
|
||||
public String getActor(){
|
||||
return this.actor.get();
|
||||
return getHeaderBlock().getActor().get();
|
||||
}
|
||||
public void setActor(String str){
|
||||
this.actor.set(str);
|
||||
getHeaderBlock().getActor().set(str);
|
||||
}
|
||||
@Override
|
||||
public void onBlockLoaded(BlockReader reader, Block sender) throws IOException {
|
||||
if(sender==this.actor){
|
||||
if(sender==getHeaderBlock().getActor()){
|
||||
HeaderBlock header = getHeaderBlock();
|
||||
int bodySize=header.getChunkSize()-header.getHeaderSize();
|
||||
this.body.setSize(bodySize);
|
||||
|
@ -16,6 +16,7 @@
|
||||
package com.reandroid.lib.arsc.chunk;
|
||||
|
||||
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.BlockReader;
|
||||
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
|
||||
* create issue on https://github.com/REAndroid/ARSCLib
|
||||
* */
|
||||
public class OverlayablePolicy extends BaseChunk implements BlockLoad {
|
||||
private final IntegerItem flags;
|
||||
private final IntegerItem entryCount;
|
||||
public class OverlayablePolicy extends BaseChunk<OverlayablePolicyHeader> implements BlockLoad {
|
||||
private final IntegerArray tableRefArray;
|
||||
public OverlayablePolicy(){
|
||||
super(ChunkType.OVERLAYABLE_POLICY, 1);
|
||||
this.flags = new IntegerItem();
|
||||
this.entryCount = new IntegerItem();
|
||||
super(new OverlayablePolicyHeader(), 1);
|
||||
this.tableRefArray = new IntegerArray();
|
||||
|
||||
addToHeader(this.flags);
|
||||
addToHeader(this.entryCount);
|
||||
|
||||
addChild(this.tableRefArray);
|
||||
|
||||
this.entryCount.setBlockLoad(this);
|
||||
getHeaderBlock().getEntryCount().setBlockLoad(this);
|
||||
}
|
||||
@Override
|
||||
public boolean isNull() {
|
||||
@ -61,10 +55,10 @@
|
||||
return tableRefArray;
|
||||
}
|
||||
public int getFlags() {
|
||||
return flags.get();
|
||||
return getHeaderBlock().getFlags().get();
|
||||
}
|
||||
public void setFlags(int flags){
|
||||
this.flags.set(flags);
|
||||
getHeaderBlock().getFlags().set(flags);
|
||||
}
|
||||
public void setFlags(PolicyFlag[] policyFlags){
|
||||
setFlags(PolicyFlag.sum(policyFlags));
|
||||
@ -78,11 +72,12 @@
|
||||
}
|
||||
@Override
|
||||
protected void onChunkRefreshed() {
|
||||
this.entryCount.set(getTableRefArray().size());
|
||||
getHeaderBlock().getEntryCount().set(getTableRefArray().size());
|
||||
}
|
||||
@Override
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ package com.reandroid.lib.arsc.chunk;
|
||||
import com.reandroid.lib.arsc.container.SingleBlockContainer;
|
||||
import com.reandroid.lib.arsc.container.SpecTypePair;
|
||||
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.BlockReader;
|
||||
import com.reandroid.lib.arsc.item.FixedLengthString;
|
||||
@ -42,17 +43,8 @@ package com.reandroid.lib.arsc.chunk;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public class PackageBlock extends BaseChunk
|
||||
implements BlockLoad, 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;
|
||||
public class PackageBlock extends BaseChunk<PackageHeader>
|
||||
implements JSONConvert<JSONObject>, Comparable<PackageBlock> {
|
||||
|
||||
private final TypeStringPool mTypeStringPool;
|
||||
private final SpecStringPool mSpecStringPool;
|
||||
@ -62,42 +54,19 @@ package com.reandroid.lib.arsc.chunk;
|
||||
private final Map<Integer, EntryGroup> mEntriesGroup;
|
||||
|
||||
public PackageBlock() {
|
||||
super(ChunkType.PACKAGE, 3);
|
||||
this.mPackageId=new IntegerItem();
|
||||
this.mPackageName = new FixedLengthString(256);
|
||||
super(new PackageHeader(), 3);
|
||||
PackageHeader header = getHeaderBlock();
|
||||
|
||||
this.mTypeStringPoolOffset = new IntegerItem();
|
||||
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.mTypeStringPool=new TypeStringPool(false, header.getTypeIdOffset());
|
||||
this.mSpecStringPool=new SpecStringPool(true);
|
||||
|
||||
this.mBody = new PackageBody();
|
||||
|
||||
this.mEntriesGroup=new HashMap<>();
|
||||
|
||||
mPackageId.setBlockLoad(this);
|
||||
|
||||
addToHeader(mPackageId);
|
||||
addToHeader(mPackageName);
|
||||
addToHeader(mTypeStringPoolOffset);
|
||||
addToHeader(mTypeStringPoolCount);
|
||||
addToHeader(mSpecStringPoolOffset);
|
||||
addToHeader(mSpecStringPoolCount);
|
||||
addToHeader(mTypeIdOffsetContainer);
|
||||
|
||||
addChild(mTypeStringPool);
|
||||
addChild(mSpecStringPool);
|
||||
|
||||
addChild(mBody);
|
||||
|
||||
}
|
||||
public BlockList<UnknownChunk> getUnknownChunkList(){
|
||||
return mBody.getUnknownChunkList();
|
||||
@ -125,16 +94,7 @@ package com.reandroid.lib.arsc.chunk;
|
||||
public void sortTypes(){
|
||||
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(){
|
||||
getSpecTypePairArray().removeEmptyPairs();
|
||||
}
|
||||
@ -142,19 +102,19 @@ package com.reandroid.lib.arsc.chunk;
|
||||
return getSpecTypePairArray().isEmpty();
|
||||
}
|
||||
public int getId(){
|
||||
return mPackageId.get();
|
||||
return getHeaderBlock().getPackageId().get();
|
||||
}
|
||||
public void setId(byte id){
|
||||
setId(0xff & id);
|
||||
}
|
||||
public void setId(int id){
|
||||
mPackageId.set(id);
|
||||
getHeaderBlock().getPackageId().set(id);
|
||||
}
|
||||
public String getName(){
|
||||
return mPackageName.get();
|
||||
return getHeaderBlock().getPackageName().get();
|
||||
}
|
||||
public void setName(String name){
|
||||
mPackageName.set(name);
|
||||
getHeaderBlock().getPackageName().set(name);
|
||||
}
|
||||
public TableBlock getTableBlock(){
|
||||
Block parent=getParent();
|
||||
@ -296,24 +256,24 @@ package com.reandroid.lib.arsc.chunk;
|
||||
|
||||
private void refreshTypeStringPoolOffset(){
|
||||
int pos=countUpTo(mTypeStringPool);
|
||||
mTypeStringPoolOffset.set(pos);
|
||||
getHeaderBlock().getTypeStringPoolOffset().set(pos);
|
||||
}
|
||||
private void refreshTypeStringPoolCount(){
|
||||
mTypeStringPoolCount.set(mTypeStringPool.countStrings());
|
||||
getHeaderBlock().getTypeStringPoolCount().set(mTypeStringPool.countStrings());
|
||||
}
|
||||
private void refreshSpecStringPoolOffset(){
|
||||
int pos=countUpTo(mSpecStringPool);
|
||||
mSpecStringPoolOffset.set(pos);
|
||||
getHeaderBlock().getSpecStringPoolOffset().set(pos);
|
||||
}
|
||||
private void refreshSpecStringCount(){
|
||||
mSpecStringPoolCount.set(mSpecStringPool.countStrings());
|
||||
getHeaderBlock().getSpecStringPoolCount().set(mSpecStringPool.countStrings());
|
||||
}
|
||||
private void refreshTypeIdOffset(){
|
||||
// TODO: find solution
|
||||
//int largest=getSpecTypePairArray().getHighestTypeId();
|
||||
//int count=getTypeStringPool().countStrings();
|
||||
//mTypeIdOffset.set(count-largest);
|
||||
mTypeIdOffset.set(0);
|
||||
//getHeaderBlock().getTypeIdOffset().set(count-largest);
|
||||
getHeaderBlock().getTypeIdOffset().set(0);
|
||||
}
|
||||
public void onEntryAdded(EntryBlock entryBlock){
|
||||
updateEntry(entryBlock);
|
||||
|
@ -18,27 +18,19 @@
|
||||
import com.reandroid.lib.arsc.array.TypeBlockArray;
|
||||
import com.reandroid.lib.arsc.base.Block;
|
||||
import com.reandroid.lib.arsc.container.SpecTypePair;
|
||||
import com.reandroid.lib.arsc.header.SpecHeader;
|
||||
import com.reandroid.lib.arsc.item.*;
|
||||
import com.reandroid.lib.json.JSONConvert;
|
||||
import com.reandroid.lib.json.JSONObject;
|
||||
|
||||
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 ByteItem mTypeId;
|
||||
public SpecBlock() {
|
||||
super(ChunkType.SPEC, 1);
|
||||
this.mTypeId=new ByteItem();
|
||||
ByteItem res0 = new ByteItem();
|
||||
ShortItem res1 = new ShortItem();
|
||||
IntegerItem entryCount = new IntegerItem();
|
||||
this.specFlagsArray = new SpecFlagsArray(entryCount);
|
||||
addToHeader(mTypeId);
|
||||
addToHeader(res0);
|
||||
addToHeader(res1);
|
||||
addToHeader(entryCount);
|
||||
|
||||
super(new SpecHeader(), 1);
|
||||
SpecHeader header = getHeaderBlock();
|
||||
this.specFlagsArray = new SpecFlagsArray(header.getEntryCount());
|
||||
addChild(specFlagsArray);
|
||||
}
|
||||
public SpecFlagsArray getSpecFlagsArray(){
|
||||
@ -48,16 +40,16 @@
|
||||
return specFlagsArray.toList();
|
||||
}
|
||||
public byte getTypeId(){
|
||||
return mTypeId.get();
|
||||
return getHeaderBlock().getId().get();
|
||||
}
|
||||
public int getTypeIdInt(){
|
||||
return (0xff & mTypeId.get());
|
||||
return getHeaderBlock().getId().unsignedInt();
|
||||
}
|
||||
public void setTypeId(int id){
|
||||
setTypeId((byte) (0xff & id));
|
||||
}
|
||||
public void setTypeId(byte id){
|
||||
mTypeId.set(id);
|
||||
getHeaderBlock().getId().set(id);
|
||||
}
|
||||
public TypeBlockArray getTypeBlockArray(){
|
||||
SpecTypePair specTypePair=getSpecTypePair();
|
||||
|
@ -16,18 +16,19 @@
|
||||
package com.reandroid.lib.arsc.chunk;
|
||||
|
||||
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.value.StagedAliasEntry;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class StagedAlias extends BaseChunk{
|
||||
public class StagedAlias extends BaseChunk<StagedAliasHeader>{
|
||||
private final StagedAliasEntryArray stagedAliasEntryArray;
|
||||
public StagedAlias() {
|
||||
super(ChunkType.STAGED_ALIAS, 1);
|
||||
IntegerItem count = new IntegerItem();
|
||||
addToHeader(count);
|
||||
stagedAliasEntryArray = new StagedAliasEntryArray(count);
|
||||
super(new StagedAliasHeader(), 1);
|
||||
StagedAliasHeader header = getHeaderBlock();
|
||||
|
||||
stagedAliasEntryArray = new StagedAliasEntryArray(header.getCount());
|
||||
addChild(stagedAliasEntryArray);
|
||||
}
|
||||
public void merge(StagedAlias stagedAlias){
|
||||
|
@ -19,6 +19,7 @@ import com.reandroid.lib.arsc.BuildInfo;
|
||||
import com.reandroid.lib.arsc.array.PackageArray;
|
||||
import com.reandroid.lib.arsc.group.EntryGroup;
|
||||
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.item.IntegerItem;
|
||||
import com.reandroid.lib.arsc.pool.TableStringPool;
|
||||
@ -33,17 +34,15 @@ import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class TableBlock extends BaseChunk implements JSONConvert<JSONObject> {
|
||||
private final IntegerItem mPackageCount;
|
||||
public class TableBlock extends BaseChunk<TableHeader> implements JSONConvert<JSONObject> {
|
||||
private final TableStringPool mTableStringPool;
|
||||
private final PackageArray mPackageArray;
|
||||
private final Set<TableBlock> mFrameWorks=new HashSet<>();
|
||||
public TableBlock() {
|
||||
super(ChunkType.TABLE, 2);
|
||||
this.mPackageCount=new IntegerItem();
|
||||
super(new TableHeader(), 2);
|
||||
TableHeader header = getHeaderBlock();
|
||||
this.mTableStringPool=new TableStringPool(true);
|
||||
this.mPackageArray=new PackageArray(mPackageCount);
|
||||
addToHeader(mPackageCount);
|
||||
this.mPackageArray=new PackageArray(header.getPackageCount());
|
||||
addChild(mTableStringPool);
|
||||
addChild(mPackageArray);
|
||||
}
|
||||
@ -68,7 +67,7 @@ public class TableBlock extends BaseChunk implements JSONConvert<JSONObject> {
|
||||
|
||||
private void refreshPackageCount(){
|
||||
int count = getPackageArray().childesCount();
|
||||
mPackageCount.set(count);
|
||||
getHeaderBlock().getPackageCount().set(count);
|
||||
}
|
||||
@Override
|
||||
protected void onChunkRefreshed() {
|
||||
|
@ -19,6 +19,7 @@ import com.reandroid.lib.arsc.array.EntryBlockArray;
|
||||
import com.reandroid.lib.arsc.array.TypeBlockArray;
|
||||
import com.reandroid.lib.arsc.base.Block;
|
||||
import com.reandroid.lib.arsc.container.SpecTypePair;
|
||||
import com.reandroid.lib.arsc.header.TypeHeader;
|
||||
import com.reandroid.lib.arsc.io.BlockLoad;
|
||||
import com.reandroid.lib.arsc.io.BlockReader;
|
||||
import com.reandroid.lib.arsc.item.*;
|
||||
@ -34,34 +35,20 @@ import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class TypeBlock extends BaseChunk
|
||||
public class TypeBlock extends BaseChunk<TypeHeader>
|
||||
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 TypeString mTypeString;
|
||||
public TypeBlock() {
|
||||
super(ChunkType.TYPE, 2);
|
||||
this.mTypeId=new ByteItem();
|
||||
this.mTypeFlags=new ByteItem();
|
||||
ShortItem reserved = new ShortItem();
|
||||
this.mEntryCount=new IntegerItem();
|
||||
super(new TypeHeader(), 2);
|
||||
TypeHeader header = getHeaderBlock();
|
||||
|
||||
IntegerItem entriesStart = new IntegerItem();
|
||||
this.mResConfig =new ResConfig();
|
||||
IntegerArray entryOffsets = new IntegerArray();
|
||||
this.mEntryArray = new EntryBlockArray(entryOffsets, mEntryCount, entriesStart);
|
||||
this.mEntryArray = new EntryBlockArray(entryOffsets,
|
||||
header.getCount(), header.getEntriesStart());
|
||||
|
||||
mTypeFlags.setBlockLoad(this);
|
||||
|
||||
addToHeader(mTypeId);
|
||||
addToHeader(mTypeFlags);
|
||||
addToHeader(reserved);
|
||||
addToHeader(mEntryCount);
|
||||
addToHeader(entriesStart);
|
||||
addToHeader(mResConfig);
|
||||
header.getFlags().setBlockLoad(this);
|
||||
|
||||
addChild(entryOffsets);
|
||||
addChild(mEntryArray);
|
||||
@ -99,16 +86,16 @@ public class TypeBlock extends BaseChunk
|
||||
return mTypeString;
|
||||
}
|
||||
public byte getTypeId(){
|
||||
return mTypeId.get();
|
||||
return getHeaderBlock().getId().get();
|
||||
}
|
||||
public int getTypeIdInt(){
|
||||
return (0xff & mTypeId.get());
|
||||
return getHeaderBlock().getId().unsignedInt();
|
||||
}
|
||||
public void setTypeId(int id){
|
||||
setTypeId((byte) (0xff & id));
|
||||
}
|
||||
public void setTypeId(byte id){
|
||||
mTypeId.set(id);
|
||||
getHeaderBlock().getId().set(id);
|
||||
}
|
||||
public void setTypeName(String name){
|
||||
TypeStringPool typeStringPool=getTypeStringPool();
|
||||
@ -127,10 +114,11 @@ public class TypeBlock extends BaseChunk
|
||||
return null;
|
||||
}
|
||||
public void setEntryCount(int count){
|
||||
if(count == mEntryCount.get()){
|
||||
IntegerItem entryCount = getHeaderBlock().getCount();
|
||||
if(count == entryCount.get()){
|
||||
return;
|
||||
}
|
||||
mEntryCount.set(count);
|
||||
entryCount.set(count);
|
||||
onSetEntryCount(count);
|
||||
}
|
||||
public boolean isEmpty(){
|
||||
@ -182,7 +170,7 @@ public class TypeBlock extends BaseChunk
|
||||
return getEntryBlockArray().getEntry(entryId);
|
||||
}
|
||||
public ResConfig getResConfig(){
|
||||
return mResConfig;
|
||||
return getHeaderBlock().getConfig();
|
||||
}
|
||||
public EntryBlockArray getEntryBlockArray(){
|
||||
return mEntryArray;
|
||||
@ -212,7 +200,7 @@ public class TypeBlock extends BaseChunk
|
||||
}
|
||||
@Override
|
||||
protected void onPreRefreshRefresh(){
|
||||
mResConfig.refresh();
|
||||
getHeaderBlock().getConfig().refresh();
|
||||
super.onPreRefreshRefresh();
|
||||
}
|
||||
/*
|
||||
@ -280,8 +268,8 @@ public class TypeBlock extends BaseChunk
|
||||
}
|
||||
@Override
|
||||
public void onBlockLoaded(BlockReader reader, Block sender) throws IOException {
|
||||
if(sender==mTypeFlags){
|
||||
if(mTypeFlags.get()==0x1){
|
||||
if(sender==getHeaderBlock().getFlags()){
|
||||
if(getHeaderBlock().getFlags().unsignedInt()==0x1){
|
||||
//ResTable_sparseTypeEntry ?
|
||||
}
|
||||
}
|
||||
|
@ -24,10 +24,10 @@ package com.reandroid.lib.arsc.chunk;
|
||||
* This class can load any valid chunk, aimed to
|
||||
* 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;
|
||||
public UnknownChunk() {
|
||||
super(INITIAL_CHUNK_TYPE, 1);
|
||||
super(new HeaderBlock(INITIAL_CHUNK_TYPE), 1);
|
||||
this.body = new ByteArray();
|
||||
addChild(body);
|
||||
setHeaderLoaded(this);
|
||||
|
@ -18,6 +18,7 @@ package com.reandroid.lib.arsc.chunk.xml;
|
||||
import com.reandroid.lib.arsc.chunk.ChunkType;
|
||||
import com.reandroid.lib.arsc.base.Block;
|
||||
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.ResXmlString;
|
||||
import com.reandroid.lib.arsc.pool.ResXmlStringPool;
|
||||
@ -26,30 +27,23 @@ import java.util.HashSet;
|
||||
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 mStringReference;
|
||||
BaseXmlChunk(ChunkType chunkType, int initialChildesCount) {
|
||||
super(chunkType, initialChildesCount+2);
|
||||
this.mLineNumber=new IntegerItem();
|
||||
this.mCommentReference =new IntegerItem(-1);
|
||||
super(new XmlNodeHeader(chunkType), initialChildesCount+2);
|
||||
|
||||
this.mNamespaceReference=new IntegerItem(-1);
|
||||
this.mStringReference=new IntegerItem(-1);
|
||||
|
||||
addToHeader(mLineNumber);
|
||||
addToHeader(mCommentReference);
|
||||
|
||||
addChild(mNamespaceReference);
|
||||
addChild(mStringReference);
|
||||
}
|
||||
Set<ResXmlString> clearStringReferences(){
|
||||
Set<ResXmlString> results=new HashSet<>();
|
||||
ResXmlString xmlString;
|
||||
xmlString=unLinkStringReference(mCommentReference);
|
||||
xmlString=unLinkStringReference(getHeaderBlock().getCommentReference());
|
||||
if(xmlString!=null){
|
||||
results.add(xmlString);
|
||||
}
|
||||
@ -64,7 +58,7 @@ import java.util.Set;
|
||||
return results;
|
||||
}
|
||||
void linkStringReferences(){
|
||||
linkStringReference(mCommentReference);
|
||||
linkStringReference(getHeaderBlock().getCommentReference());
|
||||
linkStringReference(mNamespaceReference);
|
||||
linkStringReference(mStringReference);
|
||||
}
|
||||
@ -82,18 +76,19 @@ import java.util.Set;
|
||||
return xmlString;
|
||||
}
|
||||
public void setLineNumber(int val){
|
||||
mLineNumber.set(val);
|
||||
getHeaderBlock().getLineNumber().set(val);
|
||||
}
|
||||
public int getLineNumber(){
|
||||
return mLineNumber.get();
|
||||
return getHeaderBlock().getLineNumber().get();
|
||||
}
|
||||
public void setCommentReference(int val){
|
||||
unLinkStringReference(mCommentReference);
|
||||
mCommentReference.set(val);
|
||||
linkStringReference(mCommentReference);
|
||||
IntegerItem comment=getHeaderBlock().getCommentReference();
|
||||
unLinkStringReference(comment);
|
||||
getHeaderBlock().getCommentReference().set(val);
|
||||
linkStringReference(comment);
|
||||
}
|
||||
public int getCommentReference(){
|
||||
return mCommentReference.get();
|
||||
return getHeaderBlock().getCommentReference().get();
|
||||
}
|
||||
public void setNamespaceReference(int val){
|
||||
unLinkStringReference(mNamespaceReference);
|
||||
|
@ -36,13 +36,13 @@ package com.reandroid.lib.arsc.chunk.xml;
|
||||
import java.util.List;
|
||||
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 ResXmlIDMap mResXmlIDMap;
|
||||
private ResXmlElement mResXmlElement;
|
||||
private final SingleBlockContainer<ResXmlElement> mResXmlElementContainer;
|
||||
public ResXmlBlock() {
|
||||
super(ChunkType.XML,3);
|
||||
super(new HeaderBlock(ChunkType.XML),3);
|
||||
this.mResXmlStringPool=new ResXmlStringPool(true);
|
||||
this.mResXmlIDMap=new ResXmlIDMap();
|
||||
this.mResXmlElement=new ResXmlElement();
|
||||
|
@ -19,6 +19,7 @@ import com.reandroid.lib.arsc.base.Block;
|
||||
import com.reandroid.lib.arsc.chunk.ChunkType;
|
||||
import com.reandroid.lib.arsc.array.ResXmlIDArray;
|
||||
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.item.ResXmlID;
|
||||
import com.reandroid.lib.arsc.pool.ResXmlStringPool;
|
||||
@ -26,10 +27,10 @@ import com.reandroid.lib.arsc.pool.ResXmlStringPool;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
public class ResXmlIDMap extends BaseChunk {
|
||||
public class ResXmlIDMap extends BaseChunk<HeaderBlock> {
|
||||
private final ResXmlIDArray mResXmlIDArray;
|
||||
public ResXmlIDMap() {
|
||||
super(ChunkType.XML_RESOURCE_MAP, 1);
|
||||
super(new HeaderBlock(ChunkType.XML_RESOURCE_MAP), 1);
|
||||
this.mResXmlIDArray=new ResXmlIDArray(getHeaderBlock());
|
||||
addChild(mResXmlIDArray);
|
||||
}
|
||||
|
@ -26,11 +26,9 @@ import com.reandroid.lib.arsc.item.BlockItem;
|
||||
import com.reandroid.lib.arsc.item.ByteArray;
|
||||
import com.reandroid.lib.arsc.item.IntegerItem;
|
||||
import com.reandroid.lib.arsc.item.ShortItem;
|
||||
import com.reandroid.lib.arsc.util.HexBytesWriter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.*;
|
||||
import java.util.List;
|
||||
|
||||
public class HeaderBlock extends ExpandableBlockContainer implements BlockLoad {
|
||||
@ -52,6 +50,9 @@ import java.util.List;
|
||||
this.mHeaderSize.setBlockLoad(this);
|
||||
this.mChunkSize.setBlockLoad(this);
|
||||
}
|
||||
public HeaderBlock(ChunkType chunkType){
|
||||
this(chunkType.ID);
|
||||
}
|
||||
public ByteArray getExtraBytes() {
|
||||
return extraBytes;
|
||||
}
|
||||
@ -199,7 +200,12 @@ import java.util.List;
|
||||
headerLoaded.onChunkSizeLoaded(headerSize, chunkSize);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints bytes in hex for debug/testing
|
||||
* */
|
||||
public String toHex(){
|
||||
return HexBytesWriter.toHex(getBytes());
|
||||
}
|
||||
@Override
|
||||
public String toString(){
|
||||
short t = getType();
|
||||
|
@ -16,11 +16,26 @@
|
||||
package com.reandroid.lib.arsc.header;
|
||||
|
||||
import com.reandroid.lib.arsc.chunk.ChunkType;
|
||||
import com.reandroid.lib.arsc.item.IntegerItem;
|
||||
|
||||
/**No importance of this class, to be removed latter*/
|
||||
@Deprecated
|
||||
public class AnyHeader extends HeaderBlock{
|
||||
public AnyHeader() {
|
||||
super(ChunkType.NULL.ID);
|
||||
public class LibraryHeader extends HeaderBlock{
|
||||
private final IntegerItem count;
|
||||
public LibraryHeader() {
|
||||
super(ChunkType.LIBRARY.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() + '}';
|
||||
}
|
||||
}
|
@ -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() + '}';
|
||||
}
|
||||
}
|
@ -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() + '}';
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
52
src/main/java/com/reandroid/lib/arsc/header/SpecHeader.java
Normal file
52
src/main/java/com/reandroid/lib/arsc/header/SpecHeader.java
Normal 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() + '}';
|
||||
}
|
||||
}
|
@ -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()+ '}';
|
||||
}
|
||||
}
|
@ -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() + '}';
|
||||
}
|
||||
}
|
39
src/main/java/com/reandroid/lib/arsc/header/TableHeader.java
Normal file
39
src/main/java/com/reandroid/lib/arsc/header/TableHeader.java
Normal 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() + '}';
|
||||
}
|
||||
}
|
76
src/main/java/com/reandroid/lib/arsc/header/TypeHeader.java
Normal file
76
src/main/java/com/reandroid/lib/arsc/header/TypeHeader.java
Normal 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() + '}';
|
||||
}
|
||||
}
|
@ -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() + '}';
|
||||
}
|
||||
}
|
@ -43,6 +43,12 @@ public class ByteItem extends BlockItem {
|
||||
public byte get(){
|
||||
return getBytesInternal()[0];
|
||||
}
|
||||
public int unsignedInt(){
|
||||
return 0xff & get();
|
||||
}
|
||||
public String toHex(){
|
||||
return String.format("0x%02x", unsignedInt());
|
||||
}
|
||||
@Override
|
||||
public String toString(){
|
||||
return String.valueOf(get());
|
||||
|
@ -41,6 +41,9 @@ public class IntegerItem extends BlockItem implements ReferenceItem{
|
||||
public int get(){
|
||||
return mCache;
|
||||
}
|
||||
public String toHex(){
|
||||
return String.format("0x%08x", get());
|
||||
}
|
||||
@Override
|
||||
protected void onBytesChanged() {
|
||||
// To save cpu usage, better to calculate once only when bytes changed
|
||||
|
@ -40,6 +40,9 @@ public class ShortItem extends BlockItem {
|
||||
public int unsignedInt(){
|
||||
return 0xffff & get();
|
||||
}
|
||||
public String toHex(){
|
||||
return String.format("0x%04x", unsignedInt());
|
||||
}
|
||||
@Override
|
||||
protected void onBytesChanged() {
|
||||
// To save cpu usage, better to calculate once only when bytes changed
|
||||
|
@ -15,72 +15,58 @@
|
||||
*/
|
||||
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.StyleArray;
|
||||
import com.reandroid.lib.arsc.base.Block;
|
||||
import com.reandroid.lib.arsc.chunk.BaseChunk;
|
||||
import com.reandroid.lib.arsc.group.StringGroup;
|
||||
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.model.StyleSpanInfo;
|
||||
import com.reandroid.lib.json.JSONConvert;
|
||||
import com.reandroid.lib.json.JSONArray;
|
||||
import com.reandroid.lib.json.JSONObject;
|
||||
import com.reandroid.lib.arsc.array.StringArray;
|
||||
import com.reandroid.lib.arsc.array.StyleArray;
|
||||
import com.reandroid.lib.arsc.base.Block;
|
||||
import com.reandroid.lib.arsc.chunk.BaseChunk;
|
||||
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.BlockReader;
|
||||
import com.reandroid.lib.arsc.item.*;
|
||||
import com.reandroid.lib.json.JSONArray;
|
||||
import com.reandroid.lib.json.JSONConvert;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public abstract class BaseStringPool<T extends StringItem> extends BaseChunk 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;
|
||||
public abstract class BaseStringPool<T extends StringItem> extends BaseChunk<StringPoolHeader> implements BlockLoad, JSONConvert<JSONArray>, Comparator<String> {
|
||||
private final StringArray<T> mArrayStrings;
|
||||
private final StyleArray mArrayStyles;
|
||||
|
||||
private final Map<String, StringGroup<T>> mUniqueMap;
|
||||
|
||||
|
||||
BaseStringPool(boolean is_utf8){
|
||||
super(ChunkType.STRING, 4);
|
||||
super(new StringPoolHeader(), 4);
|
||||
|
||||
this.mCountStrings=new IntegerItem(); //header
|
||||
this.mCountStyles=new IntegerItem(); //header
|
||||
this.mFlagUtf8 =new ShortItem(); //header
|
||||
this.mFlagSorted=new ShortItem(); //header
|
||||
this.mStartStrings=new IntegerItem(); //header
|
||||
this.mStartStyles=new IntegerItem(); //header
|
||||
IntegerArray offsetStrings = new IntegerArray();
|
||||
IntegerArray offsetStyles = new IntegerArray();
|
||||
|
||||
this.mOffsetStrings=new IntegerArray();//1
|
||||
this.mOffsetStyles=new IntegerArray(); //2
|
||||
this.mArrayStrings=newInstance(mOffsetStrings, mCountStrings, mStartStrings, is_utf8); //3
|
||||
this.mArrayStyles=new StyleArray(mOffsetStyles, mCountStyles, mStartStyles); //4
|
||||
StringPoolHeader header = getHeaderBlock();
|
||||
|
||||
addToHeader(mCountStrings);
|
||||
addToHeader(mCountStyles);
|
||||
addToHeader(mFlagUtf8);
|
||||
addToHeader(mFlagSorted);
|
||||
addToHeader(mStartStrings);
|
||||
addToHeader(mStartStyles);
|
||||
this.mArrayStrings = newInstance(
|
||||
offsetStrings,
|
||||
header.getCountStrings(),
|
||||
header.getStartStrings(),
|
||||
is_utf8);
|
||||
|
||||
addChild(mOffsetStrings);
|
||||
addChild(mOffsetStyles);
|
||||
this.mArrayStyles = new StyleArray(
|
||||
offsetStyles,
|
||||
header.getCountStyles(),
|
||||
header.getStartStyles());
|
||||
|
||||
|
||||
addChild(offsetStrings);
|
||||
addChild(offsetStyles);
|
||||
addChild(mArrayStrings);
|
||||
addChild(mArrayStyles);
|
||||
|
||||
setUtf8(is_utf8, false);
|
||||
|
||||
mFlagUtf8.setBlockLoad(this);
|
||||
|
||||
mUniqueMap=new HashMap<>();
|
||||
header.getFlagUtf8().setBlockLoad(this);
|
||||
|
||||
mUniqueMap = new HashMap<>();
|
||||
}
|
||||
public List<String> toStringList(){
|
||||
return getStringsArray().toStringList();
|
||||
@ -137,13 +123,12 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
|
||||
// call this after modifying string values
|
||||
public void refreshUniqueIdMap(){
|
||||
mUniqueMap.clear();
|
||||
T[] allChildes=getStrings();
|
||||
if(allChildes==null){
|
||||
T[] stringsArray = getStrings();
|
||||
if(stringsArray==null){
|
||||
return;
|
||||
}
|
||||
int max=allChildes.length;
|
||||
for(int i=0;i<max;i++){
|
||||
T item=allChildes[i];
|
||||
for(int i=0;i<stringsArray.length;i++){
|
||||
T item=stringsArray[i];
|
||||
if(item==null){
|
||||
continue;
|
||||
}
|
||||
@ -237,7 +222,7 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
|
||||
private T createNewString(String str){
|
||||
T item=mArrayStrings.createNext();
|
||||
item.set(str);
|
||||
mCountStrings.set(mArrayStrings.childesCount());
|
||||
getHeaderBlock().getCountStrings().set(mArrayStrings.childesCount());
|
||||
return item;
|
||||
}
|
||||
public final StyleItem getStyle(int index){
|
||||
@ -249,35 +234,30 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
|
||||
public final int countStyles(){
|
||||
return mArrayStyles.childesCount();
|
||||
}
|
||||
|
||||
public final T[] getStrings(){
|
||||
return mArrayStrings.getChildes();
|
||||
}
|
||||
public final StyleItem[] getStyles(){
|
||||
return mArrayStyles.getChildes();
|
||||
}
|
||||
private void setUtf8Flag(short flag){
|
||||
mFlagUtf8.set(flag);
|
||||
}
|
||||
public void setUtf8(boolean is_utf8){
|
||||
setUtf8(is_utf8, true);
|
||||
}
|
||||
private void setSortedFlag(short flag){
|
||||
mFlagSorted.set(flag);
|
||||
}
|
||||
public final void setSorted(boolean sorted){
|
||||
ShortItem flagSorted = getHeaderBlock().getFlagSorted();
|
||||
if(sorted){
|
||||
setSortedFlag(FLAG_SORTED);
|
||||
flagSorted.set(FLAG_SORTED);
|
||||
}else {
|
||||
setSortedFlag((short)0);
|
||||
flagSorted.set((short)0);
|
||||
}
|
||||
}
|
||||
private void setUtf8(boolean is_utf8, boolean updateAll){
|
||||
boolean old= isUtf8Flag();
|
||||
ShortItem flagUtf8 = getHeaderBlock().getFlagUtf8();
|
||||
boolean old = isUtf8Flag();
|
||||
if(is_utf8){
|
||||
setUtf8Flag(UTF8_FLAG_VALUE);
|
||||
flagUtf8.set(UTF8_FLAG_VALUE);
|
||||
}else {
|
||||
setUtf8Flag((short) 0);
|
||||
flagUtf8.set((short) 0);
|
||||
}
|
||||
if(!updateAll || old == isUtf8Flag()){
|
||||
return;
|
||||
@ -285,13 +265,8 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
|
||||
mArrayStrings.setUtf8(is_utf8);
|
||||
}
|
||||
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);
|
||||
@Override
|
||||
protected void onChunkRefreshed() {
|
||||
@ -305,7 +280,7 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
|
||||
|
||||
@Override
|
||||
public void onBlockLoaded(BlockReader reader, Block sender) throws IOException {
|
||||
if(sender== mFlagUtf8){
|
||||
if(sender == getHeaderBlock().getFlagUtf8()){
|
||||
mArrayStrings.setUtf8(isUtf8Flag());
|
||||
}
|
||||
}
|
||||
@ -319,112 +294,15 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
|
||||
if(json==null){
|
||||
return;
|
||||
}
|
||||
loadStyledStrings(json);
|
||||
JsonStringPoolHelper<T> helper=new JsonStringPoolHelper<>(this);
|
||||
helper.loadStyledStrings(json);
|
||||
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
|
||||
public int compare(String s1, String 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 FLAG_UTF8 = 0x0100;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -20,6 +20,7 @@ import com.reandroid.lib.arsc.array.TableStringArray;
|
||||
import com.reandroid.lib.arsc.chunk.ChunkType;
|
||||
import com.reandroid.lib.arsc.chunk.UnknownChunk;
|
||||
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.item.IntegerArray;
|
||||
import com.reandroid.lib.arsc.item.IntegerItem;
|
||||
|
@ -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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user