full implementation of SPARSE type entries

This commit is contained in:
REAndroid 2023-04-27 19:12:39 +02:00
parent c239585091
commit 21569db1f3
29 changed files with 1008 additions and 946 deletions

View File

@ -15,7 +15,6 @@
*/
package com.reandroid.arsc.array;
import com.reandroid.arsc.item.IntegerArray;
import com.reandroid.arsc.item.IntegerItem;
import com.reandroid.arsc.value.Entry;
import com.reandroid.json.JSONConvert;
@ -26,9 +25,32 @@ import java.util.Iterator;
public class EntryArray extends OffsetBlockArray<Entry> implements JSONConvert<JSONArray> {
public EntryArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart){
public EntryArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart){
super(offsets, itemCount, itemStart);
}
public int getHighestEntryId(){
if(isSparse()){
return ((SparseOffsetsArray) getOffsetArray()).getHighestId();
}
return childesCount();
}
public int getEntryId(int index){
OffsetArray offsetArray = getOffsetArray();
if(offsetArray instanceof SparseOffsetsArray){
return ((SparseOffsetsArray) offsetArray).getIdx(index);
}
return index;
}
public int getEntryIndex(int entryId){
OffsetArray offsetArray = getOffsetArray();
if(offsetArray instanceof SparseOffsetsArray){
return ((SparseOffsetsArray) offsetArray).indexOf(entryId);
}
return entryId;
}
public boolean isSparse(){
return super.getOffsetArray() instanceof SparseOffsetsArray;
}
public void destroy(){
for(Entry entry:listItems()){
if(entry!=null){
@ -47,26 +69,41 @@ public class EntryArray extends OffsetBlockArray<Entry> implements JSONConvert<J
public boolean isEmpty(){
return !iterator(true).hasNext();
}
public void setEntry(short entryId, Entry entry){
setItem(0xffff & entryId, entry);
}
public Entry getOrCreate(short entryId){
int id = 0xffff & entryId;
Entry entry =get(id);
if(entry !=null){
Entry entry = getEntry(id);
if(entry != null){
return entry;
}
int count=id+1;
boolean sparse = isSparse();
int count;
if(sparse){
count = childesCount() + 1;
}else {
count = id + 1;
}
ensureSize(count);
if(!sparse){
refreshCount();
return super.get(id);
}
SparseOffsetsArray offsetsArray = (SparseOffsetsArray) getOffsetArray();
offsetsArray.ensureArraySize(count);
int index = count - 1;
offsetsArray.setIdx(index, id);
refreshCount();
return get(id);
}
public Entry get(short entryId){
int index = 0xffff & entryId;
return super.get(index);
}
public Entry get(short entryId){
return getEntry(entryId);
}
public Entry getEntry(short entryId){
return get(0xffff & entryId);
return getEntry(0xffff & entryId);
}
public Entry getEntry(int entryId){
int index = getEntryIndex(entryId);
return super.get(index);
}
@Override
public Entry newInstance() {
@ -98,7 +135,7 @@ public class EntryArray extends OffsetBlockArray<Entry> implements JSONConvert<J
JSONArray jsonArray=new JSONArray();
int index=0;
String name_id = Entry.NAME_id;
for(Entry entry :listItems()){
for(Entry entry : listItems(true)){
JSONObject childObject = entry.toJson();
if(childObject==null){
continue;
@ -112,33 +149,74 @@ public class EntryArray extends OffsetBlockArray<Entry> implements JSONConvert<J
@Override
public void fromJson(JSONArray json) {
clearChildes();
if(isSparse()){
fromJsonSparse(json);
}else {
fromJsonNonSparse(json);
}
refreshCountAndStart();
}
private void fromJsonNonSparse(JSONArray json){
int length=json.length();
ensureSize(length);
String name_id = Entry.NAME_id;
for(int i=0;i<length;i++){
JSONObject jsonObject= json.getJSONObject(i);
JSONObject jsonObject = json.optJSONObject(i);
if(jsonObject==null){
continue;
}
int id = jsonObject.getInt(name_id);
ensureSize(id+1);
Entry entry =get(id);
ensureSize(id + 1);
Entry entry = super.get(id);
entry.fromJson(jsonObject);
}
}
private void fromJsonSparse(JSONArray json){
SparseOffsetsArray offsetsArray = (SparseOffsetsArray) getOffsetArray();
offsetsArray.setSize(0);
int length = json.length();
ensureSize(length);
offsetsArray.setSize(length);
String name_id = Entry.NAME_id;
for(int i=0;i<length;i++){
JSONObject jsonObject = json.optJSONObject(i);
if(jsonObject==null){
offsetsArray.setIdx(i , OffsetArray.NO_ENTRY);
continue;
}
int id = jsonObject.getInt(name_id);
Entry entry = super.get(i);
offsetsArray.setIdx(i, id);
entry.fromJson(jsonObject);
}
}
public void merge(EntryArray entryArray){
if(entryArray ==null|| entryArray == this|| entryArray.isEmpty()){
return;
}
if(isSparse()){
mergeSparse(entryArray);
}else {
mergeNonSparse(entryArray);
}
refreshCountAndStart();
}
public void merge(EntryArray entryArray){
if(entryArray ==null|| entryArray ==this|| entryArray.isEmpty()){
return;
private void mergeSparse(EntryArray entryArray){
Iterator<Entry> itr = entryArray.iterator(true);
while (itr.hasNext()){
Entry comingBlock = itr.next();
Entry existingBlock = getOrCreate((short) comingBlock.getId());
existingBlock.merge(comingBlock);
}
}
private void mergeNonSparse(EntryArray entryArray){
ensureSize(entryArray.childesCount());
Iterator<Entry> itr = entryArray.iterator(true);
while (itr.hasNext()){
Entry comingBlock = itr.next();
Entry existingBlock = get(comingBlock.getIndex());
Entry existingBlock = super.get(comingBlock.getIndex());
existingBlock.merge(comingBlock);
}
refreshCountAndStart();
}
@Override
public String toString(){

View File

@ -0,0 +1,40 @@
/*
* 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.arsc.array;
import com.reandroid.arsc.item.IntegerArray;
public class OffsetArray extends IntegerArray {
public OffsetArray(){
super();
}
public int getOffset(int i){
return super.getAt(i);
}
public void setOffset(int index, int value){
super.put(index, value);
}
public int[] getOffsets(){
int length = size();
int[] result = new int[length];
for(int i=0;i<length;i++){
result[i] = getOffset(i);
}
return result;
}
public static final int NO_ENTRY = 0xFFFFFFFF;
}

View File

@ -1,18 +1,18 @@
/*
* 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.
*/
/*
* 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.arsc.array;
@ -22,7 +22,6 @@ import com.reandroid.arsc.base.BlockCounter;
import com.reandroid.arsc.io.BlockLoad;
import com.reandroid.arsc.io.BlockReader;
import com.reandroid.arsc.item.ByteArray;
import com.reandroid.arsc.item.IntegerArray;
import com.reandroid.arsc.item.IntegerItem;
@ -30,12 +29,12 @@ import java.io.IOException;
import java.io.OutputStream;
public abstract class OffsetBlockArray<T extends Block> extends BlockArray<T> implements BlockLoad {
private final IntegerArray mOffsets;
private final OffsetArray mOffsets;
private final IntegerItem mItemStart;
private final IntegerItem mItemCount;
private final ByteArray mEnd4Block;
private byte mEnd4Type;
public OffsetBlockArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart){
public OffsetBlockArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart){
super();
this.mOffsets=offsets;
this.mItemCount=itemCount;
@ -43,6 +42,9 @@ public abstract class OffsetBlockArray<T extends Block> extends BlockArray<T> im
this.mEnd4Block=new ByteArray();
mItemCount.setBlockLoad(this);
}
OffsetArray getOffsetArray(){
return mOffsets;
}
void setEndBytes(byte b){
this.mEnd4Type=b;
this.mEnd4Block.fill(b);
@ -91,7 +93,8 @@ public abstract class OffsetBlockArray<T extends Block> extends BlockArray<T> im
@Override
protected void onRefreshed() {
int count=childesCount();
mOffsets.setSize(count);
OffsetArray offsetArray = this.mOffsets;
offsetArray.setSize(count);
T[] childes=getChildes();
int sum=0;
if(childes!=null){
@ -105,7 +108,7 @@ public abstract class OffsetBlockArray<T extends Block> extends BlockArray<T> im
offset=sum;
sum+=item.countBytes();
}
mOffsets.put(i, offset);
offsetArray.setOffset(i, offset);
}
}
refreshCount();
@ -167,7 +170,7 @@ public abstract class OffsetBlockArray<T extends Block> extends BlockArray<T> im
if(childes==null||childes.length==0){
return;
}
int[] offsetArray=mOffsets.toArray();
int[] offsetArray=mOffsets.getOffsets();
int max=childes.length;
int start=mItemStart.get();
reader.seek(start);

View File

@ -1,18 +1,18 @@
/*
* 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.
*/
/*
* 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.arsc.array;
import com.reandroid.arsc.chunk.xml.ResXmlDocument;
@ -24,8 +24,8 @@ import com.reandroid.arsc.item.ResXmlString;
import java.util.ArrayList;
import java.util.List;
public class ResXmlStringArray extends StringArray<ResXmlString> {
public ResXmlStringArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
public class ResXmlStringArray extends StringArray<ResXmlString> {
public ResXmlStringArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
super(offsets, itemCount, itemStart, is_utf8);
}
@Override

View File

@ -0,0 +1,87 @@
/*
* 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.arsc.array;
public class SparseOffsetsArray extends OffsetArray{
public SparseOffsetsArray(){
super();
}
public int getHighestId(){
int result = NO_ENTRY;
int size = size();
for(int i=0; i<size;i++){
int id = getIdx(i);
if(id > result){
result = id;
}
}
if(result == NO_ENTRY){
result = 0;
}
return result;
}
public int indexOf(int idx){
int size = super.size();
for(int i=0; i<size; i++){
if(idx == getIdx(i)){
return i;
}
}
return NO_ENTRY;
}
public int getIdx(int i){
int value = super.getAt(i);
if(value != NO_ENTRY) {
value = value & 0xffff;
}
return value;
}
public void setIdx(int index, int idx){
int value;
if(idx == NO_ENTRY){
value = idx;
}else {
int offset = getAt(index) & 0xffff0000;
idx = idx & 0xffff;
value = offset | idx;
}
super.put(index, value);
}
@Override
public int getOffset(int i){
int value = super.getAt(i);
if(value == NO_ENTRY){
return value;
}
value = (value >>> 16) & 0xffff;
return value * 4;
}
@Override
public void setOffset(int index, int offset){
int value;
if(offset == NO_ENTRY){
value = 0;
}else {
int idx = getAt(0);
idx = idx & 0xffff;
offset = offset & 0xffff;
offset = offset / 4;
offset = offset << 16;
value = offset | idx;
}
super.put(index, value);
}
}

View File

@ -1,39 +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.arsc.array;
import com.reandroid.arsc.base.BlockArray;
import com.reandroid.arsc.chunk.SparseTypeBlock;
public class SparseTypeBlockArray extends BlockArray<SparseTypeBlock> {
@Override
public SparseTypeBlock[] newInstance(int len) {
return new SparseTypeBlock[len];
}
@Override
public SparseTypeBlock newInstance() {
return new SparseTypeBlock();
}
@Override
protected void onRefreshed() {
}
public void merge(SparseTypeBlockArray sparse){
if(sparse == null || sparse == this){
return;
}
addAll(sparse.getChildes());
}
}

View File

@ -1,42 +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.arsc.array;
import com.reandroid.arsc.base.BlockArray;
import com.reandroid.arsc.io.BlockReader;
import com.reandroid.arsc.value.SparseTypeEntry;
import java.io.IOException;
public class SparseTypeEntryArray extends BlockArray<SparseTypeEntry> {
@Override
public SparseTypeEntry[] newInstance(int len) {
return new SparseTypeEntry[len];
}
@Override
public SparseTypeEntry newInstance() {
return new SparseTypeEntry();
}
@Override
protected void onRefreshed() {
}
@Override
public void onReadBytes(BlockReader reader) throws IOException {
int count = reader.available() / 4;
setChildesCount(count);
super.onReadBytes(reader);
}
}

View File

@ -1,26 +1,25 @@
/*
* 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.
*/
/*
* 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.arsc.array;
import com.reandroid.arsc.item.IntegerArray;
import com.reandroid.arsc.item.IntegerItem;
import com.reandroid.arsc.item.SpecString;
public class SpecStringArray extends StringArray<SpecString> {
public SpecStringArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
public SpecStringArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
super(offsets, itemCount, itemStart, is_utf8);
}
@Override

View File

@ -1,4 +1,4 @@
/*
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -90,11 +90,11 @@ public class SpecTypePairArray extends BlockArray<SpecTypePair>
return pair.getTypeBlockArray().getOrCreate(resConfig);
}
public SpecTypePair getOrCreate(byte typeId){
SpecTypePair pair=getPair(typeId);
SpecTypePair pair = getPair(typeId);
if(pair!=null){
return pair;
}
pair=createNext();
pair = createNext();
pair.setTypeId(typeId);
return pair;
}
@ -115,25 +115,9 @@ public class SpecTypePairArray extends BlockArray<SpecTypePair>
}
return null;
}
public byte getTypeId(){
SpecTypePair[] items=getChildes();
if(items==null){
return 0;
}
int max=items.length;
for(int i=0;i<max;i++){
SpecTypePair pair=items[i];
if(pair!=null){
return pair.getTypeId();
}
}
return 0;
}
@Override
public SpecTypePair newInstance() {
SpecTypePair pair=new SpecTypePair();
pair.setTypeId(getTypeId());
return pair;
return new SpecTypePair();
}
@Override
public SpecTypePair[] newInstance(int len) {
@ -147,7 +131,7 @@ public class SpecTypePairArray extends BlockArray<SpecTypePair>
protected void onPreRefreshRefresh(){
validateEntryCounts();
}
// For android API < 26, it is required to have equal entry count on all SpecTypePair
private void validateEntryCounts(){
Map<Byte, Integer> entryCountMap=mapHighestEntryCount();
for(Map.Entry<Byte, Integer> entry:entryCountMap.entrySet()){

View File

@ -1,4 +1,4 @@
/*
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -15,7 +15,6 @@
*/
package com.reandroid.arsc.array;
import com.reandroid.arsc.item.IntegerArray;
import com.reandroid.arsc.item.IntegerItem;
import com.reandroid.arsc.item.StringItem;
import com.reandroid.json.JSONConvert;
@ -29,7 +28,7 @@ import java.util.List;
public abstract class StringArray<T extends StringItem> extends OffsetBlockArray<T> implements JSONConvert<JSONArray> {
private boolean mUtf8;
public StringArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
public StringArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
super(offsets, itemCount, itemStart);
this.mUtf8=is_utf8;
setEndBytes((byte)0x00);

View File

@ -1,23 +1,22 @@
/*
* 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.
*/
/*
* 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.arsc.array;
import com.reandroid.arsc.io.BlockReader;
import com.reandroid.arsc.item.ByteArray;
import com.reandroid.arsc.item.IntegerArray;
import com.reandroid.arsc.item.IntegerItem;
import com.reandroid.arsc.item.StyleItem;
import com.reandroid.json.JSONConvert;
@ -26,7 +25,7 @@ import com.reandroid.json.JSONArray;
import java.io.IOException;
public class StyleArray extends OffsetBlockArray<StyleItem> implements JSONConvert<JSONArray> {
public StyleArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart) {
public StyleArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart) {
super(offsets, itemCount, itemStart);
setEndBytes(END_BYTE);
}

View File

@ -1,26 +1,25 @@
/*
* 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.
*/
/*
* 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.arsc.array;
import com.reandroid.arsc.item.IntegerArray;
import com.reandroid.arsc.item.IntegerItem;
import com.reandroid.arsc.item.TableString;
public class TableStringArray extends StringArray<TableString> {
public TableStringArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
public TableStringArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
super(offsets, itemCount, itemStart, is_utf8);
}
@Override

View File

@ -1,4 +1,4 @@
/*
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -95,14 +95,17 @@ public class TypeBlockArray extends BlockArray<TypeBlock>
return typeBlock.getEntry(entryId);
}
public TypeBlock getOrCreate(ResConfig resConfig){
TypeBlock typeBlock=getTypeBlock(resConfig);
if(typeBlock!=null){
return getOrCreate(resConfig, false);
}
public TypeBlock getOrCreate(ResConfig resConfig, boolean sparse){
TypeBlock typeBlock = getTypeBlock(resConfig, sparse);
if(typeBlock != null){
return typeBlock;
}
byte id=getTypeId();
typeBlock=createNext();
byte id = getTypeId();
typeBlock = createNext(sparse);
typeBlock.setTypeId(id);
ResConfig config=typeBlock.getResConfig();
ResConfig config = typeBlock.getResConfig();
config.copyFrom(resConfig);
return typeBlock;
}
@ -131,18 +134,24 @@ public class TypeBlockArray extends BlockArray<TypeBlock>
return null;
}
public TypeBlock getTypeBlock(ResConfig config){
return getTypeBlock(config, false);
}
public TypeBlock getTypeBlock(ResConfig config, boolean sparse){
if(config==null){
return null;
}
TypeBlock[] items=getChildes();
if(items==null){
TypeBlock[] items = getChildes();
if(items == null){
return null;
}
int max=items.length;
for(int i=0;i<max;i++){
TypeBlock block=items[i];
if(config.equals(block.getResConfig())){
return block;
int length = items.length;
for(int i = 0; i < length; i++){
TypeBlock typeBlock = items[i];
if(typeBlock == null || sparse != typeBlock.isSparse()){
continue;
}
if(config.equals(typeBlock.getResConfig())){
return typeBlock;
}
}
return null;
@ -204,12 +213,9 @@ public class TypeBlockArray extends BlockArray<TypeBlock>
};
}
private SpecBlock getSpecBlock(){
Block parent=getParent();
while(parent!=null){
if(parent instanceof SpecTypePair){
return ((SpecTypePair) parent).getSpecBlock();
}
parent=parent.getParent();
SpecTypePair parent = getParent(SpecTypePair.class);
if(parent != null){
return parent.getSpecBlock();
}
return null;
}
@ -223,8 +229,8 @@ public class TypeBlockArray extends BlockArray<TypeBlock>
}
@Override
public TypeBlock newInstance() {
byte id=getTypeId();
TypeBlock typeBlock=new TypeBlock();
byte id = getTypeId();
TypeBlock typeBlock = new TypeBlock(false);
typeBlock.setTypeId(id);
return typeBlock;
}
@ -232,6 +238,13 @@ public class TypeBlockArray extends BlockArray<TypeBlock>
public TypeBlock[] newInstance(int len) {
return new TypeBlock[len];
}
public TypeBlock createNext(boolean sparse){
byte id = getTypeId();
TypeBlock typeBlock = new TypeBlock(sparse);
typeBlock.setTypeId(id);
add(typeBlock);
return typeBlock;
}
@Override
protected void onRefreshed() {
@ -265,16 +278,18 @@ public class TypeBlockArray extends BlockArray<TypeBlock>
public int getHighestEntryCount(){
int result=0;
for(TypeBlock typeBlock:getChildes()){
int count=typeBlock.getEntryArray().childesCount();
if(count>result){
result=count;
int high = typeBlock.getEntryArray().getHighestEntryId();
if(high > result){
result = high;
}
}
return result;
}
public void setEntryCount(int count){
for(TypeBlock typeBlock:getChildes()){
typeBlock.setEntryCount(count);
if(!typeBlock.isSparse()){
typeBlock.setEntryCount(count);
}
}
}
public TypeString getTypeString(){
@ -305,21 +320,22 @@ public class TypeBlockArray extends BlockArray<TypeBlock>
if(json == null){
return;
}
int length= json.length();
ensureSize(length);
for (int i=0;i<length;i++){
JSONObject jsonObject=json.getJSONObject(i);
TypeBlock typeBlock=get(i);
int length = json.length();
for(int i = 0; i < length; i++){
JSONObject jsonObject = json.getJSONObject(i);
TypeBlock typeBlock = createNext(
jsonObject.optBoolean(TypeBlock.NAME_is_sparse, false));
typeBlock.fromJson(jsonObject);
}
}
public void merge(TypeBlockArray typeBlockArray){
if(typeBlockArray==null||typeBlockArray==this){
if(typeBlockArray == null || typeBlockArray == this){
return;
}
for(TypeBlock typeBlock:typeBlockArray.listItems()){
TypeBlock block=getOrCreate(typeBlock.getResConfig());
block.merge(typeBlock);
TypeBlock exist = getOrCreate(
typeBlock.getResConfig(), typeBlock.isSparse());
exist.merge(typeBlock);
}
}
/**

View File

@ -1,4 +1,4 @@
/*
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -15,13 +15,12 @@
*/
package com.reandroid.arsc.array;
import com.reandroid.arsc.item.IntegerArray;
import com.reandroid.arsc.item.IntegerItem;
import com.reandroid.arsc.item.TypeString;
public class TypeStringArray extends StringArray<TypeString> {
private int lastCreateIndex;
public TypeStringArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
public TypeStringArray(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
super(offsets, itemCount, itemStart, is_utf8);
}
@Override

View File

@ -83,10 +83,13 @@ public abstract class BlockArray<T extends Block> extends BlockContainer<T> impl
return results;
}
public Collection<T> listItems(){
return listItems(false);
}
public Collection<T> listItems(boolean skipNullBlocks){
return new AbstractCollection<T>() {
@Override
public Iterator<T> iterator(){
return BlockArray.this.iterator();
return BlockArray.this.iterator(skipNullBlocks);
}
@Override
public boolean contains(Object o){
@ -277,12 +280,15 @@ public abstract class BlockArray<T extends Block> extends BlockContainer<T> impl
}
int len=items.length;
for(int i=0;i<len;i++){
if(block==items[i]){
if(isEqual(items[i], block)){
return true;
}
}
return false;
}
protected boolean isEqual(T item, Object obj){
return obj == item;
}
public void remove(Collection<T> blockList){
T[] items=elementData;
if(items==null || items.length==0){

View File

@ -1,42 +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.arsc.chunk;
import com.reandroid.arsc.array.SparseTypeEntryArray;
import com.reandroid.arsc.header.TypeHeader;
import com.reandroid.arsc.value.SparseTypeEntry;
import java.util.Collection;
public class SparseTypeBlock extends Chunk<TypeHeader>{
private final SparseTypeEntryArray entryArray;
public SparseTypeBlock() {
super(new TypeHeader(), 1);
entryArray = new SparseTypeEntryArray();
addChild(entryArray);
getHeaderBlock().setSparse(true);
}
public Collection<SparseTypeEntry> listEntries(){
return getEntryArray().listItems();
}
public SparseTypeEntryArray getEntryArray() {
return entryArray;
}
@Override
protected void onChunkRefreshed() {
getHeaderBlock().setSparse(true);
}
}

View File

@ -1,21 +1,23 @@
/*
* 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.
*/
/*
* 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.arsc.chunk;
import com.reandroid.arsc.array.EntryArray;
import com.reandroid.arsc.array.OffsetArray;
import com.reandroid.arsc.array.SparseOffsetsArray;
import com.reandroid.arsc.base.Block;
import com.reandroid.arsc.container.SpecTypePair;
import com.reandroid.arsc.header.TypeHeader;
@ -39,11 +41,16 @@ public class TypeBlock extends Chunk<TypeHeader>
private final EntryArray mEntryArray;
private TypeString mTypeString;
public TypeBlock() {
super(new TypeHeader(), 2);
public TypeBlock(boolean sparse) {
super(new TypeHeader(sparse), 2);
TypeHeader header = getHeaderBlock();
IntegerArray entryOffsets = new IntegerArray();
OffsetArray entryOffsets;
if(sparse){
entryOffsets = new SparseOffsetsArray();
}else {
entryOffsets = new OffsetArray();
}
this.mEntryArray = new EntryArray(entryOffsets,
header.getCount(), header.getEntriesStart());
@ -52,6 +59,9 @@ public class TypeBlock extends Chunk<TypeHeader>
addChild(entryOffsets);
addChild(mEntryArray);
}
public boolean isSparse(){
return getHeaderBlock().isSparse();
}
public void destroy(){
getEntryArray().destroy();
setId(0);
@ -227,9 +237,9 @@ public class TypeBlock extends Chunk<TypeHeader>
super.onPreRefreshRefresh();
}
/*
* method Block.addBytes is inefficient for large size byte array
* so let's override here because this block is the largest
*/
* method Block.addBytes is inefficient for large size byte array
* so let's override here because this block is the largest
*/
@Override
public byte[] getBytes(){
ByteArrayOutputStream os=new ByteArrayOutputStream();
@ -242,7 +252,10 @@ public class TypeBlock extends Chunk<TypeHeader>
}
@Override
public JSONObject toJson() {
JSONObject jsonObject=new JSONObject();
JSONObject jsonObject = new JSONObject();
if(isSparse()){
jsonObject.put(NAME_is_sparse, true);
}
jsonObject.put(NAME_id, getId());
jsonObject.put(NAME_name, getTypeName());
jsonObject.put(NAME_config, getResConfig().toJson());
@ -274,12 +287,16 @@ public class TypeBlock extends Chunk<TypeHeader>
}
@Override
public int compareTo(TypeBlock typeBlock) {
int id1= getId();
int id2=typeBlock.getId();
if(id1!=id2){
int id1 = getId();
int id2 = typeBlock.getId();
if(id1 != id2){
return Integer.compare(id1, id2);
}
return getResConfig().compareTo(typeBlock.getResConfig());
String q1 = (isSparse() ? "1" : "0")
+ getResConfig().getQualifiers();
String q2 = (typeBlock.isSparse() ? "1" : "0")
+ typeBlock.getResConfig().getQualifiers();
return q1.compareTo(q2);
}
/**
* It is allowed to have duplicate entry name therefore it is not recommend to use this.
@ -311,4 +328,5 @@ public class TypeBlock extends Chunk<TypeHeader>
public static final String NAME_config = "config";
public static final String NAME_id = "id";
public static final String NAME_entries = "entries";
public static final String NAME_is_sparse = "is_sparse";
}

View File

@ -117,13 +117,10 @@ public class PackageBody extends FixedBlockContainer {
TypeHeader typeHeader = reader.readTypeHeader();
SpecTypePair specTypePair = mSpecTypePairArray.getOrCreate(typeHeader.getId().get());
if(typeHeader.isSparse()){
SparseTypeBlock sparseTypeBlock = specTypePair
.getSparseTypeBlockArray().createNext();
sparseTypeBlock.readBytes(reader);
}else {
TypeBlock typeBlock = specTypePair.getTypeBlockArray().createNext();
typeBlock.readBytes(reader);
String junk = "";
}
TypeBlock typeBlock = specTypePair.getTypeBlockArray().createNext(typeHeader.isSparse());
typeBlock.readBytes(reader);
}
private void readLibraryBlock(BlockReader reader) throws IOException{
LibraryBlock libraryBlock=new LibraryBlock();

View File

@ -1,4 +1,4 @@
/*
/*
* Copyright (C) 2022 github.com/REAndroid
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -16,7 +16,6 @@
package com.reandroid.arsc.container;
import com.reandroid.arsc.array.EntryArray;
import com.reandroid.arsc.array.SparseTypeBlockArray;
import com.reandroid.arsc.chunk.*;
import com.reandroid.arsc.array.TypeBlockArray;
import com.reandroid.arsc.base.Block;
@ -39,31 +38,23 @@ public class SpecTypePair extends BlockContainer<Block>
private final Block[] mChildes;
private final SpecBlock mSpecBlock;
private final TypeBlockArray mTypeBlockArray;
private final SparseTypeBlockArray sparseTypeBlockArray;
public SpecTypePair(SpecBlock specBlock, TypeBlockArray typeBlockArray){
this.mSpecBlock = specBlock;
this.mTypeBlockArray = typeBlockArray;
this.sparseTypeBlockArray = new SparseTypeBlockArray();
this.mChildes=new Block[]{specBlock, typeBlockArray, sparseTypeBlockArray};
mSpecBlock.setIndex(0);
mTypeBlockArray.setIndex(1);
sparseTypeBlockArray.setIndex(2);
mSpecBlock.setParent(this);
mTypeBlockArray.setParent(this);
sparseTypeBlockArray.setParent(this);
this.mChildes = new Block[]{specBlock, typeBlockArray};
specBlock.setIndex(0);
typeBlockArray.setIndex(1);
specBlock.setParent(this);
typeBlockArray.setParent(this);
}
public SpecTypePair(){
this(new SpecBlock(), new TypeBlockArray());
}
public SparseTypeBlockArray getSparseTypeBlockArray() {
return sparseTypeBlockArray;
}
public Collection<SparseTypeBlock> listSparseTypeBlock(){
return sparseTypeBlockArray.listItems();
}
public Map<Integer, EntryGroup> createEntryGroups(){
Map<Integer, EntryGroup> map = new HashMap<>();
for(TypeBlock typeBlock:listTypeBlocks()){
@ -233,12 +224,8 @@ public class SpecTypePair extends BlockContainer<Block>
}
private void readTypeBlock(BlockReader reader) throws IOException {
TypeHeader typeHeader = reader.readTypeHeader();
if(typeHeader.isSparse()){
SparseTypeBlock sparseTypeBlock = sparseTypeBlockArray.createNext();
sparseTypeBlock.readBytes(reader);
return;
}
mTypeBlockArray.readBytes(reader);
TypeBlock typeBlock = mTypeBlockArray.createNext(typeHeader.isSparse());
typeBlock.readBytes(reader);
}
private void readUnexpectedNonSpecBlock(BlockReader reader, HeaderBlock headerBlock) throws IOException{
throw new IOException("Unexpected block: "+headerBlock.toString()+", Should be: "+ChunkType.SPEC);
@ -281,7 +268,6 @@ public class SpecTypePair extends BlockContainer<Block>
}
getSpecBlock().merge(typePair.getSpecBlock());
getTypeBlockArray().merge(typePair.getTypeBlockArray());
getSparseTypeBlockArray().merge(typePair.getSparseTypeBlockArray());
}
@Override
public int compareTo(SpecTypePair specTypePair) {
@ -304,4 +290,5 @@ public class SpecTypePair extends BlockContainer<Block>
}
public static final String NAME_types = "types";
public static final String NAME_sparse_types = "sparse_types";
}

View File

@ -27,7 +27,7 @@ public class TypeHeader extends HeaderBlock{
private final IntegerItem count;
private final IntegerItem entriesStart;
private final ResConfig config;
public TypeHeader() {
public TypeHeader(boolean sparse) {
super(ChunkType.TYPE.ID);
this.id = new ByteItem();
this.flags = new ByteItem();
@ -42,6 +42,7 @@ public class TypeHeader extends HeaderBlock{
addChild(count);
addChild(entriesStart);
addChild(config);
setSparse(sparse);
}
public boolean isSparse(){
return (getFlags().get() & FLAG_SPARSE) == FLAG_SPARSE;

View File

@ -69,7 +69,7 @@ import java.io.*;
return specHeader;
}
public TypeHeader readTypeHeader() throws IOException{
TypeHeader typeHeader = new TypeHeader();
TypeHeader typeHeader = new TypeHeader(false);
if(available() < typeHeader.getMinimumSize()){
return null;
}

View File

@ -113,6 +113,14 @@ public class IntegerArray extends BlockItem {
(bts[i+2] & 0xff) << 16 |
(bts[i+3] & 0xff) << 24;
}
public int getAt(int index){
int i=index*4;
byte[] bts = getBytesInternal();
return bts[i] & 0xff |
(bts[i+1] & 0xff) << 8 |
(bts[i+2] & 0xff) << 16 |
(bts[i+3] & 0xff) << 24;
}
public final int size(){
return getBytesLength()/4;
}

View File

@ -1,24 +1,21 @@
/*
* 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.
*/
/*
* 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.arsc.pool;
import com.reandroid.arsc.array.ResXmlIDArray;
import com.reandroid.arsc.array.StringArray;
import com.reandroid.arsc.array.ResXmlStringArray;
import com.reandroid.arsc.array.StyleArray;
import com.reandroid.arsc.array.*;
import com.reandroid.arsc.chunk.xml.ResXmlDocument;
import com.reandroid.arsc.chunk.xml.ResXmlIDMap;
import com.reandroid.arsc.group.StringGroup;
@ -26,7 +23,7 @@ import com.reandroid.arsc.item.*;
import java.util.Objects;
public class ResXmlStringPool extends StringPool<ResXmlString> {
public class ResXmlStringPool extends StringPool<ResXmlString> {
public ResXmlStringPool(boolean is_utf8) {
super(is_utf8);
}
@ -55,7 +52,7 @@ import java.util.Objects;
}
}
@Override
StringArray<ResXmlString> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
StringArray<ResXmlString> newInstance(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
return new ResXmlStringArray(offsets, itemCount, itemStart, is_utf8);
}
public ResXmlString getOrCreate(String str){

View File

@ -1,25 +1,24 @@
/*
* 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.
*/
/*
* 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.arsc.pool;
import com.reandroid.arsc.array.OffsetArray;
import com.reandroid.arsc.array.SpecStringArray;
import com.reandroid.arsc.array.StringArray;
import com.reandroid.arsc.base.Block;
import com.reandroid.arsc.chunk.PackageBlock;
import com.reandroid.arsc.item.IntegerArray;
import com.reandroid.arsc.item.IntegerItem;
import com.reandroid.arsc.item.SpecString;
@ -29,7 +28,7 @@ public class SpecStringPool extends StringPool<SpecString> {
}
@Override
StringArray<SpecString> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
StringArray<SpecString> newInstance(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
return new SpecStringArray(offsets, itemCount, itemStart, is_utf8);
}
public PackageBlock getPackageBlock(){

View File

@ -1,37 +1,38 @@
/*
* 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.
*/
/*
* 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.arsc.pool;
import com.reandroid.arsc.array.StringArray;
import com.reandroid.arsc.array.StyleArray;
import com.reandroid.arsc.base.Block;
import com.reandroid.arsc.chunk.Chunk;
import com.reandroid.arsc.group.StringGroup;
import com.reandroid.arsc.header.StringPoolHeader;
import com.reandroid.arsc.io.BlockLoad;
import com.reandroid.arsc.io.BlockReader;
import com.reandroid.arsc.item.*;
import com.reandroid.json.JSONArray;
import com.reandroid.json.JSONConvert;
import com.reandroid.arsc.array.OffsetArray;
import com.reandroid.arsc.array.StringArray;
import com.reandroid.arsc.array.StyleArray;
import com.reandroid.arsc.base.Block;
import com.reandroid.arsc.chunk.Chunk;
import com.reandroid.arsc.group.StringGroup;
import com.reandroid.arsc.header.StringPoolHeader;
import com.reandroid.arsc.io.BlockLoad;
import com.reandroid.arsc.io.BlockReader;
import com.reandroid.arsc.item.*;
import com.reandroid.json.JSONArray;
import com.reandroid.json.JSONConvert;
import java.io.IOException;
import java.util.*;
import java.io.IOException;
import java.util.*;
public abstract class StringPool<T extends StringItem> extends Chunk<StringPoolHeader> implements BlockLoad, JSONConvert<JSONArray>, Comparator<String> {
public abstract class StringPool<T extends StringItem> extends Chunk<StringPoolHeader> implements BlockLoad, JSONConvert<JSONArray>, Comparator<String> {
private final StringArray<T> mArrayStrings;
private final StyleArray mArrayStyles;
@ -40,8 +41,8 @@ package com.reandroid.arsc.pool;
StringPool(boolean is_utf8){
super(new StringPoolHeader(), 4);
IntegerArray offsetStrings = new IntegerArray();
IntegerArray offsetStyles = new IntegerArray();
OffsetArray offsetStrings = new OffsetArray();
OffsetArray offsetStyles = new OffsetArray();
StringPoolHeader header = getHeaderBlock();
@ -278,7 +279,7 @@ package com.reandroid.arsc.pool;
getHeaderBlock().setSorted(sorted);
}
abstract StringArray<T> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8);
abstract StringArray<T> newInstance(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8);
@Override
protected void onChunkRefreshed() {
mArrayStrings.refreshCountAndStart();

View File

@ -1,20 +1,21 @@
/*
* 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.
*/
/*
* 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.arsc.pool;
import com.reandroid.arsc.array.OffsetArray;
import com.reandroid.arsc.array.StringArray;
import com.reandroid.arsc.array.TableStringArray;
import com.reandroid.arsc.chunk.ChunkType;
@ -29,13 +30,13 @@ import com.reandroid.arsc.item.TableString;
import java.io.IOException;
import java.io.InputStream;
public class TableStringPool extends StringPool<TableString> {
public class TableStringPool extends StringPool<TableString> {
public TableStringPool(boolean is_utf8) {
super(is_utf8);
}
@Override
StringArray<TableString> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
StringArray<TableString> newInstance(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
return new TableStringArray(offsets, itemCount, itemStart, is_utf8);
}
public void merge(TableStringPool stringPool){
@ -58,10 +59,10 @@ import java.io.InputStream;
refreshUniqueIdMap();
}
/**
* Loads string pool only from table block (resources.arsc) without
* loading other chunks
*/
/**
* Loads string pool only from table block (resources.arsc) without
* loading other chunks
*/
public static TableStringPool readFromTable(InputStream inputStream) throws IOException {
TableHeader tableHeader = new TableHeader();
tableHeader.readBytes(inputStream);

View File

@ -1,20 +1,21 @@
/*
* 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.
*/
/*
* 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.arsc.pool;
import com.reandroid.arsc.array.OffsetArray;
import com.reandroid.arsc.array.StringArray;
import com.reandroid.arsc.array.TypeStringArray;
import com.reandroid.arsc.chunk.TypeBlock;
@ -80,7 +81,7 @@ public class TypeStringPool extends StringPool<TypeString> {
return group.get(0);
}
@Override
StringArray<TypeString> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
StringArray<TypeString> newInstance(OffsetArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
return new TypeStringArray(offsets, itemCount, itemStart, is_utf8);
}
}

View File

@ -1,459 +1,465 @@
/*
* 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.arsc.value;
/*
* 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.arsc.value;
import com.reandroid.arsc.array.ResValueMapArray;
import com.reandroid.arsc.base.Block;
import com.reandroid.arsc.base.BlockCounter;
import com.reandroid.arsc.chunk.PackageBlock;
import com.reandroid.arsc.chunk.SpecBlock;
import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.arsc.chunk.TypeBlock;
import com.reandroid.arsc.container.SpecTypePair;
import com.reandroid.arsc.group.EntryGroup;
import com.reandroid.arsc.io.BlockReader;
import com.reandroid.arsc.item.*;
import com.reandroid.json.JSONConvert;
import com.reandroid.json.JSONObject;
import com.reandroid.arsc.array.EntryArray;
import com.reandroid.arsc.array.ResValueMapArray;
import com.reandroid.arsc.base.Block;
import com.reandroid.arsc.base.BlockCounter;
import com.reandroid.arsc.chunk.PackageBlock;
import com.reandroid.arsc.chunk.SpecBlock;
import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.arsc.chunk.TypeBlock;
import com.reandroid.arsc.container.SpecTypePair;
import com.reandroid.arsc.group.EntryGroup;
import com.reandroid.arsc.io.BlockReader;
import com.reandroid.arsc.item.*;
import com.reandroid.json.JSONConvert;
import com.reandroid.json.JSONObject;
import java.io.IOException;
import java.io.OutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class Entry extends Block implements JSONConvert<JSONObject> {
private TableEntry<?, ?> mTableEntry;
public class Entry extends Block implements JSONConvert<JSONObject> {
private TableEntry<?, ?> mTableEntry;
public Entry(){
super();
}
public Entry(){
super();
}
public ResValue getResValue(){
TableEntry<?, ?> tableEntry = getTableEntry();
if(tableEntry instanceof ResTableEntry){
return ((ResTableEntry)tableEntry).getValue();
}
return null;
}
public ResValueMapArray getResValueMapArray(){
TableEntry<?, ?> tableEntry = getTableEntry();
if(tableEntry instanceof ResTableMapEntry){
return ((ResTableMapEntry)tableEntry).getValue();
}
return null;
}
public SpecFlag getSpecFlag(){
SpecBlock specBlock = getSpecBlock();
if(specBlock == null){
return null;
}
return specBlock.getSpecFlag(getId());
}
public void ensureComplex(boolean isComplex){
ensureTableEntry(isComplex);
}
public int getId(){
return getIndex();
}
public String getName(){
SpecString specString = getSpecString();
if(specString!=null){
return specString.get();
}
return null;
}
public String getTypeName(){
TypeBlock typeBlock = getTypeBlock();
if(typeBlock!=null){
return typeBlock.getTypeName();
}
return null;
}
public int getResourceId(){
PackageBlock packageBlock = getPackageBlock();
if(packageBlock==null){
return 0;
}
TypeBlock typeBlock = getTypeBlock();
if(typeBlock==null){
return 0;
}
return (packageBlock.getId()<<24)
| (typeBlock.getId() << 16)
| getId();
}
public int getSpecReference(){
TableEntry<?, ?> tableEntry = getTableEntry();
if(tableEntry == null){
return 0;
}
return tableEntry.getHeader().getKey();
}
public TypeString getTypeString(){
TypeBlock typeBlock = getTypeBlock();
if(typeBlock!=null){
return typeBlock.getTypeString();
}
return null;
}
public boolean isDefault(){
ResConfig resConfig = getResConfig();
if(resConfig!=null){
return resConfig.isDefault();
}
return false;
}
public void setSpecReference(StringItem specReference){
TableEntry<?, ?> tableEntry = getTableEntry();
if(tableEntry == null){
return;
}
tableEntry.getHeader().setKey(specReference);
}
public void setSpecReference(int ref){
TableEntry<?, ?> tableEntry = getTableEntry();
if(tableEntry == null){
return;
}
tableEntry.getHeader().setKey(ref);
}
private Entry searchEntry(int resourceId){
if(resourceId==getResourceId()){
return this;
}
PackageBlock packageBlock= getPackageBlock();
if(packageBlock==null){
return null;
}
TableBlock tableBlock = packageBlock.getTableBlock();
if(tableBlock==null){
return null;
}
EntryGroup entryGroup = tableBlock.search(resourceId);
if(entryGroup!=null){
return entryGroup.pickOne();
}
return null;
}
public ResValue setValueAsRaw(ValueType valueType, int data){
TableEntry<?, ?> tableEntry = ensureTableEntry(false);
ResValue resValue = (ResValue) tableEntry.getValue();
resValue.setTypeAndData(valueType, data);
return resValue;
}
public ResValue setValueAsBoolean(boolean val){
int data = val?0xffffffff:0;
return setValueAsRaw(ValueType.INT_BOOLEAN, data);
}
public ResValue setValueAsReference(int resourceId){
return setValueAsRaw(ValueType.REFERENCE, resourceId);
}
public ResValue setValueAsString(String str){
TableEntry<?, ?> tableEntry = ensureTableEntry(false);
ResValue resValue = (ResValue) tableEntry.getValue();
resValue.setValueAsString(str);
return resValue;
}
public SpecString getSpecString(){
TableEntry<?, ?> tableEntry = getTableEntry();
if(tableEntry == null){
return null;
}
PackageBlock packageBlock = getPackageBlock();
if(packageBlock == null){
return null;
}
return packageBlock.getSpecStringPool()
.get(tableEntry.getHeader().getKey());
}
public ResConfig getResConfig(){
TypeBlock typeBlock = getTypeBlock();
if(typeBlock!=null){
return typeBlock.getResConfig();
}
return null;
}
public SpecBlock getSpecBlock(){
TypeBlock typeBlock = getTypeBlock();
if(typeBlock == null){
return null;
}
SpecTypePair specTypePair = typeBlock.getParentSpecTypePair();
if(specTypePair==null){
return null;
}
return specTypePair.getSpecBlock();
}
public TypeBlock getTypeBlock(){
return getParent(TypeBlock.class);
}
private String getPackageName(){
PackageBlock packageBlock = getPackageBlock();
if(packageBlock!=null){
return packageBlock.getName();
}
return null;
}
public PackageBlock getPackageBlock(){
return getParent(PackageBlock.class);
}
private TableEntry<?, ?> ensureTableEntry(boolean is_complex){
TableEntry<?, ?> tableEntry = getTableEntry();
public ResValue getResValue(){
TableEntry<?, ?> tableEntry = getTableEntry();
if(tableEntry instanceof ResTableEntry){
return ((ResTableEntry)tableEntry).getValue();
}
return null;
}
public ResValueMapArray getResValueMapArray(){
TableEntry<?, ?> tableEntry = getTableEntry();
if(tableEntry instanceof ResTableMapEntry){
return ((ResTableMapEntry)tableEntry).getValue();
}
return null;
}
public SpecFlag getSpecFlag(){
SpecBlock specBlock = getSpecBlock();
if(specBlock == null){
return null;
}
return specBlock.getSpecFlag(getId());
}
public void ensureComplex(boolean isComplex){
ensureTableEntry(isComplex);
}
public int getId(){
int id = getIndex();
EntryArray entryArray = getParentInstance(EntryArray.class);
if(entryArray != null){
id = entryArray.getEntryId(id);
}
return id;
}
public String getName(){
SpecString specString = getSpecString();
if(specString!=null){
return specString.get();
}
return null;
}
public String getTypeName(){
TypeBlock typeBlock = getTypeBlock();
if(typeBlock!=null){
return typeBlock.getTypeName();
}
return null;
}
public int getResourceId(){
PackageBlock packageBlock = getPackageBlock();
if(packageBlock==null){
return 0;
}
TypeBlock typeBlock = getTypeBlock();
if(typeBlock==null){
return 0;
}
return (packageBlock.getId()<<24)
| (typeBlock.getId() << 16)
| getId();
}
public int getSpecReference(){
TableEntry<?, ?> tableEntry = getTableEntry();
if(tableEntry == null){
return 0;
}
return tableEntry.getHeader().getKey();
}
public TypeString getTypeString(){
TypeBlock typeBlock = getTypeBlock();
if(typeBlock!=null){
return typeBlock.getTypeString();
}
return null;
}
public boolean isDefault(){
ResConfig resConfig = getResConfig();
if(resConfig!=null){
return resConfig.isDefault();
}
return false;
}
public void setSpecReference(StringItem specReference){
TableEntry<?, ?> tableEntry = getTableEntry();
if(tableEntry == null){
return;
}
tableEntry.getHeader().setKey(specReference);
}
public void setSpecReference(int ref){
TableEntry<?, ?> tableEntry = getTableEntry();
if(tableEntry == null){
return;
}
tableEntry.getHeader().setKey(ref);
}
private Entry searchEntry(int resourceId){
if(resourceId==getResourceId()){
return this;
}
PackageBlock packageBlock= getPackageBlock();
if(packageBlock==null){
return null;
}
TableBlock tableBlock = packageBlock.getTableBlock();
if(tableBlock==null){
return null;
}
EntryGroup entryGroup = tableBlock.search(resourceId);
if(entryGroup!=null){
return entryGroup.pickOne();
}
return null;
}
public ResValue setValueAsRaw(ValueType valueType, int data){
TableEntry<?, ?> tableEntry = ensureTableEntry(false);
ResValue resValue = (ResValue) tableEntry.getValue();
resValue.setTypeAndData(valueType, data);
return resValue;
}
public ResValue setValueAsBoolean(boolean val){
int data = val?0xffffffff:0;
return setValueAsRaw(ValueType.INT_BOOLEAN, data);
}
public ResValue setValueAsReference(int resourceId){
return setValueAsRaw(ValueType.REFERENCE, resourceId);
}
public ResValue setValueAsString(String str){
TableEntry<?, ?> tableEntry = ensureTableEntry(false);
ResValue resValue = (ResValue) tableEntry.getValue();
resValue.setValueAsString(str);
return resValue;
}
public SpecString getSpecString(){
TableEntry<?, ?> tableEntry = getTableEntry();
if(tableEntry == null){
return null;
}
PackageBlock packageBlock = getPackageBlock();
if(packageBlock == null){
return null;
}
return packageBlock.getSpecStringPool()
.get(tableEntry.getHeader().getKey());
}
public ResConfig getResConfig(){
TypeBlock typeBlock = getTypeBlock();
if(typeBlock!=null){
return typeBlock.getResConfig();
}
return null;
}
public SpecBlock getSpecBlock(){
TypeBlock typeBlock = getTypeBlock();
if(typeBlock == null){
return null;
}
SpecTypePair specTypePair = typeBlock.getParentSpecTypePair();
if(specTypePair==null){
return null;
}
return specTypePair.getSpecBlock();
}
public TypeBlock getTypeBlock(){
return getParent(TypeBlock.class);
}
private String getPackageName(){
PackageBlock packageBlock = getPackageBlock();
if(packageBlock!=null){
return packageBlock.getName();
}
return null;
}
public PackageBlock getPackageBlock(){
return getParent(PackageBlock.class);
}
private TableEntry<?, ?> ensureTableEntry(boolean is_complex){
TableEntry<?, ?> tableEntry = getTableEntry();
boolean is_correct_type = (is_complex && tableEntry instanceof ResTableMapEntry) || (!is_complex && tableEntry instanceof ResTableEntry);
if (tableEntry == null || !is_correct_type) {
tableEntry = createTableEntry(is_complex);
setTableEntry(tableEntry);
}
return tableEntry;
}
boolean is_correct_type = (is_complex && tableEntry instanceof ResTableMapEntry) || (!is_complex && tableEntry instanceof ResTableEntry);
if (tableEntry == null || !is_correct_type) {
tableEntry = createTableEntry(is_complex);
setTableEntry(tableEntry);
}
return tableEntry;
}
public TableEntry<?, ?> getTableEntry(){
return mTableEntry;
}
public ValueHeader getHeader(){
TableEntry<?, ?> tableEntry = getTableEntry();
if(tableEntry!=null){
return tableEntry.getHeader();
}
return null;
}
public TableEntry<?, ?> getTableEntry(){
return mTableEntry;
}
public ValueHeader getHeader(){
TableEntry<?, ?> tableEntry = getTableEntry();
if(tableEntry!=null){
return tableEntry.getHeader();
}
return null;
}
@Override
public boolean isNull(){
return getTableEntry()==null;
}
@Override
public void setNull(boolean is_null){
if(is_null){
setTableEntry(null);
}
}
@Override
public byte[] getBytes() {
if(isNull()){
return null;
}
return getTableEntry().getBytes();
}
@Override
public int countBytes() {
if(isNull()){
return 0;
}
return getTableEntry().countBytes();
}
@Override
public void onCountUpTo(BlockCounter counter) {
if(counter.FOUND){
return;
}
if(counter.END==this){
counter.FOUND=true;
return;
}
if(isNull()){
return;
}
counter.addCount(getTableEntry().countBytes());
}
@Override
protected int onWriteBytes(OutputStream stream) throws IOException {
if(isNull()){
return 0;
}
return getTableEntry().writeBytes(stream);
}
@Override
public void onReadBytes(BlockReader reader) throws IOException {
TableEntry<?, ?> tableEntry = createTableEntry(reader);
setTableEntry(tableEntry);
tableEntry.readBytes(reader);
}
@Override
public boolean isNull(){
return getTableEntry()==null;
}
@Override
public void setNull(boolean is_null){
if(is_null){
setTableEntry(null);
}
}
@Override
public byte[] getBytes() {
if(isNull()){
return null;
}
return getTableEntry().getBytes();
}
@Override
public int countBytes() {
if(isNull()){
return 0;
}
return getTableEntry().countBytes();
}
@Override
public void onCountUpTo(BlockCounter counter) {
if(counter.FOUND){
return;
}
if(counter.END==this){
counter.FOUND=true;
return;
}
if(isNull()){
return;
}
counter.addCount(getTableEntry().countBytes());
}
@Override
protected int onWriteBytes(OutputStream stream) throws IOException {
if(isNull()){
return 0;
}
return getTableEntry().writeBytes(stream);
}
@Override
public void onReadBytes(BlockReader reader) throws IOException {
TableEntry<?, ?> tableEntry = createTableEntry(reader);
setTableEntry(tableEntry);
tableEntry.readBytes(reader);
}
public boolean isComplex(){
return getTableEntry() instanceof ResTableMapEntry;
}
public void setTableEntry(TableEntry<?, ?> tableEntry){
if(tableEntry==this.mTableEntry){
return;
}
onTableEntryRemoved();
if(tableEntry==null){
return;
}
tableEntry.setIndex(0);
tableEntry.setParent(this);
this.mTableEntry = tableEntry;
onTableEntryAdded();
}
private void onTableEntryAdded(){
PackageBlock packageBlock = getPackageBlock();
if(packageBlock!=null){
packageBlock.onEntryAdded(this);
}
}
private void onTableEntryRemoved(){
TableEntry<?, ?> exist = this.mTableEntry;
if(exist == null){
return;
}
PackageBlock packageBlock = getPackageBlock();
if(packageBlock!=null){
packageBlock.removeEntryGroup(this);
}
exist.onRemoved();
exist.setIndex(-1);
exist.setParent(null);
this.mTableEntry = null;
}
private TableEntry<?, ?> createTableEntry(BlockReader reader) throws IOException {
int startPosition = reader.getPosition();
reader.offset(2);
boolean is_complex = (0x0001 & reader.readShort()) == 0x0001;
reader.seek(startPosition);
return createTableEntry(is_complex);
}
private TableEntry<?, ?> createTableEntry(boolean is_complex) {
if(is_complex){
return new ResTableMapEntry();
}else {
return new ResTableEntry();
}
}
public boolean isComplex(){
return getTableEntry() instanceof ResTableMapEntry;
}
public void setTableEntry(TableEntry<?, ?> tableEntry){
if(tableEntry==this.mTableEntry){
return;
}
onTableEntryRemoved();
if(tableEntry==null){
return;
}
tableEntry.setIndex(0);
tableEntry.setParent(this);
this.mTableEntry = tableEntry;
onTableEntryAdded();
}
private void onTableEntryAdded(){
PackageBlock packageBlock = getPackageBlock();
if(packageBlock!=null){
packageBlock.onEntryAdded(this);
}
}
private void onTableEntryRemoved(){
TableEntry<?, ?> exist = this.mTableEntry;
if(exist == null){
return;
}
PackageBlock packageBlock = getPackageBlock();
if(packageBlock!=null){
packageBlock.removeEntryGroup(this);
}
exist.onRemoved();
exist.setIndex(-1);
exist.setParent(null);
this.mTableEntry = null;
}
private TableEntry<?, ?> createTableEntry(BlockReader reader) throws IOException {
int startPosition = reader.getPosition();
reader.offset(2);
boolean is_complex = (0x0001 & reader.readShort()) == 0x0001;
reader.seek(startPosition);
return createTableEntry(is_complex);
}
private TableEntry<?, ?> createTableEntry(boolean is_complex) {
if(is_complex){
return new ResTableMapEntry();
}else {
return new ResTableEntry();
}
}
@Override
public JSONObject toJson() {
if(isNull()){
return null;
}
return getTableEntry().toJson();
}
@Override
public void fromJson(JSONObject json) {
if(json==null){
setNull(true);
return;
}
boolean is_complex = json.optBoolean(ValueHeader.NAME_is_complex, false);
TableEntry<?, ?> entry = createTableEntry(is_complex);
setTableEntry(entry);
entry.fromJson(json);
}
@Override
public JSONObject toJson() {
if(isNull()){
return null;
}
return getTableEntry().toJson();
}
@Override
public void fromJson(JSONObject json) {
if(json==null){
setNull(true);
return;
}
boolean is_complex = json.optBoolean(ValueHeader.NAME_is_complex, false);
TableEntry<?, ?> entry = createTableEntry(is_complex);
setTableEntry(entry);
entry.fromJson(json);
}
public void merge(Entry entry){
if(!shouldMerge(entry)){
return;
}
TableEntry<?, ?> tableEntry = entry.getTableEntry();
TableEntry<?, ?> existEntry = ensureTableEntry(tableEntry instanceof ResTableMapEntry);
existEntry.merge(tableEntry);
}
private boolean shouldMerge(Entry coming){
if(coming == null || coming == this || coming.isNull()){
return false;
}
if(this.isNull()){
return true;
}
return getTableEntry().shouldMerge(coming.getTableEntry());
}
public void merge(Entry entry){
if(!shouldMerge(entry)){
return;
}
TableEntry<?, ?> tableEntry = entry.getTableEntry();
TableEntry<?, ?> existEntry = ensureTableEntry(tableEntry instanceof ResTableMapEntry);
existEntry.merge(tableEntry);
}
private boolean shouldMerge(Entry coming){
if(coming == null || coming == this || coming.isNull()){
return false;
}
if(this.isNull()){
return true;
}
return getTableEntry().shouldMerge(coming.getTableEntry());
}
public String buildResourceName(int resourceId, char prefix, boolean includeType){
if(resourceId==0){
return null;
}
Entry entry=searchEntry(resourceId);
return buildResourceName(entry, prefix, includeType);
}
public String buildResourceName(Entry entry, char prefix, boolean includeType){
if(entry==null){
return null;
}
String pkgName=entry.getPackageName();
if(getResourceId()==entry.getResourceId()){
pkgName=null;
}else if(pkgName!=null){
if(pkgName.equals(this.getPackageName())){
pkgName=null;
}
}
String type=null;
if(includeType){
type=entry.getTypeName();
}
String name=entry.getName();
return buildResourceName(prefix, pkgName, type, name);
}
public String getResourceName(){
return buildResourceName('@',null, getTypeName(), getName());
}
public String getResourceName(char prefix){
return getResourceName(prefix, false, true);
}
public String getResourceName(char prefix, boolean includePackage, boolean includeType){
String pkg=includePackage?getPackageName():null;
String type=includeType?getTypeName():null;
return buildResourceName(prefix,pkg, type, getName());
}
public String buildResourceName(int resourceId, char prefix, boolean includeType){
if(resourceId==0){
return null;
}
Entry entry=searchEntry(resourceId);
return buildResourceName(entry, prefix, includeType);
}
public String buildResourceName(Entry entry, char prefix, boolean includeType){
if(entry==null){
return null;
}
String pkgName=entry.getPackageName();
if(getResourceId()==entry.getResourceId()){
pkgName=null;
}else if(pkgName!=null){
if(pkgName.equals(this.getPackageName())){
pkgName=null;
}
}
String type=null;
if(includeType){
type=entry.getTypeName();
}
String name=entry.getName();
return buildResourceName(prefix, pkgName, type, name);
}
public String getResourceName(){
return buildResourceName('@',null, getTypeName(), getName());
}
public String getResourceName(char prefix){
return getResourceName(prefix, false, true);
}
public String getResourceName(char prefix, boolean includePackage, boolean includeType){
String pkg=includePackage?getPackageName():null;
String type=includeType?getTypeName():null;
return buildResourceName(prefix,pkg, type, getName());
}
@Override
public String toString(){
StringBuilder builder = new StringBuilder();
builder.append(String.format("0x%08x", getResourceId()));
builder.append(' ');
ResConfig resConfig = getResConfig();
if(resConfig!=null){
builder.append(resConfig);
builder.append(' ');
}
SpecFlag specFlag = getSpecFlag();
if(specFlag!=null){
builder.append(specFlag);
builder.append(' ');
}
if(isNull()){
builder.append("NULL");
return builder.toString();
}
builder.append('@');
builder.append(getTypeName());
builder.append('/');
builder.append(getName());
return builder.toString();
}
@Override
public String toString(){
StringBuilder builder = new StringBuilder();
builder.append(String.format("0x%08x", getResourceId()));
builder.append(' ');
ResConfig resConfig = getResConfig();
if(resConfig!=null){
builder.append(resConfig);
builder.append(' ');
}
SpecFlag specFlag = getSpecFlag();
if(specFlag!=null){
builder.append(specFlag);
builder.append(' ');
}
if(isNull()){
builder.append("NULL");
return builder.toString();
}
builder.append('@');
builder.append(getTypeName());
builder.append('/');
builder.append(getName());
return builder.toString();
}
public static String buildResourceName(char prefix, String packageName, String type, String name){
if(name==null){
return null;
}
StringBuilder builder=new StringBuilder();
if(prefix!=0){
builder.append(prefix);
}
if(packageName!=null){
builder.append(packageName);
builder.append(':');
}
if(type!=null){
builder.append(type);
builder.append('/');
}
builder.append(name);
return builder.toString();
}
public static String buildResourceName(char prefix, String packageName, String type, String name){
if(name==null){
return null;
}
StringBuilder builder=new StringBuilder();
if(prefix!=0){
builder.append(prefix);
}
if(packageName!=null){
builder.append(packageName);
builder.append(':');
}
if(type!=null){
builder.append(type);
builder.append('/');
}
builder.append(name);
return builder.toString();
}
public static final String NAME_id = "id";
}
public static final String NAME_id = "id";
}

View File

@ -1,40 +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.arsc.value;
import com.reandroid.arsc.item.BlockItem;
public class SparseTypeEntry extends BlockItem {
public SparseTypeEntry() {
super(4);
}
public int getIdx(){
return getShort(getBytesInternal(), 0) & 0xffff;
}
public void setIdx(int idx){
putShort(getBytesInternal(), 0, (short) idx);
}
public int getOffset(){
return getShort(getBytesInternal(), 2) & 0xffff;
}
public void setOffset(int offset){
putShort(getBytesInternal(), 2, (short) offset);
}
@Override
public String toString(){
return "idx=" + getIdx() + ", offset=" + getOffset();
}
}