diff --git a/src/main/java/com/reandroid/apk/xmlencoder/XMLTableBlockEncoder.java b/src/main/java/com/reandroid/apk/xmlencoder/XMLTableBlockEncoder.java index afcb4fa6d..a17f45843 100644 --- a/src/main/java/com/reandroid/apk/xmlencoder/XMLTableBlockEncoder.java +++ b/src/main/java/com/reandroid/apk/xmlencoder/XMLTableBlockEncoder.java @@ -268,7 +268,7 @@ private void initializeMainPackageId(XMLDocument xmlDocument) { logMessage("WARN: failed to resolve: " + ref); return; } - int packageId = (resourceId >> 24 ) & 0xff; + int packageId = resourceId >>> 24; this.mMainPackageId = packageId; logMessage("Main package id initialized: id = " + HexUtil.toHex2((byte)packageId) + ", from: " + ref ); diff --git a/src/main/java/com/reandroid/archive/block/CommonHeader.java b/src/main/java/com/reandroid/archive/block/CommonHeader.java index a69e45cbf..2d77428b0 100644 --- a/src/main/java/com/reandroid/archive/block/CommonHeader.java +++ b/src/main/java/com/reandroid/archive/block/CommonHeader.java @@ -378,7 +378,7 @@ public String toString(){ } static boolean isZip64Value(long value){ - return value == 0xffffffffL || (value & 0xffffffff00000000L) != 0; + return value == 0xffffffffL || (value >>> 32) != 0; } static boolean isZip64Value(int value){ return value == 0xffffffff; diff --git a/src/main/java/com/reandroid/archive/block/ZipHeader.java b/src/main/java/com/reandroid/archive/block/ZipHeader.java index 3d66093b1..9dafde449 100644 --- a/src/main/java/com/reandroid/archive/block/ZipHeader.java +++ b/src/main/java/com/reandroid/archive/block/ZipHeader.java @@ -85,7 +85,7 @@ public void setSignature(ZipSignature signature){ } public static boolean isZip64Length(long length){ - return (length == 0xffffffff || (length & 0xffffffff00000000L) != 0); + return (length == 0xffffffffL || (length >>> 32) != 0); } private static final int OFFSET_signature = 0; } diff --git a/src/main/java/com/reandroid/arsc/array/CompoundItemArray.java b/src/main/java/com/reandroid/arsc/array/CompoundItemArray.java index 712bc0bd5..35a117c87 100644 --- a/src/main/java/com/reandroid/arsc/array/CompoundItemArray.java +++ b/src/main/java/com/reandroid/arsc/array/CompoundItemArray.java @@ -50,8 +50,7 @@ private void updateCountToHeader() { public AttributeDataFormat[] getFormats(){ ResValueMap formatsMap = getByType(AttributeType.FORMATS); if(formatsMap != null){ - return AttributeDataFormat.decodeValueTypes( - formatsMap.getData() & 0xff); + return AttributeDataFormat.decodeValueTypes((byte) formatsMap.getData()); } return null; } diff --git a/src/main/java/com/reandroid/arsc/array/SparseOffsetsArray.java b/src/main/java/com/reandroid/arsc/array/SparseOffsetsArray.java index 3b2475e56..cefe561ad 100644 --- a/src/main/java/com/reandroid/arsc/array/SparseOffsetsArray.java +++ b/src/main/java/com/reandroid/arsc/array/SparseOffsetsArray.java @@ -66,7 +66,7 @@ public int getOffset(int i){ if(value == NO_ENTRY){ return value; } - value = (value >>> 16) & 0xffff; + value = value >>> 16; return value * 4; } @Override @@ -77,9 +77,8 @@ public void setOffset(int index, int offset){ }else { int idx = get(index); idx = idx & 0xffff; - offset = offset & 0xffff; - offset = offset / 4; - offset = offset << 16; + //use unsigned shifting to combine unsigning and division by 4 + offset = (offset >>> 2) << 16; value = offset | idx; } super.put(index, value); diff --git a/src/main/java/com/reandroid/arsc/base/Block.java b/src/main/java/com/reandroid/arsc/base/Block.java index 7b7bae5f3..058f14994 100755 --- a/src/main/java/com/reandroid/arsc/base/Block.java +++ b/src/main/java/com/reandroid/arsc/base/Block.java @@ -148,7 +148,7 @@ public static void putInteger(byte[] bytes, int offset, int val){ if((offset + 4) > bytes.length){ return; } - bytes[offset + 3]= (byte) (val >>> 24 & 0xff); + bytes[offset + 3]= (byte) (val >>> 24); bytes[offset + 2]= (byte) (val >>> 16 & 0xff); bytes[offset + 1]= (byte) (val >>> 8 & 0xff); bytes[offset]= (byte) (val & 0xff); @@ -240,7 +240,7 @@ public static void putBigEndianInteger(byte[] bytes, int offset, int value) { if((offset + 4) > bytes.length) { return; } - bytes[offset]= (byte) (value >>> 24 & 0xff); + bytes[offset]= (byte) (value >>> 24); bytes[offset + 1]= (byte) (value >>> 16 & 0xff); bytes[offset + 2]= (byte) (value >>> 8 & 0xff); bytes[offset + 3]= (byte) (value & 0xff); diff --git a/src/main/java/com/reandroid/arsc/chunk/PackageBlock.java b/src/main/java/com/reandroid/arsc/chunk/PackageBlock.java index d7078e8ec..36460ba01 100755 --- a/src/main/java/com/reandroid/arsc/chunk/PackageBlock.java +++ b/src/main/java/com/reandroid/arsc/chunk/PackageBlock.java @@ -121,7 +121,7 @@ public Iterator getTypes() { return ComputeIterator.of(getSpecTypePairs(), ResourceType::new); } public ResourceEntry getResource(int resourceId){ - int packageId = (resourceId >> 24 ) & 0xff; + int packageId = resourceId >>> 24; if(packageId == 0){ return null; } @@ -141,7 +141,7 @@ public ResourceEntry getResource(int resourceId){ if(alias == 0 || alias == resourceId){ return null; } - packageId = (alias >> 24 ) & 0xff; + packageId = alias >>> 24; if(packageId != getId()){ return null; } @@ -325,7 +325,7 @@ public Iterator getEntries(int resourceId){ return getEntries(resourceId, true); } public Iterator getEntries(int resourceId, boolean skipNull){ - int packageId = (resourceId >> 24) & 0xff; + int packageId = resourceId >>> 24; if(packageId != getId()){ return EmptyIterator.of(); } @@ -557,7 +557,7 @@ public Entry getOrCreateEntry(byte typeId, short entryId, ResConfig resConfig){ } public Entry getAnyEntry(int resourceId){ - int packageId = (resourceId >> 24) & 0xff; + int packageId = resourceId >>> 24; if(packageId != getId()){ return null; } @@ -811,17 +811,10 @@ public String toString(){ return builder.toString(); } public static boolean isPackageId(int packageId){ - if(packageId == 0){ - return false; - } return packageId > 0 && packageId <= 0xff; } public static boolean isResourceId(int resourceId){ - if(resourceId == 0){ - return false; - } - return (resourceId & 0x00ff0000) != 0 - && (resourceId & 0xff000000) != 0; + return ((resourceId >> 24) & (byte) (resourceId >> 16)) != 0; } public static void changePackageId(ValueItem valueItem, int packageIdOld, int packageIdNew){ @@ -835,7 +828,7 @@ private static void changePackageIdName(int packageIdOld, int packageIdNew, Attr if(!isResourceId(resourceId)){ return; } - int id = (resourceId >> 24) & 0xff; + int id = resourceId >>> 24; if(id != packageIdOld){ return; } @@ -853,7 +846,7 @@ private static void changePackageIdValue(int packageIdOld, int packageIdNew, Val if(!isResourceId(resourceId)){ return; } - int id = (resourceId >> 24) & 0xff; + int id = resourceId >>> 24; if(id != packageIdOld){ return; } @@ -867,7 +860,7 @@ public static int replacePackageId(int resourceId, int packageIdOld, int package if(!isResourceId(resourceId)){ return resourceId; } - int id = (resourceId >> 24) & 0xff; + int id = resourceId >>> 24; if(id != packageIdOld){ return resourceId; } @@ -925,7 +918,7 @@ private void parsePublicTag(XMLElement element) throws XmlEncodeException { throw new XmlEncodeException("Invalid id value: " + element.getDebugText()); } int resourceId = encodeResult.value; - int packageId = (resourceId >> 24) & 0xff; + int packageId = resourceId >>> 24; int i = packageBlock.getId(); if(i == 0){ packageBlock.setId(packageId); diff --git a/src/main/java/com/reandroid/arsc/chunk/TableBlock.java b/src/main/java/com/reandroid/arsc/chunk/TableBlock.java index 5bd4aa4a9..e4964c385 100755 --- a/src/main/java/com/reandroid/arsc/chunk/TableBlock.java +++ b/src/main/java/com/reandroid/arsc/chunk/TableBlock.java @@ -311,7 +311,7 @@ public Iterator getEntries(int resourceId){ } public Iterator getEntries(int resourceId, boolean skipNull){ - final int packageId = (resourceId >> 24) & 0xff; + final int packageId = resourceId >>> 24; final int typeId = (resourceId >> 16) & 0xff; final int entryId = resourceId & 0xffff; return new IterableIterator(getAllPackages(packageId)) { diff --git a/src/main/java/com/reandroid/arsc/chunk/xml/AndroidManifestBlock.java b/src/main/java/com/reandroid/arsc/chunk/xml/AndroidManifestBlock.java index 4aff0dd2f..a665dc742 100644 --- a/src/main/java/com/reandroid/arsc/chunk/xml/AndroidManifestBlock.java +++ b/src/main/java/com/reandroid/arsc/chunk/xml/AndroidManifestBlock.java @@ -181,7 +181,7 @@ public boolean clearFusedModuleNames() { // TODO: find a better way public int guessCurrentPackageId() { if (mGuessedPackageId == 0) { - mGuessedPackageId = ((getIconResourceId()>>24) & 0xff); + mGuessedPackageId = getIconResourceId() >>> 24; } return mGuessedPackageId; } diff --git a/src/main/java/com/reandroid/arsc/item/ByteArray.java b/src/main/java/com/reandroid/arsc/item/ByteArray.java index 39ffd6efa..be081246d 100755 --- a/src/main/java/com/reandroid/arsc/item/ByteArray.java +++ b/src/main/java/com/reandroid/arsc/item/ByteArray.java @@ -106,7 +106,7 @@ public final void putInteger(int offset, int val){ if((offset+4)>bts.length){ return; } - bts[offset+3]= (byte) (val >>> 24 & 0xff); + bts[offset+3]= (byte) (val >>> 24); bts[offset+2]= (byte) (val >>> 16 & 0xff); bts[offset+1]= (byte) (val >>> 8 & 0xff); bts[offset]= (byte) (val & 0xff); diff --git a/src/main/java/com/reandroid/arsc/item/ByteItem.java b/src/main/java/com/reandroid/arsc/item/ByteItem.java index ea018e764..751e78db0 100755 --- a/src/main/java/com/reandroid/arsc/item/ByteItem.java +++ b/src/main/java/com/reandroid/arsc/item/ByteItem.java @@ -29,18 +29,13 @@ public boolean getBit(int index){ return ((getByte()>>index) & 0x1) == 1; } public void putBit(int index, boolean bit){ - int val= getByte(); - int left=val>>index; + int b = getByte(); + int one = 1 << index; + b &= ~one; if(bit){ - left=left|0x1; - }else { - left=left & 0xFE; + b |= one; } - left=left<>index) & val; - val=left|right; - set((byte) val); + set((byte) b); } public void set(byte value) { getBytesInternal()[0] = value; diff --git a/src/main/java/com/reandroid/arsc/item/SpecFlag.java b/src/main/java/com/reandroid/arsc/item/SpecFlag.java index ff9757f75..887d10d41 100644 --- a/src/main/java/com/reandroid/arsc/item/SpecFlag.java +++ b/src/main/java/com/reandroid/arsc/item/SpecFlag.java @@ -29,7 +29,7 @@ public void setFlagByte(byte flag){ getBlockItem().getBytesInternal()[getOffset() + OFFSET_FLAG] = flag; } public void addFlagByte(byte flag){ - flag = (byte) ((getFlagByte() & 0xff) | (flag & 0xff)); + flag = (byte) ((getFlagByte() | flag) & 0xff); setFlagByte(flag); } public void addFlag(SpecBlock.Flag flag){ diff --git a/src/main/java/com/reandroid/arsc/item/StringItem.java b/src/main/java/com/reandroid/arsc/item/StringItem.java index e2c84da41..43b10c6e2 100755 --- a/src/main/java/com/reandroid/arsc/item/StringItem.java +++ b/src/main/java/com/reandroid/arsc/item/StringItem.java @@ -553,7 +553,7 @@ private static byte[] encodeUtf16ToBytes(String str) { lenBytes[3] = (byte) (high >> 8); lenBytes[2] = (byte) low; low = rem & 0xff; - high = (rem & 0xff00) >> 8; + high = rem >>> 8; lenBytes[1] = (byte) (high | 0x80); lenBytes[0] = (byte) low; } else { diff --git a/src/main/java/com/reandroid/arsc/list/StyleItemListEnd.java b/src/main/java/com/reandroid/arsc/list/StyleItemListEnd.java index 20868d5f8..d063f4e4b 100644 --- a/src/main/java/com/reandroid/arsc/list/StyleItemListEnd.java +++ b/src/main/java/com/reandroid/arsc/list/StyleItemListEnd.java @@ -22,6 +22,7 @@ import com.reandroid.utils.HexUtil; import java.io.IOException; +import java.util.Arrays; public class StyleItemListEnd extends BlockItem implements BlockRefresh { @@ -33,22 +34,15 @@ public StyleItemListEnd(IntegerReference stylesCount) { } private boolean updateSize() { - int size; - if (stylesCount.get() != 0) { - size = 8; - } else { - size = 0; + if(stylesCount.get() == 0){ + setBytesLength(0, false); + return false; } + + final int size = 8; setBytesLength(size, false); - if (size != 0) { - byte b = (byte) 0xff; - byte[] bytes = getBytesInternal(); - for (int i = 0; i < size; i++) { - bytes[i] = b; - } - return true; - } - return false; + Arrays.fill(getBytesInternal(), 0, size, (byte) 0xff); + return true; } @Override public void refresh() { diff --git a/src/main/java/com/reandroid/arsc/value/AttributeDataFormat.java b/src/main/java/com/reandroid/arsc/value/AttributeDataFormat.java index 1ed19c6a3..8e5d232e3 100644 --- a/src/main/java/com/reandroid/arsc/value/AttributeDataFormat.java +++ b/src/main/java/com/reandroid/arsc/value/AttributeDataFormat.java @@ -157,7 +157,10 @@ public static int sum(AttributeDataFormat[] typeValues){ } return result; } - + /** Decodes value types ignoring {@link #ANY} */ + public static AttributeDataFormat[] decodeValueTypes(byte data) { + return decodeValueTypes((int) data); + } public static AttributeDataFormat[] decodeValueTypes(int data) { if ((data & 0xffff) == 0xffff) { return new AttributeDataFormat[]{ANY}; diff --git a/src/main/java/com/reandroid/arsc/value/AttributeType.java b/src/main/java/com/reandroid/arsc/value/AttributeType.java index ee1ab35ec..93840120b 100644 --- a/src/main/java/com/reandroid/arsc/value/AttributeType.java +++ b/src/main/java/com/reandroid/arsc/value/AttributeType.java @@ -41,8 +41,8 @@ public int getId() { } public boolean isPlural(){ - int i = id & 0xffff; - return i>=4 && i<=9; + //a hack to detect plurals (they have id with 0xc bit set) + return (id & 0xc) != 0; } public String getName(){ diff --git a/src/main/java/com/reandroid/arsc/value/ResValueMap.java b/src/main/java/com/reandroid/arsc/value/ResValueMap.java index 183980425..7b0c3a065 100755 --- a/src/main/java/com/reandroid/arsc/value/ResValueMap.java +++ b/src/main/java/com/reandroid/arsc/value/ResValueMap.java @@ -39,8 +39,8 @@ public void setArrayIndex(int index){ } public int getArrayIndex(){ int name = getNameId(); - int high = name & 0xffff0000; - if(high != 0x01000000 && high != 0x02000000){ + int high = name >>> 16; + if(high != 0x0100 && high != 0x0200){ return -1; } return name & 0xffff; diff --git a/src/main/java/com/reandroid/arsc/value/ValueType.java b/src/main/java/com/reandroid/arsc/value/ValueType.java index 096dd173e..444310062 100755 --- a/src/main/java/com/reandroid/arsc/value/ValueType.java +++ b/src/main/java/com/reandroid/arsc/value/ValueType.java @@ -53,20 +53,17 @@ public String getTypeName() { return typeName; } public boolean isColor(){ - return this == COLOR_ARGB8 - || this == COLOR_RGB8 - || this == COLOR_ARGB4 - || this == COLOR_RGB4; + //a hack for color types check + return this.mByte >> 3 == 0b11; } public boolean isInteger(){ - return this == DEC - || this == HEX; + //a hack for integer types check + return (this.mByte ^ 0x10) <= 1; } public boolean isReference(){ - return this == REFERENCE - || this == ATTRIBUTE - || this == DYNAMIC_REFERENCE - || this == DYNAMIC_ATTRIBUTE; + //using bitset lookup to check reference types + final int bitmask = 0b110000110; + return (bitmask >> this.mByte & 1) == 1; } public static ValueType valueOf(byte b){ diff --git a/src/main/java/com/reandroid/arsc/value/array/ArrayBag.java b/src/main/java/com/reandroid/arsc/value/array/ArrayBag.java index f8220f28a..dfc97cafc 100644 --- a/src/main/java/com/reandroid/arsc/value/array/ArrayBag.java +++ b/src/main/java/com/reandroid/arsc/value/array/ArrayBag.java @@ -156,7 +156,7 @@ public static boolean isArray(Entry entry) { while (iterator.hasNext()) { ResValueMap resValueMap = iterator.next(); int name = resValueMap.getNameId(); - int high = (name >> 16) & 0xffff; + int high = name >>> 16; if(high != 0x0100){ return false; } diff --git a/src/main/java/com/reandroid/common/Namespace.java b/src/main/java/com/reandroid/common/Namespace.java index a80a59c2a..6a98fd21d 100644 --- a/src/main/java/com/reandroid/common/Namespace.java +++ b/src/main/java/com/reandroid/common/Namespace.java @@ -26,7 +26,7 @@ static boolean isValidNamespace(String uri, String prefix) { return isValidUri(uri) && isValidPrefix(prefix); } static boolean isValidUri(String uri, int resourceId) { - int packageId = (resourceId >> 24 ) & 0xff; + int packageId = resourceId >>> 24; if(packageId == 0) { if(StringsUtil.isEmpty(uri)) { return true; @@ -98,7 +98,7 @@ static String prefixForResourceId(int resourceId) { if(resourceId == 0) { return null; } - int packageId = (resourceId >> 24) & 0xff; + int packageId = resourceId >>> 24; if(packageId == 0x1) { return PREFIX_ANDROID; }else if(packageId != 0){ @@ -111,7 +111,7 @@ static String uriForResourceId(int resourceId) { if(resourceId == 0) { return null; } - int packageId = (resourceId >> 24) & 0xff; + int packageId = resourceId >>> 24; if(packageId == 0x1) { return URI_ANDROID; }else if(packageId != 0){ diff --git a/src/main/java/com/reandroid/identifiers/PackageIdentifier.java b/src/main/java/com/reandroid/identifiers/PackageIdentifier.java index f3768d236..b15fce40b 100644 --- a/src/main/java/com/reandroid/identifiers/PackageIdentifier.java +++ b/src/main/java/com/reandroid/identifiers/PackageIdentifier.java @@ -261,7 +261,7 @@ private void parseEntry(XmlPullParser parser) throws XmlPullParserException { } int resourceId = (int) Long.decode(resourceIdStr).longValue(); - int packageId = (resourceId >> 24) & 0xff; + int packageId = resourceId >>> 24; int typeId = (resourceId >> 16) & 0xff; int entryId = resourceId & 0xffff; diff --git a/src/test/java/com/reandroid/arsc/array/SparseOffsetsArrayTest.java b/src/test/java/com/reandroid/arsc/array/SparseOffsetsArrayTest.java new file mode 100644 index 000000000..4f983b875 --- /dev/null +++ b/src/test/java/com/reandroid/arsc/array/SparseOffsetsArrayTest.java @@ -0,0 +1,26 @@ +package com.reandroid.arsc.array; + +import org.junit.Assert; +import org.junit.Test; + +public class SparseOffsetsArrayTest { + @Test + public void testSetOffset() { + //offsets are encoded is 16-bit, real_offset = offset * 4 + final SparseOffsetsArray sparseArr = new SparseOffsetsArray(); + + final int offset = 0x10; + final int index = 0x0000; + + //put data + final int data = ((offset / 4) << 16) | index; + sparseArr.set(new int[]{ data }); + Assert.assertEquals(offset, sparseArr.getOffset(0)); + + //test setOffset + sparseArr.clear(); + sparseArr.setSize(1); + sparseArr.setOffset(0, offset); + Assert.assertEquals(offset, sparseArr.getOffset(0)); + } +} diff --git a/src/test/java/com/reandroid/arsc/value/AttributeTypeTest.java b/src/test/java/com/reandroid/arsc/value/AttributeTypeTest.java new file mode 100644 index 000000000..2db62c361 --- /dev/null +++ b/src/test/java/com/reandroid/arsc/value/AttributeTypeTest.java @@ -0,0 +1,32 @@ +package com.reandroid.arsc.value; + +import org.junit.Assert; +import org.junit.Test; + +public class AttributeTypeTest { + private final static AttributeType[] PLURALS = new AttributeType[]{ + AttributeType.OTHER, + AttributeType.ZERO, + AttributeType.ONE, + AttributeType.TWO, + AttributeType.FEW, + AttributeType.MANY + }; + private final static AttributeType[] NON_PLURALS = new AttributeType[]{ + AttributeType.FORMATS, + AttributeType.MIN, + AttributeType.MAX, + AttributeType.L10N + }; + + @Test + public void testIsPlural() { + for(AttributeType type : PLURALS) { + Assert.assertTrue(type.isPlural()); + } + + for(AttributeType type : NON_PLURALS) { + Assert.assertFalse(type.isPlural()); + } + } +} diff --git a/src/test/java/com/reandroid/arsc/value/ValueTypeTest.java b/src/test/java/com/reandroid/arsc/value/ValueTypeTest.java new file mode 100644 index 000000000..f3028d22c --- /dev/null +++ b/src/test/java/com/reandroid/arsc/value/ValueTypeTest.java @@ -0,0 +1,48 @@ +package com.reandroid.arsc.value; + +import org.junit.Assert; +import org.junit.Test; + +public class ValueTypeTest { + private static final ValueType[] ALL = ValueType.values(); + + @Test + public void testIsColor() { + for(ValueType type : ALL) { + Assert.assertEquals(isColor(type), type.isColor()); + } + } + + @Test + public void testIsInteger() { + for(ValueType type : ALL) { + Assert.assertEquals(isInteger(type), type.isInteger()); + } + } + + @Test + public void testIsReference() { + for(ValueType type : ALL) { + Assert.assertEquals(isReference(type), type.isReference()); + } + } + + private static boolean isColor(ValueType valueType) { + return valueType == ValueType.COLOR_ARGB8 + || valueType == ValueType.COLOR_RGB8 + || valueType == ValueType.COLOR_ARGB4 + || valueType == ValueType.COLOR_RGB4; + } + + private static boolean isInteger(ValueType valueType) { + return valueType == ValueType.DEC + || valueType == ValueType.HEX; + } + + private static boolean isReference(ValueType valueType) { + return valueType == ValueType.REFERENCE + || valueType == ValueType.ATTRIBUTE + || valueType == ValueType.DYNAMIC_REFERENCE + || valueType == ValueType.DYNAMIC_ATTRIBUTE; + } +}