ZipEightByteInteger.java

  1. /*
  2.  *  Licensed to the Apache Software Foundation (ASF) under one or more
  3.  *  contributor license agreements.  See the NOTICE file distributed with
  4.  *  this work for additional information regarding copyright ownership.
  5.  *  The ASF licenses this file to You under the Apache License, Version 2.0
  6.  *  (the "License"); you may not use this file except in compliance with
  7.  *  the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  *  Unless required by applicable law or agreed to in writing, software
  12.  *  distributed under the License is distributed on an "AS IS" BASIS,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  */
  17. package org.apache.commons.compress.archivers.zip;

  18. import static org.apache.commons.compress.archivers.zip.ZipConstants.BYTE_MASK;

  19. import java.io.Serializable;
  20. import java.math.BigInteger;

  21. /**
  22.  * Utility class that represents an eight byte integer with conversion rules for the little-endian byte order of ZIP files.
  23.  *
  24.  * @Immutable
  25.  *
  26.  * @since 1.2
  27.  */
  28. public final class ZipEightByteInteger implements Serializable {
  29.     private static final long serialVersionUID = 1L;

  30.     private static final int BYTE_1 = 1;
  31.     private static final int BYTE_1_MASK = 0xFF00;
  32.     private static final int BYTE_1_SHIFT = 8;

  33.     private static final int BYTE_2 = 2;
  34.     private static final int BYTE_2_MASK = 0xFF0000;
  35.     private static final int BYTE_2_SHIFT = 16;

  36.     private static final int BYTE_3 = 3;
  37.     private static final long BYTE_3_MASK = 0xFF000000L;
  38.     private static final int BYTE_3_SHIFT = 24;

  39.     private static final int BYTE_4 = 4;
  40.     private static final long BYTE_4_MASK = 0xFF00000000L;
  41.     private static final int BYTE_4_SHIFT = 32;

  42.     private static final int BYTE_5 = 5;
  43.     private static final long BYTE_5_MASK = 0xFF0000000000L;
  44.     private static final int BYTE_5_SHIFT = 40;

  45.     private static final int BYTE_6 = 6;
  46.     private static final long BYTE_6_MASK = 0xFF000000000000L;
  47.     private static final int BYTE_6_SHIFT = 48;

  48.     private static final int BYTE_7 = 7;
  49.     private static final long BYTE_7_MASK = 0x7F00000000000000L;
  50.     private static final int BYTE_7_SHIFT = 56;

  51.     private static final int LEFTMOST_BIT_SHIFT = 63;
  52.     private static final byte LEFTMOST_BIT = (byte) 0x80;

  53.     public static final ZipEightByteInteger ZERO = new ZipEightByteInteger(0);

  54.     /**
  55.      * Gets value as eight bytes in big-endian byte order.
  56.      *
  57.      * @param value the value to convert
  58.      * @return value as eight bytes in big-endian byte order
  59.      */
  60.     public static byte[] getBytes(final BigInteger value) {
  61.         final byte[] result = new byte[8];
  62.         final long val = value.longValue();
  63.         result[0] = (byte) (val & BYTE_MASK);
  64.         result[BYTE_1] = (byte) ((val & BYTE_1_MASK) >> BYTE_1_SHIFT);
  65.         result[BYTE_2] = (byte) ((val & BYTE_2_MASK) >> BYTE_2_SHIFT);
  66.         result[BYTE_3] = (byte) ((val & BYTE_3_MASK) >> BYTE_3_SHIFT);
  67.         result[BYTE_4] = (byte) ((val & BYTE_4_MASK) >> BYTE_4_SHIFT);
  68.         result[BYTE_5] = (byte) ((val & BYTE_5_MASK) >> BYTE_5_SHIFT);
  69.         result[BYTE_6] = (byte) ((val & BYTE_6_MASK) >> BYTE_6_SHIFT);
  70.         result[BYTE_7] = (byte) ((val & BYTE_7_MASK) >> BYTE_7_SHIFT);
  71.         if (value.testBit(LEFTMOST_BIT_SHIFT)) {
  72.             result[BYTE_7] |= LEFTMOST_BIT;
  73.         }
  74.         return result;
  75.     }

  76.     /**
  77.      * Gets value as eight bytes in big-endian byte order.
  78.      *
  79.      * @param value the value to convert
  80.      * @return value as eight bytes in big-endian byte order
  81.      */
  82.     public static byte[] getBytes(final long value) {
  83.         return getBytes(BigInteger.valueOf(value));
  84.     }

  85.     /**
  86.      * Helper method to get the value as a Java long from an eight-byte array
  87.      *
  88.      * @param bytes the array of bytes
  89.      * @return the corresponding Java long value
  90.      */
  91.     public static long getLongValue(final byte[] bytes) {
  92.         return getLongValue(bytes, 0);
  93.     }

  94.     /**
  95.      * Helper method to get the value as a Java long from eight bytes starting at given array offset
  96.      *
  97.      * @param bytes  the array of bytes
  98.      * @param offset the offset to start
  99.      * @return the corresponding Java long value
  100.      */
  101.     public static long getLongValue(final byte[] bytes, final int offset) {
  102.         return getValue(bytes, offset).longValue();
  103.     }

  104.     /**
  105.      * Helper method to get the value as a Java long from an eight-byte array
  106.      *
  107.      * @param bytes the array of bytes
  108.      * @return the corresponding Java BigInteger value
  109.      */
  110.     public static BigInteger getValue(final byte[] bytes) {
  111.         return getValue(bytes, 0);
  112.     }

  113.     /**
  114.      * Helper method to get the value as a Java BigInteger from eight bytes starting at given array offset
  115.      *
  116.      * @param bytes  the array of bytes
  117.      * @param offset the offset to start
  118.      * @return the corresponding Java BigInteger value
  119.      */
  120.     public static BigInteger getValue(final byte[] bytes, final int offset) {
  121.         long value = (long) bytes[offset + BYTE_7] << BYTE_7_SHIFT & BYTE_7_MASK;
  122.         value += (long) bytes[offset + BYTE_6] << BYTE_6_SHIFT & BYTE_6_MASK;
  123.         value += (long) bytes[offset + BYTE_5] << BYTE_5_SHIFT & BYTE_5_MASK;
  124.         value += (long) bytes[offset + BYTE_4] << BYTE_4_SHIFT & BYTE_4_MASK;
  125.         value += (long) bytes[offset + BYTE_3] << BYTE_3_SHIFT & BYTE_3_MASK;
  126.         value += (long) bytes[offset + BYTE_2] << BYTE_2_SHIFT & BYTE_2_MASK;
  127.         value += (long) bytes[offset + BYTE_1] << BYTE_1_SHIFT & BYTE_1_MASK;
  128.         value += (long) bytes[offset] & BYTE_MASK;
  129.         final BigInteger val = BigInteger.valueOf(value);
  130.         return (bytes[offset + BYTE_7] & LEFTMOST_BIT) == LEFTMOST_BIT ? val.setBit(LEFTMOST_BIT_SHIFT) : val;
  131.     }

  132.     private final BigInteger value;

  133.     /**
  134.      * Constructs a new instance from a number.
  135.      *
  136.      * @param value the BigInteger to store as a ZipEightByteInteger
  137.      */
  138.     public ZipEightByteInteger(final BigInteger value) {
  139.         this.value = value;
  140.     }

  141.     /**
  142.      * Constructs a new instance from bytes.
  143.      *
  144.      * @param bytes the bytes to store as a ZipEightByteInteger
  145.      */
  146.     public ZipEightByteInteger(final byte[] bytes) {
  147.         this(bytes, 0);
  148.     }

  149.     /**
  150.      * Constructs a new instance from the eight bytes starting at offset.
  151.      *
  152.      * @param bytes  the bytes to store as a ZipEightByteInteger
  153.      * @param offset the offset to start
  154.      */
  155.     public ZipEightByteInteger(final byte[] bytes, final int offset) {
  156.         value = getValue(bytes, offset);
  157.     }

  158.     /**
  159.      * Constructs a new instance from a number.
  160.      *
  161.      * @param value the long to store as a ZipEightByteInteger
  162.      */
  163.     public ZipEightByteInteger(final long value) {
  164.         this(BigInteger.valueOf(value));
  165.     }

  166.     /**
  167.      * Override to make two instances with same value equal.
  168.      *
  169.      * @param o an object to compare
  170.      * @return true if the objects are equal
  171.      */
  172.     @Override
  173.     public boolean equals(final Object o) {
  174.         if (!(o instanceof ZipEightByteInteger)) {
  175.             return false;
  176.         }
  177.         return value.equals(((ZipEightByteInteger) o).getValue());
  178.     }

  179.     /**
  180.      * Gets value as eight bytes in big-endian byte order.
  181.      *
  182.      * @return value as eight bytes in big-endian order
  183.      */
  184.     public byte[] getBytes() {
  185.         return getBytes(value);
  186.     }

  187.     /**
  188.      * Gets value as Java long.
  189.      *
  190.      * @return value as a long
  191.      */
  192.     public long getLongValue() {
  193.         return value.longValue();
  194.     }

  195.     /**
  196.      * Gets value as Java BigInteger.
  197.      *
  198.      * @return value as a BigInteger
  199.      */
  200.     public BigInteger getValue() {
  201.         return value;
  202.     }

  203.     /**
  204.      * Override to make two instances with same value equal.
  205.      *
  206.      * @return the hash code of the value stored in the ZipEightByteInteger
  207.      */
  208.     @Override
  209.     public int hashCode() {
  210.         return value.hashCode();
  211.     }

  212.     @Override
  213.     public String toString() {
  214.         return "ZipEightByteInteger value: " + value;
  215.     }
  216. }