1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.dex;
18
19import com.android.dex.util.ByteInput;
20import com.android.dex.util.ByteOutput;
21
22/**
23 * Read and write {@code encoded_value} primitives.
24 */
25public final class EncodedValueCodec {
26    private EncodedValueCodec() {
27    }
28
29    /**
30     * Writes a signed integral to {@code out}.
31     */
32    public static void writeSignedIntegralValue(ByteOutput out, int type, long value) {
33        /*
34         * Figure out how many bits are needed to represent the value,
35         * including a sign bit: The bit count is subtracted from 65
36         * and not 64 to account for the sign bit. The xor operation
37         * has the effect of leaving non-negative values alone and
38         * unary complementing negative values (so that a leading zero
39         * count always returns a useful number for our present
40         * purpose).
41         */
42        int requiredBits = 65 - Long.numberOfLeadingZeros(value ^ (value >> 63));
43
44        // Round up the requiredBits to a number of bytes.
45        int requiredBytes = (requiredBits + 0x07) >> 3;
46
47        /*
48         * Write the header byte, which includes the type and
49         * requiredBytes - 1.
50         */
51        out.writeByte(type | ((requiredBytes - 1) << 5));
52
53        // Write the value, per se.
54        while (requiredBytes > 0) {
55            out.writeByte((byte) value);
56            value >>= 8;
57            requiredBytes--;
58        }
59    }
60
61    /**
62     * Writes an unsigned integral to {@code out}.
63     */
64    public static void writeUnsignedIntegralValue(ByteOutput out, int type, long value) {
65        // Figure out how many bits are needed to represent the value.
66        int requiredBits = 64 - Long.numberOfLeadingZeros(value);
67        if (requiredBits == 0) {
68            requiredBits = 1;
69        }
70
71        // Round up the requiredBits to a number of bytes.
72        int requiredBytes = (requiredBits + 0x07) >> 3;
73
74        /*
75         * Write the header byte, which includes the type and
76         * requiredBytes - 1.
77         */
78        out.writeByte(type | ((requiredBytes - 1) << 5));
79
80        // Write the value, per se.
81        while (requiredBytes > 0) {
82            out.writeByte((byte) value);
83            value >>= 8;
84            requiredBytes--;
85        }
86    }
87
88    /**
89     * Writes a right-zero-extended value to {@code out}.
90     */
91    public static void writeRightZeroExtendedValue(ByteOutput out, int type, long value) {
92        // Figure out how many bits are needed to represent the value.
93        int requiredBits = 64 - Long.numberOfTrailingZeros(value);
94        if (requiredBits == 0) {
95            requiredBits = 1;
96        }
97
98        // Round up the requiredBits to a number of bytes.
99        int requiredBytes = (requiredBits + 0x07) >> 3;
100
101        // Scootch the first bits to be written down to the low-order bits.
102        value >>= 64 - (requiredBytes * 8);
103
104        /*
105         * Write the header byte, which includes the type and
106         * requiredBytes - 1.
107         */
108        out.writeByte(type | ((requiredBytes - 1) << 5));
109
110        // Write the value, per se.
111        while (requiredBytes > 0) {
112            out.writeByte((byte) value);
113            value >>= 8;
114            requiredBytes--;
115        }
116    }
117
118    /**
119     * Read a signed integer.
120     *
121     * @param zwidth byte count minus one
122     */
123    public static int readSignedInt(ByteInput in, int zwidth) {
124        int result = 0;
125        for (int i = zwidth; i >= 0; i--) {
126            result = (result >>> 8) | ((in.readByte() & 0xff) << 24);
127        }
128        result >>= (3 - zwidth) * 8;
129        return result;
130    }
131
132    /**
133     * Read an unsigned integer.
134     *
135     * @param zwidth byte count minus one
136     * @param fillOnRight true to zero fill on the right; false on the left
137     */
138    public static int readUnsignedInt(ByteInput in, int zwidth, boolean fillOnRight) {
139        int result = 0;
140        if (!fillOnRight) {
141            for (int i = zwidth; i >= 0; i--) {
142                result = (result >>> 8) | ((in.readByte() & 0xff) << 24);
143            }
144            result >>>= (3 - zwidth) * 8;
145        } else {
146            for (int i = zwidth; i >= 0; i--) {
147                result = (result >>> 8) | ((in.readByte() & 0xff) << 24);
148            }
149        }
150        return result;
151    }
152
153    /**
154     * Read a signed long.
155     *
156     * @param zwidth byte count minus one
157     */
158    public static long readSignedLong(ByteInput in, int zwidth) {
159        long result = 0;
160        for (int i = zwidth; i >= 0; i--) {
161            result = (result >>> 8) | ((in.readByte() & 0xffL) << 56);
162        }
163        result >>= (7 - zwidth) * 8;
164        return result;
165    }
166
167    /**
168     * Read an unsigned long.
169     *
170     * @param zwidth byte count minus one
171     * @param fillOnRight true to zero fill on the right; false on the left
172     */
173    public static long readUnsignedLong(ByteInput in, int zwidth, boolean fillOnRight) {
174        long result = 0;
175        if (!fillOnRight) {
176            for (int i = zwidth; i >= 0; i--) {
177                result = (result >>> 8) | ((in.readByte() & 0xffL) << 56);
178            }
179            result >>>= (7 - zwidth) * 8;
180        } else {
181            for (int i = zwidth; i >= 0; i--) {
182                result = (result >>> 8) | ((in.readByte() & 0xffL) << 56);
183            }
184        }
185        return result;
186    }
187}
188