001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 * 017 */ 018package org.apache.commons.compress.archivers.zip; 019 020import java.io.Serializable; 021import java.math.BigInteger; 022 023import static org.apache.commons.compress.archivers.zip.ZipConstants.BYTE_MASK; 024 025/** 026 * Utility class that represents an eight byte integer with conversion 027 * rules for the little endian byte order of ZIP files. 028 * @Immutable 029 * 030 * @since 1.2 031 */ 032public final class ZipEightByteInteger implements Serializable { 033 private static final long serialVersionUID = 1L; 034 035 private static final int BYTE_1 = 1; 036 private static final int BYTE_1_MASK = 0xFF00; 037 private static final int BYTE_1_SHIFT = 8; 038 039 private static final int BYTE_2 = 2; 040 private static final int BYTE_2_MASK = 0xFF0000; 041 private static final int BYTE_2_SHIFT = 16; 042 043 private static final int BYTE_3 = 3; 044 private static final long BYTE_3_MASK = 0xFF000000L; 045 private static final int BYTE_3_SHIFT = 24; 046 047 private static final int BYTE_4 = 4; 048 private static final long BYTE_4_MASK = 0xFF00000000L; 049 private static final int BYTE_4_SHIFT = 32; 050 051 private static final int BYTE_5 = 5; 052 private static final long BYTE_5_MASK = 0xFF0000000000L; 053 private static final int BYTE_5_SHIFT = 40; 054 055 private static final int BYTE_6 = 6; 056 private static final long BYTE_6_MASK = 0xFF000000000000L; 057 private static final int BYTE_6_SHIFT = 48; 058 059 private static final int BYTE_7 = 7; 060 private static final long BYTE_7_MASK = 0x7F00000000000000L; 061 private static final int BYTE_7_SHIFT = 56; 062 063 private static final int LEFTMOST_BIT_SHIFT = 63; 064 private static final byte LEFTMOST_BIT = (byte) 0x80; 065 066 private final BigInteger value; 067 068 public static final ZipEightByteInteger ZERO = new ZipEightByteInteger(0); 069 070 /** 071 * Create instance from a number. 072 * @param value the long to store as a ZipEightByteInteger 073 */ 074 public ZipEightByteInteger(final long value) { 075 this(BigInteger.valueOf(value)); 076 } 077 078 /** 079 * Create instance from a number. 080 * @param value the BigInteger to store as a ZipEightByteInteger 081 */ 082 public ZipEightByteInteger(final BigInteger value) { 083 this.value = value; 084 } 085 086 /** 087 * Create instance from bytes. 088 * @param bytes the bytes to store as a ZipEightByteInteger 089 */ 090 public ZipEightByteInteger (final byte[] bytes) { 091 this(bytes, 0); 092 } 093 094 /** 095 * Create instance from the eight bytes starting at offset. 096 * @param bytes the bytes to store as a ZipEightByteInteger 097 * @param offset the offset to start 098 */ 099 public ZipEightByteInteger (final byte[] bytes, final int offset) { 100 value = ZipEightByteInteger.getValue(bytes, offset); 101 } 102 103 /** 104 * Get value as eight bytes in big endian byte order. 105 * @return value as eight bytes in big endian order 106 */ 107 public byte[] getBytes() { 108 return ZipEightByteInteger.getBytes(value); 109 } 110 111 /** 112 * Get value as Java long. 113 * @return value as a long 114 */ 115 public long getLongValue() { 116 return value.longValue(); 117 } 118 119 /** 120 * Get value as Java long. 121 * @return value as a long 122 */ 123 public BigInteger getValue() { 124 return value; 125 } 126 127 /** 128 * Get value as eight bytes in big endian byte order. 129 * @param value the value to convert 130 * @return value as eight bytes in big endian byte order 131 */ 132 public static byte[] getBytes(final long value) { 133 return getBytes(BigInteger.valueOf(value)); 134 } 135 136 /** 137 * Get value as eight bytes in big endian byte order. 138 * @param value the value to convert 139 * @return value as eight bytes in big endian byte order 140 */ 141 public static byte[] getBytes(final BigInteger value) { 142 final byte[] result = new byte[8]; 143 final long val = value.longValue(); 144 result[0] = (byte) ((val & BYTE_MASK)); 145 result[BYTE_1] = (byte) ((val & BYTE_1_MASK) >> BYTE_1_SHIFT); 146 result[BYTE_2] = (byte) ((val & BYTE_2_MASK) >> BYTE_2_SHIFT); 147 result[BYTE_3] = (byte) ((val & BYTE_3_MASK) >> BYTE_3_SHIFT); 148 result[BYTE_4] = (byte) ((val & BYTE_4_MASK) >> BYTE_4_SHIFT); 149 result[BYTE_5] = (byte) ((val & BYTE_5_MASK) >> BYTE_5_SHIFT); 150 result[BYTE_6] = (byte) ((val & BYTE_6_MASK) >> BYTE_6_SHIFT); 151 result[BYTE_7] = (byte) ((val & BYTE_7_MASK) >> BYTE_7_SHIFT); 152 if (value.testBit(LEFTMOST_BIT_SHIFT)) { 153 result[BYTE_7] |= LEFTMOST_BIT; 154 } 155 return result; 156 } 157 158 /** 159 * Helper method to get the value as a Java long from eight bytes 160 * starting at given array offset 161 * @param bytes the array of bytes 162 * @param offset the offset to start 163 * @return the corresponding Java long value 164 */ 165 public static long getLongValue(final byte[] bytes, final int offset) { 166 return getValue(bytes, offset).longValue(); 167 } 168 169 /** 170 * Helper method to get the value as a Java BigInteger from eight 171 * bytes starting at given array offset 172 * @param bytes the array of bytes 173 * @param offset the offset to start 174 * @return the corresponding Java BigInteger value 175 */ 176 public static BigInteger getValue(final byte[] bytes, final int offset) { 177 long value = ((long) bytes[offset + BYTE_7] << BYTE_7_SHIFT) & BYTE_7_MASK; 178 value += ((long) bytes[offset + BYTE_6] << BYTE_6_SHIFT) & BYTE_6_MASK; 179 value += ((long) bytes[offset + BYTE_5] << BYTE_5_SHIFT) & BYTE_5_MASK; 180 value += ((long) bytes[offset + BYTE_4] << BYTE_4_SHIFT) & BYTE_4_MASK; 181 value += ((long) bytes[offset + BYTE_3] << BYTE_3_SHIFT) & BYTE_3_MASK; 182 value += ((long) bytes[offset + BYTE_2] << BYTE_2_SHIFT) & BYTE_2_MASK; 183 value += ((long) bytes[offset + BYTE_1] << BYTE_1_SHIFT) & BYTE_1_MASK; 184 value += ((long) bytes[offset] & BYTE_MASK); 185 final BigInteger val = BigInteger.valueOf(value); 186 return (bytes[offset + BYTE_7] & LEFTMOST_BIT) == LEFTMOST_BIT 187 ? val.setBit(LEFTMOST_BIT_SHIFT) : val; 188 } 189 190 /** 191 * Helper method to get the value as a Java long from an eight-byte array 192 * @param bytes the array of bytes 193 * @return the corresponding Java long value 194 */ 195 public static long getLongValue(final byte[] bytes) { 196 return getLongValue(bytes, 0); 197 } 198 199 /** 200 * Helper method to get the value as a Java long from an eight-byte array 201 * @param bytes the array of bytes 202 * @return the corresponding Java BigInteger value 203 */ 204 public static BigInteger getValue(final byte[] bytes) { 205 return getValue(bytes, 0); 206 } 207 208 /** 209 * Override to make two instances with same value equal. 210 * @param o an object to compare 211 * @return true if the objects are equal 212 */ 213 @Override 214 public boolean equals(final Object o) { 215 if (o == null || !(o instanceof ZipEightByteInteger)) { 216 return false; 217 } 218 return value.equals(((ZipEightByteInteger) o).getValue()); 219 } 220 221 /** 222 * Override to make two instances with same value equal. 223 * @return the hashCode of the value stored in the ZipEightByteInteger 224 */ 225 @Override 226 public int hashCode() { 227 return value.hashCode(); 228 } 229 230 @Override 231 public String toString() { 232 return "ZipEightByteInteger value: " + value; 233 } 234}