/* * ==================================================================== * Copyright (c) 2004-2012 TMate Software Ltd. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://svnkit.com/license.html * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * ==================================================================== */ package org.tmatesoft.svn.core.internal.util; import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; import org.tmatesoft.svn.util.SVNLogType; import java.rmi.server.UID; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.Random; /** * @version 1.3 * @author TMate Software Ltd. */ public class SVNUUIDGenerator { private static final int NODE_LENGTH = 6; private static byte[] ourUUIDStateNode = new byte[NODE_LENGTH]; private static long ourUUIDStateSeqNum; private static long ourLastGeneratedTime; private static long ourFudgeFactor; /* * We must be sure we don't use the same time values for generating 'random' * UUIDs */ private static long getCurrentTime() { long currentTime = System.currentTimeMillis(); /* if clock reading changed since last UUID generated... */ if (ourLastGeneratedTime != currentTime) { /* * The clock reading has changed since the last UUID was generated. * Reset the fudge factor. if we are generating them too fast, then * the fudge may need to be reset to something greater than zero. */ if (ourLastGeneratedTime + ourFudgeFactor >= currentTime) { ourFudgeFactor = ourLastGeneratedTime + ourFudgeFactor - currentTime + 1; } else { ourFudgeFactor = 0; } ourLastGeneratedTime = currentTime; } else { /* We generated two really fast. Bump the fudge factor. */ ++ourFudgeFactor; } return currentTime + ourFudgeFactor; } public static String generateUUIDString() throws SVNException { return formatUUID(generateUUID()); } public static synchronized byte[] generateUUID() throws SVNException { if (ourUUIDStateNode[0] == 0) { initState(); } long timestamp = getCurrentTime(); byte[] uuidData = new byte[16]; uuidData[0] = (byte) timestamp; uuidData[1] = (byte) (timestamp >> 8); uuidData[2] = (byte) (timestamp >> 16); uuidData[3] = (byte) (timestamp >> 24); uuidData[4] = (byte) (timestamp >> 32); uuidData[5] = (byte) (timestamp >> 40); uuidData[6] = (byte) (timestamp >> 48); uuidData[7] = (byte) (((timestamp >> 56) & 0x0F) | 0x10); uuidData[8] = (byte) (((ourUUIDStateSeqNum >> 8) & 0x3F) | 0x80); uuidData[9] = (byte) ourUUIDStateSeqNum; System.arraycopy(ourUUIDStateNode, 0, uuidData, 10, NODE_LENGTH); return uuidData; } public static String formatUUID(byte[] uuid) { if (uuid.length < 16) { byte[] tmpBuf = new byte[16]; Arrays.fill(tmpBuf, (byte) 0); System.arraycopy(uuid, 0, tmpBuf, 0, uuid.length); uuid = tmpBuf; } StringBuffer sb = new StringBuffer(); SVNFormatUtil.appendHexNumber(sb, uuid[0]); SVNFormatUtil.appendHexNumber(sb, uuid[1]); SVNFormatUtil.appendHexNumber(sb, uuid[2]); SVNFormatUtil.appendHexNumber(sb, uuid[3]); sb.append('-'); SVNFormatUtil.appendHexNumber(sb, uuid[4]); SVNFormatUtil.appendHexNumber(sb, uuid[5]); sb.append('-'); SVNFormatUtil.appendHexNumber(sb, uuid[6]); SVNFormatUtil.appendHexNumber(sb, uuid[7]); sb.append('-'); SVNFormatUtil.appendHexNumber(sb, uuid[8]); SVNFormatUtil.appendHexNumber(sb, uuid[9]); sb.append('-'); SVNFormatUtil.appendHexNumber(sb, uuid[10]); SVNFormatUtil.appendHexNumber(sb, uuid[11]); SVNFormatUtil.appendHexNumber(sb, uuid[12]); SVNFormatUtil.appendHexNumber(sb, uuid[13]); SVNFormatUtil.appendHexNumber(sb, uuid[14]); SVNFormatUtil.appendHexNumber(sb, uuid[15]); return sb.toString(); } private static void initState() throws SVNException { /* * Offset between UUID formatted times and System.currentTimeMillis() * formatted times. UUID UTC base time is October 15, 1582. * System.currentTimeMillis() base time is January 1, 1970. */ long currentTime = System.currentTimeMillis() * 10 + 0x01B21DD213814000L; Random randomGen = new Random(); randomGen.setSeed(((currentTime >> 32) ^ currentTime) & 0xffffffffL); ourUUIDStateSeqNum = randomGen.nextLong() & 0x0FFFFL; getRandomInfo(ourUUIDStateNode); } private static void getRandomInfo(byte[] node) throws SVNException { UID uid = new UID(); MessageDigest digest = null; try { digest = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "MD5 implementation not found: {0}", e.getLocalizedMessage()); SVNErrorManager.error(err, e, SVNLogType.DEFAULT); } digest.update(uid.toString().getBytes()); byte[] seed = digest.digest(); int numToCopy = node.length < seed.length ? node.length : seed.length; System.arraycopy(seed, 0, node, 0, numToCopy); node[0] |= 0x01; } }