12bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson/*
22bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * Copyright (C) 2011 The Android Open Source Project
32bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson *
42bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
52bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * you may not use this file except in compliance with the License.
62bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * You may obtain a copy of the License at
72bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson *
82bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
92bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson *
102bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * Unless required by applicable law or agreed to in writing, software
112bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
122bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * See the License for the specific language governing permissions and
142bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * limitations under the License.
152bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson */
162bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
172bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonpackage com.android.dex;
182bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
192bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport com.android.dex.util.ByteInput;
202bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport com.android.dex.util.ByteOutput;
212bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
222bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson/**
232bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * Read and write {@code encoded_value} primitives.
242bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson */
252bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonpublic final class EncodedValueCodec {
262bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    private EncodedValueCodec() {
272bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
282bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
292bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    /**
302bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     * Writes a signed integral to {@code out}.
312bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     */
322bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public static void writeSignedIntegralValue(ByteOutput out, int type, long value) {
332bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        /*
342bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         * Figure out how many bits are needed to represent the value,
352bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         * including a sign bit: The bit count is subtracted from 65
362bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         * and not 64 to account for the sign bit. The xor operation
372bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         * has the effect of leaving non-negative values alone and
382bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         * unary complementing negative values (so that a leading zero
392bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         * count always returns a useful number for our present
402bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         * purpose).
412bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         */
422bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        int requiredBits = 65 - Long.numberOfLeadingZeros(value ^ (value >> 63));
432bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
442bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        // Round up the requiredBits to a number of bytes.
452bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        int requiredBytes = (requiredBits + 0x07) >> 3;
462bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
472bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        /*
482bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         * Write the header byte, which includes the type and
492bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         * requiredBytes - 1.
502bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         */
512bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        out.writeByte(type | ((requiredBytes - 1) << 5));
522bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
532bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        // Write the value, per se.
542bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        while (requiredBytes > 0) {
552bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            out.writeByte((byte) value);
562bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            value >>= 8;
572bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            requiredBytes--;
582bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
592bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
602bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
612bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    /**
622bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     * Writes an unsigned integral to {@code out}.
632bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     */
642bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public static void writeUnsignedIntegralValue(ByteOutput out, int type, long value) {
652bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        // Figure out how many bits are needed to represent the value.
662bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        int requiredBits = 64 - Long.numberOfLeadingZeros(value);
672bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        if (requiredBits == 0) {
682bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            requiredBits = 1;
692bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
702bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
712bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        // Round up the requiredBits to a number of bytes.
722bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        int requiredBytes = (requiredBits + 0x07) >> 3;
732bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
742bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        /*
752bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         * Write the header byte, which includes the type and
762bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         * requiredBytes - 1.
772bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         */
782bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        out.writeByte(type | ((requiredBytes - 1) << 5));
792bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
802bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        // Write the value, per se.
812bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        while (requiredBytes > 0) {
822bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            out.writeByte((byte) value);
832bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            value >>= 8;
842bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            requiredBytes--;
852bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
862bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
872bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
882bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    /**
892bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     * Writes a right-zero-extended value to {@code out}.
902bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     */
912bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public static void writeRightZeroExtendedValue(ByteOutput out, int type, long value) {
922bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        // Figure out how many bits are needed to represent the value.
932bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        int requiredBits = 64 - Long.numberOfTrailingZeros(value);
942bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        if (requiredBits == 0) {
952bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            requiredBits = 1;
962bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
972bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
982bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        // Round up the requiredBits to a number of bytes.
992bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        int requiredBytes = (requiredBits + 0x07) >> 3;
1002bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
1012bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        // Scootch the first bits to be written down to the low-order bits.
1022bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        value >>= 64 - (requiredBytes * 8);
1032bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
1042bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        /*
1052bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         * Write the header byte, which includes the type and
1062bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         * requiredBytes - 1.
1072bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         */
1082bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        out.writeByte(type | ((requiredBytes - 1) << 5));
1092bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
1102bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        // Write the value, per se.
1112bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        while (requiredBytes > 0) {
1122bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            out.writeByte((byte) value);
1132bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            value >>= 8;
1142bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            requiredBytes--;
1152bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
1162bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
1172bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
1182bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    /**
1192bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     * Read a signed integer.
1202bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     *
1212bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     * @param zwidth byte count minus one
1222bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     */
1232bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public static int readSignedInt(ByteInput in, int zwidth) {
1242bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        int result = 0;
1252bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        for (int i = zwidth; i >= 0; i--) {
1262bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            result = (result >>> 8) | ((in.readByte() & 0xff) << 24);
1272bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
1282bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        result >>= (3 - zwidth) * 8;
1292bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return result;
1302bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
1312bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
1322bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    /**
1332bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     * Read an unsigned integer.
1342bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     *
1352bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     * @param zwidth byte count minus one
1362bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     * @param fillOnRight true to zero fill on the right; false on the left
1372bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     */
1382bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public static int readUnsignedInt(ByteInput in, int zwidth, boolean fillOnRight) {
1392bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        int result = 0;
1402bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        if (!fillOnRight) {
1412bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            for (int i = zwidth; i >= 0; i--) {
1422bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                result = (result >>> 8) | ((in.readByte() & 0xff) << 24);
1432bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
1442bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            result >>>= (3 - zwidth) * 8;
1452bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        } else {
1462bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            for (int i = zwidth; i >= 0; i--) {
1472bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                result = (result >>> 8) | ((in.readByte() & 0xff) << 24);
1482bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
1492bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
1502bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return result;
1512bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
1522bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
1532bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    /**
1542bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     * Read a signed long.
1552bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     *
1562bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     * @param zwidth byte count minus one
1572bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     */
1582bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public static long readSignedLong(ByteInput in, int zwidth) {
1592bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        long result = 0;
1602bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        for (int i = zwidth; i >= 0; i--) {
1612bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            result = (result >>> 8) | ((in.readByte() & 0xffL) << 56);
1622bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
1632bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        result >>= (7 - zwidth) * 8;
1642bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return result;
1652bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
1662bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
1672bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    /**
1682bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     * Read an unsigned long.
1692bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     *
1702bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     * @param zwidth byte count minus one
1712bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     * @param fillOnRight true to zero fill on the right; false on the left
1722bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     */
1732bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public static long readUnsignedLong(ByteInput in, int zwidth, boolean fillOnRight) {
1742bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        long result = 0;
1752bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        if (!fillOnRight) {
1762bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            for (int i = zwidth; i >= 0; i--) {
1772bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                result = (result >>> 8) | ((in.readByte() & 0xffL) << 56);
1782bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
1792bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            result >>>= (7 - zwidth) * 8;
1802bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        } else {
1812bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            for (int i = zwidth; i >= 0; i--) {
1822bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                result = (result >>> 8) | ((in.readByte() & 0xffL) << 56);
1832bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
1842bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
1852bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return result;
1862bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
1872bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson}
188