package com.hapiware.asm.timemachine; import static org.objectweb.asm.Opcodes.DUP; import static org.objectweb.asm.Opcodes.INVOKESPECIAL; import static org.objectweb.asm.Opcodes.INVOKESTATIC; import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; import static org.objectweb.asm.Opcodes.LADD; import static org.objectweb.asm.Opcodes.POP2; import org.objectweb.asm.MethodAdapter; import org.objectweb.asm.MethodVisitor; import com.hapiware.asm.timemachine.TimeMachineAgentDelegate.Milliseconds; /** * TimeMachineAdapter is used to catch all the system time queries and manipulate the result * to effectively get a shift in time. * * @see TimeMachineAgentDelegate * * @author <a href="http://www.hapiware.com" target="_blank">hapi</a> * */ public class TimeMachineAdapter extends MethodAdapter { private final Milliseconds milliseconds; public TimeMachineAdapter(Milliseconds milliseconds, MethodVisitor mv) { super(mv); this.milliseconds = milliseconds; } /** * Catches all the system time queries and manipulates the result either by adding * (or subtracting) time from it or replacing the system time value altogether with * absolute time. */ @Override public void visitMethodInsn( int opcode, String owner, String name, String desc ) { mv.visitMethodInsn(opcode, owner, name, desc); switch(opcode) { case INVOKESPECIAL : if( owner.equals("java/util/Date") && name.equals("<init>") && desc.equals("()V") ) { mv.visitInsn(DUP); if(milliseconds.isRelative()) { mv.visitInsn(DUP); mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/Date", "getTime", "()J"); mv.visitLdcInsn(milliseconds.getTime()); mv.visitInsn(LADD); } else mv.visitLdcInsn(milliseconds.getTime()); mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/Date", "setTime", "(J)V"); } break; case INVOKESTATIC : if( owner.equals("java/lang/System") && name.equals("currentTimeMillis") && desc.equals("()J") ) { if(milliseconds.isRelative()) { mv.visitLdcInsn(milliseconds.getTime()); mv.visitInsn(LADD); } else { mv.visitInsn(POP2); mv.visitLdcInsn(milliseconds.getTime()); } } else if( owner.equals("java/util/Calendar") && name.equals("getInstance") && desc.equals("()Ljava/util/Calendar;") ) { mv.visitInsn(DUP); if(milliseconds.isRelative()) { mv.visitInsn(DUP); mv.visitMethodInsn( INVOKEVIRTUAL, "java/util/Calendar", "getTimeInMillis", "()J" ); mv.visitLdcInsn(milliseconds.getTime()); mv.visitInsn(LADD); } else mv.visitLdcInsn(milliseconds.getTime()); mv.visitMethodInsn( INVOKEVIRTUAL, "java/util/Calendar", "setTimeInMillis", "(J)V" ); } break; } } @Override public void visitMaxs(int maxStack, int maxLocals) { mv.visitMaxs(maxStack + 6, maxLocals); } }