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;
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();
}
}

View File

@ -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){

View File

@ -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);

View File

@ -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());
}
}

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.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);

View File

@ -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();

View File

@ -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){

View File

@ -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() {

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.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 ?
}
}

View File

@ -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);

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.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);

View File

@ -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();

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.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);
}

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.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();

View File

@ -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() + '}';
}
}

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(){
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());

View File

@ -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

View File

@ -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

View File

@ -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;

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.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;

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;
}