mirror of
https://github.com/revanced/smali.git
synced 2025-05-03 16:14:29 +02:00
Add support for writing code_items
This commit is contained in:
parent
56c7adde03
commit
f3c33259dd
@ -40,10 +40,7 @@ import org.jf.dexlib2.iface.instruction.Instruction;
|
|||||||
import org.jf.dexlib2.iface.instruction.OffsetInstruction;
|
import org.jf.dexlib2.iface.instruction.OffsetInstruction;
|
||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
|
||||||
import org.jf.dexlib2.iface.reference.MethodReference;
|
import org.jf.dexlib2.iface.reference.MethodReference;
|
||||||
import org.jf.dexlib2.util.InstructionOffsetMap;
|
import org.jf.dexlib2.util.*;
|
||||||
import org.jf.dexlib2.util.MethodUtil;
|
|
||||||
import org.jf.dexlib2.util.SyntheticAccessorResolver;
|
|
||||||
import org.jf.dexlib2.util.TypeUtils;
|
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.baksmali.baksmali;
|
import org.jf.baksmali.baksmali;
|
||||||
import org.jf.util.ExceptionWithContext;
|
import org.jf.util.ExceptionWithContext;
|
||||||
@ -103,7 +100,7 @@ public class MethodDefinition {
|
|||||||
}catch (Exception ex) {
|
}catch (Exception ex) {
|
||||||
String methodString;
|
String methodString;
|
||||||
try {
|
try {
|
||||||
methodString = MethodUtil.buildFullMethodString(classDef.classDef, method);
|
methodString = ReferenceUtil.getMethodDescriptor(method);
|
||||||
} catch (Exception ex2) {
|
} catch (Exception ex2) {
|
||||||
throw ExceptionWithContext.withContext(ex, "Error while processing method");
|
throw ExceptionWithContext.withContext(ex, "Error while processing method");
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ import org.jf.dexlib2.iface.ExceptionHandler;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
public abstract class BaseExceptionHandler implements ExceptionHandler {
|
public abstract class BaseExceptionHandler implements ExceptionHandler {
|
||||||
@Override
|
@Override
|
||||||
@ -65,9 +66,31 @@ public abstract class BaseExceptionHandler implements ExceptionHandler {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
String otherExceptionType = o.getExceptionType();
|
||||||
|
if (otherExceptionType == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
res = exceptionType.compareTo(o.getExceptionType());
|
res = exceptionType.compareTo(o.getExceptionType());
|
||||||
if (res != 0) return res;
|
if (res != 0) return res;
|
||||||
}
|
}
|
||||||
return Ints.compare(getHandlerCodeAddress(), o.getHandlerCodeAddress());
|
return Ints.compare(getHandlerCodeAddress(), o.getHandlerCodeAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final Comparator<ExceptionHandler> BY_EXCEPTION = new Comparator<ExceptionHandler>() {
|
||||||
|
@Override public int compare(ExceptionHandler o1, ExceptionHandler o2) {
|
||||||
|
String exceptionType1 = o1.getExceptionType();
|
||||||
|
if (exceptionType1 == null) {
|
||||||
|
if (o2.getExceptionType() != null) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
String exceptionType2 = o2.getExceptionType();
|
||||||
|
if (exceptionType2 == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return exceptionType1.compareTo(o2.getExceptionType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -61,8 +61,8 @@ public interface TryBlock {
|
|||||||
/**
|
/**
|
||||||
* A list of the exception handlers associated with this try block.
|
* A list of the exception handlers associated with this try block.
|
||||||
*
|
*
|
||||||
* The exception handlers in the returned set will all have a unique type, including at most 1 with no type, which
|
* The exception handlers in the returned list will all have a unique type, including at most 1 with no type, which
|
||||||
* is the catch-all handler.
|
* is the catch-all handler. Catch-all handler is always the last item in the list.
|
||||||
*
|
*
|
||||||
* @return A list of ExceptionHandler objects
|
* @return A list of ExceptionHandler objects
|
||||||
*/
|
*/
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import org.jf.dexlib2.Opcode;
|
||||||
|
|
||||||
|
public final class InstructionUtil {
|
||||||
|
public static boolean isInvokeStatic(Opcode opcode) {
|
||||||
|
return opcode == Opcode.INVOKE_STATIC || opcode == Opcode.INVOKE_STATIC_RANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private InstructionUtil() {}
|
||||||
|
}
|
@ -32,31 +32,38 @@
|
|||||||
package org.jf.dexlib2.util;
|
package org.jf.dexlib2.util;
|
||||||
|
|
||||||
import org.jf.dexlib2.AccessFlags;
|
import org.jf.dexlib2.AccessFlags;
|
||||||
import org.jf.dexlib2.iface.ClassDef;
|
|
||||||
import org.jf.dexlib2.iface.Method;
|
import org.jf.dexlib2.iface.Method;
|
||||||
import org.jf.dexlib2.iface.MethodParameter;
|
import org.jf.dexlib2.iface.reference.MethodReference;
|
||||||
|
import org.jf.dexlib2.iface.reference.TypeReference;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
public final class MethodUtil {
|
public final class MethodUtil {
|
||||||
public static String buildFullMethodString(ClassDef classDef, Method method) {
|
|
||||||
//TODO: consider using a cached thread-local StringBuilder
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append(classDef.getType());
|
|
||||||
sb.append("->");
|
|
||||||
sb.append(method.getName());
|
|
||||||
sb.append("(");
|
|
||||||
for (MethodParameter methodParameter: method.getParameters()) {
|
|
||||||
sb.append(methodParameter.getType());
|
|
||||||
}
|
|
||||||
sb.append(")");
|
|
||||||
sb.append(method.getReturnType());
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int directMask = AccessFlags.STATIC.getValue() | AccessFlags.PRIVATE.getValue() |
|
private static int directMask = AccessFlags.STATIC.getValue() | AccessFlags.PRIVATE.getValue() |
|
||||||
AccessFlags.CONSTRUCTOR.getValue();
|
AccessFlags.CONSTRUCTOR.getValue();
|
||||||
|
|
||||||
public static boolean isDirect(Method method) {
|
public static boolean isDirect(@Nonnull Method method) {
|
||||||
return (method.getAccessFlags() | directMask) != 0;
|
return (method.getAccessFlags() & directMask) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isStatic(@Nonnull Method method) {
|
||||||
|
return AccessFlags.STATIC.isSet(method.getAccessFlags());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getParameterRegisterCount(@Nonnull MethodReference methodRef, boolean isStatic) {
|
||||||
|
int regCount = 0;
|
||||||
|
for (TypeReference param: methodRef.getParameters()) {
|
||||||
|
int firstChar = param.getType().charAt(0);
|
||||||
|
if (firstChar == 'J' || firstChar == 'D') {
|
||||||
|
regCount += 2;
|
||||||
|
} else {
|
||||||
|
regCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isStatic) {
|
||||||
|
regCount++;
|
||||||
|
}
|
||||||
|
return regCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MethodUtil() {}
|
private MethodUtil() {}
|
||||||
|
552
dexlib2/src/main/java/org/jf/dexlib2/writer/CodeItemPool.java
Normal file
552
dexlib2/src/main/java/org/jf/dexlib2/writer/CodeItemPool.java
Normal file
@ -0,0 +1,552 @@
|
|||||||
|
/*
|
||||||
|
* 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.writer;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import org.jf.dexlib2.ReferenceType;
|
||||||
|
import org.jf.dexlib2.iface.ExceptionHandler;
|
||||||
|
import org.jf.dexlib2.iface.Method;
|
||||||
|
import org.jf.dexlib2.iface.MethodImplementation;
|
||||||
|
import org.jf.dexlib2.iface.TryBlock;
|
||||||
|
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||||
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
|
||||||
|
import org.jf.dexlib2.iface.instruction.SwitchElement;
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.*;
|
||||||
|
import org.jf.dexlib2.iface.reference.*;
|
||||||
|
import org.jf.dexlib2.util.InstructionUtil;
|
||||||
|
import org.jf.dexlib2.util.MethodUtil;
|
||||||
|
import org.jf.dexlib2.util.ReferenceUtil;
|
||||||
|
import org.jf.util.ExceptionWithContext;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class CodeItemPool {
|
||||||
|
@Nonnull private final Map<Method, Integer> codeItemOffsetMap = Maps.newHashMap();
|
||||||
|
@Nonnull private final DexFile dexFile;
|
||||||
|
private int sectionOffset = -1;
|
||||||
|
|
||||||
|
public CodeItemPool(@Nonnull DexFile dexFile) {
|
||||||
|
this.dexFile = dexFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void intern(@Nonnull Method method) {
|
||||||
|
// TODO: can we have parameter names (in the debug_info_item), without having any other sort of method implementation
|
||||||
|
// this also handles parameter names, which aren't directly tied to the MethodImplementation, even though the debug items are
|
||||||
|
boolean hasDebugInfo = dexFile.debugInfoPool.intern(method);
|
||||||
|
boolean hasInstruction = false;
|
||||||
|
|
||||||
|
MethodImplementation methodImpl = method.getImplementation();
|
||||||
|
if (methodImpl != null) {
|
||||||
|
for (Instruction instruction: methodImpl.getInstructions()) {
|
||||||
|
hasInstruction = true;
|
||||||
|
if (instruction instanceof ReferenceInstruction) {
|
||||||
|
Reference reference = ((ReferenceInstruction)instruction).getReference();
|
||||||
|
switch (instruction.getOpcode().referenceType) {
|
||||||
|
case ReferenceType.STRING:
|
||||||
|
dexFile.stringPool.intern((StringReference) reference);
|
||||||
|
break;
|
||||||
|
case ReferenceType.TYPE:
|
||||||
|
dexFile.typePool.intern((TypeReference)reference);
|
||||||
|
break;
|
||||||
|
case ReferenceType.FIELD:
|
||||||
|
dexFile.fieldPool.intern((FieldReference) reference);
|
||||||
|
break;
|
||||||
|
case ReferenceType.METHOD:
|
||||||
|
dexFile.methodPool.intern((MethodReference)reference);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ExceptionWithContext("Unrecognized reference type: %d",
|
||||||
|
instruction.getOpcode().referenceType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<? extends TryBlock> tryBlocks = methodImpl.getTryBlocks();
|
||||||
|
if (!hasInstruction && tryBlocks.size() > 0) {
|
||||||
|
throw new ExceptionWithContext("Method %s has no instructions, but has try blocks.",
|
||||||
|
ReferenceUtil.getMethodDescriptor(method));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TryBlock tryBlock: methodImpl.getTryBlocks()) {
|
||||||
|
for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) {
|
||||||
|
dexFile.typePool.internNullable(handler.getExceptionType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasDebugInfo || hasInstruction) {
|
||||||
|
codeItemOffsetMap.put(method, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOffset(@Nonnull Method method) {
|
||||||
|
Integer offset = codeItemOffsetMap.get(method);
|
||||||
|
if (offset == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumItems() {
|
||||||
|
return codeItemOffsetMap.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSectionOffset() {
|
||||||
|
if (sectionOffset < 0) {
|
||||||
|
throw new ExceptionWithContext("Section offset has not been set yet!");
|
||||||
|
}
|
||||||
|
return sectionOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(@Nonnull DexWriter writer) throws IOException {
|
||||||
|
ByteArrayOutputStream ehBuf = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
writer.align();
|
||||||
|
sectionOffset = writer.getPosition();
|
||||||
|
List<Method> methods = Lists.newArrayList(codeItemOffsetMap.keySet());
|
||||||
|
Collections.sort(methods);
|
||||||
|
for (Method method: methods) {
|
||||||
|
writer.align();
|
||||||
|
codeItemOffsetMap.put(method, writer.getPosition());
|
||||||
|
|
||||||
|
MethodImplementation methodImpl = method.getImplementation();
|
||||||
|
if (methodImpl != null) {
|
||||||
|
writer.writeUshort(methodImpl.getRegisterCount());
|
||||||
|
writer.writeUshort(MethodUtil.getParameterRegisterCount(method, MethodUtil.isStatic(method)));
|
||||||
|
|
||||||
|
int maxOutParamCount = 0;
|
||||||
|
int codeUnitCount = 0;
|
||||||
|
for (Instruction instruction: methodImpl.getInstructions()) {
|
||||||
|
if (instruction.getOpcode().referenceType == ReferenceType.METHOD) {
|
||||||
|
codeUnitCount += instruction.getCodeUnits();
|
||||||
|
|
||||||
|
ReferenceInstruction refInsn = (ReferenceInstruction)instruction;
|
||||||
|
MethodReference methodRef = (MethodReference)refInsn.getReference();
|
||||||
|
int paramCount = MethodUtil.getParameterRegisterCount(methodRef,
|
||||||
|
InstructionUtil.isInvokeStatic(instruction.getOpcode()));
|
||||||
|
if (paramCount > maxOutParamCount) {
|
||||||
|
maxOutParamCount = paramCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.writeUshort(maxOutParamCount);
|
||||||
|
|
||||||
|
List<? extends TryBlock> tryBlocks = methodImpl.getTryBlocks();
|
||||||
|
writer.writeUshort(tryBlocks.size());
|
||||||
|
writer.writeInt(dexFile.debugInfoPool.getOffset(method));
|
||||||
|
writer.writeInt(codeUnitCount);
|
||||||
|
|
||||||
|
// TODO: need to fix up instructions. Add alignment nops, convert to const-string/jumbos, etc.
|
||||||
|
|
||||||
|
for (Instruction instruction: methodImpl.getInstructions()) {
|
||||||
|
switch (instruction.getOpcode().format) {
|
||||||
|
case Format10t:
|
||||||
|
writeFormat10t(writer, (Instruction10t)instruction);
|
||||||
|
break;
|
||||||
|
case Format10x:
|
||||||
|
writeFormat10x(writer, (Instruction10x)instruction);
|
||||||
|
break;
|
||||||
|
case Format11n:
|
||||||
|
writeFormat11n(writer, (Instruction11n)instruction);
|
||||||
|
break;
|
||||||
|
case Format11x:
|
||||||
|
writeFormat11x(writer, (Instruction11x)instruction);
|
||||||
|
break;
|
||||||
|
case Format12x:
|
||||||
|
writeFormat12x(writer, (Instruction12x)instruction);
|
||||||
|
break;
|
||||||
|
case Format20t:
|
||||||
|
writeFormat20t(writer, (Instruction20t)instruction);
|
||||||
|
break;
|
||||||
|
case Format21c:
|
||||||
|
writeFormat21c(writer, (Instruction21c)instruction);
|
||||||
|
break;
|
||||||
|
case Format21ih:
|
||||||
|
writeFormat21ih(writer, (Instruction21ih)instruction);
|
||||||
|
break;
|
||||||
|
case Format21lh:
|
||||||
|
writeFormat21lh(writer, (Instruction21lh)instruction);
|
||||||
|
break;
|
||||||
|
case Format21s:
|
||||||
|
writeFormat21s(writer, (Instruction21s)instruction);
|
||||||
|
break;
|
||||||
|
case Format21t:
|
||||||
|
writeFormat21t(writer, (Instruction21t)instruction);
|
||||||
|
break;
|
||||||
|
case Format22b:
|
||||||
|
writeFormat22b(writer, (Instruction22b)instruction);
|
||||||
|
break;
|
||||||
|
case Format22c:
|
||||||
|
writeFormat22c(writer, (Instruction22c)instruction);
|
||||||
|
break;
|
||||||
|
case Format22s:
|
||||||
|
writeFormat22s(writer, (Instruction22s)instruction);
|
||||||
|
break;
|
||||||
|
case Format22t:
|
||||||
|
writeFormat22t(writer, (Instruction22t)instruction);
|
||||||
|
break;
|
||||||
|
case Format22x:
|
||||||
|
writeFormat22x(writer, (Instruction22x)instruction);
|
||||||
|
break;
|
||||||
|
case Format23x:
|
||||||
|
writeFormat23x(writer, (Instruction23x)instruction);
|
||||||
|
break;
|
||||||
|
case Format30t:
|
||||||
|
writeFormat30t(writer, (Instruction30t)instruction);
|
||||||
|
break;
|
||||||
|
case Format31c:
|
||||||
|
writeFormat31c(writer, (Instruction31c)instruction);
|
||||||
|
break;
|
||||||
|
case Format31i:
|
||||||
|
writeFormat31i(writer, (Instruction31i)instruction);
|
||||||
|
break;
|
||||||
|
case Format31t:
|
||||||
|
writeFormat31t(writer, (Instruction31t)instruction);
|
||||||
|
break;
|
||||||
|
case Format32x:
|
||||||
|
writeFormat32x(writer, (Instruction32x)instruction);
|
||||||
|
break;
|
||||||
|
case Format35c:
|
||||||
|
writeFormat35c(writer, (Instruction35c)instruction);
|
||||||
|
break;
|
||||||
|
case Format3rc:
|
||||||
|
writeFormat3rc(writer, (Instruction3rc)instruction);
|
||||||
|
break;
|
||||||
|
case Format51l:
|
||||||
|
writeFormat51l(writer, (Instruction51l)instruction);
|
||||||
|
break;
|
||||||
|
case ArrayPayload:
|
||||||
|
writeArrayPayload(writer, (ArrayPayload)instruction);
|
||||||
|
break;
|
||||||
|
case SparseSwitchPayload:
|
||||||
|
writeSparseSwitchPayload(writer, (SparseSwitchPayload)instruction);
|
||||||
|
break;
|
||||||
|
case PackedSwitchPayload:
|
||||||
|
writePackedSwitchPayload(writer, (PackedSwitchPayload)instruction);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ExceptionWithContext("Unexpected format: %s", instruction.getOpcode().format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tryBlocks.size() > 0) {
|
||||||
|
writer.align();
|
||||||
|
|
||||||
|
// filter out unique lists of exception handlers
|
||||||
|
Map<List<? extends ExceptionHandler>, Integer> exceptionHandlerOffsetMap = Maps.newHashMap();
|
||||||
|
for (TryBlock tryBlock: tryBlocks) {
|
||||||
|
exceptionHandlerOffsetMap.put(tryBlock.getExceptionHandlers(), 0);
|
||||||
|
}
|
||||||
|
DexWriter.writeUleb128(ehBuf, exceptionHandlerOffsetMap.size());
|
||||||
|
|
||||||
|
for (TryBlock tryBlock: tryBlocks) {
|
||||||
|
writer.writeInt(tryBlock.getStartCodeAddress());
|
||||||
|
writer.writeUshort(tryBlock.getCodeUnitCount());
|
||||||
|
|
||||||
|
if (tryBlock.getExceptionHandlers().size() == 0) {
|
||||||
|
throw new ExceptionWithContext("No exception handlers for the try block!");
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer offset = exceptionHandlerOffsetMap.get(tryBlock.getExceptionHandlers());
|
||||||
|
if (offset != 0) {
|
||||||
|
// exception handler has already been written out, just use it
|
||||||
|
writer.writeUshort(offset);
|
||||||
|
} else {
|
||||||
|
// if offset has not been set yet, we are about to write out a new exception handler
|
||||||
|
offset = ehBuf.size();
|
||||||
|
writer.writeUshort(offset);
|
||||||
|
exceptionHandlerOffsetMap.put(tryBlock.getExceptionHandlers(), offset);
|
||||||
|
|
||||||
|
// check if the last exception handler is a catch-all and adjust the size accordingly
|
||||||
|
int ehSize = tryBlock.getExceptionHandlers().size();
|
||||||
|
ExceptionHandler ehLast = tryBlock.getExceptionHandlers().get(ehSize-1);
|
||||||
|
if (ehLast.getExceptionType() == null) {
|
||||||
|
ehSize = ehSize * (-1) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now let's layout the exception handlers, assuming that catch-all is always last
|
||||||
|
DexWriter.writeSleb128(ehBuf, ehSize);
|
||||||
|
for (ExceptionHandler eh : tryBlock.getExceptionHandlers()) {
|
||||||
|
String exceptionType = eh.getExceptionType();
|
||||||
|
int codeAddress = eh.getHandlerCodeAddress();
|
||||||
|
|
||||||
|
if (exceptionType != null) {
|
||||||
|
//regular exception handling
|
||||||
|
DexWriter.writeUleb128(ehBuf, dexFile.typePool.getIndex(exceptionType));
|
||||||
|
DexWriter.writeUleb128(ehBuf, codeAddress);
|
||||||
|
} else {
|
||||||
|
//catch-all
|
||||||
|
DexWriter.writeUleb128(ehBuf, codeAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ehBuf.size() > 0) {
|
||||||
|
ehBuf.writeTo(writer);
|
||||||
|
ehBuf.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int packNibbles(int a, int b) {
|
||||||
|
return (b << 4) | a;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getReferenceIndex(ReferenceInstruction referenceInstruction) {
|
||||||
|
switch (referenceInstruction.getOpcode().referenceType) {
|
||||||
|
case ReferenceType.FIELD:
|
||||||
|
return dexFile.fieldPool.getIndex((FieldReference)referenceInstruction.getReference());
|
||||||
|
case ReferenceType.METHOD:
|
||||||
|
return dexFile.methodPool.getIndex((MethodReference)referenceInstruction.getReference());
|
||||||
|
case ReferenceType.STRING:
|
||||||
|
return dexFile.stringPool.getIndex((StringReference)referenceInstruction.getReference());
|
||||||
|
case ReferenceType.TYPE:
|
||||||
|
return dexFile.typePool.getIndex((TypeReference)referenceInstruction.getReference());
|
||||||
|
default:
|
||||||
|
throw new ExceptionWithContext("Unknown reference type: %d",
|
||||||
|
referenceInstruction.getOpcode().referenceType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat10t(@Nonnull DexWriter writer, @Nonnull Instruction10t instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(instruction.getCodeOffset());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat10x(@Nonnull DexWriter writer, @Nonnull Instruction10x instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat11n(@Nonnull DexWriter writer, @Nonnull Instruction11n instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(packNibbles(instruction.getRegisterA(), instruction.getNarrowLiteral()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat11x(@Nonnull DexWriter writer, @Nonnull Instruction11x instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(instruction.getRegisterA());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat12x(@Nonnull DexWriter writer, @Nonnull Instruction12x instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat20t(@Nonnull DexWriter writer, @Nonnull Instruction20t instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(0);
|
||||||
|
writer.writeShort(instruction.getCodeOffset());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat21c(@Nonnull DexWriter writer, @Nonnull Instruction21c instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(instruction.getRegisterA());
|
||||||
|
writer.writeUshort(getReferenceIndex(instruction));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat21ih(@Nonnull DexWriter writer, @Nonnull Instruction21ih instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(instruction.getRegisterA());
|
||||||
|
writer.writeShort(instruction.getHatLiteral());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat21lh(@Nonnull DexWriter writer, @Nonnull Instruction21lh instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(instruction.getRegisterA());
|
||||||
|
writer.writeShort(instruction.getHatLiteral());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat21s(@Nonnull DexWriter writer, @Nonnull Instruction21s instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(instruction.getRegisterA());
|
||||||
|
writer.writeShort(instruction.getNarrowLiteral());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat21t(@Nonnull DexWriter writer, @Nonnull Instruction21t instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(instruction.getRegisterA());
|
||||||
|
writer.writeShort(instruction.getCodeOffset());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat22b(@Nonnull DexWriter writer, @Nonnull Instruction22b instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(instruction.getRegisterA());
|
||||||
|
writer.write(instruction.getRegisterB());
|
||||||
|
writer.write(instruction.getNarrowLiteral());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat22c(@Nonnull DexWriter writer, @Nonnull Instruction22c instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
|
||||||
|
writer.writeUshort(getReferenceIndex(instruction));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat22s(@Nonnull DexWriter writer, @Nonnull Instruction22s instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
|
||||||
|
writer.writeShort(instruction.getNarrowLiteral());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat22t(@Nonnull DexWriter writer, @Nonnull Instruction22t instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
|
||||||
|
writer.writeShort(instruction.getCodeOffset());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat22x(@Nonnull DexWriter writer, @Nonnull Instruction22x instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(instruction.getRegisterA());
|
||||||
|
writer.writeUshort(instruction.getRegisterB());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat23x(@Nonnull DexWriter writer, @Nonnull Instruction23x instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(instruction.getRegisterA());
|
||||||
|
writer.write(instruction.getRegisterB());
|
||||||
|
writer.write(instruction.getRegisterC());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat30t(@Nonnull DexWriter writer, @Nonnull Instruction30t instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(0);
|
||||||
|
writer.writeInt(instruction.getCodeOffset());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat31c(@Nonnull DexWriter writer, @Nonnull Instruction31c instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(instruction.getRegisterA());
|
||||||
|
writer.writeInt(getReferenceIndex(instruction));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat31i(@Nonnull DexWriter writer, @Nonnull Instruction31i instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(instruction.getRegisterA());
|
||||||
|
writer.writeInt(instruction.getNarrowLiteral());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat31t(@Nonnull DexWriter writer, @Nonnull Instruction31t instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(instruction.getRegisterA());
|
||||||
|
writer.writeInt(instruction.getCodeOffset());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat32x(@Nonnull DexWriter writer, @Nonnull Instruction32x instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(0);
|
||||||
|
writer.writeUshort(instruction.getRegisterA());
|
||||||
|
writer.writeUshort(instruction.getRegisterB());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat35c(@Nonnull DexWriter writer, @Nonnull Instruction35c instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(packNibbles(instruction.getRegisterG(), instruction.getRegisterCount()));
|
||||||
|
writer.write(getReferenceIndex(instruction));
|
||||||
|
writer.write(packNibbles(instruction.getRegisterC(), instruction.getRegisterD()));
|
||||||
|
writer.write(packNibbles(instruction.getRegisterE(), instruction.getRegisterF()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat3rc(@Nonnull DexWriter writer, @Nonnull Instruction3rc instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(instruction.getRegisterCount());
|
||||||
|
writer.write(getReferenceIndex(instruction));
|
||||||
|
writer.writeUshort(instruction.getStartRegister());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeFormat51l(@Nonnull DexWriter writer, @Nonnull Instruction51l instruction) throws IOException {
|
||||||
|
writer.write(instruction.getOpcode().value);
|
||||||
|
writer.write(instruction.getRegisterA());
|
||||||
|
writer.writeLong(instruction.getWideLiteral());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeArrayPayload(@Nonnull DexWriter writer, @Nonnull ArrayPayload instruction) throws IOException {
|
||||||
|
writer.writeUshort(instruction.getOpcode().value);
|
||||||
|
writer.writeUshort(instruction.getElementWidth());
|
||||||
|
List<Number> elements = instruction.getArrayElements();
|
||||||
|
writer.writeInt(elements.size());
|
||||||
|
// TODO: validate that dalvik only allows these element widths
|
||||||
|
switch (instruction.getElementWidth()) {
|
||||||
|
case 1:
|
||||||
|
for (Number element: elements) {
|
||||||
|
writer.write(element.byteValue());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 2:
|
||||||
|
for (Number element: elements) {
|
||||||
|
writer.writeShort(element.shortValue());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 4:
|
||||||
|
for (Number element: elements) {
|
||||||
|
writer.writeInt(element.intValue());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 8:
|
||||||
|
for (Number element: elements) {
|
||||||
|
writer.writeLong(element.longValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeSparseSwitchPayload(@Nonnull DexWriter writer, @Nonnull SparseSwitchPayload instruction)
|
||||||
|
throws IOException {
|
||||||
|
writer.writeUshort(instruction.getOpcode().value);
|
||||||
|
List<? extends SwitchElement> elements = instruction.getSwitchElements();
|
||||||
|
writer.writeUshort(elements.size());
|
||||||
|
for (SwitchElement element: elements) {
|
||||||
|
writer.writeInt(element.getKey());
|
||||||
|
}
|
||||||
|
for (SwitchElement element: elements) {
|
||||||
|
writer.writeInt(element.getOffset());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writePackedSwitchPayload(@Nonnull DexWriter writer, @Nonnull PackedSwitchPayload instruction)
|
||||||
|
throws IOException {
|
||||||
|
writer.writeUshort(instruction.getOpcode().value);
|
||||||
|
List<? extends SwitchElement> elements = instruction.getSwitchElements();
|
||||||
|
writer.writeUshort(elements.size());
|
||||||
|
writer.writeInt(elements.get(0).getKey());
|
||||||
|
for (SwitchElement element: elements) {
|
||||||
|
writer.writeInt(element.getOffset());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -54,7 +54,7 @@ public class DebugInfoPool {
|
|||||||
this.dexFile = dexFile;
|
this.dexFile = dexFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void intern(@Nonnull Method method) {
|
public boolean intern(@Nonnull Method method) {
|
||||||
boolean hasDebugInfo = false;
|
boolean hasDebugInfo = false;
|
||||||
for (MethodParameter param: method.getParameters()) {
|
for (MethodParameter param: method.getParameters()) {
|
||||||
String paramName = param.getName();
|
String paramName = param.getName();
|
||||||
@ -85,6 +85,7 @@ public class DebugInfoPool {
|
|||||||
if (hasDebugInfo) {
|
if (hasDebugInfo) {
|
||||||
debugInfoOffsetMap.put(method, 0);
|
debugInfoOffsetMap.put(method, 0);
|
||||||
}
|
}
|
||||||
|
return hasDebugInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getOffset(@Nonnull Method method) {
|
public int getOffset(@Nonnull Method method) {
|
||||||
|
@ -67,6 +67,7 @@ public class DexFile {
|
|||||||
@Nonnull final AnnotationSetRefPool annotationSetRefPool = new AnnotationSetRefPool(this);
|
@Nonnull final AnnotationSetRefPool annotationSetRefPool = new AnnotationSetRefPool(this);
|
||||||
@Nonnull final AnnotationDirectoryPool annotationDirectoryPool = new AnnotationDirectoryPool(this);
|
@Nonnull final AnnotationDirectoryPool annotationDirectoryPool = new AnnotationDirectoryPool(this);
|
||||||
@Nonnull final DebugInfoPool debugInfoPool = new DebugInfoPool(this);
|
@Nonnull final DebugInfoPool debugInfoPool = new DebugInfoPool(this);
|
||||||
|
@Nonnull final CodeItemPool codeItemPool = new CodeItemPool(this);
|
||||||
|
|
||||||
@Nonnull private final Set<? extends ClassDef> classes;
|
@Nonnull private final Set<? extends ClassDef> classes;
|
||||||
|
|
||||||
@ -197,10 +198,7 @@ public class DexFile {
|
|||||||
public void internMethods(@Nonnull ClassDef classDef) {
|
public void internMethods(@Nonnull ClassDef classDef) {
|
||||||
for (Method method: classDef.getMethods()) {
|
for (Method method: classDef.getMethods()) {
|
||||||
methodPool.intern(method);
|
methodPool.intern(method);
|
||||||
// TODO: can we have parameter names (in the debug_info_item), without having any other sort of method implementation
|
codeItemPool.intern(method);
|
||||||
|
|
||||||
// this also handles parameter names, which aren't directly tied to the MethodImplementation, even though the debug items are
|
|
||||||
debugInfoPool.intern(method);
|
|
||||||
|
|
||||||
MethodImplementation methodImpl = method.getImplementation();
|
MethodImplementation methodImpl = method.getImplementation();
|
||||||
if (methodImpl != null) {
|
if (methodImpl != null) {
|
||||||
@ -293,6 +291,7 @@ public class DexFile {
|
|||||||
annotationSetRefPool.write(offsetWriter);
|
annotationSetRefPool.write(offsetWriter);
|
||||||
annotationDirectoryPool.write(offsetWriter);
|
annotationDirectoryPool.write(offsetWriter);
|
||||||
debugInfoPool.write(offsetWriter);
|
debugInfoPool.write(offsetWriter);
|
||||||
|
codeItemPool.write(offsetWriter);
|
||||||
} finally {
|
} finally {
|
||||||
indexWriter.close();
|
indexWriter.close();
|
||||||
offsetWriter.close();
|
offsetWriter.close();
|
||||||
|
@ -112,6 +112,11 @@ public class DexWriter extends OutputStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void writeLong(long value) throws IOException {
|
||||||
|
writeInt((int)value);
|
||||||
|
writeInt((int)(value >> 32));
|
||||||
|
}
|
||||||
|
|
||||||
public void writeInt(int value) throws IOException {
|
public void writeInt(int value) throws IOException {
|
||||||
write(value);
|
write(value);
|
||||||
write(value >> 8);
|
write(value >> 8);
|
||||||
@ -142,67 +147,38 @@ public class DexWriter extends OutputStream {
|
|||||||
write(value);
|
write(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeUleb128(int value) throws IOException {
|
public static void writeUleb128(OutputStream out, int value) throws IOException {
|
||||||
while (value > 0x7f) {
|
while (value > 0x7f) {
|
||||||
write((value & 0x7f) | 0x80);
|
out.write((value & 0x7f) | 0x80);
|
||||||
value >>>= 7;
|
value >>>= 7;
|
||||||
}
|
}
|
||||||
write(value);
|
out.write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeUleb128(int value) throws IOException {
|
||||||
|
writeUleb128(this, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeSleb128(OutputStream out, int value) throws IOException {
|
||||||
|
if (value >= 0) {
|
||||||
|
while (value > 0x3f) {
|
||||||
|
out.write((value & 0x7f) | 0x80);
|
||||||
|
value >>>= 7;
|
||||||
|
}
|
||||||
|
out.write(value & 0x7f);
|
||||||
|
} else {
|
||||||
|
while (value < -0x40) {
|
||||||
|
out.write((value & 0x7f) | 0x80);
|
||||||
|
value >>= 7;
|
||||||
|
}
|
||||||
|
out.write(value & 0x7f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeSleb128(int value) throws IOException {
|
public void writeSleb128(int value) throws IOException {
|
||||||
if (value >= 0) {
|
writeSleb128(this, value);
|
||||||
while (value > 0x3f) {
|
|
||||||
write((value & 0x7f) | 0x80);
|
|
||||||
value >>>= 7;
|
|
||||||
}
|
|
||||||
write(value & 0x7f);
|
|
||||||
} else {
|
|
||||||
while (value < -0x40) {
|
|
||||||
write((value & 0x7f) | 0x80);
|
|
||||||
value >>= 7;
|
|
||||||
}
|
|
||||||
write(value & 0x7f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* public static byte[] encodeSignedIntegralValue(long value) {
|
|
||||||
int requiredBytes = getRequiredBytesForSignedIntegralValue(value);
|
|
||||||
|
|
||||||
byte[] bytes = new byte[requiredBytes];
|
|
||||||
|
|
||||||
for (int i = 0; i < requiredBytes; i++) {
|
|
||||||
bytes[i] = (byte) value;
|
|
||||||
value >>= 8;
|
|
||||||
}
|
|
||||||
return bytes;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
public static long decodeUnsignedIntegralValue(byte[] bytes) {
|
|
||||||
long value = 0;
|
|
||||||
for (int i = 0; i < bytes.length; i++) {
|
|
||||||
value |= (((long)(bytes[i] & 0xFF)) << i * 8);
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
public static byte[] encodeUnsignedIntegralValue(long value) {
|
|
||||||
int requiredBytes = getRequiredBytesForUnsignedIntegralValue(value);
|
|
||||||
|
|
||||||
byte[] bytes = new byte[requiredBytes];
|
|
||||||
|
|
||||||
for (int i = 0; i < requiredBytes; i++) {
|
|
||||||
bytes[i] = (byte) value;
|
|
||||||
value >>= 8;
|
|
||||||
}
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void writeEncodedValueHeader(int valueType, int valueArg) throws IOException {
|
public void writeEncodedValueHeader(int valueType, int valueArg) throws IOException {
|
||||||
write(valueType | (valueArg << 5));
|
write(valueType | (valueArg << 5));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user