diff options
author | McCabe Maxsted | 2009-01-12 15:33:52 -0700 |
---|---|---|
committer | McCabe Maxsted | 2009-01-12 15:33:52 -0700 |
commit | 2258733ba2adffbedd8104e1a7d9e762a578054e (patch) | |
tree | bfd25c7d90ff580c183fa0d75c41248c574428fa /linden/indra/lib/python | |
parent | Added inventory changes to fix one method of inventory loss. (diff) | |
download | meta-impy-2258733ba2adffbedd8104e1a7d9e762a578054e.zip meta-impy-2258733ba2adffbedd8104e1a7d9e762a578054e.tar.gz meta-impy-2258733ba2adffbedd8104e1a7d9e762a578054e.tar.bz2 meta-impy-2258733ba2adffbedd8104e1a7d9e762a578054e.tar.xz |
Updated changes to LLSD.
Diffstat (limited to 'linden/indra/lib/python')
-rw-r--r-- | linden/indra/lib/python/indra/base/llsd.py | 142 | ||||
-rw-r--r-- | linden/indra/lib/python/indra/util/fastest_elementtree.py | 31 |
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 | |||
33 | import types | 33 | import types |
34 | import re | 34 | import re |
35 | 35 | ||
36 | from indra.util.fastest_elementtree import fromstring | 36 | from indra.util.fastest_elementtree import ElementTreeError, fromstring |
37 | from indra.base import lluuid | 37 | from indra.base import lluuid |
38 | 38 | ||
39 | int_regex = re.compile("[-+]?\d+") | 39 | try: |
40 | real_regex = re.compile("[-+]?(\d+(\.\d*)?|\d*\.\d+)([eE][-+]?\d+)?") | 40 | import cllsd |
41 | alpha_regex = re.compile("[a-zA-Z]+") | 41 | except ImportError: |
42 | date_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 | |||
44 | int_regex = re.compile(r"[-+]?\d+") | ||
45 | real_regex = re.compile(r"[-+]?(\d+(\.\d*)?|\d*\.\d+)([eE][-+]?\d+)?") | ||
46 | alpha_regex = re.compile(r"[a-zA-Z]+") | ||
47 | date_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 | ||
45 | class LLSDParseError(Exception): | 52 | class LLSDParseError(Exception): |
46 | pass | 53 | pass |
47 | 54 | ||
48 | class LLSDSerializationError(Exception): | 55 | class 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 | ||
118 | def str_to_python(node): | 125 | def str_to_python(node): |
119 | return unicode(node.text or '').encode('utf8', 'replace') | 126 | return node.text or '' |
120 | 127 | ||
121 | def bin_to_python(node): | 128 | def 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('&', '&').replace('<', '<').replace('>', '>') | 206 | return v.replace('&', '&').replace('<', '<').replace('>', '>') |
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 |
244 | def format_xml(something): | 260 | def 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 | ||
842 | def _format_binary_recurse(something): | 872 | def _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 | |||
929 | def 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 | |||
935 | def parse_xml(something): | ||
936 | try: | ||
937 | return to_python(fromstring(something)[0]) | ||
938 | except ElementTreeError, err: | ||
939 | raise LLSDParseError(*err.args) | ||
885 | 940 | ||
941 | def parse_notation(something): | ||
942 | return LLSDNotationParser().parse(something) | ||
886 | 943 | ||
887 | def parse(something): | 944 | def 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 | ||
7 | Copyright (c) 2006-2008, Linden Research, Inc. | 7 | Copyright (c) 2008, Linden Research, Inc. |
8 | 8 | ||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | of this software and associated documentation files (the "Software"), to deal | 10 | of 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 | 40 | use_celementree = True |
33 | use_celementree = False | ||
34 | 41 | ||
35 | try: | 42 | try: |
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 | ||
39 | except ImportError: | 48 | except 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 | ||