PageRenderTime 46ms CodeModel.GetById 13ms app.highlight 28ms RepoModel.GetById 1ms app.codeStats 0ms

/mysql_watcher/indra/base/lluuid.py

https://bitbucket.org/lindenlab/apiary/
Python | 319 lines | 310 code | 0 blank | 9 comment | 0 complexity | 9d9bad77d0f95b3fa77e1551a8f39274 MD5 | raw file
  1"""\
  2@file lluuid.py
  3@brief UUID parser/generator.
  4
  5$LicenseInfo:firstyear=2004&license=mit$
  6
  7Copyright (c) 2004-2009, Linden Research, Inc.
  8
  9Permission is hereby granted, free of charge, to any person obtaining a copy
 10of this software and associated documentation files (the "Software"), to deal
 11in the Software without restriction, including without limitation the rights
 12to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 13copies of the Software, and to permit persons to whom the Software is
 14furnished to do so, subject to the following conditions:
 15
 16The above copyright notice and this permission notice shall be included in
 17all copies or substantial portions of the Software.
 18
 19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 20IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 21FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 22AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 23LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 24OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 25THE SOFTWARE.
 26$/LicenseInfo$
 27"""
 28
 29import random, socket, string, time, re
 30import uuid
 31try:
 32    # Python 2.6
 33    from hashlib import md5
 34except ImportError:
 35    # Python 2.5 and earlier
 36    from md5 import new as md5
 37
 38def _int2binstr(i,l):
 39    s=''
 40    for a in range(l):
 41        s=chr(i&0xFF)+s
 42        i>>=8
 43    return s
 44
 45def _binstr2int(s):
 46    i = long(0)
 47    for c in s:
 48        i = (i<<8) + ord(c)
 49    return i
 50
 51class UUID(object):
 52    """
 53    A class which represents a 16 byte integer. Stored as a 16 byte 8
 54    bit character string.
 55
 56    The string version is to be of the form:
 57    AAAAAAAA-AAAA-BBBB-BBBB-BBBBBBCCCCCC  (a 128-bit number in hex)
 58    where A=network address, B=timestamp, C=random.
 59    """
 60
 61    NULL_STR = "00000000-0000-0000-0000-000000000000"
 62
 63    # the UUIDREGEX_STRING is helpful for parsing UUID's in text
 64    hex_wildcard = r"[0-9a-fA-F]"
 65    word = hex_wildcard + r"{4,4}-"
 66    long_word = hex_wildcard + r"{8,8}-"
 67    very_long_word = hex_wildcard + r"{12,12}"
 68    UUID_REGEX_STRING = long_word + word + word + word + very_long_word
 69    uuid_regex = re.compile(UUID_REGEX_STRING)
 70
 71    rand = random.Random()
 72    ip = ''
 73    try:
 74        ip = socket.gethostbyname(socket.gethostname())
 75    except(socket.gaierror):
 76        # no ip address, so just default to somewhere in 10.x.x.x
 77        ip = '10'
 78        for i in range(3):
 79            ip += '.' + str(rand.randrange(1,254))
 80    hexip = ''.join(["%04x" % long(i) for i in ip.split('.')])
 81    lastid = ''
 82
 83    def __init__(self, possible_uuid=None):
 84        """
 85        Initialize to first valid UUID in argument (if a string),
 86        or to null UUID if none found or argument is not supplied.
 87
 88        If the argument is a UUID, the constructed object will be a copy of it.
 89        """
 90        self._bits = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
 91        if possible_uuid is None:
 92            return
 93
 94        if isinstance(possible_uuid, type(self)):
 95            self.set(possible_uuid)
 96            return
 97
 98        uuid_match = UUID.uuid_regex.search(possible_uuid)
 99        if uuid_match:
100            uuid_string = uuid_match.group()
101            s = string.replace(uuid_string, '-', '')
102            self._bits = _int2binstr(string.atol(s[:8],16),4) + \
103                         _int2binstr(string.atol(s[8:16],16),4) + \
104                         _int2binstr(string.atol(s[16:24],16),4) + \
105                         _int2binstr(string.atol(s[24:],16),4) 
106
107    def __len__(self):
108        """
109        Used by the len() builtin.
110        """
111        return 36
112
113    def __nonzero__(self):
114        return self._bits != "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
115
116    def __str__(self):
117        uuid_string = self.toString()
118        return uuid_string
119
120    __repr__ = __str__
121
122    def __getitem__(self, index):
123        return str(self)[index]
124
125    def __eq__(self, other):
126        if isinstance(other, (str, unicode)):
127            return other == str(self)
128        return self._bits == getattr(other, '_bits', '')
129
130    def __ne__(self, other):
131        return not self.__eq__(other)
132
133    def __le__(self, other):
134        return self._bits <= other._bits
135
136    def __ge__(self, other):
137        return self._bits >= other._bits
138
139    def __lt__(self, other):
140        return self._bits < other._bits
141
142    def __gt__(self, other):
143        return self._bits > other._bits
144
145    def __hash__(self):
146        return hash(self._bits)
147
148    def set(self, uuid):
149        self._bits = uuid._bits
150
151    def setFromString(self, uuid_string):
152        """
153        Given a string version of a uuid, set self bits
154        appropriately. Returns self.
155        """
156        s = string.replace(uuid_string, '-', '')
157        self._bits = _int2binstr(string.atol(s[:8],16),4) + \
158                     _int2binstr(string.atol(s[8:16],16),4) + \
159                     _int2binstr(string.atol(s[16:24],16),4) + \
160                     _int2binstr(string.atol(s[24:],16),4) 
161        return self
162
163    def setFromMemoryDump(self, gdb_string):
164        """
165        We expect to get gdb_string as four hex units. eg:
166        0x147d54db		0xc34b3f1b		0x714f989b		0x0a892fd2
167        Which will be translated to:
168        db547d14-1b3f4bc3-9b984f71-d22f890a
169        Returns self.
170        """
171        s = string.replace(gdb_string, '0x', '')
172        s = string.replace(s, ' ', '')
173        t = ''
174        for i in range(8,40,8):
175            for j in range(0,8,2):
176                t = t + s[i-j-2:i-j]
177        self.setFromString(t)
178
179    def toString(self):
180        """
181        Return as a string matching the LL standard
182        AAAAAAAA-AAAA-BBBB-BBBB-BBBBBBCCCCCC  (a 128-bit number in hex)
183        where A=network address, B=timestamp, C=random.
184        """
185        return uuid_bits_to_string(self._bits)
186
187    def getAsString(self):
188        """
189        Return a different string representation of the form
190        AAAAAAAA-AAAABBBB-BBBBBBBB-BBCCCCCC	 (a 128-bit number in hex)
191        where A=network address, B=timestamp, C=random.
192        """
193        i1 = _binstr2int(self._bits[0:4])
194        i2 = _binstr2int(self._bits[4:8])
195        i3 = _binstr2int(self._bits[8:12])
196        i4 = _binstr2int(self._bits[12:16])
197        return '%08lx-%08lx-%08lx-%08lx' % (i1,i2,i3,i4)
198
199    def generate(self):
200        """
201        Generate a new uuid. This algorithm is slightly different
202        from c++ implementation for portability reasons.
203        Returns self.
204        """
205        m = md5()
206        m.update(uuid.uuid1().bytes)
207        self._bits = m.digest()
208        return self
209
210    def isNull(self):
211        """
212        Returns 1 if the uuid is null - ie, equal to default uuid.
213        """
214        return (self._bits == "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")
215
216    def xor(self, rhs):
217        """
218        xors self with rhs.
219        """
220        v1 = _binstr2int(self._bits[0:4]) ^ _binstr2int(rhs._bits[0:4])
221        v2 = _binstr2int(self._bits[4:8]) ^ _binstr2int(rhs._bits[4:8])
222        v3 = _binstr2int(self._bits[8:12]) ^ _binstr2int(rhs._bits[8:12])
223        v4 = _binstr2int(self._bits[12:16]) ^ _binstr2int(rhs._bits[12:16])
224        self._bits = _int2binstr(v1,4) + \
225                     _int2binstr(v2,4) + \
226                     _int2binstr(v3,4) + \
227                     _int2binstr(v4,4) 
228
229
230# module-level null constant
231NULL = UUID()
232
233def printTranslatedMemory(four_hex_uints):
234    """
235    We expect to get the string as four hex units. eg:
236    0x147d54db		0xc34b3f1b		0x714f989b		0x0a892fd2
237    Which will be translated to:
238    db547d14-1b3f4bc3-9b984f71-d22f890a
239    """
240    uuid = UUID()
241    uuid.setFromMemoryDump(four_hex_uints)
242    print uuid.toString()
243
244def isUUID(id_str):
245    """
246    This function returns:
247    - 1 if the string passed is a UUID
248    - 0 is the string passed is not a UUID
249    - None if it neither of the if's below is satisfied
250    """
251    if not id_str or len(id_str) <  5 or len(id_str) > 36:
252        return 0
253
254    if isinstance(id_str, UUID) or UUID.uuid_regex.match(id_str):
255        return 1
256
257    return None
258
259def isPossiblyID(id_str):
260    """
261    This function returns 1 if the string passed has some uuid-like
262    characteristics. Otherwise returns 0.
263    """
264
265    is_uuid = isUUID(id_str)
266    if is_uuid is not None:
267        return is_uuid
268
269    # build a string which matches every character.
270    hex_wildcard = r"[0-9a-fA-F]"
271    chars = len(id_str)
272    next = min(chars, 8)
273    matcher = hex_wildcard+"{"+str(next)+","+str(next)+"}"
274    chars = chars - next
275    if chars > 0:
276        matcher = matcher + "-"
277        chars = chars - 1
278    for block in range(3):
279        next = max(min(chars, 4), 0)
280        if next:
281            matcher = matcher + hex_wildcard+"{"+str(next)+","+str(next)+"}"
282            chars = chars - next
283        if chars > 0:
284            matcher = matcher + "-"
285            chars = chars - 1
286    if chars > 0:
287        next = min(chars, 12)
288        matcher = matcher + hex_wildcard+"{"+str(next)+","+str(next)+"}"
289    #print matcher
290    uuid_matcher = re.compile(matcher)
291    if uuid_matcher.match(id_str):
292        return 1
293    return 0
294
295def uuid_bits_to_string(bits):
296    i1 = _binstr2int(bits[0:4])
297    i2 = _binstr2int(bits[4:6])
298    i3 = _binstr2int(bits[6:8])
299    i4 = _binstr2int(bits[8:10])
300    i5 = _binstr2int(bits[10:12])
301    i6 = _binstr2int(bits[12:16])
302    return '%08lx-%04lx-%04lx-%04lx-%04lx%08lx' % (i1,i2,i3,i4,i5,i6)
303
304def uuid_bits_to_uuid(bits):
305    return UUID(uuid_bits_to_string(bits))
306
307
308try:
309    from mulib import stacked
310    stacked.NoProducer()  # just to exercise stacked
311except:
312    #print "Couldn't import mulib.stacked, not registering UUID converter"
313    pass
314else:
315    def convertUUID(uuid, req):
316        req.write(str(uuid))
317
318    stacked.add_producer(UUID, convertUUID, "*/*")
319    stacked.add_producer(UUID, convertUUID, "text/html")