Advertisement
Anon5703

Untitled

Jul 28th, 2016
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 5 22.02 KB | None | 0 0
  1. package com.Joedobo27.WUmod;
  2.  
  3. import javassist.ClassPool;
  4. import javassist.CtClass;
  5. import javassist.NotFoundException;
  6. import javassist.bytecode.*;
  7. import org.gotti.wurmunlimited.modloader.classhooks.HookManager;
  8. import org.gotti.wurmunlimited.modloader.interfaces.Initable;
  9. import org.gotti.wurmunlimited.modloader.interfaces.WurmServerMod;
  10.  
  11. import java.util.*;
  12. import java.util.logging.Level;
  13. import java.util.logging.Logger;
  14.  
  15. public class Test implements WurmServerMod, Initable {
  16.  
  17.     private static ClassPool pool;
  18.     private static CtClass ctcItem;
  19.     private static ClassFile cfItem;
  20.     private static ConstPool cpItem;
  21.     private static CodeAttribute moveToItemAttribute;
  22.     private static CodeIterator moveToItemIterator;
  23.     private static MethodInfo moveToItemMInfo;
  24.     private static final Logger logger = Logger.getLogger(Test.class.getName());
  25.     private static final String EMPTY_STRING = "";
  26.     private static final int EMPTY_INT = Integer.MAX_VALUE;
  27.  
  28.     @Override
  29.     public void init() {
  30.         try {
  31.             pool = HookManager.getInstance().getClassPool();
  32.             setJSItem();
  33.             moveItemsIntoBinWithinContainerBytecode();
  34.         }catch (NotFoundException | BadBytecode e){
  35.             logger.log(Level.WARNING, e.getMessage(), e);
  36.         }
  37.     }
  38.  
  39.     private void moveItemsIntoBinWithinContainerBytecode() throws BadBytecode {
  40.  
  41.         //<editor-fold desc="moveToItem() of Item.class changes">
  42.             /*
  43.             Lines 3990 to 4046 in moveToItem of Javap.exe dump.
  44.             Removed-
  45.                 if (target.getTopParent() != target.getWurmId() && !target.isCrate()) {
  46.                     if (mover != null) {
  47.                         final String message = StringUtil.format("The %s needs to be on the ground.", target.getName());
  48.                         mover.getCommunicator().sendNormalServerMessage(message);
  49.                     }
  50.                     return false;
  51.                 }
  52.             */
  53.         //</editor-fold>
  54.         ArrayList<Integer> findPoolResult;
  55.  
  56.         setMoveToItem(cfItem, "(Lcom/wurmonline/server/creatures/Creature;JZ)Z", "moveToItem");
  57.         Bytecode find = new Bytecode(cpItem);
  58.         find.addAload(8);//2
  59.  
  60.         find.addOpcode(Opcode.INVOKEVIRTUAL);
  61.         findPoolResult = findConstantPoolReference(cpItem, "// Method getTopParent:()J");
  62.         find.add(findPoolResult.get(0), findPoolResult.get(1));
  63.  
  64.         find.addAload(8);//2 7
  65.  
  66.         find.addOpcode(Opcode.INVOKEVIRTUAL);
  67.         findPoolResult = findConstantPoolReference(cpItem, "// Method getWurmId:()J");
  68.         find.add(findPoolResult.get(0), findPoolResult.get(1));
  69.  
  70.         find.addOpcode(Opcode.LCMP);//1 11
  71.         find.addOpcode(Opcode.IFEQ); find.add(0,46);//3 14 jump forward 46 lines
  72.         find.addAload(8);//2 16
  73.  
  74.         find.addOpcode(Opcode.INVOKEVIRTUAL);
  75.         findPoolResult = findConstantPoolReference(cpItem, "// Method isCrate:()Z");
  76.         find.add(findPoolResult.get(0), findPoolResult.get(1));
  77.  
  78.         find.addOpcode(Opcode.IFNE); find.add(0,38);//3 22 jump forward 38 lines
  79.         find.addOpcode(Opcode.ALOAD_1);//1 23
  80.         find.addOpcode(Opcode.IFNULL); find.add(0, 32);//3 26 jump forward 20 lines
  81.  
  82.         find.addOpcode(Opcode.LDC_W);
  83.         findPoolResult = findConstantPoolReference(cpItem, "// String The %s needs to be on the ground.");
  84.         find.add(findPoolResult.get(0), findPoolResult.get(1));
  85.  
  86.         find.addOpcode(Opcode.ICONST_1);//1 30
  87.  
  88.         find.addOpcode(Opcode.ANEWARRAY);
  89.         findPoolResult = findConstantPoolReference(cpItem, "// class java/lang/Object");
  90.         find.add(findPoolResult.get(0), findPoolResult.get(1));
  91.  
  92.         find.addOpcode(Opcode.DUP);//1 34
  93.         find.addOpcode(Opcode.ICONST_0);//1 35
  94.         find.addAload(8);//2 37
  95.  
  96.         find.addOpcode(Opcode.INVOKEVIRTUAL);
  97.         findPoolResult = findConstantPoolReference(cpItem, "// Method getName:()Ljava/lang/String;");
  98.         find.add(findPoolResult.get(0), findPoolResult.get(1));
  99.  
  100.         find.addOpcode(Opcode.AASTORE);//1 41
  101.  
  102.         find.addOpcode(Opcode.INVOKESTATIC);
  103.         findPoolResult = findConstantPoolReference(cpItem, "// Method com/wurmonline/server/utils/StringUtil.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;");
  104.         find.add(findPoolResult.get(0), findPoolResult.get(1));
  105.  
  106.         find.addAstore(19);//2 46
  107.         find.addOpcode(Opcode.ALOAD_1);//1 47
  108.  
  109.         find.addOpcode(Opcode.INVOKEVIRTUAL);
  110.         findPoolResult = findConstantPoolReference(cpItem, "// Method com/wurmonline/server/creatures/Creature.getCommunicator:()Lcom/wurmonline/server/creatures/Communicator;");
  111.         find.add(findPoolResult.get(0), findPoolResult.get(1));
  112.  
  113.         find.addAload(19);//2 52
  114.  
  115.         find.addOpcode(Opcode.INVOKEVIRTUAL);
  116.         findPoolResult = findConstantPoolReference(cpItem, "// Method com/wurmonline/server/creatures/Communicator.sendNormalServerMessage:(Ljava/lang/String;)V");
  117.         find.add(findPoolResult.get(0), findPoolResult.get(1));
  118.  
  119.         find.addOpcode(Opcode.ICONST_0);//1 56
  120.         find.addReturn(CtClass.intType);//1 57
  121.  
  122.         Bytecode replace = new Bytecode(cpItem);
  123.         int nopLength = 57;
  124.         for (int i=0;i<nopLength;i++){
  125.             replace.addOpcode(Opcode.NOP);
  126.         }
  127.         findReplaceCodeIterator(moveToItemIterator, find, replace);
  128.  
  129.     }
  130.  
  131.     private void setJSItem() throws NotFoundException {
  132.         ctcItem = pool.get("com.wurmonline.server.items.Item");
  133.         cfItem = ctcItem.getClassFile();
  134.         cpItem = cfItem.getConstPool();
  135.     }
  136.  
  137.     private static void setMoveToItem(ClassFile cf, String desc, String name) {
  138.         if (moveToItemMInfo == null || moveToItemIterator == null || moveToItemAttribute == null) {
  139.             for (List a : new List[]{cf.getMethods()}){
  140.                 for(Object b : a){
  141.                     MethodInfo MInfo = (MethodInfo) b;
  142.                     if (Objects.equals(MInfo.getDescriptor(), desc) && Objects.equals(MInfo.getName(), name)){
  143.                         moveToItemMInfo = MInfo;
  144.                         break;
  145.                     }
  146.                 }
  147.             }
  148.             if (moveToItemMInfo == null){
  149.                 throw new NullPointerException();
  150.             }
  151.             moveToItemAttribute = moveToItemMInfo.getCodeAttribute();
  152.             moveToItemIterator = moveToItemAttribute.iterator();
  153.         }
  154.     }
  155.  
  156.     //*****************************************************************************************
  157.     //*****************************************************************************************
  158.     //*****************************************************************************************
  159.  
  160.     public static void findReplaceCodeIterator(CodeIterator ci, Bytecode find, Bytecode replace) throws BadBytecode {
  161.  
  162.         byte[] findSimpleB = find.get();
  163.         LinkedList<Integer> findSimpleI = new LinkedList<>();
  164.         for (byte aFindSimpleB : findSimpleB) {
  165.             findSimpleI.add(Byte.toUnsignedInt(aFindSimpleB));
  166.         }
  167.         findSimpleB = null; // void out unused.
  168.  
  169.         int index;
  170.         int bitLine;
  171.         int bitLine2;
  172.         int findSize = findSimpleI.size();
  173.         CIStack ciStack = new CIStack(findSize);
  174.  
  175.         ci.begin();
  176.         while (ci.hasNext()) {
  177.             index = ci.next();
  178.             ciStack.indexPush(index);
  179.             switch (ci.lookAhead() - index){
  180.                 case 1:
  181.                     ciStack.stackPush(ci.byteAt(index));
  182.                     break;
  183.                 case 2:
  184.                     bitLine = ci.s16bitAt(index);
  185.                     ciStack.stackPush((bitLine & 0xff00) >>> 8);
  186.                     ciStack.stackPush(bitLine & 0x00ff);
  187.                     break;
  188.                 case 3:
  189.                     bitLine = ci.s32bitAt(index);
  190.                     ciStack.stackPush((bitLine & 0xff000000) >>> 24);
  191.                     ciStack.stackPush((bitLine & 0x00ff0000) >>> 16);
  192.                     ciStack.stackPush((bitLine & 0x0000ff00) >>> 8);
  193.                     // not using the last byte
  194.                     break;
  195.                 case 4:
  196.                     bitLine = ci.s32bitAt(index);
  197.                     ciStack.stackPush((bitLine & 0xff000000) >>> 24);
  198.                     ciStack.stackPush((bitLine & 0x00ff0000) >>> 16);
  199.                     ciStack.stackPush((bitLine & 0x0000ff00) >>> 8);
  200.                     ciStack.stackPush((bitLine & 0x000000ff));
  201.                     break;
  202.                 case 5:
  203.                     bitLine = ci.s32bitAt(index);
  204.                     ciStack.stackPush((bitLine & 0xff000000) >>> 24);
  205.                     ciStack.stackPush((bitLine & 0x00ff0000) >>> 16);
  206.                     ciStack.stackPush((bitLine & 0x0000ff00) >>> 8);
  207.                     ciStack.stackPush((bitLine & 0x000000ff));
  208.                     bitLine2 = ci.byteAt(index + 4);
  209.                     ciStack.stackPush(bitLine2);
  210.                     break;
  211.                 case 6:
  212.                     bitLine = ci.s32bitAt(index);
  213.                     ciStack.stackPush((bitLine & 0xff000000) >>> 24);
  214.                     ciStack.stackPush((bitLine & 0x00ff0000) >>> 16);
  215.                     ciStack.stackPush((bitLine & 0x0000ff00) >>> 8);
  216.                     ciStack.stackPush((bitLine & 0x000000ff));
  217.                     bitLine2 = ci.s16bitAt(index + 4);
  218.                     ciStack.stackPush((bitLine2 & 0xff00) >>> 8);
  219.                     ciStack.stackPush((bitLine2 & 0x00ff));
  220.                     break;
  221.                 case 7:
  222.                     bitLine = ci.s32bitAt(index);
  223.                     ciStack.stackPush((bitLine & 0xff000000) >>> 24);
  224.                     ciStack.stackPush((bitLine & 0x00ff0000) >>> 16);
  225.                     ciStack.stackPush((bitLine & 0x0000ff00) >>> 8);
  226.                     ciStack.stackPush((bitLine & 0x000000ff));
  227.                     bitLine2 = ci.s32bitAt(index + 4);
  228.                     ciStack.stackPush((bitLine2 & 0xff000000) >>> 24);
  229.                     ciStack.stackPush((bitLine2 & 0x00ff0000) >>> 16);
  230.                     ciStack.stackPush((bitLine2 & 0x0000ff00) >>> 8);
  231.                     break;
  232.                 case 8:
  233.                     bitLine = ci.s32bitAt(index);
  234.                     ciStack.stackPush((bitLine & 0xff000000) >>> 24);
  235.                     ciStack.stackPush((bitLine & 0x00ff0000) >>> 16);
  236.                     ciStack.stackPush((bitLine & 0x0000ff00) >>> 8);
  237.                     ciStack.stackPush((bitLine & 0x000000ff));
  238.                     bitLine2 = ci.s32bitAt(index + 4);
  239.                     ciStack.stackPush((bitLine2 & 0xff000000) >>> 24);
  240.                     ciStack.stackPush((bitLine2 & 0x00ff0000) >>> 16);
  241.                     ciStack.stackPush((bitLine2 & 0x0000ff00) >>> 8);
  242.                     ciStack.stackPush((bitLine2 & 0x000000ff));
  243.                     break;
  244.             }
  245.             if (ciStack.getStackSize()<findSize) {
  246.                 continue;
  247.             }
  248.             while (ciStack.getStackSize() > findSize) {
  249.                 int[] removed = ciStack.stackPop();
  250.             }
  251.  
  252.             if (4100 > index && index > 4000 ) {
  253.                 printArrayToHex(ciStack.getStack().toArray(), "ciStack");
  254.                 printArrayToHex(findSimpleI.toArray(), "findSimpleI");
  255.                 logger.log(Level.INFO, "ArrayPos: " + Arrays.toString(ciStack.getListPositions().toArray()));
  256.                 logger.log(Level.INFO, "Indexes: " + Arrays.toString(ciStack.getByteIndexes().toArray()));
  257.                 logger.log(Level.INFO, "stackSize: " + ciStack.getStackSize());
  258.                 logger.log(Level.INFO, "findSize: " + findSize);
  259.             }
  260.  
  261.             if (ciStack.getStackSize() != findSize || !Arrays.equals(ciStack.getStack().toArray(), findSimpleI.toArray())){
  262.                 //logger.log(Level.INFO,"ciQueue: " + ciQueue.toString());
  263.                 continue;
  264.             }
  265.             logger.log(Level.INFO, "Insert index: " + ciStack.getInsertPoint());
  266.  
  267.             // Match found and insert the replace array at index
  268.             ci.write(replace.get(), ciStack.getInsertPoint());
  269.             break;
  270.         }
  271.         logger.log(Level.INFO, "DONE");
  272.     }
  273.  
  274.  
  275.     public static String addConstantPoolReference(ConstPool cp, String javapDesc) {
  276.         String[] splitDesc1;
  277.         String[] splitDesc2;
  278.         //String refType = "";
  279.         //String classInfo = "";
  280.         String name = "";
  281.         String descriptor = "";
  282.         int classConstPoolIndex = Integer.MAX_VALUE;
  283.         int poolIndex = Integer.MAX_VALUE;
  284.  
  285.  
  286.         splitDesc1 = javapDesc.split("[ .:]");
  287.         if (Objects.equals(splitDesc1[1], "String")) {
  288.             splitDesc2 = javapDesc.split("String ");
  289.             splitDesc1 = new String[]{"//", "String", splitDesc2[1]};
  290.         }
  291.  
  292.         if (splitDesc1.length < 3 || splitDesc1.length > 5)
  293.             throw new UnsupportedOperationException();
  294.         if ( (Objects.equals(splitDesc1[1], "Method") || Objects.equals(splitDesc1[1], "Field")) && splitDesc1.length == 3) {
  295.             throw new UnsupportedOperationException();
  296.         }
  297.  
  298.         if ( (Objects.equals(splitDesc1[1], "Method") || Objects.equals(splitDesc1[1], "Field")) && splitDesc1.length == 4) {
  299.             // The class reference is missing. This happens when a field or method is defined in the same class and javap
  300.             // assumes the reader is aware. addFieldrefInfo and addMethodrefInfo need specifics not assumptions.
  301.             try {
  302.                 //classConstPoolIndex = Integer.valueOf(findConstantPoolReference(cp, "// class " + cp.getClassName().replaceAll("\\.", "/")), 16);
  303.             }catch (UnsupportedOperationException e) {
  304.                 classConstPoolIndex = cp.addClassInfo(cp.getClassName().replaceAll("/", "."));
  305.             }
  306.             name = splitDesc1[2];
  307.             name = name.replaceAll("\"", "");
  308.             descriptor = splitDesc1[3];
  309.         }
  310.         if ( (Objects.equals(splitDesc1[1], "Method") || Objects.equals(splitDesc1[1], "Field")) && splitDesc1.length == 5) {
  311.             try {
  312.                 //classConstPoolIndex = Integer.valueOf(findConstantPoolReference(cp, "// class " + splitDesc1[2].replaceAll("\\.", "/")), 16);
  313.             }catch (UnsupportedOperationException e) {
  314.                 classConstPoolIndex = cp.addClassInfo(splitDesc1[2].replaceAll("/", "."));
  315.             }
  316.             name = splitDesc1[3];
  317.             name = name.replaceAll("\"", "");
  318.             descriptor = splitDesc1[4];
  319.         }
  320.         switch (splitDesc1[1]){
  321.             case "Method":
  322.                 poolIndex = cp.addMethodrefInfo(classConstPoolIndex, name, descriptor);
  323.                 break;
  324.             case "Field":
  325.                 poolIndex = cp.addFieldrefInfo(classConstPoolIndex, name, descriptor);
  326.                 break;
  327.             case "class":
  328.                 try {
  329.                     //poolIndex = Integer.valueOf(findConstantPoolReference(cp, "// class " + splitDesc1[2].replaceAll("\\.", "/")), 16);
  330.                 }catch (UnsupportedOperationException e) {
  331.                     poolIndex = cp.addClassInfo(splitDesc1[2].replaceAll("/", "."));
  332.                 }
  333.                 break;
  334.             case "String":
  335.                 poolIndex = cp.addStringInfo(splitDesc1[2]);
  336.         }
  337.         if (Objects.equals(poolIndex, EMPTY_INT))
  338.             throw new UnsupportedOperationException();
  339.  
  340.         return String.format("%04X", poolIndex & 0xffff);
  341.     }
  342.  
  343.     /**
  344.      * This method looks for matches in the constantPool and returns found addresses.
  345.      *
  346.      * @param cp is type ConstPool. This object is for accessing a specific ConstPool.
  347.      * @param javapDesc is a string. This string data is copied directly from javap.exe data dump and represents a description
  348.      *                  of its explanatory value in the constantPool.
  349.      * @return is a string of 4 digits. These 4 numbers(in string form) are the address in the ConstantPool
  350.      */
  351.     public static ArrayList<Integer> findConstantPoolReference(ConstPool cp, String javapDesc) {
  352.         String[] splitDesc1;
  353.         String[] splitDesc2;
  354.         String refClass = "";
  355.         String cpClass;
  356.         String name = "";
  357.         String eqResult;
  358.         String descriptor = "";
  359.         int classConstPoolIndex = Integer.MAX_VALUE;
  360.         int poolIndex = Integer.MAX_VALUE;
  361.         byte[] byteAddress = null;
  362.  
  363.  
  364.         splitDesc1 = javapDesc.split("[ .:]");
  365.         if (Objects.equals(splitDesc1[1], "String")) {
  366.             splitDesc2 = javapDesc.split("String ");
  367.             splitDesc1 = new String[]{"//", "String", splitDesc2[1]};
  368.         }
  369.         if (Objects.equals(splitDesc1[1], "float")) {
  370.             splitDesc2 = javapDesc.split("float ");
  371.             splitDesc1 = new String[]{"//", "float", splitDesc2[1]};
  372.         }
  373.  
  374.         if (splitDesc1.length < 3 || splitDesc1.length > 5)
  375.             throw new UnsupportedOperationException();
  376.         if ( (Objects.equals(splitDesc1[1], "Method") || Objects.equals(splitDesc1[1], "Field")) && splitDesc1.length == 3) {
  377.             throw new UnsupportedOperationException();
  378.         }
  379.  
  380.         if ( (Objects.equals(splitDesc1[1], "Method") || Objects.equals(splitDesc1[1], "Field") || Objects.equals(splitDesc1[1], "InterfaceMethod"))
  381.                 && splitDesc1.length == 4) {
  382.             // The class reference is missing. This happens when a field or method is defined in the same class and javap
  383.             // assumes the reader is aware. ConstPool references still show the class reference even if the lines in methods don't.
  384.             //classConstPoolIndex = cp.addClassInfo(cp.getClassName().replaceAll("/", "."));
  385.             refClass = cp.getClassName();
  386.             refClass = refClass.replace("/", ".");
  387.             name = splitDesc1[2];
  388.             name = name.replaceAll("\"", "");
  389.             descriptor = splitDesc1[3];
  390.         }
  391.         if ( (Objects.equals(splitDesc1[1], "Method") || Objects.equals(splitDesc1[1], "Field") || Objects.equals(splitDesc1[1], "InterfaceMethod"))
  392.                 && splitDesc1.length == 5) {
  393.             //classConstPoolIndex = cp.addClassInfo(splitDesc1[2]);
  394.             refClass = splitDesc1[2];
  395.             refClass = refClass.replace("/", ".");
  396.             name = splitDesc1[3];
  397.             name = name.replaceAll("\"", "");
  398.             descriptor = splitDesc1[4];
  399.         }
  400.         for (int i = 1; i < cp.getSize(); i++) {
  401.             try {
  402.                 switch (splitDesc1[1]) {
  403.                     case "Method":
  404.                         eqResult = cp.eqMember(name, descriptor, i);
  405.                         cpClass = cp.getMethodrefClassName(i);
  406.                         if (eqResult != null && Objects.equals(refClass, cpClass)) {
  407.                             byteAddress = intToByteArray(i);
  408.                         }
  409.                         break;
  410.                     case "String":
  411.                         String cpStr = cp.getStringInfo(i);
  412.                         String refStr = splitDesc1[2];
  413.                         if (cpStr != null && Objects.equals(cpStr, refStr))
  414.                             byteAddress = intToByteArray(i);
  415.                         break;
  416.                     case "Field":
  417.                         eqResult = cp.eqMember(name, descriptor, i);
  418.                         cpClass = cp.getMethodrefClassName(i);
  419.                         if (eqResult != null && Objects.equals(refClass, cpClass))
  420.                             byteAddress = intToByteArray(i);
  421.                         break;
  422.                     case "class":
  423.                         refClass = splitDesc1[2];
  424.                         refClass = refClass.replace("/", ".");
  425.                         cpClass = cp.getClassInfo(i);
  426.                         if (cpClass != null && Objects.equals(cpClass, refClass))
  427.                             byteAddress = intToByteArray(i);
  428.                         break;
  429.                     case "long":
  430.                         long cpLong = cp.getLongInfo(i);
  431.                         long refLong = Long.parseLong(splitDesc1[2].replace("l", ""), 10);
  432.                         if (Objects.equals(cpLong, refLong))
  433.                             byteAddress = intToByteArray(i);
  434.                         break;
  435.                     case "float":
  436.                         float cpFloat = cp.getFloatInfo(i);
  437.                         float refFloat = Float.parseFloat(splitDesc1[2].replace("f", ""));
  438.                         if (Objects.equals(cpFloat, refFloat))
  439.                             byteAddress = intToByteArray(i);
  440.                         break;
  441.                     case "InterfaceMethod":
  442.                         eqResult = cp.eqMember(name, descriptor, i);
  443.                         cpClass = cp.getInterfaceMethodrefClassName(i);
  444.                         if (eqResult != null && Objects.equals(refClass, cpClass))
  445.                             byteAddress = intToByteArray(i);
  446.                         break;
  447.                 }
  448.             } catch (ClassCastException ignored) {
  449.                 // This method does ConstPool information fetching that throws this exception often, ignore it.
  450.             }
  451.             if (byteAddress != null) {
  452.                 break;
  453.             }
  454.         }
  455.         if (byteAddress == null) {
  456.             throw new UnsupportedOperationException();
  457.         }
  458.  
  459.         ArrayList<Integer> toReturn = new ArrayList<>(byteAddress.length);
  460.         for (byte b : byteAddress){
  461.             toReturn.add(Byte.toUnsignedInt(b));
  462.         }
  463.         return toReturn;
  464.     }
  465.  
  466.     public static byte[] intToByteArray(int value) {
  467.         //(byte)(value >>> 24),
  468.         //(byte)(value >>> 16),
  469.         return new byte[] {
  470.                 (byte)(value >>> 8),
  471.                 (byte)value};
  472.     }
  473.  
  474.     public static void printArrayToHex(Object[] obj, String name){
  475.         int length = obj.length;
  476.         int[] c = new int[length];
  477.         for (int i=0;i<length;i++){
  478.             c[i]=(int)obj[i];
  479.         }
  480.         String[] a = new String[length];
  481.         for (int i=0;i<length;i++){
  482.             a[i]=String.format("%02X", c[i] & 0xff);
  483.         }
  484.         logger.log(Level.INFO,name + " : " + Arrays.toString(a));
  485.     }
  486. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement