| /* | |
| * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com> | |
| * Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org> and others | |
| * | |
| * This program and the accompanying materials are made available under the | |
| * terms of the Eclipse Distribution License v. 1.0 which is available at | |
| * https://www.eclipse.org/org/documents/edl-v10.php. | |
| * | |
| * SPDX-License-Identifier: BSD-3-Clause | |
| */ | |
| package org.eclipse.jgit.lib; | |
| import java.io.IOException; | |
| import java.io.ObjectInputStream; | |
| import java.io.ObjectOutputStream; | |
| import java.io.Serializable; | |
| import java.nio.ByteBuffer; | |
| import org.eclipse.jgit.annotations.Nullable; | |
| import org.eclipse.jgit.errors.InvalidObjectIdException; | |
| import org.eclipse.jgit.util.NB; | |
| import org.eclipse.jgit.util.RawParseUtils; | |
| /** | |
| * A SHA-1 abstraction. | |
| */ | |
| public class ObjectId extends AnyObjectId implements Serializable { | |
| private static final long serialVersionUID = 1L; | |
| private static final ObjectId ZEROID; | |
| private static final String ZEROID_STR; | |
| static { | |
| ZEROID = new ObjectId(0, 0, 0, 0, 0); | |
| ZEROID_STR = ZEROID.name(); | |
| } | |
| /** | |
| * Get the special all-null ObjectId. | |
| * | |
| * @return the all-null ObjectId, often used to stand-in for no object. | |
| */ | |
| public static final ObjectId zeroId() { | |
| return ZEROID; | |
| } | |
| /** | |
| * Test a string of characters to verify it is a hex format. | |
| * <p> | |
| * If true the string can be parsed with {@link #fromString(String)}. | |
| * | |
| * @param id | |
| * the string to test. | |
| * @return true if the string can converted into an ObjectId. | |
| */ | |
| public static final boolean isId(@Nullable String id) { | |
| if (id == null) { | |
| return false; | |
| } | |
| if (id.length() != Constants.OBJECT_ID_STRING_LENGTH) | |
| return false; | |
| try { | |
| for (int i = 0; i < Constants.OBJECT_ID_STRING_LENGTH; i++) { | |
| RawParseUtils.parseHexInt4((byte) id.charAt(i)); | |
| } | |
| return true; | |
| } catch (ArrayIndexOutOfBoundsException e) { | |
| return false; | |
| } | |
| } | |
| /** | |
| * Convert an ObjectId into a hex string representation. | |
| * | |
| * @param i | |
| * the id to convert. May be null. | |
| * @return the hex string conversion of this id's content. | |
| */ | |
| public static final String toString(ObjectId i) { | |
| return i != null ? i.name() : ZEROID_STR; | |
| } | |
| /** | |
| * Compare two object identifier byte sequences for equality. | |
| * | |
| * @param firstBuffer | |
| * the first buffer to compare against. Must have at least 20 | |
| * bytes from position fi through the end of the buffer. | |
| * @param fi | |
| * first offset within firstBuffer to begin testing. | |
| * @param secondBuffer | |
| * the second buffer to compare against. Must have at least 20 | |
| * bytes from position si through the end of the buffer. | |
| * @param si | |
| * first offset within secondBuffer to begin testing. | |
| * @return true if the two identifiers are the same. | |
| */ | |
| public static boolean equals(final byte[] firstBuffer, final int fi, | |
| final byte[] secondBuffer, final int si) { | |
| return firstBuffer[fi] == secondBuffer[si] | |
| && firstBuffer[fi + 1] == secondBuffer[si + 1] | |
| && firstBuffer[fi + 2] == secondBuffer[si + 2] | |
| && firstBuffer[fi + 3] == secondBuffer[si + 3] | |
| && firstBuffer[fi + 4] == secondBuffer[si + 4] | |
| && firstBuffer[fi + 5] == secondBuffer[si + 5] | |
| && firstBuffer[fi + 6] == secondBuffer[si + 6] | |
| && firstBuffer[fi + 7] == secondBuffer[si + 7] | |
| && firstBuffer[fi + 8] == secondBuffer[si + 8] | |
| && firstBuffer[fi + 9] == secondBuffer[si + 9] | |
| && firstBuffer[fi + 10] == secondBuffer[si + 10] | |
| && firstBuffer[fi + 11] == secondBuffer[si + 11] | |
| && firstBuffer[fi + 12] == secondBuffer[si + 12] | |
| && firstBuffer[fi + 13] == secondBuffer[si + 13] | |
| && firstBuffer[fi + 14] == secondBuffer[si + 14] | |
| && firstBuffer[fi + 15] == secondBuffer[si + 15] | |
| && firstBuffer[fi + 16] == secondBuffer[si + 16] | |
| && firstBuffer[fi + 17] == secondBuffer[si + 17] | |
| && firstBuffer[fi + 18] == secondBuffer[si + 18] | |
| && firstBuffer[fi + 19] == secondBuffer[si + 19]; | |
| } | |
| /** | |
| * Convert an ObjectId from raw binary representation. | |
| * | |
| * @param bs | |
| * the raw byte buffer to read from. At least 20 bytes must be | |
| * available within this byte array. | |
| * @return the converted object id. | |
| */ | |
| public static final ObjectId fromRaw(byte[] bs) { | |
| return fromRaw(bs, 0); | |
| } | |
| /** | |
| * Convert an ObjectId from raw binary representation. | |
| * | |
| * @param bs | |
| * the raw byte buffer to read from. At least 20 bytes after p | |
| * must be available within this byte array. | |
| * @param p | |
| * position to read the first byte of data from. | |
| * @return the converted object id. | |
| */ | |
| public static final ObjectId fromRaw(byte[] bs, int p) { | |
| final int a = NB.decodeInt32(bs, p); | |
| final int b = NB.decodeInt32(bs, p + 4); | |
| final int c = NB.decodeInt32(bs, p + 8); | |
| final int d = NB.decodeInt32(bs, p + 12); | |
| final int e = NB.decodeInt32(bs, p + 16); | |
| return new ObjectId(a, b, c, d, e); | |
| } | |
| /** | |
| * Convert an ObjectId from raw binary representation | |
| * | |
| * @param bb | |
| * a bytebuffer with the objectid encoded as 5 consecutive ints. | |
| * This is the reverse of {@link ObjectId#copyRawTo(ByteBuffer)} | |
| * | |
| * @return the converted object id. | |
| * | |
| * @since 7.0 | |
| */ | |
| public static final ObjectId fromRaw(ByteBuffer bb) { | |
| return new ObjectId(bb.getInt(), bb.getInt(), bb.getInt(), bb.getInt(), | |
| bb.getInt()); | |
| } | |
| /** | |
| * Convert an ObjectId from raw binary representation. | |
| * | |
| * @param is | |
| * the raw integers buffer to read from. At least 5 integers must | |
| * be available within this int array. | |
| * @return the converted object id. | |
| */ | |
| public static final ObjectId fromRaw(int[] is) { | |
| return fromRaw(is, 0); | |
| } | |
| /** | |
| * Convert an ObjectId from raw binary representation. | |
| * | |
| * @param is | |
| * the raw integers buffer to read from. At least 5 integers | |
| * after p must be available within this int array. | |
| * @param p | |
| * position to read the first integer of data from. | |
| * @return the converted object id. | |
| */ | |
| public static final ObjectId fromRaw(int[] is, int p) { | |
| return new ObjectId(is[p], is[p + 1], is[p + 2], is[p + 3], is[p + 4]); | |
| } | |
| /** | |
| * Convert an ObjectId from hex characters (US-ASCII). | |
| * | |
| * @param buf | |
| * the US-ASCII buffer to read from. At least 40 bytes after | |
| * offset must be available within this byte array. | |
| * @param offset | |
| * position to read the first character from. | |
| * @return the converted object id. | |
| */ | |
| public static final ObjectId fromString(byte[] buf, int offset) { | |
| return fromHexString(buf, offset); | |
| } | |
| /** | |
| * Convert an ObjectId from hex characters. | |
| * | |
| * @param str | |
| * the string to read from. Must be 40 characters long. | |
| * @return the converted object id. | |
| */ | |
| public static ObjectId fromString(String str) { | |
| if (str.length() != Constants.OBJECT_ID_STRING_LENGTH) { | |
| throw new InvalidObjectIdException(str); | |
| } | |
| return fromHexString(Constants.encodeASCII(str), 0); | |
| } | |
| private static final ObjectId fromHexString(byte[] bs, int p) { | |
| try { | |
| final int a = RawParseUtils.parseHexInt32(bs, p); | |
| final int b = RawParseUtils.parseHexInt32(bs, p + 8); | |
| final int c = RawParseUtils.parseHexInt32(bs, p + 16); | |
| final int d = RawParseUtils.parseHexInt32(bs, p + 24); | |
| final int e = RawParseUtils.parseHexInt32(bs, p + 32); | |
| return new ObjectId(a, b, c, d, e); | |
| } catch (ArrayIndexOutOfBoundsException e) { | |
| InvalidObjectIdException e1 = new InvalidObjectIdException(bs, p, | |
| Constants.OBJECT_ID_STRING_LENGTH); | |
| e1.initCause(e); | |
| throw e1; | |
| } | |
| } | |
| /** | |
| * Construct an ObjectId from 160 bits provided in 5 words. | |
| * | |
| * @param new_1 | |
| * an int | |
| * @param new_2 | |
| * an int | |
| * @param new_3 | |
| * an int | |
| * @param new_4 | |
| * an int | |
| * @param new_5 | |
| * an int | |
| * @since 4.7 | |
| */ | |
| public ObjectId(int new_1, int new_2, int new_3, int new_4, int new_5) { | |
| w1 = new_1; | |
| w2 = new_2; | |
| w3 = new_3; | |
| w4 = new_4; | |
| w5 = new_5; | |
| } | |
| /** | |
| * Initialize this instance by copying another existing ObjectId. | |
| * <p> | |
| * This constructor is mostly useful for subclasses who want to extend an | |
| * ObjectId with more properties, but initialize from an existing ObjectId | |
| * instance acquired by other means. | |
| * | |
| * @param src | |
| * another already parsed ObjectId to copy the value out of. | |
| */ | |
| protected ObjectId(AnyObjectId src) { | |
| w1 = src.w1; | |
| w2 = src.w2; | |
| w3 = src.w3; | |
| w4 = src.w4; | |
| w5 = src.w5; | |
| } | |
| @Override | |
| public ObjectId toObjectId() { | |
| return this; | |
| } | |
| private void writeObject(ObjectOutputStream os) throws IOException { | |
| os.writeInt(w1); | |
| os.writeInt(w2); | |
| os.writeInt(w3); | |
| os.writeInt(w4); | |
| os.writeInt(w5); | |
| } | |
| private void readObject(ObjectInputStream ois) throws IOException { | |
| w1 = ois.readInt(); | |
| w2 = ois.readInt(); | |
| w3 = ois.readInt(); | |
| w4 = ois.readInt(); | |
| w5 = ois.readInt(); | |
| } | |
| } |