content: /*
   * Copyright (C) 2011 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.taobao.atlas.dex;
  
  import com.taobao.atlas.dex.util.ByteInput;
  import com.taobao.atlas.dex.util.ByteOutput;
  
  /**
   * Read and write {@code encoded_value} primitives.
   */
  public final class EncodedValueCodec {
      private EncodedValueCodec() {
      }
  
      /**
       * Writes a signed integral to {@code out}.
       */
      public static void writeSignedIntegralValue(ByteOutput out, int type, long value) {
          /*
           * Figure out how many bits are needed to represent the value,
           * including a sign bit: The bit count is subtracted from 65
           * and not 64 to account for the sign bit. The xor operation
           * has the effect of leaving non-negative values alone and
           * unary complementing negative values (so that a leading zero
           * count always returns a useful number for our present
           * purpose).
           */
          int requiredBits = 65 - Long.numberOfLeadingZeros(value ^ (value >> 63));
  
          // Round up the requiredBits to a number of bytes.
          int requiredBytes = (requiredBits + 0x07) >> 3;
  
          /*
           * Write the header byte, which includes the type and
           * requiredBytes - 1.
           */
          out.writeByte(type | ((requiredBytes - 1) << 5));
  
          // Write the value, per se.
          while (requiredBytes > 0) {
              out.writeByte((byte) value);
              value >>= 8;
              requiredBytes--;
          }
      }
  
      /**
       * Writes an unsigned integral to {@code out}.
       */
      public static void writeUnsignedIntegralValue(ByteOutput out, int type, long value) {
          // Figure out how many bits are needed to represent the value.
          int requiredBits = 64 - Long.numberOfLeadingZeros(value);
          if (requiredBits == 0) {
              requiredBits = 1;
          }
  
          // Round up the requiredBits to a number of bytes.
          int requiredBytes = (requiredBits + 0x07) >> 3;
  
          /*
           * Write the header byte, which includes the type and
           * requiredBytes - 1.
           */
          out.writeByte(type | ((requiredBytes - 1) << 5));
  
          // Write the value, per se.
          while (requiredBytes > 0) {
              out.writeByte((byte) value);
              value >>= 8;
              requiredBytes--;
          }
      }
  
      /**
       * Writes a right-zero-extended value to {@code out}.
       */
      public static void writeRightZeroExtendedValue(ByteOutput out, int type, long value) {
          // Figure out how many bits are needed to represent the value.
          int requiredBits = 64 - Long.numberOfTrailingZeros(value);
          if (requiredBits == 0) {
              requiredBits = 1;
          }
  
          // Round up the requiredBits to a number of bytes.
          int requiredBytes = (requiredBits + 0x07) >> 3;
  
          // Scootch the first bits to be written down to the low-order bits.
          value >>= 64 - (requiredBytes * 8);
  
          /*
           * Write the header byte, which includes the type and
           * requiredBytes - 1.
           */
          out.writeByte(type | ((requiredBytes - 1) << 5));
  
          // Write the value, per se.
          while (requiredBytes > 0) {
              out.writeByte((byte) value);
              value >>= 8;
              requiredBytes--;
          }
      }
  
      /**
       * Read a signed integer.
       *
       * @param zwidth byte count minus one
       */
      public static int readSignedInt(ByteInput in, int zwidth) {
          int result = 0;
          for (int i = zwidth; i >= 0; i--) {
              result = (result >>> 8) | ((in.readByte() & 0xff) << 24);
          }
          result >>= (3 - zwidth) * 8;
          return result;
      }
  
      /**
       * Read an unsigned integer.
       *
       * @param zwidth byte count minus one
       * @param fillOnRight true to zero fill on the right; false on the left
       */
      public static int readUnsignedInt(ByteInput in, int zwidth, boolean fillOnRight) {
          int result = 0;
          if (!fillOnRight) {
              for (int i = zwidth; i >= 0; i--) {
                  result = (result >>> 8) | ((in.readByte() & 0xff) << 24);
              }
              result >>>= (3 - zwidth) * 8;
          } else {
              for (int i = zwidth; i >= 0; i--) {
                  result = (result >>> 8) | ((in.readByte() & 0xff) << 24);
              }
          }
          return result;
      }
  
      /**
       * Read a signed long.
       *
       * @param zwidth byte count minus one
       */
      public static long readSignedLong(ByteInput in, int zwidth) {
          long result = 0;
          for (int i = zwidth; i >= 0; i--) {
              result = (result >>> 8) | ((in.readByte() & 0xffL) << 56);
          }
          result >>= (7 - zwidth) * 8;
          return result;
      }
  
      /**
       * Read an unsigned long.
       *
       * @param zwidth byte count minus one
       * @param fillOnRight true to zero fill on the right; false on the left
       */
      public static long readUnsignedLong(ByteInput in, int zwidth, boolean fillOnRight) {
          long result = 0;
          if (!fillOnRight) {
              for (int i = zwidth; i >= 0; i--) {
                  result = (result >>> 8) | ((in.readByte() & 0xffL) << 56);
              }
              result >>>= (7 - zwidth) * 8;
          } else {
              for (int i = zwidth; i >= 0; i--) {
                  result = (result >>> 8) | ((in.readByte() & 0xffL) << 56);
              }
          }
          return result;
      }
  }
  