/* * Copyright 2012, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.jf.dexlib2.dexbacked; import org.jf.util.ExceptionWithContext; import org.jf.util.Utf8Utils; import javax.annotation.Nonnull; public class BaseDexReader<T extends BaseDexBuffer> { @Nonnull public final T dexBuf; private int offset; public BaseDexReader(@Nonnull T dexBuf, int offset) { this.dexBuf = dexBuf; this.offset = offset; } public int getOffset() { return offset; } public void setOffset(int offset) { this.offset = offset; } /** {@inheritDoc} */ public int readSleb128() { if (dexBuf.getReader() == null) { int end = offset; int currentByteValue; int result; byte[] buf = dexBuf.buf; result = buf[end++] & 0xff; if (result <= 0x7f) { result = (result << 25) >> 25; } else { currentByteValue = buf[end++] & 0xff; result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7); if (currentByteValue <= 0x7f) { result = (result << 18) >> 18; } else { currentByteValue = buf[end++] & 0xff; result |= (currentByteValue & 0x7f) << 14; if (currentByteValue <= 0x7f) { result = (result << 11) >> 11; } else { currentByteValue = buf[end++] & 0xff; result |= (currentByteValue & 0x7f) << 21; if (currentByteValue <= 0x7f) { result = (result << 4) >> 4; } else { currentByteValue = buf[end++] & 0xff; if (currentByteValue > 0x7f) { throw new ExceptionWithContext( "Invalid sleb128 integer encountered at offset 0x%x", offset); } result |= currentByteValue << 28; } } } } offset = end; return result; } else { int end = offset; int currentByteValue; int result; result = dexBuf.getReader() .readBytes(dexBuf.getBaseAddr() + end, 1)[0] & 0xff; end++; if (result <= 0x7f) { result = (result << 25) >> 25; } else { currentByteValue = dexBuf.getReader().readBytes( dexBuf.getBaseAddr() + end, 1)[0] & 0xff; end++; result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7); if (currentByteValue <= 0x7f) { result = (result << 18) >> 18; } else { currentByteValue = dexBuf.getReader().readBytes( dexBuf.getBaseAddr() + end, 1)[0] & 0xff; end++; result |= (currentByteValue & 0x7f) << 14; if (currentByteValue <= 0x7f) { result = (result << 11) >> 11; } else { currentByteValue = dexBuf.getReader().readBytes( dexBuf.getBaseAddr() + end, 1)[0] & 0xff; end++; result |= (currentByteValue & 0x7f) << 21; if (currentByteValue <= 0x7f) { result = (result << 4) >> 4; } else { currentByteValue = dexBuf.getReader().readBytes( dexBuf.getBaseAddr() + end, 1)[0] & 0xff; end++; if (currentByteValue > 0x7f) { throw new ExceptionWithContext( "Invalid sleb128 integer encountered at offset 0x%x", offset); } result |= currentByteValue << 28; } } } } offset = end; return result; } } public int readSmallUleb128() { return readUleb128(false); } private int readUleb128(boolean allowLarge) { if (this.dexBuf.getReader() == null) { int end = offset; int currentByteValue; int result; byte[] buf = dexBuf.buf; result = buf[end++] & 0xff; if (result > 0x7f) { currentByteValue = buf[end++] & 0xff; result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7); if (currentByteValue > 0x7f) { currentByteValue = buf[end++] & 0xff; result |= (currentByteValue & 0x7f) << 14; if (currentByteValue > 0x7f) { currentByteValue = buf[end++] & 0xff; result |= (currentByteValue & 0x7f) << 21; if (currentByteValue > 0x7f) { currentByteValue = buf[end++]; // MSB shouldn't be set on last byte if (currentByteValue < 0) { throw new ExceptionWithContext( "Invalid uleb128 integer encountered at offset 0x%x", offset); } else if ((currentByteValue & 0xf) > 0x07) { if (!allowLarge) { // for non-large uleb128s, we assume most // significant bit of the result will not be // set, so that it can fit into a signed // integer // without wrapping throw new ExceptionWithContext( "Encountered valid uleb128 that is out of range at offset 0x%x", offset); } } result |= currentByteValue << 28; } } } } offset = end; return result; } else { int end = offset; int currentByteValue; int result; result = dexBuf.getReader() .readBytes(dexBuf.getBaseAddr() + end, 1)[0] & 0xff; end++; if (result > 0x7f) { currentByteValue = dexBuf.getReader().readBytes( dexBuf.getBaseAddr() + end, 1)[0] & 0xff; end++; result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7); if (currentByteValue > 0x7f) { currentByteValue = dexBuf.getReader().readBytes( dexBuf.getBaseAddr() + end, 1)[0] & 0xff; end++; result |= (currentByteValue & 0x7f) << 14; if (currentByteValue > 0x7f) { currentByteValue = dexBuf.getReader().readBytes( dexBuf.getBaseAddr() + end, 1)[0] & 0xff; end++; result |= (currentByteValue & 0x7f) << 21; if (currentByteValue > 0x7f) { currentByteValue = dexBuf.getReader().readBytes( dexBuf.getBaseAddr() + end, 1)[0]; end++; // MSB shouldn't be set on last byte if (currentByteValue < 0) { throw new ExceptionWithContext( "Invalid uleb128 integer encountered at offset 0x%x", offset); } else if ((currentByteValue & 0xf) > 0x07) { if (!allowLarge) { // for non-large uleb128s, we assume most // significant bit of the result will not be // set, so that it can fit into a signed // integer // without wrapping throw new ExceptionWithContext( "Encountered valid uleb128 that is out of range at offset 0x%x", offset); } } result |= currentByteValue << 28; } } } } offset = end; return result; } } /** * Reads a "large" uleb128. That is, one that may legitimately be greater * than a signed int. * * The value is returned as if it were signed. i.e. a value of 0xFFFFFFFF * would be returned as -1. It is up to the caller to handle the value * appropriately. */ public int readLargeUleb128() { return readUleb128(true); } /** * Reads a "big" uleb128 that can legitimately be > 2^31. The value is * returned as a signed integer, with the expected semantics of * re-interpreting an unsigned value as a signed value. * * @return The unsigned value, reinterpreted as a signed int */ public int readBigUleb128() { if (this.dexBuf.getReader() == null) { int end = offset; int currentByteValue; int result; byte[] buf = dexBuf.buf; result = buf[end++] & 0xff; if (result > 0x7f) { currentByteValue = buf[end++] & 0xff; result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7); if (currentByteValue > 0x7f) { currentByteValue = buf[end++] & 0xff; result |= (currentByteValue & 0x7f) << 14; if (currentByteValue > 0x7f) { currentByteValue = buf[end++] & 0xff; result |= (currentByteValue & 0x7f) << 21; if (currentByteValue > 0x7f) { currentByteValue = buf[end++]; // MSB shouldn't be set on last byte if (currentByteValue < 0) { throw new ExceptionWithContext( "Invalid uleb128 integer encountered at offset 0x%x", offset); } result |= currentByteValue << 28; } } } } offset = end; return result; } else { int end = offset; int currentByteValue; int result; result = dexBuf.getReader() .readBytes(dexBuf.getBaseAddr() + end, 1)[0] & 0xff; end++; if (result > 0x7f) { currentByteValue = dexBuf.getReader().readBytes( dexBuf.getBaseAddr() + end, 1)[0] & 0xff; end++; result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7); if (currentByteValue > 0x7f) { currentByteValue = dexBuf.getReader().readBytes( dexBuf.getBaseAddr() + end, 1)[0] & 0xff; end++; result |= (currentByteValue & 0x7f) << 14; if (currentByteValue > 0x7f) { currentByteValue = dexBuf.getReader().readBytes( dexBuf.getBaseAddr() + end, 1)[0] & 0xff; end++; result |= (currentByteValue & 0x7f) << 21; if (currentByteValue > 0x7f) { currentByteValue = dexBuf.getReader().readBytes( dexBuf.getBaseAddr() + end, 1)[0]; end++; // MSB shouldn't be set on last byte if (currentByteValue < 0) { throw new ExceptionWithContext( "Invalid uleb128 integer encountered at offset 0x%x", offset); } result |= currentByteValue << 28; } } } } offset = end; return result; } } public void skipUleb128() { if (this.dexBuf.getReader() == null) { int end = offset; byte currentByteValue; byte[] buf = dexBuf.buf; currentByteValue = buf[end++]; if (currentByteValue < 0) { // if the MSB is set currentByteValue = buf[end++]; if (currentByteValue < 0) { // if the MSB is set currentByteValue = buf[end++]; if (currentByteValue < 0) { // if the MSB is set currentByteValue = buf[end++]; if (currentByteValue < 0) { // if the MSB is set currentByteValue = buf[end++]; if (currentByteValue < 0) { throw new ExceptionWithContext( "Invalid uleb128 integer encountered at offset 0x%x", offset); } } } } } offset = end; } else { int end = offset; byte currentByteValue; currentByteValue = dexBuf.getReader().readBytes( dexBuf.getBaseAddr() + end, 1)[0]; end++; if (currentByteValue < 0) { // if the MSB is set currentByteValue = dexBuf.getReader().readBytes( dexBuf.getBaseAddr() + end, 1)[0]; end++; if (currentByteValue < 0) { // if the MSB is set currentByteValue = dexBuf.getReader().readBytes( dexBuf.getBaseAddr() + end, 1)[0]; end++; if (currentByteValue < 0) { // if the MSB is set currentByteValue = dexBuf.getReader().readBytes( dexBuf.getBaseAddr() + end, 1)[0]; end++; if (currentByteValue < 0) { // if the MSB is set currentByteValue = dexBuf.getReader().readBytes( dexBuf.getBaseAddr() + end, 1)[0]; end++; if (currentByteValue < 0) { throw new ExceptionWithContext( "Invalid uleb128 integer encountered at offset 0x%x", offset); } } } } } offset = end; } } public int readSmallUint() { int o = offset; int result = dexBuf.readSmallUint(o); offset = o + 4; return result; } public int readOptionalUint() { int o = offset; int result = dexBuf.readOptionalUint(o); offset = o + 4; return result; } public int peekUshort() { return dexBuf.readUshort(offset); } public int readUshort() { int o = offset; int result = dexBuf.readUshort(offset); offset = o + 2; return result; } public int peekUbyte() { return dexBuf.readUbyte(offset); } public int readUbyte() { int o = offset; int result = dexBuf.readUbyte(offset); offset = o + 1; return result; } public long readLong() { int o = offset; long result = dexBuf.readLong(offset); offset = o + 8; return result; } public int readInt() { int o = offset; int result = dexBuf.readInt(offset); offset = o + 4; return result; } public int readShort() { int o = offset; int result = dexBuf.readShort(offset); offset = o + 2; return result; } public int readByte() { int o = offset; int result = dexBuf.readByte(offset); offset = o + 1; return result; } public void skipByte() { offset++; } public void moveRelative(int i) { offset += i; } public int readSmallUint(int offset) { return dexBuf.readSmallUint(offset); } public int readUshort(int offset) { return dexBuf.readUshort(offset); } public int readUbyte(int offset) { return dexBuf.readUbyte(offset); } public long readLong(int offset) { return dexBuf.readLong(offset); } public int readInt(int offset) { return dexBuf.readInt(offset); } public int readShort(int offset) { return dexBuf.readShort(offset); } public int readByte(int offset) { return dexBuf.readByte(offset); } public int readSizedInt(int bytes) { if (this.dexBuf.getReader() == null) { int o = offset; byte[] buf = dexBuf.buf; int result; switch (bytes) { case 4: result = (buf[o] & 0xff) | ((buf[o + 1] & 0xff) << 8) | ((buf[o + 2] & 0xff) << 16) | (buf[o + 3] << 24); break; case 3: result = (buf[o] & 0xff) | ((buf[o + 1] & 0xff) << 8) | ((buf[o + 2]) << 16); break; case 2: result = (buf[o] & 0xff) | ((buf[o + 1]) << 8); break; case 1: result = buf[o]; break; default: throw new ExceptionWithContext( "Invalid size %d for sized int at offset 0x%x", bytes, offset); } offset = o + bytes; return result; } else { int o = offset; byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o, bytes); int result; switch (bytes) { case 4:{ result = (buf[0] & 0xff) | ((buf[1] & 0xff) << 8) | ((buf[2] & 0xff) << 16) | (buf[3] << 24); break; } case 3:{ result = (buf[0] & 0xff) | ((buf[1] & 0xff) << 8) | ((buf[2]) << 16); break; } case 2:{ result = (buf[0] & 0xff) | ((buf[1]) << 8); break; } case 1:{ result = buf[0]; break; } default: throw new ExceptionWithContext( "Invalid size %d for sized int at offset 0x%x", bytes, offset); } offset = o + bytes; return result; } } public int readSizedSmallUint(int bytes) { if (this.dexBuf.getReader() == null) { int o = offset; byte[] buf = dexBuf.buf; int result = 0; switch (bytes) { case 4: int b = buf[o + 3]; if (b < 0) { throw new ExceptionWithContext( "Encountered valid sized uint that is out of range at offset 0x%x", offset); } result = b << 24; // fall-through case 3: result |= (buf[o + 2] & 0xff) << 16; // fall-through case 2: result |= (buf[o + 1] & 0xff) << 8; // fall-through case 1: result |= (buf[o] & 0xff); break; default: throw new ExceptionWithContext( "Invalid size %d for sized uint at offset 0x%x", bytes, offset); } offset = o + bytes; return result; } else { int o = offset; byte[] buf = null; buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,bytes); int result = 0; switch (bytes) { case 4:{ int b = buf[3]; if (b < 0) { throw new ExceptionWithContext( "Encountered valid sized uint that is out of range at offset 0x%x", offset); } result = b << 24; } // fall-through case 3:{ result |= (buf[2] & 0xff) << 16; } // fall-through case 2:{ result |= (buf[1] & 0xff) << 8; } // fall-through case 1:{ result |= (buf[0] & 0xff); break; } default: throw new ExceptionWithContext( "Invalid size %d for sized uint at offset 0x%x", bytes, offset); } offset = o + bytes; return result; } } public int readSizedRightExtendedInt(int bytes) { if (this.dexBuf.getReader() == null) { int o = offset; byte[] buf = dexBuf.buf; int result; switch (bytes) { case 4: result = (buf[o] & 0xff) | ((buf[o + 1] & 0xff) << 8) | ((buf[o + 2] & 0xff) << 16) | (buf[o + 3] << 24); break; case 3: result = (buf[o] & 0xff) << 8 | ((buf[o + 1] & 0xff) << 16) | (buf[o + 2] << 24); break; case 2: result = (buf[o] & 0xff) << 16 | (buf[o + 1] << 24); break; case 1: result = buf[o] << 24; break; default: throw new ExceptionWithContext( "Invalid size %d for sized, right extended int at offset 0x%x", bytes, offset); } offset = o + bytes; return result; } else { int o = offset; int result; switch (bytes) { case 4:{ byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,4); result = (buf[0] & 0xff) | ((buf[1] & 0xff) << 8) | ((buf[2] & 0xff) << 16) | (buf[3] << 24); break; } case 3:{ byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,3); result = (buf[0] & 0xff) << 8 | ((buf[1] & 0xff) << 16) | (buf[2] << 24); break; } case 2:{ byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,2); result = (buf[0] & 0xff) << 16 | (buf[1] << 24); break; } case 1:{ byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,1); result = buf[0] << 24; break; } default: throw new ExceptionWithContext( "Invalid size %d for sized, right extended int at offset 0x%x", bytes, offset); } offset = o + bytes; return result; } } public long readSizedRightExtendedLong(int bytes) { if (this.dexBuf.getReader() == null) { int o = offset; byte[] buf = dexBuf.buf; long result; switch (bytes) { case 8: result = (buf[o] & 0xff) | ((buf[o + 1] & 0xff) << 8) | ((buf[o + 2] & 0xff) << 16) | ((buf[o + 3] & 0xffL) << 24) | ((buf[o + 4] & 0xffL) << 32) | ((buf[o + 5] & 0xffL) << 40) | ((buf[o + 6] & 0xffL) << 48) | (((long) buf[o + 7]) << 56); break; case 7: result = ((buf[o] & 0xff)) << 8 | ((buf[o + 1] & 0xff) << 16) | ((buf[o + 2] & 0xffL) << 24) | ((buf[o + 3] & 0xffL) << 32) | ((buf[o + 4] & 0xffL) << 40) | ((buf[o + 5] & 0xffL) << 48) | (((long) buf[o + 6]) << 56); break; case 6: result = ((buf[o] & 0xff)) << 16 | ((buf[o + 1] & 0xffL) << 24) | ((buf[o + 2] & 0xffL) << 32) | ((buf[o + 3] & 0xffL) << 40) | ((buf[o + 4] & 0xffL) << 48) | (((long) buf[o + 5]) << 56); break; case 5: result = ((buf[o] & 0xffL)) << 24 | ((buf[o + 1] & 0xffL) << 32) | ((buf[o + 2] & 0xffL) << 40) | ((buf[o + 3] & 0xffL) << 48) | (((long) buf[o + 4]) << 56); break; case 4: result = ((buf[o] & 0xffL)) << 32 | ((buf[o + 1] & 0xffL) << 40) | ((buf[o + 2] & 0xffL) << 48) | (((long) buf[o + 3]) << 56); break; case 3: result = ((buf[o] & 0xffL)) << 40 | ((buf[o + 1] & 0xffL) << 48) | (((long) buf[o + 2]) << 56); break; case 2: result = ((buf[o] & 0xffL)) << 48 | (((long) buf[o + 1]) << 56); break; case 1: result = ((long) buf[o]) << 56; break; default: throw new ExceptionWithContext( "Invalid size %d for sized, right extended long at offset 0x%x", bytes, offset); } offset = o + bytes; return result; } else { int o = offset; long result; switch (bytes) { case 8:{ byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,8); result = (buf[0] & 0xff) | ((buf[1] & 0xff) << 8) | ((buf[2] & 0xff) << 16) | ((buf[3] & 0xffL) << 24) | ((buf[4] & 0xffL) << 32) | ((buf[5] & 0xffL) << 40) | ((buf[6] & 0xffL) << 48) | (((long) buf[7]) << 56); break; } case 7:{ byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,7); result = ((buf[0] & 0xff)) << 8 | ((buf[1] & 0xff) << 16) | ((buf[2] & 0xffL) << 24) | ((buf[3] & 0xffL) << 32) | ((buf[4] & 0xffL) << 40) | ((buf[5] & 0xffL) << 48) | (((long) buf[6]) << 56); break; } case 6: { byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,6); result = ((buf[0] & 0xff)) << 16 | ((buf[1] & 0xffL) << 24) | ((buf[2] & 0xffL) << 32) | ((buf[3] & 0xffL) << 40) | ((buf[4] & 0xffL) << 48) | (((long) buf[5]) << 56); break; } case 5:{ byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,5); result = ((buf[0] & 0xffL)) << 24 | ((buf[1] & 0xffL) << 32) | ((buf[2] & 0xffL) << 40) | ((buf[3] & 0xffL) << 48) | (((long) buf[4]) << 56); break; } case 4:{ byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,4); result = ((buf[0] & 0xffL)) << 32 | ((buf[1] & 0xffL) << 40) | ((buf[2] & 0xffL) << 48) | (((long) buf[3]) << 56); break; } case 3:{ byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,3); result = ((buf[0] & 0xffL)) << 40 | ((buf[1] & 0xffL) << 48) | (((long) buf[2]) << 56); break; } case 2:{ byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,2); result = ((buf[0] & 0xffL)) << 48 | (((long) buf[1]) << 56); break; } case 1:{ byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,1); result = ((long) buf[0]) << 56; break; } default: throw new ExceptionWithContext( "Invalid size %d for sized, right extended long at offset 0x%x", bytes, offset); } offset = o + bytes; return result; } } public long readSizedLong(int bytes) { if (this.dexBuf.getReader() == null) { int o = offset; byte[] buf = dexBuf.buf; long result; switch (bytes) { case 8: result = (buf[o] & 0xff) | ((buf[o + 1] & 0xff) << 8) | ((buf[o + 2] & 0xff) << 16) | ((buf[o + 3] & 0xffL) << 24) | ((buf[o + 4] & 0xffL) << 32) | ((buf[o + 5] & 0xffL) << 40) | ((buf[o + 6] & 0xffL) << 48) | (((long) buf[o + 7]) << 56); break; case 7: result = (buf[o] & 0xff) | ((buf[o + 1] & 0xff) << 8) | ((buf[o + 2] & 0xff) << 16) | ((buf[o + 3] & 0xffL) << 24) | ((buf[o + 4] & 0xffL) << 32) | ((buf[o + 5] & 0xffL) << 40) | ((long) (buf[o + 6]) << 48); break; case 6: result = (buf[o] & 0xff) | ((buf[o + 1] & 0xff) << 8) | ((buf[o + 2] & 0xff) << 16) | ((buf[o + 3] & 0xffL) << 24) | ((buf[o + 4] & 0xffL) << 32) | ((long) (buf[o + 5]) << 40); break; case 5: result = (buf[o] & 0xff) | ((buf[o + 1] & 0xff) << 8) | ((buf[o + 2] & 0xff) << 16) | ((buf[o + 3] & 0xffL) << 24) | ((long) (buf[o + 4]) << 32); break; case 4: result = (buf[o] & 0xff) | ((buf[o + 1] & 0xff) << 8) | ((buf[o + 2] & 0xff) << 16) | (((long) buf[o + 3]) << 24); break; case 3: result = (buf[o] & 0xff) | ((buf[o + 1] & 0xff) << 8) | (buf[o + 2] << 16); break; case 2: result = (buf[o] & 0xff) | (buf[o + 1] << 8); break; case 1: result = buf[o]; break; default: throw new ExceptionWithContext( "Invalid size %d for sized long at offset 0x%x", bytes, offset); } offset = o + bytes; return result; } else { int o = offset; long result; switch (bytes) { case 8:{ byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,8); result = (buf[0] & 0xff) | ((buf[1] & 0xff) << 8) | ((buf[2] & 0xff) << 16) | ((buf[3] & 0xffL) << 24) | ((buf[4] & 0xffL) << 32) | ((buf[5] & 0xffL) << 40) | ((buf[6] & 0xffL) << 48) | (((long) buf[7]) << 56); break; } case 7:{ byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,7); result = (buf[0] & 0xff) | ((buf[1] & 0xff) << 8) | ((buf[2] & 0xff) << 16) | ((buf[3] & 0xffL) << 24) | ((buf[4] & 0xffL) << 32) | ((buf[5] & 0xffL) << 40) | ((long) (buf[6]) << 48); break; } case 6:{ byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,6); result = (buf[0] & 0xff) | ((buf[1] & 0xff) << 8) | ((buf[2] & 0xff) << 16) | ((buf[3] & 0xffL) << 24) | ((buf[4] & 0xffL) << 32) | ((long) (buf[5]) << 40); break; } case 5:{ byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,5); result = (buf[0] & 0xff) | ((buf[1] & 0xff) << 8) | ((buf[2] & 0xff) << 16) | ((buf[3] & 0xffL) << 24) | ((long) (buf[4]) << 32); break; } case 4:{ byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,4); result = (buf[0] & 0xff) | ((buf[1] & 0xff) << 8) | ((buf[2] & 0xff) << 16) | (((long) buf[3]) << 24); break; } case 3:{ byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,3); result = (buf[0] & 0xff) | ((buf[1] & 0xff) << 8) | (buf[2] << 16); break; } case 2:{ byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,2); result = (buf[0] & 0xff) | (buf[1] << 8); break; } case 1:{ byte[] buf = dexBuf.getReader().readBytes(dexBuf.getBaseAddr() + o,1); result = buf[0]; break; } default: throw new ExceptionWithContext( "Invalid size %d for sized long at offset 0x%x", bytes, offset); } offset = o + bytes; return result; } } public String readString(int utf16Length) { if (this.dexBuf.getReader() == null) { int[] ret = new int[1]; String value = Utf8Utils.utf8BytesWithUtf16LengthToString( dexBuf.buf, offset, utf16Length, ret); offset += ret[0]; return value; } else { int[] ret = new int[1]; byte[] buf = dexBuf.getReader().readBytes( dexBuf.getBaseAddr() + offset, utf16Length*4); String value = Utf8Utils.utf8BytesWithUtf16LengthToString(buf, 0, utf16Length, ret); offset += ret[0]; return value; } } }