1 /* 2 * Copyright (C) 2015, Matthias Sohn <matthias.sohn@sap.com> and others 3 * 4 * This program and the accompanying materials are made available under the 5 * terms of the Eclipse Distribution License v. 1.0 which is available at 6 * https://www.eclipse.org/org/documents/edl-v10.php. 7 * 8 * SPDX-License-Identifier: BSD-3-Clause 9 */ 10 11 package org.eclipse.jgit.lfs.lib; 12 13 import java.io.IOException; 14 import java.io.ObjectInputStream; 15 import java.io.ObjectOutputStream; 16 import java.io.Serializable; 17 18 import org.eclipse.jgit.lfs.errors.InvalidLongObjectIdException; 19 import org.eclipse.jgit.util.NB; 20 import org.eclipse.jgit.util.RawParseUtils; 21 22 /** 23 * A SHA-256 abstraction. 24 * 25 * Ported to SHA-256 from {@link org.eclipse.jgit.lib.ObjectId} 26 * 27 * @since 4.3 28 */ 29 public class LongObjectId extends AnyLongObjectId implements Serializable { 30 private static final long serialVersionUID = 1L; 31 32 private static final LongObjectId ZEROID; 33 34 private static final String ZEROID_STR; 35 36 static { 37 ZEROID = new LongObjectId(0L, 0L, 0L, 0L); 38 ZEROID_STR = ZEROID.name(); 39 } 40 41 /** 42 * Get the special all-zero LongObjectId. 43 * 44 * @return the all-zero LongObjectId, often used to stand-in for no object. 45 */ zeroId()46 public static final LongObjectId zeroId() { 47 return ZEROID; 48 } 49 50 /** 51 * Test a string of characters to verify that it can be interpreted as 52 * LongObjectId. 53 * <p> 54 * If true the string can be parsed with {@link #fromString(String)}. 55 * 56 * @param id 57 * the string to test. 58 * @return true if the string can converted into an LongObjectId. 59 */ isId(String id)60 public static final boolean isId(String id) { 61 if (id.length() != Constants.LONG_OBJECT_ID_STRING_LENGTH) 62 return false; 63 try { 64 for (int i = 0; i < Constants.LONG_OBJECT_ID_STRING_LENGTH; i++) { 65 RawParseUtils.parseHexInt4((byte) id.charAt(i)); 66 } 67 return true; 68 } catch (ArrayIndexOutOfBoundsException e) { 69 return false; 70 } 71 } 72 73 /** 74 * Convert a LongObjectId into a hex string representation. 75 * 76 * @param i 77 * the id to convert. May be null. 78 * @return the hex string conversion of this id's content. 79 */ toString(LongObjectId i)80 public static final String toString(LongObjectId i) { 81 return i != null ? i.name() : ZEROID_STR; 82 } 83 84 /** 85 * Compare two object identifier byte sequences for equality. 86 * 87 * @param firstBuffer 88 * the first buffer to compare against. Must have at least 32 89 * bytes from position fi through the end of the buffer. 90 * @param fi 91 * first offset within firstBuffer to begin testing. 92 * @param secondBuffer 93 * the second buffer to compare against. Must have at least 32 94 * bytes from position si through the end of the buffer. 95 * @param si 96 * first offset within secondBuffer to begin testing. 97 * @return true if the two identifiers are the same. 98 */ equals(final byte[] firstBuffer, final int fi, final byte[] secondBuffer, final int si)99 public static boolean equals(final byte[] firstBuffer, final int fi, 100 final byte[] secondBuffer, final int si) { 101 return firstBuffer[fi] == secondBuffer[si] 102 && firstBuffer[fi + 1] == secondBuffer[si + 1] 103 && firstBuffer[fi + 2] == secondBuffer[si + 2] 104 && firstBuffer[fi + 3] == secondBuffer[si + 3] 105 && firstBuffer[fi + 4] == secondBuffer[si + 4] 106 && firstBuffer[fi + 5] == secondBuffer[si + 5] 107 && firstBuffer[fi + 6] == secondBuffer[si + 6] 108 && firstBuffer[fi + 7] == secondBuffer[si + 7] 109 && firstBuffer[fi + 8] == secondBuffer[si + 8] 110 && firstBuffer[fi + 9] == secondBuffer[si + 9] 111 && firstBuffer[fi + 10] == secondBuffer[si + 10] 112 && firstBuffer[fi + 11] == secondBuffer[si + 11] 113 && firstBuffer[fi + 12] == secondBuffer[si + 12] 114 && firstBuffer[fi + 13] == secondBuffer[si + 13] 115 && firstBuffer[fi + 14] == secondBuffer[si + 14] 116 && firstBuffer[fi + 15] == secondBuffer[si + 15] 117 && firstBuffer[fi + 16] == secondBuffer[si + 16] 118 && firstBuffer[fi + 17] == secondBuffer[si + 17] 119 && firstBuffer[fi + 18] == secondBuffer[si + 18] 120 && firstBuffer[fi + 19] == secondBuffer[si + 19] 121 && firstBuffer[fi + 20] == secondBuffer[si + 20] 122 && firstBuffer[fi + 21] == secondBuffer[si + 21] 123 && firstBuffer[fi + 22] == secondBuffer[si + 22] 124 && firstBuffer[fi + 23] == secondBuffer[si + 23] 125 && firstBuffer[fi + 24] == secondBuffer[si + 24] 126 && firstBuffer[fi + 25] == secondBuffer[si + 25] 127 && firstBuffer[fi + 26] == secondBuffer[si + 26] 128 && firstBuffer[fi + 27] == secondBuffer[si + 27] 129 && firstBuffer[fi + 28] == secondBuffer[si + 28] 130 && firstBuffer[fi + 29] == secondBuffer[si + 29] 131 && firstBuffer[fi + 30] == secondBuffer[si + 30] 132 && firstBuffer[fi + 31] == secondBuffer[si + 31]; 133 } 134 135 /** 136 * Convert a LongObjectId from raw binary representation. 137 * 138 * @param bs 139 * the raw byte buffer to read from. At least 32 bytes must be 140 * available within this byte array. 141 * @return the converted object id. 142 */ fromRaw(byte[] bs)143 public static final LongObjectId fromRaw(byte[] bs) { 144 return fromRaw(bs, 0); 145 } 146 147 /** 148 * Convert a LongObjectId from raw binary representation. 149 * 150 * @param bs 151 * the raw byte buffer to read from. At least 32 bytes after p 152 * must be available within this byte array. 153 * @param p 154 * position to read the first byte of data from. 155 * @return the converted object id. 156 */ fromRaw(byte[] bs, int p)157 public static final LongObjectId fromRaw(byte[] bs, int p) { 158 final long a = NB.decodeInt64(bs, p); 159 final long b = NB.decodeInt64(bs, p + 8); 160 final long c = NB.decodeInt64(bs, p + 16); 161 final long d = NB.decodeInt64(bs, p + 24); 162 return new LongObjectId(a, b, c, d); 163 } 164 165 /** 166 * Convert a LongObjectId from raw binary representation. 167 * 168 * @param is 169 * the raw long buffer to read from. At least 4 longs must be 170 * available within this long array. 171 * @return the converted object id. 172 */ fromRaw(long[] is)173 public static final LongObjectId fromRaw(long[] is) { 174 return fromRaw(is, 0); 175 } 176 177 /** 178 * Convert a LongObjectId from raw binary representation. 179 * 180 * @param is 181 * the raw long buffer to read from. At least 4 longs after p 182 * must be available within this long array. 183 * @param p 184 * position to read the first long of data from. 185 * @return the converted object id. 186 */ fromRaw(long[] is, int p)187 public static final LongObjectId fromRaw(long[] is, int p) { 188 return new LongObjectId(is[p], is[p + 1], is[p + 2], is[p + 3]); 189 } 190 191 /** 192 * Convert a LongObjectId from hex characters (US-ASCII). 193 * 194 * @param buf 195 * the US-ASCII buffer to read from. At least 64 bytes after 196 * offset must be available within this byte array. 197 * @param offset 198 * position to read the first character from. 199 * @return the converted object id. 200 */ fromString(byte[] buf, int offset)201 public static final LongObjectId fromString(byte[] buf, int offset) { 202 return fromHexString(buf, offset); 203 } 204 205 /** 206 * Convert a LongObjectId from hex characters. 207 * 208 * @param str 209 * the string to read from. Must be 64 characters long. 210 * @return the converted object id. 211 */ fromString(String str)212 public static LongObjectId fromString(String str) { 213 if (str.length() != Constants.LONG_OBJECT_ID_STRING_LENGTH) 214 throw new InvalidLongObjectIdException(str); 215 return fromHexString(org.eclipse.jgit.lib.Constants.encodeASCII(str), 216 0); 217 } 218 fromHexString(byte[] bs, int p)219 private static final LongObjectId fromHexString(byte[] bs, int p) { 220 try { 221 final long a = RawParseUtils.parseHexInt64(bs, p); 222 final long b = RawParseUtils.parseHexInt64(bs, p + 16); 223 final long c = RawParseUtils.parseHexInt64(bs, p + 32); 224 final long d = RawParseUtils.parseHexInt64(bs, p + 48); 225 return new LongObjectId(a, b, c, d); 226 } catch (ArrayIndexOutOfBoundsException e) { 227 InvalidLongObjectIdException e1 = new InvalidLongObjectIdException( 228 bs, p, Constants.LONG_OBJECT_ID_STRING_LENGTH); 229 e1.initCause(e); 230 throw e1; 231 } 232 } 233 LongObjectId(final long new_1, final long new_2, final long new_3, final long new_4)234 LongObjectId(final long new_1, final long new_2, final long new_3, 235 final long new_4) { 236 w1 = new_1; 237 w2 = new_2; 238 w3 = new_3; 239 w4 = new_4; 240 } 241 242 /** 243 * Initialize this instance by copying another existing LongObjectId. 244 * <p> 245 * This constructor is mostly useful for subclasses which want to extend a 246 * LongObjectId with more properties, but initialize from an existing 247 * LongObjectId instance acquired by other means. 248 * 249 * @param src 250 * another already parsed LongObjectId to copy the value out of. 251 */ LongObjectId(AnyLongObjectId src)252 protected LongObjectId(AnyLongObjectId src) { 253 w1 = src.w1; 254 w2 = src.w2; 255 w3 = src.w3; 256 w4 = src.w4; 257 } 258 259 /** {@inheritDoc} */ 260 @Override toObjectId()261 public LongObjectId toObjectId() { 262 return this; 263 } 264 writeObject(ObjectOutputStream os)265 private void writeObject(ObjectOutputStream os) throws IOException { 266 os.writeLong(w1); 267 os.writeLong(w2); 268 os.writeLong(w3); 269 os.writeLong(w4); 270 } 271 readObject(ObjectInputStream ois)272 private void readObject(ObjectInputStream ois) throws IOException { 273 w1 = ois.readLong(); 274 w2 = ois.readLong(); 275 w3 = ois.readLong(); 276 w4 = ois.readLong(); 277 } 278 } 279