aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/lib
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/lib')
-rw-r--r--linden/indra/lib/python/indra/base/llsd.py142
-rw-r--r--linden/indra/lib/python/indra/util/fastest_elementtree.py31
2 files changed, 121 insertions, 52 deletions
diff --git a/linden/indra/lib/python/indra/base/llsd.py b/linden/indra/lib/python/indra/base/llsd.py
index 995ace7..521b79c 100644
--- a/linden/indra/lib/python/indra/base/llsd.py
+++ b/linden/indra/lib/python/indra/base/llsd.py
@@ -33,19 +33,26 @@ import time
33import types 33import types
34import re 34import re
35 35
36from indra.util.fastest_elementtree import fromstring 36from indra.util.fastest_elementtree import ElementTreeError, fromstring
37from indra.base import lluuid 37from indra.base import lluuid
38 38
39int_regex = re.compile("[-+]?\d+") 39try:
40real_regex = re.compile("[-+]?(\d+(\.\d*)?|\d*\.\d+)([eE][-+]?\d+)?") 40 import cllsd
41alpha_regex = re.compile("[a-zA-Z]+") 41except ImportError:
42date_regex = re.compile("(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})T(?P<hour>\d{2}):(?P<minute>\d{2}):(?P<second>\d{2})(?P<second_float>\.\d{2})?Z") 42 cllsd = None
43
44int_regex = re.compile(r"[-+]?\d+")
45real_regex = re.compile(r"[-+]?(\d+(\.\d*)?|\d*\.\d+)([eE][-+]?\d+)?")
46alpha_regex = re.compile(r"[a-zA-Z]+")
47date_regex = re.compile(r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})T"
48 r"(?P<hour>\d{2}):(?P<minute>\d{2}):(?P<second>\d{2})"
49 r"(?P<second_float>(\.\d+)?)Z")
43#date: d"YYYY-MM-DDTHH:MM:SS.FFZ" 50#date: d"YYYY-MM-DDTHH:MM:SS.FFZ"
44 51
45class LLSDParseError(Exception): 52class LLSDParseError(Exception):
46 pass 53 pass
47 54
48class LLSDSerializationError(Exception): 55class LLSDSerializationError(TypeError):
49 pass 56 pass
50 57
51 58
@@ -64,10 +71,10 @@ def format_datestr(v):
64 """ Formats a datetime object into the string format shared by xml and notation serializations.""" 71 """ Formats a datetime object into the string format shared by xml and notation serializations."""
65 second_str = "" 72 second_str = ""
66 if v.microsecond > 0: 73 if v.microsecond > 0:
67 seconds = v.second + float(v.microsecond) / 1000000 74 seconds = v.second + float(v.microsecond) / 1e6
68 second_str = "%05.2f" % seconds 75 second_str = "%05.2f" % seconds
69 else: 76 else:
70 second_str = "%d" % v.second 77 second_str = "%02d" % v.second
71 return '%s%sZ' % (v.strftime('%Y-%m-%dT%H:%M:'), second_str) 78 return '%s%sZ' % (v.strftime('%Y-%m-%dT%H:%M:'), second_str)
72 79
73 80
@@ -89,7 +96,7 @@ def parse_datestr(datestr):
89 seconds_float = match.group('second_float') 96 seconds_float = match.group('second_float')
90 microsecond = 0 97 microsecond = 0
91 if seconds_float: 98 if seconds_float:
92 microsecond = int(seconds_float[1:]) * 10000 99 microsecond = int(float('0' + seconds_float) * 1e6)
93 return datetime.datetime(year, month, day, hour, minute, second, microsecond) 100 return datetime.datetime(year, month, day, hour, minute, second, microsecond)
94 101
95 102
@@ -116,7 +123,7 @@ def uuid_to_python(node):
116 return lluuid.UUID(node.text) 123 return lluuid.UUID(node.text)
117 124
118def str_to_python(node): 125def str_to_python(node):
119 return unicode(node.text or '').encode('utf8', 'replace') 126 return node.text or ''
120 127
121def bin_to_python(node): 128def bin_to_python(node):
122 return binary(base64.decodestring(node.text or '')) 129 return binary(base64.decodestring(node.text or ''))
@@ -189,9 +196,13 @@ class LLSDXMLFormatter(object):
189 if(contents is None or contents is ''): 196 if(contents is None or contents is ''):
190 return "<%s />" % (name,) 197 return "<%s />" % (name,)
191 else: 198 else:
199 if type(contents) is unicode:
200 contents = contents.encode('utf-8')
192 return "<%s>%s</%s>" % (name, contents, name) 201 return "<%s>%s</%s>" % (name, contents, name)
193 202
194 def xml_esc(self, v): 203 def xml_esc(self, v):
204 if type(v) is unicode:
205 v = v.encode('utf-8')
195 return v.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;') 206 return v.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
196 207
197 def LLSD(self, v): 208 def LLSD(self, v):
@@ -237,9 +248,14 @@ class LLSDXMLFormatter(object):
237 raise LLSDSerializationError("Cannot serialize unknown type: %s (%s)" % ( 248 raise LLSDSerializationError("Cannot serialize unknown type: %s (%s)" % (
238 t, something)) 249 t, something))
239 250
240 def format(self, something): 251 def _format(self, something):
241 return '<?xml version="1.0" ?>' + self.elt("llsd", self.generate(something)) 252 return '<?xml version="1.0" ?>' + self.elt("llsd", self.generate(something))
242 253
254 def format(self, something):
255 if cllsd:
256 return cllsd.llsd_to_xml(something)
257 return self._format(something)
258
243_g_xml_formatter = None 259_g_xml_formatter = None
244def format_xml(something): 260def format_xml(something):
245 global _g_xml_formatter 261 global _g_xml_formatter
@@ -356,8 +372,10 @@ class LLSDNotationFormatter(object):
356 def UUID(self, v): 372 def UUID(self, v):
357 return "u%s" % v 373 return "u%s" % v
358 def BINARY(self, v): 374 def BINARY(self, v):
359 raise LLSDSerializationError("binary notation not yet supported") 375 return 'b64"' + base64.encodestring(v) + '"'
360 def STRING(self, v): 376 def STRING(self, v):
377 if isinstance(v, unicode):
378 v = v.encode('utf-8')
361 return "'%s'" % v.replace("\\", "\\\\").replace("'", "\\'") 379 return "'%s'" % v.replace("\\", "\\\\").replace("'", "\\'")
362 def URI(self, v): 380 def URI(self, v):
363 return 'l"%s"' % str(v).replace("\\", "\\\\").replace('"', '\\"') 381 return 'l"%s"' % str(v).replace("\\", "\\\\").replace('"', '\\"')
@@ -366,16 +384,24 @@ class LLSDNotationFormatter(object):
366 def ARRAY(self, v): 384 def ARRAY(self, v):
367 return "[%s]" % ','.join([self.generate(item) for item in v]) 385 return "[%s]" % ','.join([self.generate(item) for item in v])
368 def MAP(self, v): 386 def MAP(self, v):
369 return "{%s}" % ','.join(["'%s':%s" % (key.replace("\\", "\\\\").replace("'", "\\'"), self.generate(value)) 387 def fix(key):
388 if isinstance(key, unicode):
389 return key.encode('utf-8')
390 return key
391 return "{%s}" % ','.join(["'%s':%s" % (fix(key).replace("\\", "\\\\").replace("'", "\\'"), self.generate(value))
370 for key, value in v.items()]) 392 for key, value in v.items()])
371 393
372 def generate(self, something): 394 def generate(self, something):
373 t = type(something) 395 t = type(something)
374 if self.type_map.has_key(t): 396 handler = self.type_map.get(t)
375 return self.type_map[t](something) 397 if handler:
398 return handler(something)
376 else: 399 else:
377 raise LLSDSerializationError("Cannot serialize unknown type: %s (%s)" % ( 400 try:
378 t, something)) 401 return self.ARRAY(iter(something))
402 except TypeError:
403 raise LLSDSerializationError(
404 "Cannot serialize unknown type: %s (%s)" % (t, something))
379 405
380 def format(self, something): 406 def format(self, something):
381 return self.generate(something) 407 return self.generate(something)
@@ -479,7 +505,6 @@ class LLSDBinaryParser(object):
479 raise LLSDParseError("invalid map key at byte %d." % ( 505 raise LLSDParseError("invalid map key at byte %d." % (
480 self._index - 1,)) 506 self._index - 1,))
481 value = self._parse() 507 value = self._parse()
482 #print "kv:",key,value
483 rv[key] = value 508 rv[key] = value
484 count += 1 509 count += 1
485 cc = self._buffer[self._index] 510 cc = self._buffer[self._index]
@@ -636,11 +661,23 @@ class LLSDNotationParser(object):
636 # 'd' = date in seconds since epoch 661 # 'd' = date in seconds since epoch
637 return self._parse_date() 662 return self._parse_date()
638 elif cc == 'b': 663 elif cc == 'b':
639 raise LLSDParseError("binary notation not yet supported") 664 return self._parse_binary()
640 else: 665 else:
641 raise LLSDParseError("invalid token at index %d: %d" % ( 666 raise LLSDParseError("invalid token at index %d: %d" % (
642 self._index - 1, ord(cc))) 667 self._index - 1, ord(cc)))
643 668
669 def _parse_binary(self):
670 i = self._index
671 if self._buffer[i:i+2] == '64':
672 q = self._buffer[i+2]
673 e = self._buffer.find(q, i+3)
674 try:
675 return base64.decodestring(self._buffer[i+3:e])
676 finally:
677 self._index = e + 1
678 else:
679 raise LLSDParseError('random horrible binary format not supported')
680
644 def _parse_map(self): 681 def _parse_map(self):
645 """ map: { string:object, string:object } """ 682 """ map: { string:object, string:object } """
646 rv = {} 683 rv = {}
@@ -653,30 +690,23 @@ class LLSDNotationParser(object):
653 if cc in ("'", '"', 's'): 690 if cc in ("'", '"', 's'):
654 key = self._parse_string(cc) 691 key = self._parse_string(cc)
655 found_key = True 692 found_key = True
656 #print "key:",key
657 elif cc.isspace() or cc == ',': 693 elif cc.isspace() or cc == ',':
658 cc = self._buffer[self._index] 694 cc = self._buffer[self._index]
659 self._index += 1 695 self._index += 1
660 else: 696 else:
661 raise LLSDParseError("invalid map key at byte %d." % ( 697 raise LLSDParseError("invalid map key at byte %d." % (
662 self._index - 1,)) 698 self._index - 1,))
699 elif cc.isspace() or cc == ':':
700 cc = self._buffer[self._index]
701 self._index += 1
702 continue
663 else: 703 else:
664 if cc.isspace() or cc == ':':
665 #print "skipping whitespace '%s'" % cc
666 cc = self._buffer[self._index]
667 self._index += 1
668 continue
669 self._index += 1 704 self._index += 1
670 value = self._parse() 705 value = self._parse()
671 #print "kv:",key,value
672 rv[key] = value 706 rv[key] = value
673 found_key = False 707 found_key = False
674 cc = self._buffer[self._index] 708 cc = self._buffer[self._index]
675 self._index += 1 709 self._index += 1
676 #if cc == '}':
677 # break
678 #cc = self._buffer[self._index]
679 #self._index += 1
680 710
681 return rv 711 return rv
682 712
@@ -840,6 +870,14 @@ def format_binary(something):
840 return '<?llsd/binary?>\n' + _format_binary_recurse(something) 870 return '<?llsd/binary?>\n' + _format_binary_recurse(something)
841 871
842def _format_binary_recurse(something): 872def _format_binary_recurse(something):
873 def _format_list(something):
874 array_builder = []
875 array_builder.append('[' + struct.pack('!i', len(something)))
876 for item in something:
877 array_builder.append(_format_binary_recurse(item))
878 array_builder.append(']')
879 return ''.join(array_builder)
880
843 if something is None: 881 if something is None:
844 return '!' 882 return '!'
845 elif isinstance(something, LLSD): 883 elif isinstance(something, LLSD):
@@ -857,7 +895,10 @@ def _format_binary_recurse(something):
857 return 'u' + something._bits 895 return 'u' + something._bits
858 elif isinstance(something, binary): 896 elif isinstance(something, binary):
859 return 'b' + struct.pack('!i', len(something)) + something 897 return 'b' + struct.pack('!i', len(something)) + something
860 elif isinstance(something, (str, unicode)): 898 elif isinstance(something, str):
899 return 's' + struct.pack('!i', len(something)) + something
900 elif isinstance(something, unicode):
901 something = something.encode('utf-8')
861 return 's' + struct.pack('!i', len(something)) + something 902 return 's' + struct.pack('!i', len(something)) + something
862 elif isinstance(something, uri): 903 elif isinstance(something, uri):
863 return 'l' + struct.pack('!i', len(something)) + something 904 return 'l' + struct.pack('!i', len(something)) + something
@@ -865,35 +906,50 @@ def _format_binary_recurse(something):
865 seconds_since_epoch = time.mktime(something.timetuple()) 906 seconds_since_epoch = time.mktime(something.timetuple())
866 return 'd' + struct.pack('!d', seconds_since_epoch) 907 return 'd' + struct.pack('!d', seconds_since_epoch)
867 elif isinstance(something, (list, tuple)): 908 elif isinstance(something, (list, tuple)):
868 array_builder = [] 909 return _format_list(something)
869 array_builder.append('[' + struct.pack('!i', len(something)))
870 for item in something:
871 array_builder.append(_format_binary_recurse(item))
872 array_builder.append(']')
873 return ''.join(array_builder)
874 elif isinstance(something, dict): 910 elif isinstance(something, dict):
875 map_builder = [] 911 map_builder = []
876 map_builder.append('{' + struct.pack('!i', len(something))) 912 map_builder.append('{' + struct.pack('!i', len(something)))
877 for key, value in something.items(): 913 for key, value in something.items():
914 if isinstance(key, unicode):
915 key = key.encode('utf-8')
878 map_builder.append('k' + struct.pack('!i', len(key)) + key) 916 map_builder.append('k' + struct.pack('!i', len(key)) + key)
879 map_builder.append(_format_binary_recurse(value)) 917 map_builder.append(_format_binary_recurse(value))
880 map_builder.append('}') 918 map_builder.append('}')
881 return ''.join(map_builder) 919 return ''.join(map_builder)
882 else: 920 else:
883 raise LLSDSerializationError("Cannot serialize unknown type: %s (%s)" % ( 921 try:
884 type(something), something)) 922 return _format_list(list(something))
923 except TypeError:
924 raise LLSDSerializationError(
925 "Cannot serialize unknown type: %s (%s)" %
926 (type(something), something))
927
928
929def parse_binary(something):
930 header = '<?llsd/binary?>\n'
931 if not something.startswith(header):
932 raise LLSDParseError('LLSD binary encoding header not found')
933 return LLSDBinaryParser().parse(something[len(header):])
934
935def parse_xml(something):
936 try:
937 return to_python(fromstring(something)[0])
938 except ElementTreeError, err:
939 raise LLSDParseError(*err.args)
885 940
941def parse_notation(something):
942 return LLSDNotationParser().parse(something)
886 943
887def parse(something): 944def parse(something):
888 try: 945 try:
889 if something.startswith('<?llsd/binary?>'): 946 if something.startswith('<?llsd/binary?>'):
890 just_binary = something.split('\n', 1)[1] 947 return parse_binary(something)
891 return LLSDBinaryParser().parse(just_binary)
892 # This should be better. 948 # This should be better.
893 elif something.startswith('<'): 949 elif something.startswith('<'):
894 return to_python(fromstring(something)[0]) 950 return parse_xml(something)
895 else: 951 else:
896 return LLSDNotationParser().parse(something) 952 return parse_notation(something)
897 except KeyError, e: 953 except KeyError, e:
898 raise Exception('LLSD could not be parsed: %s' % (e,)) 954 raise Exception('LLSD could not be parsed: %s' % (e,))
899 955
diff --git a/linden/indra/lib/python/indra/util/fastest_elementtree.py b/linden/indra/lib/python/indra/util/fastest_elementtree.py
index 64aed09..2470143 100644
--- a/linden/indra/lib/python/indra/util/fastest_elementtree.py
+++ b/linden/indra/lib/python/indra/util/fastest_elementtree.py
@@ -2,9 +2,9 @@
2@file fastest_elementtree.py 2@file fastest_elementtree.py
3@brief Concealing some gnarly import logic in here. This should export the interface of elementtree. 3@brief Concealing some gnarly import logic in here. This should export the interface of elementtree.
4 4
5$LicenseInfo:firstyear=2006&license=mit$ 5$LicenseInfo:firstyear=2008&license=mit$
6 6
7Copyright (c) 2006-2008, Linden Research, Inc. 7Copyright (c) 2008, Linden Research, Inc.
8 8
9Permission is hereby granted, free of charge, to any person obtaining a copy 9Permission is hereby granted, free of charge, to any person obtaining a copy
10of this software and associated documentation files (the "Software"), to deal 10of this software and associated documentation files (the "Software"), to deal
@@ -26,27 +26,40 @@ THE SOFTWARE.
26$/LicenseInfo$ 26$/LicenseInfo$
27""" 27"""
28 28
29# Using celementree might cause some unforeseen problems so here's a 29# The parsing exception raised by the underlying library depends
30# on the ElementTree implementation we're using, so we provide an
31# alias here.
32#
33# Use ElementTreeError as the exception type for catching parsing
34# errors.
35
36
37# Using cElementTree might cause some unforeseen problems, so here's a
30# convenient off switch. 38# convenient off switch.
31 39
32# *NOTE: turned off cause of problems. :-( *TODO: debug 40use_celementree = True
33use_celementree = False
34 41
35try: 42try:
36 if not use_celementree: 43 if not use_celementree:
37 raise ImportError() 44 raise ImportError()
38 from cElementTree import * ## This does not work under Windows 45 # Python 2.3 and 2.4.
46 from cElementTree import *
47 ElementTreeError = SyntaxError
39except ImportError: 48except ImportError:
40 try: 49 try:
41 if not use_celementree: 50 if not use_celementree:
42 raise ImportError() 51 raise ImportError()
43 ## This is the name of cElementTree under python 2.5 52 # Python 2.5 and above.
44 from xml.etree.cElementTree import * 53 from xml.etree.cElementTree import *
54 ElementTreeError = SyntaxError
45 except ImportError: 55 except ImportError:
56 # Pure Python code.
46 try: 57 try:
47 ## This is the old name of elementtree, for use with 2.3 58 # Python 2.3 and 2.4.
48 from elementtree.ElementTree import * 59 from elementtree.ElementTree import *
49 except ImportError: 60 except ImportError:
50 ## This is the name of elementtree under python 2.5 61 # Python 2.5 and above.
51 from xml.etree.ElementTree import * 62 from xml.etree.ElementTree import *
52 63
64 # The pure Python ElementTree module uses Expat for parsing.
65 from xml.parsers.expat import ExpatError as ElementTreeError