View Javadoc
1   /*
2    * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
3    * Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org> and others
4    *
5    * This program and the accompanying materials are made available under the
6    * terms of the Eclipse Distribution License v. 1.0 which is available at
7    * https://www.eclipse.org/org/documents/edl-v10.php.
8    *
9    * SPDX-License-Identifier: BSD-3-Clause
10   */
11  
12  package org.eclipse.jgit.lib;
13  
14  import java.io.IOException;
15  import java.io.ObjectInputStream;
16  import java.io.ObjectOutputStream;
17  import java.io.Serializable;
18  
19  import org.eclipse.jgit.annotations.Nullable;
20  import org.eclipse.jgit.errors.InvalidObjectIdException;
21  import org.eclipse.jgit.util.NB;
22  import org.eclipse.jgit.util.RawParseUtils;
23  
24  /**
25   * A SHA-1 abstraction.
26   */
27  public class ObjectId extends AnyObjectId implements Serializable {
28  	private static final long serialVersionUID = 1L;
29  
30  	private static final ObjectId ZEROID;
31  
32  	private static final String ZEROID_STR;
33  
34  	static {
35  		ZEROID = new ObjectId(0, 0, 0, 0, 0);
36  		ZEROID_STR = ZEROID.name();
37  	}
38  
39  	/**
40  	 * Get the special all-null ObjectId.
41  	 *
42  	 * @return the all-null ObjectId, often used to stand-in for no object.
43  	 */
44  	public static final ObjectId zeroId() {
45  		return ZEROID;
46  	}
47  
48  	/**
49  	 * Test a string of characters to verify it is a hex format.
50  	 * <p>
51  	 * If true the string can be parsed with {@link #fromString(String)}.
52  	 *
53  	 * @param id
54  	 *            the string to test.
55  	 * @return true if the string can converted into an ObjectId.
56  	 */
57  	public static final boolean isId(@Nullable String id) {
58  		if (id == null) {
59  			return false;
60  		}
61  		if (id.length() != Constants.OBJECT_ID_STRING_LENGTH)
62  			return false;
63  		try {
64  			for (int i = 0; i < Constants.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 an ObjectId 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  	 */
80  	public static final String toString(ObjectId 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 20
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 20
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  	 */
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 	}
122 
123 	/**
124 	 * Convert an ObjectId from raw binary representation.
125 	 *
126 	 * @param bs
127 	 *            the raw byte buffer to read from. At least 20 bytes must be
128 	 *            available within this byte array.
129 	 * @return the converted object id.
130 	 */
131 	public static final ObjectId fromRaw(byte[] bs) {
132 		return fromRaw(bs, 0);
133 	}
134 
135 	/**
136 	 * Convert an ObjectId from raw binary representation.
137 	 *
138 	 * @param bs
139 	 *            the raw byte buffer to read from. At least 20 bytes after p
140 	 *            must be available within this byte array.
141 	 * @param p
142 	 *            position to read the first byte of data from.
143 	 * @return the converted object id.
144 	 */
145 	public static final ObjectId fromRaw(byte[] bs, int p) {
146 		final int a = NB.decodeInt32(bs, p);
147 		final int b = NB.decodeInt32(bs, p + 4);
148 		final int c = NB.decodeInt32(bs, p + 8);
149 		final int d = NB.decodeInt32(bs, p + 12);
150 		final int e = NB.decodeInt32(bs, p + 16);
151 		return new ObjectId(a, b, c, d, e);
152 	}
153 
154 	/**
155 	 * Convert an ObjectId from raw binary representation.
156 	 *
157 	 * @param is
158 	 *            the raw integers buffer to read from. At least 5 integers must
159 	 *            be available within this int array.
160 	 * @return the converted object id.
161 	 */
162 	public static final ObjectId fromRaw(int[] is) {
163 		return fromRaw(is, 0);
164 	}
165 
166 	/**
167 	 * Convert an ObjectId from raw binary representation.
168 	 *
169 	 * @param is
170 	 *            the raw integers buffer to read from. At least 5 integers
171 	 *            after p must be available within this int array.
172 	 * @param p
173 	 *            position to read the first integer of data from.
174 	 * @return the converted object id.
175 	 */
176 	public static final ObjectId fromRaw(int[] is, int p) {
177 		return new ObjectId(is[p], is[p + 1], is[p + 2], is[p + 3], is[p + 4]);
178 	}
179 
180 	/**
181 	 * Convert an ObjectId from hex characters (US-ASCII).
182 	 *
183 	 * @param buf
184 	 *            the US-ASCII buffer to read from. At least 40 bytes after
185 	 *            offset must be available within this byte array.
186 	 * @param offset
187 	 *            position to read the first character from.
188 	 * @return the converted object id.
189 	 */
190 	public static final ObjectId fromString(byte[] buf, int offset) {
191 		return fromHexString(buf, offset);
192 	}
193 
194 	/**
195 	 * Convert an ObjectId from hex characters.
196 	 *
197 	 * @param str
198 	 *            the string to read from. Must be 40 characters long.
199 	 * @return the converted object id.
200 	 */
201 	public static ObjectId fromString(String str) {
202 		if (str.length() != Constants.OBJECT_ID_STRING_LENGTH) {
203 			throw new InvalidObjectIdException(str);
204 		}
205 		return fromHexString(Constants.encodeASCII(str), 0);
206 	}
207 
208 	private static final ObjectId fromHexString(byte[] bs, int p) {
209 		try {
210 			final int a = RawParseUtils.parseHexInt32(bs, p);
211 			final int b = RawParseUtils.parseHexInt32(bs, p + 8);
212 			final int c = RawParseUtils.parseHexInt32(bs, p + 16);
213 			final int d = RawParseUtils.parseHexInt32(bs, p + 24);
214 			final int e = RawParseUtils.parseHexInt32(bs, p + 32);
215 			return new ObjectId(a, b, c, d, e);
216 		} catch (ArrayIndexOutOfBoundsException e) {
217 			InvalidObjectIdException e1 = new InvalidObjectIdException(bs, p,
218 					Constants.OBJECT_ID_STRING_LENGTH);
219 			e1.initCause(e);
220 			throw e1;
221 		}
222 	}
223 
224 	/**
225 	 * Construct an ObjectId from 160 bits provided in 5 words.
226 	 *
227 	 * @param new_1
228 	 *            an int
229 	 * @param new_2
230 	 *            an int
231 	 * @param new_3
232 	 *            an int
233 	 * @param new_4
234 	 *            an int
235 	 * @param new_5
236 	 *            an int
237 	 * @since 4.7
238 	 */
239 	public ObjectId(int new_1, int new_2, int new_3, int new_4, int new_5) {
240 		w1 = new_1;
241 		w2 = new_2;
242 		w3 = new_3;
243 		w4 = new_4;
244 		w5 = new_5;
245 	}
246 
247 	/**
248 	 * Initialize this instance by copying another existing ObjectId.
249 	 * <p>
250 	 * This constructor is mostly useful for subclasses who want to extend an
251 	 * ObjectId with more properties, but initialize from an existing ObjectId
252 	 * instance acquired by other means.
253 	 *
254 	 * @param src
255 	 *            another already parsed ObjectId to copy the value out of.
256 	 */
257 	protected ObjectId(AnyObjectId src) {
258 		w1 = src.w1;
259 		w2 = src.w2;
260 		w3 = src.w3;
261 		w4 = src.w4;
262 		w5 = src.w5;
263 	}
264 
265 	/** {@inheritDoc} */
266 	@Override
267 	public ObjectId toObjectId() {
268 		return this;
269 	}
270 
271 	private void writeObject(ObjectOutputStream os) throws IOException {
272 		os.writeInt(w1);
273 		os.writeInt(w2);
274 		os.writeInt(w3);
275 		os.writeInt(w4);
276 		os.writeInt(w5);
277 	}
278 
279 	private void readObject(ObjectInputStream ois) throws IOException {
280 		w1 = ois.readInt();
281 		w2 = ois.readInt();
282 		w3 = ois.readInt();
283 		w4 = ois.readInt();
284 		w5 = ois.readInt();
285 	}
286 }