164 * A byte array to be used to construct a {@code UUID}
165 *
166 * @return A {@code UUID} generated from the specified array
167 */
168 public static UUID nameUUIDFromBytes(byte[] name) {
169 MessageDigest md;
170 try {
171 md = MessageDigest.getInstance("MD5");
172 } catch (NoSuchAlgorithmException nsae) {
173 throw new InternalError("MD5 not supported", nsae);
174 }
175 byte[] md5Bytes = md.digest(name);
176 md5Bytes[6] &= 0x0f; /* clear version */
177 md5Bytes[6] |= 0x30; /* set to version 3 */
178 md5Bytes[8] &= 0x3f; /* clear variant */
179 md5Bytes[8] |= 0x80; /* set to IETF variant */
180 return new UUID(md5Bytes);
181 }
182
183 /**
184 * Creates a {@code UUID} from the string standard representation as
185 * described in the {@link #toString} method.
186 *
187 * @param name
188 * A string that specifies a {@code UUID}
189 *
190 * @return A {@code UUID} with the specified value
191 *
192 * @throws IllegalArgumentException
193 * If name does not conform to the string representation as
194 * described in {@link #toString}
195 *
196 */
197 public static UUID fromString(String name) {
198 int len = name.length();
199 if (len > 36) {
200 throw new IllegalArgumentException("UUID string too large");
201 }
202
203 int dash1 = name.indexOf('-', 0);
204 int dash2 = name.indexOf('-', dash1 + 1);
205 int dash3 = name.indexOf('-', dash2 + 1);
206 int dash4 = name.indexOf('-', dash3 + 1);
207 int dash5 = name.indexOf('-', dash4 + 1);
208
209 // For any valid input, dash1 through dash4 will be positive and dash5
210 // negative, but it's enough to check dash4 and dash5:
211 // - if dash1 is -1, dash4 will be -1
212 // - if dash1 is positive but dash2 is -1, dash4 will be -1
213 // - if dash1 and dash2 is positive, dash3 will be -1, dash4 will be
214 // positive, but so will dash5
215 if (dash4 < 0 || dash5 >= 0) {
216 throw new IllegalArgumentException("Invalid UUID string: " + name);
217 }
|
164 * A byte array to be used to construct a {@code UUID}
165 *
166 * @return A {@code UUID} generated from the specified array
167 */
168 public static UUID nameUUIDFromBytes(byte[] name) {
169 MessageDigest md;
170 try {
171 md = MessageDigest.getInstance("MD5");
172 } catch (NoSuchAlgorithmException nsae) {
173 throw new InternalError("MD5 not supported", nsae);
174 }
175 byte[] md5Bytes = md.digest(name);
176 md5Bytes[6] &= 0x0f; /* clear version */
177 md5Bytes[6] |= 0x30; /* set to version 3 */
178 md5Bytes[8] &= 0x3f; /* clear variant */
179 md5Bytes[8] |= 0x80; /* set to IETF variant */
180 return new UUID(md5Bytes);
181 }
182
183 /**
184 * Used by {@code fromString}. While {@code Character.digit(ch, 16)}
185 * could be used to the same effect, benchmarks show specializing
186 * for ASCII hex is still a small but significant gain. We should
187 * examine if {@code Character.digit(ch, 16)} can be optimized and
188 * this code replaced without adding any overhead.
189 */
190 private static final byte[] NIBBLES = new byte[256];
191
192 static {
193 byte[] ns = NIBBLES;
194 java.util.Arrays.fill(ns, (byte) -1);
195 ns['0'] = 0;
196 ns['1'] = 1;
197 ns['2'] = 2;
198 ns['3'] = 3;
199 ns['4'] = 4;
200 ns['5'] = 5;
201 ns['6'] = 6;
202 ns['7'] = 7;
203 ns['8'] = 8;
204 ns['9'] = 9;
205 ns['A'] = 10;
206 ns['B'] = 11;
207 ns['C'] = 12;
208 ns['D'] = 13;
209 ns['E'] = 14;
210 ns['F'] = 15;
211 ns['a'] = 10;
212 ns['b'] = 11;
213 ns['c'] = 12;
214 ns['d'] = 13;
215 ns['e'] = 14;
216 ns['f'] = 15;
217 }
218
219 /**
220 * Creates a {@code UUID} from the string standard representation as
221 * described in the {@link #toString} method.
222 *
223 * @param name
224 * A string that specifies a {@code UUID}
225 *
226 * @return A {@code UUID} with the specified value
227 *
228 * @throws IllegalArgumentException
229 * If name does not conform to the string representation as
230 * described in {@link #toString}
231 *
232 */
233 public static UUID fromString(String name) {
234 if (name.length() == 36) {
235 long ch1 = name.charAt(8);
236 long ch2 = name.charAt(13);
237 long ch3 = name.charAt(18);
238 long ch4 = name.charAt(23);
239 if ((ch1 << 48 | ch2 << 32 | ch3 << 16 | ch4) == 0x2d002d002d002dL) {
240 long msb1 = parse4Nibbles(name, 0);
241 long msb2 = parse4Nibbles(name, 4);
242 long msb3 = parse4Nibbles(name, 9);
243 long msb4 = parse4Nibbles(name, 14);
244 long lsb1 = parse4Nibbles(name, 19);
245 long lsb2 = parse4Nibbles(name, 24);
246 long lsb3 = parse4Nibbles(name, 28);
247 long lsb4 = parse4Nibbles(name, 32);
248 if ((msb1 | msb2 | msb3 | msb4 | lsb1 | lsb2 | lsb3 | lsb4) >= 0) {
249 return new UUID(msb1 << 48 | msb2 << 32 | msb3 << 16 | msb4,
250 lsb1 << 48 | lsb2 << 32 | lsb3 << 16 | lsb4);
251 }
252 }
253 }
254 return fromString1(name);
255 }
256
257 private static long parse4Nibbles(String name, int pos) {
258 byte[] ns = NIBBLES;
259 char ch1 = name.charAt(pos);
260 char ch2 = name.charAt(pos + 1);
261 char ch3 = name.charAt(pos + 2);
262 char ch4 = name.charAt(pos + 3);
263 return (ch1 | ch2 | ch3 | ch4) > 0xff ?
264 -1 : ns[ch1] << 12 | ns[ch2] << 8 | ns[ch3] << 4 | ns[ch4];
265 }
266
267 private static UUID fromString1(String name) {
268 int len = name.length();
269 if (len > 36) {
270 throw new IllegalArgumentException("UUID string too large");
271 }
272
273 int dash1 = name.indexOf('-', 0);
274 int dash2 = name.indexOf('-', dash1 + 1);
275 int dash3 = name.indexOf('-', dash2 + 1);
276 int dash4 = name.indexOf('-', dash3 + 1);
277 int dash5 = name.indexOf('-', dash4 + 1);
278
279 // For any valid input, dash1 through dash4 will be positive and dash5
280 // negative, but it's enough to check dash4 and dash5:
281 // - if dash1 is -1, dash4 will be -1
282 // - if dash1 is positive but dash2 is -1, dash4 will be -1
283 // - if dash1 and dash2 is positive, dash3 will be -1, dash4 will be
284 // positive, but so will dash5
285 if (dash4 < 0 || dash5 >= 0) {
286 throw new IllegalArgumentException("Invalid UUID string: " + name);
287 }
|