    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one
    003 * or more contributor license agreements.  See the NOTICE file
    004 * distributed with this work for additional information
    005 * regarding copyright ownership.  The ASF licenses this file
    006 * to you under the Apache License, Version 2.0 (the
    007 * "License"); you may not use this file except in compliance
    008 * with the License.  You may obtain a copy of the License at
    009 *
    010 *   https://www.apache.org/licenses/LICENSE-2.0
    011 *
    012 * Unless required by applicable law or agreed to in writing,
    013 * software distributed under the License is distributed on an
    014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    015 * KIND, either express or implied.  See the License for the
    016 * specific language governing permissions and limitations
    017 * under the License.
    018 */
    019package org.apache.commons.compress.harmony.unpack200.bytecode.forms;
    020
    021/**
    022 * This abstract class implements the common code for instructions which have variable lengths. This is currently the *switch instructions and some wide (_w)
    023 * instructions.
    024 */
    025public abstract class VariableInstructionForm extends ByteCodeForm {
    026
    027    /**
    028     * Constructs a new instance with the specified opcode, name, operandType and rewrite.
    029     *
    030     * @param opcode  index corresponding to the opcode's value.
    031     * @param name    String printable name of the opcode.
    032     */
    033    public VariableInstructionForm(final int opcode, final String name) {
    034        super(opcode, name);
    035    }
    036
    037    /**
    038     * This method writes operand directly into the rewrite array at index position specified.
    039     *
    040     * @param operand     value to write
    041     * @param absPosition position in array to write. Note that this is absolute position in the array, so one can overwrite the bytecode if one isn't careful.
    042     * @param rewrite     array to write into
    043     */
    044    public void setRewrite2Bytes(final int operand, final int absPosition, final int[] rewrite) {
    045        if (absPosition < 0) {
    046            throw new Error("Trying to rewrite " + this + " but there is no room for 4 bytes");
    047        }
    048
    049        final int byteCodeRewriteLength = rewrite.length;
    050
    051        if (absPosition + 1 > byteCodeRewriteLength) {
    052            throw new Error("Trying to rewrite " + this + " with an int at position " + absPosition + " but this won't fit in the rewrite array");
    053        }
    054
    055        rewrite[absPosition] = (0xFF00 & operand) >> 8;
    056        rewrite[absPosition + 1] = 0x00FF & operand;
    057    }
    058
    059    /**
    060     * This method writes operand directly into the rewrite array at index position specified.
    061     *
    062     * @param operand     value to write
    063     * @param absPosition position in array to write. Note that this is absolute position in the array, so one can overwrite the bytecode if one isn't careful.
    064     * @param rewrite     array to write into
    065     */
    066    public void setRewrite4Bytes(final int operand, final int absPosition, final int[] rewrite) {
    067        if (absPosition < 0) {
    068            throw new Error("Trying to rewrite " + this + " but there is no room for 4 bytes");
    069        }
    070
    071        final int byteCodeRewriteLength = rewrite.length;
    072
    073        if (absPosition + 3 > byteCodeRewriteLength) {
    074            throw new Error("Trying to rewrite " + this + " with an int at position " + absPosition + " but this won't fit in the rewrite array");
    075        }
    076
    077        rewrite[absPosition] = (0xFF000000 & operand) >> 24;
    078        rewrite[absPosition + 1] = (0x00FF0000 & operand) >> 16;
    079        rewrite[absPosition + 2] = (0x0000FF00 & operand) >> 8;
    080        rewrite[absPosition + 3] = 0x000000FF & operand;
    081    }
    082
    083    /**
    084     * Given an int operand, set the rewrite bytes for the next available operand position and the three immediately following it to a highest-byte, mid-high,
    085     * mid-low, low-byte encoding of the operand.
    086     *
    087     * Note that unlike the ByteCode setOperand* operations, this starts with an actual bytecode rewrite array (rather than a ByteCodeForm prototype rewrite
    088     * array). Also, this method overwrites -1 values in the rewrite array - so if you start with an array that looks like: {100, -1, -1, -1, -1, 200, -1, -1,
    089     * -1, -1} then calling setRewrite4Bytes(0, rewrite) the first time will convert it to: {100, 0, 0, 0, 0, 200, -1, -1, -1, -1} Calling setRewrite4Bytes(0,
    090     * rewrite) a second time will convert it to: {100, 0, 0, 0, 0, 200, 0, 0, 0, 0}
    091     *
    092     * @param operand int to set the rewrite bytes to
    093     * @param rewrite int[] bytes to rewrite
    094     */
    095    public void setRewrite4Bytes(final int operand, final int[] rewrite) {
    096        int firstOperandPosition = -1;
    097
    098        // Find the first -1 in the rewrite array
    099        for (int index = 0; index < rewrite.length - 3; index++) {
    100            if (rewrite[index] == -1 && rewrite[index + 1] == -1 && rewrite[index + 2] == -1 && rewrite[index + 3] == -1) {
    101                firstOperandPosition = index;
    102                break;
    103            }
    104        }
    105        setRewrite4Bytes(operand, firstOperandPosition, rewrite);
    106    }
    107}