diff --git a/src/main/java/com/reandroid/arsc/array/StagedAliasEntryArray.java b/src/main/java/com/reandroid/arsc/array/StagedAliasEntryArray.java index 8656f5f..9977738 100644 --- a/src/main/java/com/reandroid/arsc/array/StagedAliasEntryArray.java +++ b/src/main/java/com/reandroid/arsc/array/StagedAliasEntryArray.java @@ -34,6 +34,19 @@ this.count=count; this.count.setBlockLoad(this); } + public boolean contains(StagedAliasEntry aliasEntry){ + StagedAliasEntry[] childes=getChildes(); + if(childes==null){ + return false; + } + for(int i=0;i implements BlockLoad { - /** - * @link body - * As on AOSP there is only a description of header struct but no mention about - * chunk-content/body, thus we will use empty body byte array to avoid parse error - * */ - private final ByteArray body; + public class Overlayable extends Chunk implements JSONConvert { + private final BlockList policyList; + private final ByteArray extraBytes; + public Overlayable() { - super(new OverlayableHeader(), 1); - this.body = new ByteArray(); - addChild(this.body); - getHeaderBlock().getActor().setBlockLoad(this); + super(new OverlayableHeader(), 2); + this.policyList = new BlockList<>(); + this.extraBytes = new ByteArray(); + addChild(this.policyList); + addChild(this.extraBytes); } - public ByteArray getBody() { - return body; + + public OverlayablePolicy get(int flags){ + for(OverlayablePolicy policy:listOverlayablePolicies()){ + if(flags==policy.getFlags()){ + return policy; + } + } + return null; } + public void addOverlayablePolicy(OverlayablePolicy overlayablePolicy){ + this.policyList.add(overlayablePolicy); + } + public List listOverlayablePolicies() { + return policyList.getChildes(); + } + public ByteArray getExtraBytes() { + return extraBytes; + } + public String getName(){ return getHeaderBlock().getName().get(); } @@ -57,22 +74,95 @@ public void setActor(String str){ getHeaderBlock().getActor().set(str); } - @Override - public void onBlockLoaded(BlockReader reader, Block sender) throws IOException { - if(sender==getHeaderBlock().getActor()){ - HeaderBlock header = getHeaderBlock(); - int bodySize=header.getChunkSize()-header.getHeaderSize(); - this.body.setSize(bodySize); - } - } + @Override protected void onChunkRefreshed() { } + + @Override + public void onReadBytes(BlockReader reader) throws IOException { + HeaderBlock headerBlock = reader.readHeaderBlock(); + checkInvalidChunk(headerBlock); + + int size = headerBlock.getChunkSize(); + BlockReader chunkReader = reader.create(size); + headerBlock = getHeaderBlock(); + headerBlock.readBytes(chunkReader); + + readOverlayablePlolicies(chunkReader); + readExtraBytes(chunkReader); + + reader.offset(size); + chunkReader.close(); + onChunkLoaded(); + } + private void readOverlayablePlolicies(BlockReader reader) throws IOException { + HeaderBlock headerBlock = reader.readHeaderBlock(); + BlockList policyList = this.policyList; + while (headerBlock!=null && headerBlock.getChunkType()==ChunkType.OVERLAYABLE_POLICY){ + OverlayablePolicy policy = new OverlayablePolicy(); + policyList.add(policy); + policy.readBytes(reader); + headerBlock = reader.readHeaderBlock(); + } + } + private void readExtraBytes(BlockReader reader) throws IOException { + int remaining = reader.available(); + this.extraBytes.setSize(remaining); + this.extraBytes.readBytes(reader); + } + + @Override + public JSONObject toJson() { + JSONObject jsonObject = new JSONObject(); + jsonObject.put(NAME_name, getName()); + jsonObject.put(NAME_actor, getActor()); + JSONArray jsonArray = new JSONArray(); + for(OverlayablePolicy policy:listOverlayablePolicies()){ + jsonArray.put(policy); + } + return jsonObject; + } + @Override + public void fromJson(JSONObject json) { + setName(json.getString(NAME_name)); + setActor(json.getString(NAME_actor)); + JSONArray jsonArray = json.getJSONArray(NAME_policies); + int length = jsonArray.length(); + BlockList policyList = this.policyList; + for(int i=0;i implements BlockLoad { + public class OverlayablePolicy extends Chunk implements BlockLoad, + JSONConvert { private final IntegerArray tableRefArray; public OverlayablePolicy(){ super(new OverlayablePolicyHeader(), 1); @@ -81,6 +85,43 @@ this.tableRefArray.setSize(entryCount.get()); } } + + @Override + public JSONObject toJson() { + JSONObject jsonObject = new JSONObject(); + jsonObject.put(NAME_flags, getFlags()); + JSONArray jsonArray = new JSONArray(); + for(Integer reference:listTableReferences()){ + jsonArray.put(reference); + } + jsonObject.put(NAME_references, jsonArray); + return jsonObject; + } + @Override + public void fromJson(JSONObject json) { + setFlags(json.getInt(NAME_flags)); + JSONArray jsonArray = json.getJSONArray(NAME_references); + IntegerArray integerArray = getTableRefArray(); + int length = jsonArray.length(); + integerArray.setSize(length); + for(int i=0;i listStagedAlias(){ return getStagedAliasList().getChildes(); } - public BlockList getStagedAliasList(){ + public StagedAliasList getStagedAliasList(){ return mBody.getStagedAliasList(); } - public BlockList getOverlayableList(){ + public OverlayableList getOverlayableList(){ return mBody.getOverlayableList(); } public BlockList getOverlayablePolicyList(){ @@ -341,6 +344,10 @@ package com.reandroid.arsc.chunk; jsonObject.put(NAME_staged_aliases, stagedAlias.getStagedAliasEntryArray().toJson()); } + JSONArray jsonArray = getOverlayableList().toJson(); + if(jsonArray!=null){ + jsonObject.put(NAME_overlaybles, jsonArray); + } return jsonObject; } @Override @@ -356,6 +363,9 @@ package com.reandroid.arsc.chunk; .fromJson(json.getJSONArray(NAME_staged_aliases)); getStagedAliasList().add(stagedAlias); } + if(json.has(NAME_overlaybles)){ + getOverlayableList().fromJson(json.getJSONArray(NAME_overlaybles)); + } } public void merge(PackageBlock packageBlock){ if(packageBlock==null||packageBlock==this){ @@ -368,6 +378,8 @@ package com.reandroid.arsc.chunk; setName(packageBlock.getName()); getLibraryBlock().merge(packageBlock.getLibraryBlock()); getSpecTypePairArray().merge(packageBlock.getSpecTypePairArray()); + getOverlayableList().merge(packageBlock.getOverlayableList()); + getStagedAliasList().merge(packageBlock.getStagedAliasList()); } /** * It is allowed to have duplicate type name therefore it is not recommend to use this. @@ -400,7 +412,8 @@ package com.reandroid.arsc.chunk; public static final String NAME_package_id = "package_id"; public static final String NAME_package_name = "package_name"; public static final String JSON_FILE_NAME = "package.json"; - private static final String NAME_specs="specs"; - public static final String NAME_libraries="libraries"; - public static final String NAME_staged_aliases="staged_aliases"; + private static final String NAME_specs = "specs"; + public static final String NAME_libraries = "libraries"; + public static final String NAME_staged_aliases = "staged_aliases"; + public static final String NAME_overlaybles = "overlaybles"; } diff --git a/src/main/java/com/reandroid/arsc/chunk/StagedAlias.java b/src/main/java/com/reandroid/arsc/chunk/StagedAlias.java index d070ff9..ed1421f 100644 --- a/src/main/java/com/reandroid/arsc/chunk/StagedAlias.java +++ b/src/main/java/com/reandroid/arsc/chunk/StagedAlias.java @@ -34,8 +34,12 @@ if(stagedAlias==null||stagedAlias==this){ return; } - stagedAliasEntryArray.addAll(stagedAlias - .getStagedAliasEntryArray().getChildes()); + StagedAliasEntryArray exist = getStagedAliasEntryArray(); + for(StagedAliasEntry entry:stagedAlias.listStagedAliasEntry()){ + if(!exist.contains(entry)){ + exist.add(entry); + } + } } public StagedAliasEntryArray getStagedAliasEntryArray() { return stagedAliasEntryArray; @@ -52,6 +56,7 @@ } @Override protected void onChunkRefreshed() { + getHeaderBlock().getCount().set(getStagedAliasEntryCount()); } @Override public String toString(){ diff --git a/src/main/java/com/reandroid/arsc/container/PackageBody.java b/src/main/java/com/reandroid/arsc/container/PackageBody.java index 5236c04..c5e43b2 100755 --- a/src/main/java/com/reandroid/arsc/container/PackageBody.java +++ b/src/main/java/com/reandroid/arsc/container/PackageBody.java @@ -19,6 +19,8 @@ import com.reandroid.arsc.chunk.*; import com.reandroid.arsc.array.SpecTypePairArray; import com.reandroid.arsc.header.HeaderBlock; import com.reandroid.arsc.io.BlockReader; +import com.reandroid.arsc.list.OverlayableList; +import com.reandroid.arsc.list.StagedAliasList; import java.io.IOException; @@ -26,16 +28,16 @@ public class PackageBody extends FixedBlockContainer { private final SpecTypePairArray mSpecTypePairArray; private final LibraryBlock mLibraryBlock; - private final BlockList mStagedAliasList; - private final BlockList mOverlayableList; + private final StagedAliasList mStagedAliasList; + private final OverlayableList mOverlayableList; private final BlockList mOverlayablePolicyList; private final BlockList mUnknownChunkList; public PackageBody(){ super(6); this.mSpecTypePairArray = new SpecTypePairArray(); this.mLibraryBlock = new LibraryBlock(); - this.mStagedAliasList = new BlockList<>(); - this.mOverlayableList = new BlockList<>(); + this.mStagedAliasList = new StagedAliasList(); + this.mOverlayableList = new OverlayableList(); this.mOverlayablePolicyList = new BlockList<>(); this.mUnknownChunkList = new BlockList<>(); @@ -46,13 +48,13 @@ public class PackageBody extends FixedBlockContainer { addChild(4, mOverlayablePolicyList); addChild(5, mUnknownChunkList); } - public BlockList getOverlayableList() { + public OverlayableList getOverlayableList() { return mOverlayableList; } public BlockList getOverlayablePolicyList() { return mOverlayablePolicyList; } - public BlockList getStagedAliasList() { + public StagedAliasList getStagedAliasList() { return mStagedAliasList; } public LibraryBlock getLibraryBlock(){ diff --git a/src/main/java/com/reandroid/arsc/item/IntegerArray.java b/src/main/java/com/reandroid/arsc/item/IntegerArray.java index 62c1b22..db3f926 100755 --- a/src/main/java/com/reandroid/arsc/item/IntegerArray.java +++ b/src/main/java/com/reandroid/arsc/item/IntegerArray.java @@ -23,9 +23,23 @@ public class IntegerArray extends BlockItem { public IntegerArray() { super(0); } + public final boolean contains(int value){ + int s=size(); + for(int i=0;i implements JSONConvert { + public OverlayableList(){ + super(); + } + public Overlayable get(String name){ + for(Overlayable overlayable:getChildes()){ + if(name.equals(overlayable.getName())){ + return overlayable; + } + } + return null; + } + @Override + public JSONArray toJson() { + if(size()==0){ + return null; + } + JSONArray jsonArray = new JSONArray(); + for(Overlayable overlayable:getChildes()){ + JSONObject jsonOverlayble = overlayable.toJson(); + jsonArray.put(jsonOverlayble); + } + return jsonArray; + } + @Override + public void fromJson(JSONArray json) { + if(json==null){ + return; + } + int length = json.length(); + for(int i=0;i { + public StagedAliasList(){ + super(); + } + private StagedAlias pickOne(){ + for(StagedAlias stagedAlias:getChildes()){ + if(stagedAlias!=null){ + return stagedAlias; + } + } + return null; + } + public void merge(StagedAliasList stagedAliasList){ + if(stagedAliasList==null || stagedAliasList==this || stagedAliasList.size()==0){ + return; + } + StagedAlias exist = pickOne(); + if(exist==null){ + exist=new StagedAlias(); + add(exist); + } + for(StagedAlias stagedAlias:stagedAliasList.getChildes()){ + exist.merge(stagedAlias); + } + } +} diff --git a/src/main/java/com/reandroid/arsc/value/StagedAliasEntry.java b/src/main/java/com/reandroid/arsc/value/StagedAliasEntry.java index 55eeca5..72f5ee4 100644 --- a/src/main/java/com/reandroid/arsc/value/StagedAliasEntry.java +++ b/src/main/java/com/reandroid/arsc/value/StagedAliasEntry.java @@ -8,6 +8,16 @@ public class StagedAliasEntry extends ByteArray implements JSONConvert