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