00001 """\
00002 @file lluuid.py
00003 @brief UUID parser/generator.
00004
00005 $LicenseInfo:firstyear=2004&license=mit$
00006
00007 Copyright (c) 2004-2008, Linden Research, Inc.
00008
00009 Permission is hereby granted, free of charge, to any person obtaining a copy
00010 of this software and associated documentation files (the "Software"), to deal
00011 in the Software without restriction, including without limitation the rights
00012 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00013 copies of the Software, and to permit persons to whom the Software is
00014 furnished to do so, subject to the following conditions:
00015
00016 The above copyright notice and this permission notice shall be included in
00017 all copies or substantial portions of the Software.
00018
00019 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00020 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00021 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00022 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00023 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00024 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00025 THE SOFTWARE.
00026 $/LicenseInfo$
00027 """
00028
00029 import md5, random, socket, string, time, re
00030 import uuid
00031
00032 def _int2binstr(i,l):
00033 s=''
00034 for a in range(l):
00035 s=chr(i&0xFF)+s
00036 i>>=8
00037 return s
00038
00039 def _binstr2int(s):
00040 i = long(0)
00041 for c in s:
00042 i = (i<<8) + ord(c)
00043 return i
00044
00045 class UUID(object):
00046 """
00047 A class which represents a 16 byte integer. Stored as a 16 byte 8
00048 bit character string.
00049
00050 The string version is to be of the form:
00051 AAAAAAAA-AAAA-BBBB-BBBB-BBBBBBCCCCCC (a 128-bit number in hex)
00052 where A=network address, B=timestamp, C=random.
00053 """
00054
00055 NULL_STR = "00000000-0000-0000-0000-000000000000"
00056
00057
00058 hex_wildcard = r"[0-9a-fA-F]"
00059 word = hex_wildcard + r"{4,4}-"
00060 long_word = hex_wildcard + r"{8,8}-"
00061 very_long_word = hex_wildcard + r"{12,12}"
00062 UUID_REGEX_STRING = long_word + word + word + word + very_long_word
00063 uuid_regex = re.compile(UUID_REGEX_STRING)
00064
00065 rand = random.Random()
00066 ip = ''
00067 try:
00068 ip = socket.gethostbyname(socket.gethostname())
00069 except(socket.gaierror):
00070
00071 ip = '10'
00072 for i in range(3):
00073 ip += '.' + str(rand.randrange(1,254))
00074 hexip = ''.join(["%04x" % long(i) for i in ip.split('.')])
00075 lastid = ''
00076
00077 def __init__(self, possible_uuid=None):
00078 """
00079 Initialize to first valid UUID in argument (if a string),
00080 or to null UUID if none found or argument is not supplied.
00081
00082 If the argument is a UUID, the constructed object will be a copy of it.
00083 """
00084 self._bits = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
00085 if possible_uuid is None:
00086 return
00087
00088 if isinstance(possible_uuid, type(self)):
00089 self.set(possible_uuid)
00090 return
00091
00092 uuid_match = UUID.uuid_regex.search(possible_uuid)
00093 if uuid_match:
00094 uuid_string = uuid_match.group()
00095 s = string.replace(uuid_string, '-', '')
00096 self._bits = _int2binstr(string.atol(s[:8],16),4) + \
00097 _int2binstr(string.atol(s[8:16],16),4) + \
00098 _int2binstr(string.atol(s[16:24],16),4) + \
00099 _int2binstr(string.atol(s[24:],16),4)
00100
00101 def __len__(self):
00102 """
00103 Used by the len() builtin.
00104 """
00105 return 36
00106
00107 def __nonzero__(self):
00108 return self._bits != "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
00109
00110 def __str__(self):
00111 uuid_string = self.toString()
00112 return uuid_string
00113
00114 __repr__ = __str__
00115
00116 def __getitem__(self, index):
00117 return str(self)[index]
00118
00119 def __eq__(self, other):
00120 if isinstance(other, (str, unicode)):
00121 return other == str(self)
00122 return self._bits == getattr(other, '_bits', '')
00123
00124 def __ne__(self, other):
00125 return not self.__eq__(other)
00126
00127 def __le__(self, other):
00128 return self._bits <= other._bits
00129
00130 def __ge__(self, other):
00131 return self._bits >= other._bits
00132
00133 def __lt__(self, other):
00134 return self._bits < other._bits
00135
00136 def __gt__(self, other):
00137 return self._bits > other._bits
00138
00139 def __hash__(self):
00140 return hash(self._bits)
00141
00142 def set(self, uuid):
00143 self._bits = uuid._bits
00144
00145 def setFromString(self, uuid_string):
00146 """
00147 Given a string version of a uuid, set self bits
00148 appropriately. Returns self.
00149 """
00150 s = string.replace(uuid_string, '-', '')
00151 self._bits = _int2binstr(string.atol(s[:8],16),4) + \
00152 _int2binstr(string.atol(s[8:16],16),4) + \
00153 _int2binstr(string.atol(s[16:24],16),4) + \
00154 _int2binstr(string.atol(s[24:],16),4)
00155 return self
00156
00157 def setFromMemoryDump(self, gdb_string):
00158 """
00159 We expect to get gdb_string as four hex units. eg:
00160 0x147d54db 0xc34b3f1b 0x714f989b 0x0a892fd2
00161 Which will be translated to:
00162 db547d14-1b3f4bc3-9b984f71-d22f890a
00163 Returns self.
00164 """
00165 s = string.replace(gdb_string, '0x', '')
00166 s = string.replace(s, ' ', '')
00167 t = ''
00168 for i in range(8,40,8):
00169 for j in range(0,8,2):
00170 t = t + s[i-j-2:i-j]
00171 self.setFromString(t)
00172
00173 def toString(self):
00174 """
00175 Return as a string matching the LL standard
00176 AAAAAAAA-AAAA-BBBB-BBBB-BBBBBBCCCCCC (a 128-bit number in hex)
00177 where A=network address, B=timestamp, C=random.
00178 """
00179 return uuid_bits_to_string(self._bits)
00180
00181 def getAsString(self):
00182 """
00183 Return a different string representation of the form
00184 AAAAAAAA-AAAABBBB-BBBBBBBB-BBCCCCCC (a 128-bit number in hex)
00185 where A=network address, B=timestamp, C=random.
00186 """
00187 i1 = _binstr2int(self._bits[0:4])
00188 i2 = _binstr2int(self._bits[4:8])
00189 i3 = _binstr2int(self._bits[8:12])
00190 i4 = _binstr2int(self._bits[12:16])
00191 return '%08lx-%08lx-%08lx-%08lx' % (i1,i2,i3,i4)
00192
00193 def generate(self):
00194 """
00195 Generate a new uuid. This algorithm is slightly different
00196 from c++ implementation for portability reasons.
00197 Returns self.
00198 """
00199 m = md5.new()
00200 m.update(uuid.uuid1().bytes)
00201 self._bits = m.digest()
00202 return self
00203
00204 def isNull(self):
00205 """
00206 Returns 1 if the uuid is null - ie, equal to default uuid.
00207 """
00208 return (self._bits == "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")
00209
00210 def xor(self, rhs):
00211 """
00212 xors self with rhs.
00213 """
00214 v1 = _binstr2int(self._bits[0:4]) ^ _binstr2int(rhs._bits[0:4])
00215 v2 = _binstr2int(self._bits[4:8]) ^ _binstr2int(rhs._bits[4:8])
00216 v3 = _binstr2int(self._bits[8:12]) ^ _binstr2int(rhs._bits[8:12])
00217 v4 = _binstr2int(self._bits[12:16]) ^ _binstr2int(rhs._bits[12:16])
00218 self._bits = _int2binstr(v1,4) + \
00219 _int2binstr(v2,4) + \
00220 _int2binstr(v3,4) + \
00221 _int2binstr(v4,4)
00222
00223
00224
00225 NULL = UUID()
00226
00227 def printTranslatedMemory(four_hex_uints):
00228 """
00229 We expect to get the string as four hex units. eg:
00230 0x147d54db 0xc34b3f1b 0x714f989b 0x0a892fd2
00231 Which will be translated to:
00232 db547d14-1b3f4bc3-9b984f71-d22f890a
00233 """
00234 uuid = UUID()
00235 uuid.setFromMemoryDump(four_hex_uints)
00236 print uuid.toString()
00237
00238 def isUUID(id_str):
00239 """
00240 This function returns:
00241 - 1 if the string passed is a UUID
00242 - 0 is the string passed is not a UUID
00243 - None if it neither of the if's below is satisfied
00244 """
00245 if not id_str or len(id_str) < 5 or len(id_str) > 36:
00246 return 0
00247
00248 if isinstance(id_str, UUID) or UUID.uuid_regex.match(id_str):
00249 return 1
00250
00251 return None
00252
00253 def isPossiblyID(id_str):
00254 """
00255 This function returns 1 if the string passed has some uuid-like
00256 characteristics. Otherwise returns 0.
00257 """
00258
00259 is_uuid = isUUID(id_str)
00260 if is_uuid is not None:
00261 return is_uuid
00262
00263
00264 hex_wildcard = r"[0-9a-fA-F]"
00265 chars = len(id_str)
00266 next = min(chars, 8)
00267 matcher = hex_wildcard+"{"+str(next)+","+str(next)+"}"
00268 chars = chars - next
00269 if chars > 0:
00270 matcher = matcher + "-"
00271 chars = chars - 1
00272 for block in range(3):
00273 next = max(min(chars, 4), 0)
00274 if next:
00275 matcher = matcher + hex_wildcard+"{"+str(next)+","+str(next)+"}"
00276 chars = chars - next
00277 if chars > 0:
00278 matcher = matcher + "-"
00279 chars = chars - 1
00280 if chars > 0:
00281 next = min(chars, 12)
00282 matcher = matcher + hex_wildcard+"{"+str(next)+","+str(next)+"}"
00283
00284 uuid_matcher = re.compile(matcher)
00285 if uuid_matcher.match(id_str):
00286 return 1
00287 return 0
00288
00289 def uuid_bits_to_string(bits):
00290 i1 = _binstr2int(bits[0:4])
00291 i2 = _binstr2int(bits[4:6])
00292 i3 = _binstr2int(bits[6:8])
00293 i4 = _binstr2int(bits[8:10])
00294 i5 = _binstr2int(bits[10:12])
00295 i6 = _binstr2int(bits[12:16])
00296 return '%08lx-%04lx-%04lx-%04lx-%04lx%08lx' % (i1,i2,i3,i4,i5,i6)
00297
00298 def uuid_bits_to_uuid(bits):
00299 return UUID(uuid_bits_to_string(bits))
00300
00301
00302 try:
00303 from mulib import stacked
00304 stacked.NoProducer()
00305 except:
00306
00307 pass
00308 else:
00309 def convertUUID(uuid, req):
00310 req.write(str(uuid))
00311
00312 stacked.add_producer(UUID, convertUUID, "*/*")
00313 stacked.add_producer(UUID, convertUUID, "text/html")