llsd.py
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:34k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. """
  2. @file llsd.py
  3. @brief Types as well as parsing and formatting functions for handling LLSD.
  4. $LicenseInfo:firstyear=2006&license=mit$
  5. Copyright (c) 2006-2010, Linden Research, Inc.
  6. Permission is hereby granted, free of charge, to any person obtaining a copy
  7. of this software and associated documentation files (the "Software"), to deal
  8. in the Software without restriction, including without limitation the rights
  9. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. copies of the Software, and to permit persons to whom the Software is
  11. furnished to do so, subject to the following conditions:
  12. The above copyright notice and this permission notice shall be included in
  13. all copies or substantial portions of the Software.
  14. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. THE SOFTWARE.
  21. $/LicenseInfo$
  22. """
  23. import datetime
  24. import base64
  25. import string
  26. import struct
  27. import time
  28. import types
  29. import re
  30. from indra.util.fastest_elementtree import ElementTreeError, fromstring
  31. from indra.base import lluuid
  32. # cllsd.c in server/server-1.25 has memory leaks,
  33. #   so disabling cllsd for now
  34. #try:
  35. #    import cllsd
  36. #except ImportError:
  37. #    cllsd = None
  38. cllsd = None
  39. int_regex = re.compile(r"[-+]?d+")
  40. real_regex = re.compile(r"[-+]?(d+(.d*)?|d*.d+)([eE][-+]?d+)?")
  41. alpha_regex = re.compile(r"[a-zA-Z]+")
  42. date_regex = re.compile(r"(?P<year>d{4})-(?P<month>d{2})-(?P<day>d{2})T"
  43.                         r"(?P<hour>d{2}):(?P<minute>d{2}):(?P<second>d{2})"
  44.                         r"(?P<second_float>(.d+)?)Z")
  45. #date: d"YYYY-MM-DDTHH:MM:SS.FFFFFFZ"
  46. class LLSDParseError(Exception):
  47.     pass
  48. class LLSDSerializationError(TypeError):
  49.     pass
  50. class binary(str):
  51.     pass
  52. class uri(str):
  53.     pass
  54. BOOL_TRUE = ('1', '1.0', 'true')
  55. BOOL_FALSE = ('0', '0.0', 'false', '')
  56. def format_datestr(v):
  57.     """ Formats a datetime or date object into the string format shared by xml and notation serializations."""
  58.     if hasattr(v, 'microsecond'):
  59.         return v.isoformat() + 'Z'
  60.     else:
  61.         return v.strftime('%Y-%m-%dT%H:%M:%SZ')
  62. def parse_datestr(datestr):
  63.     """Parses a datetime object from the string format shared by xml and notation serializations."""
  64.     if datestr == "":
  65.         return datetime.datetime(1970, 1, 1)
  66.     
  67.     match = re.match(date_regex, datestr)
  68.     if not match:
  69.         raise LLSDParseError("invalid date string '%s'." % datestr)
  70.     
  71.     year = int(match.group('year'))
  72.     month = int(match.group('month'))
  73.     day = int(match.group('day'))
  74.     hour = int(match.group('hour'))
  75.     minute = int(match.group('minute'))
  76.     second = int(match.group('second'))
  77.     seconds_float = match.group('second_float')
  78.     microsecond = 0
  79.     if seconds_float:
  80.         microsecond = int(float('0' + seconds_float) * 1e6)
  81.     return datetime.datetime(year, month, day, hour, minute, second, microsecond)
  82. def bool_to_python(node):
  83.     val = node.text or ''
  84.     if val in BOOL_TRUE:
  85.         return True
  86.     else:
  87.         return False
  88. def int_to_python(node):
  89.     val = node.text or ''
  90.     if not val.strip():
  91.         return 0
  92.     return int(val)
  93. def real_to_python(node):
  94.     val = node.text or ''
  95.     if not val.strip():
  96.         return 0.0
  97.     return float(val)
  98. def uuid_to_python(node):
  99.     return lluuid.UUID(node.text)
  100. def str_to_python(node):
  101.     return node.text or ''
  102. def bin_to_python(node):
  103.     return binary(base64.decodestring(node.text or ''))
  104. def date_to_python(node):
  105.     val = node.text or ''
  106.     if not val:
  107.         val = "1970-01-01T00:00:00Z"
  108.     return parse_datestr(val)
  109.     
  110. def uri_to_python(node):
  111.     val = node.text or ''
  112.     if not val:
  113.         return None
  114.     return uri(val)
  115. def map_to_python(node):
  116.     result = {}
  117.     for index in range(len(node))[::2]:
  118.         result[node[index].text] = to_python(node[index+1])
  119.     return result
  120. def array_to_python(node):
  121.     return [to_python(child) for child in node]
  122. NODE_HANDLERS = dict(
  123.     undef=lambda x: None,
  124.     boolean=bool_to_python,
  125.     integer=int_to_python,
  126.     real=real_to_python,
  127.     uuid=uuid_to_python,
  128.     string=str_to_python,
  129.     binary=bin_to_python,
  130.     date=date_to_python,
  131.     uri=uri_to_python,
  132.     map=map_to_python,
  133.     array=array_to_python,
  134.     )
  135. def to_python(node):
  136.     return NODE_HANDLERS[node.tag](node)
  137. class Nothing(object):
  138.     pass
  139. class LLSDXMLFormatter(object):
  140.     def __init__(self):
  141.         self.type_map = {
  142.             type(None) : self.UNDEF,
  143.             bool : self.BOOLEAN,
  144.             int : self.INTEGER,
  145.             long : self.INTEGER,
  146.             float : self.REAL,
  147.             lluuid.UUID : self.UUID,
  148.             binary : self.BINARY,
  149.             str : self.STRING,
  150.             unicode : self.STRING,
  151.             uri : self.URI,
  152.             datetime.datetime : self.DATE,
  153.             datetime.date : self.DATE,
  154.             list : self.ARRAY,
  155.             tuple : self.ARRAY,
  156.             types.GeneratorType : self.ARRAY,
  157.             dict : self.MAP,
  158.             LLSD : self.LLSD
  159.         }
  160.     def elt(self, name, contents=None):
  161.         if(contents is None or contents is ''):
  162.             return "<%s />" % (name,)
  163.         else:
  164.             if type(contents) is unicode:
  165.                 contents = contents.encode('utf-8')
  166.             return "<%s>%s</%s>" % (name, contents, name)
  167.     def xml_esc(self, v):
  168.         if type(v) is unicode:
  169.             v = v.encode('utf-8')
  170.         return v.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
  171.     def LLSD(self, v):
  172.         return self.generate(v.thing)
  173.     def UNDEF(self, v):
  174.         return self.elt('undef')
  175.     def BOOLEAN(self, v):
  176.         if v:
  177.             return self.elt('boolean', 'true')
  178.         else:
  179.             return self.elt('boolean', 'false')
  180.     def INTEGER(self, v):
  181.         return self.elt('integer', v)
  182.     def REAL(self, v):
  183.         return self.elt('real', v)
  184.     def UUID(self, v):
  185.         if(v.isNull()):
  186.             return self.elt('uuid')
  187.         else:
  188.             return self.elt('uuid', v)
  189.     def BINARY(self, v):
  190.         return self.elt('binary', base64.encodestring(v))
  191.     def STRING(self, v):
  192.         return self.elt('string', self.xml_esc(v))
  193.     def URI(self, v):
  194.         return self.elt('uri', self.xml_esc(str(v)))
  195.     def DATE(self, v):
  196.         return self.elt('date', format_datestr(v))
  197.     def ARRAY(self, v):
  198.         return self.elt('array', ''.join([self.generate(item) for item in v]))
  199.     def MAP(self, v):
  200.         return self.elt(
  201.             'map',
  202.             ''.join(["%s%s" % (self.elt('key', self.xml_esc(str(key))), self.generate(value))
  203.              for key, value in v.items()]))
  204.     typeof = type
  205.     def generate(self, something):
  206.         t = self.typeof(something)
  207.         if self.type_map.has_key(t):
  208.             return self.type_map[t](something)
  209.         else:
  210.             raise LLSDSerializationError("Cannot serialize unknown type: %s (%s)" % (
  211.                 t, something))
  212.     def _format(self, something):
  213.         return '<?xml version="1.0" ?>' + self.elt("llsd", self.generate(something))
  214.     def format(self, something):
  215.         if cllsd:
  216.             return cllsd.llsd_to_xml(something)
  217.         return self._format(something)
  218. _g_xml_formatter = None
  219. def format_xml(something):
  220.     global _g_xml_formatter
  221.     if _g_xml_formatter is None:
  222.         _g_xml_formatter = LLSDXMLFormatter()
  223.     return _g_xml_formatter.format(something)
  224. class LLSDXMLPrettyFormatter(LLSDXMLFormatter):
  225.     def __init__(self, indent_atom = None):
  226.         # Call the super class constructor so that we have the type map
  227.         super(LLSDXMLPrettyFormatter, self).__init__()
  228.         # Override the type map to use our specialized formatters to
  229.         # emit the pretty output.
  230.         self.type_map[list] = self.PRETTY_ARRAY
  231.         self.type_map[tuple] = self.PRETTY_ARRAY
  232.         self.type_map[types.GeneratorType] = self.PRETTY_ARRAY,
  233.         self.type_map[dict] = self.PRETTY_MAP
  234.         # Private data used for indentation.
  235.         self._indent_level = 1
  236.         if indent_atom is None:
  237.             self._indent_atom = '  '
  238.         else:
  239.             self._indent_atom = indent_atom
  240.     def _indent(self):
  241.         "Return an indentation based on the atom and indentation level."
  242.         return self._indent_atom * self._indent_level
  243.     def PRETTY_ARRAY(self, v):
  244.         rv = []
  245.         rv.append('<array>n')
  246.         self._indent_level = self._indent_level + 1
  247.         rv.extend(["%s%sn" %
  248.                    (self._indent(),
  249.                     self.generate(item))
  250.                    for item in v])
  251.         self._indent_level = self._indent_level - 1
  252.         rv.append(self._indent())
  253.         rv.append('</array>')
  254.         return ''.join(rv)
  255.     def PRETTY_MAP(self, v):
  256.         rv = []
  257.         rv.append('<map>n')
  258.         self._indent_level = self._indent_level + 1
  259.         keys = v.keys()
  260.         keys.sort()
  261.         rv.extend(["%s%sn%s%sn" %
  262.                    (self._indent(),
  263.                     self.elt('key', key),
  264.                     self._indent(),
  265.                     self.generate(v[key]))
  266.                    for key in keys])
  267.         self._indent_level = self._indent_level - 1
  268.         rv.append(self._indent())
  269.         rv.append('</map>')
  270.         return ''.join(rv)
  271.     def format(self, something):
  272.         data = []
  273.         data.append('<?xml version="1.0" ?>n<llsd>')
  274.         data.append(self.generate(something))
  275.         data.append('</llsd>n')
  276.         return 'n'.join(data)
  277. def format_pretty_xml(something):
  278.     """@brief Serialize a python object as 'pretty' llsd xml.
  279.     The output conforms to the LLSD DTD, unlike the output from the
  280.     standard python xml.dom DOM::toprettyxml() method which does not
  281.     preserve significant whitespace. 
  282.     This function is not necessarily suited for serializing very large
  283.     objects. It is not optimized by the cllsd module, and sorts on
  284.     dict (llsd map) keys alphabetically to ease human reading.
  285.     """
  286.     return LLSDXMLPrettyFormatter().format(something)
  287. class LLSDNotationFormatter(object):
  288.     def __init__(self):
  289.         self.type_map = {
  290.             type(None) : self.UNDEF,
  291.             bool : self.BOOLEAN,
  292.             int : self.INTEGER,
  293.             long : self.INTEGER,
  294.             float : self.REAL,
  295.             lluuid.UUID : self.UUID,
  296.             binary : self.BINARY,
  297.             str : self.STRING,
  298.             unicode : self.STRING,
  299.             uri : self.URI,
  300.             datetime.datetime : self.DATE,
  301.             datetime.date : self.DATE,
  302.             list : self.ARRAY,
  303.             tuple : self.ARRAY,
  304.             types.GeneratorType : self.ARRAY,
  305.             dict : self.MAP,
  306.             LLSD : self.LLSD
  307.         }
  308.     def LLSD(self, v):
  309.         return self.generate(v.thing)
  310.     def UNDEF(self, v):
  311.         return '!'
  312.     def BOOLEAN(self, v):
  313.         if v:
  314.             return 'true'
  315.         else:
  316.             return 'false'
  317.     def INTEGER(self, v):
  318.         return "i%s" % v
  319.     def REAL(self, v):
  320.         return "r%s" % v
  321.     def UUID(self, v):
  322.         return "u%s" % v
  323.     def BINARY(self, v):
  324.         return 'b64"' + base64.encodestring(v) + '"'
  325.     def STRING(self, v):
  326.         if isinstance(v, unicode):
  327.             v = v.encode('utf-8')
  328.         return "'%s'" % v.replace("\", "\\").replace("'", "\'")
  329.     def URI(self, v):
  330.         return 'l"%s"' % str(v).replace("\", "\\").replace('"', '\"')
  331.     def DATE(self, v):
  332.         return 'd"%s"' % format_datestr(v)
  333.     def ARRAY(self, v):
  334.         return "[%s]" % ','.join([self.generate(item) for item in v])
  335.     def MAP(self, v):
  336.         def fix(key):
  337.             if isinstance(key, unicode):
  338.                 return key.encode('utf-8')
  339.             return key
  340.         return "{%s}" % ','.join(["'%s':%s" % (fix(key).replace("\", "\\").replace("'", "\'"), self.generate(value))
  341.              for key, value in v.items()])
  342.     def generate(self, something):
  343.         t = type(something)
  344.         handler = self.type_map.get(t)
  345.         if handler:
  346.             return handler(something)
  347.         else:
  348.             try:
  349.                 return self.ARRAY(iter(something))
  350.             except TypeError:
  351.                 raise LLSDSerializationError(
  352.                     "Cannot serialize unknown type: %s (%s)" % (t, something))
  353.     def format(self, something):
  354.         return self.generate(something)
  355. def format_notation(something):
  356.     return LLSDNotationFormatter().format(something)
  357. def _hex_as_nybble(hex):
  358.     if (hex >= '0') and (hex <= '9'):
  359.         return ord(hex) - ord('0')
  360.     elif (hex >= 'a') and (hex <='f'):
  361.         return 10 + ord(hex) - ord('a')
  362.     elif (hex >= 'A') and (hex <='F'):
  363.         return 10 + ord(hex) - ord('A');
  364. class LLSDBinaryParser(object):
  365.     def __init__(self):
  366.         pass
  367.     def parse(self, buffer, ignore_binary = False):
  368.         """
  369.         This is the basic public interface for parsing.
  370.         @param buffer the binary data to parse in an indexable sequence.
  371.         @param ignore_binary parser throws away data in llsd binary nodes.
  372.         @return returns a python object.
  373.         """
  374.         self._buffer = buffer
  375.         self._index = 0
  376.         self._keep_binary = not ignore_binary
  377.         return self._parse()
  378.     def _parse(self):
  379.         cc = self._buffer[self._index]
  380.         self._index += 1
  381.         if cc == '{':
  382.             return self._parse_map()
  383.         elif cc == '[':
  384.             return self._parse_array()
  385.         elif cc == '!':
  386.             return None
  387.         elif cc == '0':
  388.             return False
  389.         elif cc == '1':
  390.             return True
  391.         elif cc == 'i':
  392.             # 'i' = integer
  393.             idx = self._index
  394.             self._index += 4
  395.             return struct.unpack("!i", self._buffer[idx:idx+4])[0]
  396.         elif cc == ('r'):
  397.             # 'r' = real number
  398.             idx = self._index
  399.             self._index += 8
  400.             return struct.unpack("!d", self._buffer[idx:idx+8])[0]
  401.         elif cc == 'u':
  402.             # 'u' = uuid
  403.             idx = self._index
  404.             self._index += 16
  405.             return lluuid.uuid_bits_to_uuid(self._buffer[idx:idx+16])
  406.         elif cc == 's':
  407.             # 's' = string
  408.             return self._parse_string()
  409.         elif cc in ("'", '"'):
  410.             # delimited/escaped string
  411.             return self._parse_string_delim(cc)
  412.         elif cc == 'l':
  413.             # 'l' = uri
  414.             return uri(self._parse_string())
  415.         elif cc == ('d'):
  416.             # 'd' = date in seconds since epoch
  417.             idx = self._index
  418.             self._index += 8
  419.             seconds = struct.unpack("!d", self._buffer[idx:idx+8])[0]
  420.             return datetime.datetime.fromtimestamp(seconds)
  421.         elif cc == 'b':
  422.             binary = self._parse_string()
  423.             if self._keep_binary:
  424.                 return binary
  425.             # *NOTE: maybe have a binary placeholder which has the
  426.             # length.
  427.             return None
  428.         else:
  429.             raise LLSDParseError("invalid binary token at byte %d: %d" % (
  430.                 self._index - 1, ord(cc)))
  431.     def _parse_map(self):
  432.         rv = {}
  433.         size = struct.unpack("!i", self._buffer[self._index:self._index+4])[0]
  434.         self._index += 4
  435.         count = 0
  436.         cc = self._buffer[self._index]
  437.         self._index += 1
  438.         key = ''
  439.         while (cc != '}') and (count < size):
  440.             if cc == 'k':
  441.                 key = self._parse_string()
  442.             elif cc in ("'", '"'):
  443.                 key = self._parse_string_delim(cc)
  444.             else:
  445.                 raise LLSDParseError("invalid map key at byte %d." % (
  446.                     self._index - 1,))
  447.             value = self._parse()
  448.             rv[key] = value
  449.             count += 1
  450.             cc = self._buffer[self._index]
  451.             self._index += 1
  452.         if cc != '}':
  453.             raise LLSDParseError("invalid map close token at byte %d." % (
  454.                 self._index,))
  455.         return rv
  456.     def _parse_array(self):
  457.         rv = []
  458.         size = struct.unpack("!i", self._buffer[self._index:self._index+4])[0]
  459.         self._index += 4
  460.         count = 0
  461.         cc = self._buffer[self._index]
  462.         while (cc != ']') and (count < size):
  463.             rv.append(self._parse())
  464.             count += 1
  465.             cc = self._buffer[self._index]
  466.         if cc != ']':
  467.             raise LLSDParseError("invalid array close token at byte %d." % (
  468.                 self._index,))
  469.         self._index += 1
  470.         return rv
  471.     def _parse_string(self):
  472.         size = struct.unpack("!i", self._buffer[self._index:self._index+4])[0]
  473.         self._index += 4
  474.         rv = self._buffer[self._index:self._index+size]
  475.         self._index += size
  476.         return rv
  477.     def _parse_string_delim(self, delim):
  478.         list = []
  479.         found_escape = False
  480.         found_hex = False
  481.         found_digit = False
  482.         byte = 0
  483.         while True:
  484.             cc = self._buffer[self._index]
  485.             self._index += 1
  486.             if found_escape:
  487.                 if found_hex:
  488.                     if found_digit:
  489.                         found_escape = False
  490.                         found_hex = False
  491.                         found_digit = False
  492.                         byte <<= 4
  493.                         byte |= _hex_as_nybble(cc)
  494.                         list.append(chr(byte))
  495.                         byte = 0
  496.                     else:
  497.                         found_digit = True
  498.                         byte = _hex_as_nybble(cc)
  499.                 elif cc == 'x':
  500.                     found_hex = True
  501.                 else:
  502.                     if cc == 'a':
  503.                         list.append('a')
  504.                     elif cc == 'b':
  505.                         list.append('b')
  506.                     elif cc == 'f':
  507.                         list.append('f')
  508.                     elif cc == 'n':
  509.                         list.append('n')
  510.                     elif cc == 'r':
  511.                         list.append('r')
  512.                     elif cc == 't':
  513.                         list.append('t')
  514.                     elif cc == 'v':
  515.                         list.append('v')
  516.                     else:
  517.                         list.append(cc)
  518.                     found_escape = False
  519.             elif cc == '\':
  520.                 found_escape = True
  521.             elif cc == delim:
  522.                 break
  523.             else:
  524.                 list.append(cc)
  525.         return ''.join(list)
  526. class LLSDNotationParser(object):
  527.     """ Parse LLSD notation:
  528.     map: { string:object, string:object }
  529.     array: [ object, object, object ]
  530.     undef: !
  531.     boolean: true | false | 1 | 0 | T | F | t | f | TRUE | FALSE
  532.     integer: i####
  533.     real: r####
  534.     uuid: u####
  535.     string: "g'day" | 'have a "nice" day' | s(size)"raw data"
  536.     uri: l"escaped"
  537.     date: d"YYYY-MM-DDTHH:MM:SS.FFZ"
  538.     binary: b##"ff3120ab1" | b(size)"raw data"
  539.     """
  540.     def __init__(self):
  541.         pass
  542.     def parse(self, buffer, ignore_binary = False):
  543.         """
  544.         This is the basic public interface for parsing.
  545.         @param buffer the notation string to parse.
  546.         @param ignore_binary parser throws away data in llsd binary nodes.
  547.         @return returns a python object.
  548.         """
  549.         if buffer == "":
  550.             return False
  551.         self._buffer = buffer
  552.         self._index = 0
  553.         return self._parse()
  554.     def _parse(self):
  555.         cc = self._buffer[self._index]
  556.         self._index += 1
  557.         if cc == '{':
  558.             return self._parse_map()
  559.         elif cc == '[':
  560.             return self._parse_array()
  561.         elif cc == '!':
  562.             return None
  563.         elif cc == '0':
  564.             return False
  565.         elif cc == '1':
  566.             return True
  567.         elif cc in ('F', 'f'):
  568.             self._skip_alpha()
  569.             return False
  570.         elif cc in ('T', 't'):
  571.             self._skip_alpha()
  572.             return True
  573.         elif cc == 'i':
  574.             # 'i' = integer
  575.             return self._parse_integer()
  576.         elif cc == ('r'):
  577.             # 'r' = real number
  578.             return self._parse_real()
  579.         elif cc == 'u':
  580.             # 'u' = uuid
  581.             return self._parse_uuid()
  582.         elif cc in ("'", '"', 's'):
  583.             return self._parse_string(cc)
  584.         elif cc == 'l':
  585.             # 'l' = uri
  586.             delim = self._buffer[self._index]
  587.             self._index += 1
  588.             val = uri(self._parse_string(delim))
  589.             if len(val) == 0:
  590.                 return None
  591.             return val
  592.         elif cc == ('d'):
  593.             # 'd' = date in seconds since epoch
  594.             return self._parse_date()
  595.         elif cc == 'b':
  596.             return self._parse_binary()
  597.         else:
  598.             raise LLSDParseError("invalid token at index %d: %d" % (
  599.                 self._index - 1, ord(cc)))
  600.     def _parse_binary(self):
  601.         i = self._index
  602.         if self._buffer[i:i+2] == '64':
  603.             q = self._buffer[i+2]
  604.             e = self._buffer.find(q, i+3)
  605.             try:
  606.                 return base64.decodestring(self._buffer[i+3:e])
  607.             finally:
  608.                 self._index = e + 1
  609.         else:
  610.             raise LLSDParseError('random horrible binary format not supported')
  611.     def _parse_map(self):
  612.         """ map: { string:object, string:object } """
  613.         rv = {}
  614.         cc = self._buffer[self._index]
  615.         self._index += 1
  616.         key = ''
  617.         found_key = False
  618.         while (cc != '}'):
  619.             if not found_key:
  620.                 if cc in ("'", '"', 's'):
  621.                     key = self._parse_string(cc)
  622.                     found_key = True
  623.                 elif cc.isspace() or cc == ',':
  624.                     cc = self._buffer[self._index]
  625.                     self._index += 1
  626.                 else:
  627.                     raise LLSDParseError("invalid map key at byte %d." % (
  628.                                         self._index - 1,))
  629.             elif cc.isspace() or cc == ':':
  630.                 cc = self._buffer[self._index]
  631.                 self._index += 1
  632.                 continue
  633.             else:
  634.                 self._index += 1
  635.                 value = self._parse()
  636.                 rv[key] = value
  637.                 found_key = False
  638.                 cc = self._buffer[self._index]
  639.                 self._index += 1
  640.         return rv
  641.     def _parse_array(self):
  642.         """ array: [ object, object, object ] """
  643.         rv = []
  644.         cc = self._buffer[self._index]
  645.         while (cc != ']'):
  646.             if cc.isspace() or cc == ',':
  647.                 self._index += 1
  648.                 cc = self._buffer[self._index]
  649.                 continue
  650.             rv.append(self._parse())
  651.             cc = self._buffer[self._index]
  652.         if cc != ']':
  653.             raise LLSDParseError("invalid array close token at index %d." % (
  654.                 self._index,))
  655.         self._index += 1
  656.         return rv
  657.     def _parse_uuid(self):
  658.         match = re.match(lluuid.UUID.uuid_regex, self._buffer[self._index:])
  659.         if not match:
  660.             raise LLSDParseError("invalid uuid token at index %d." % self._index)
  661.         (start, end) = match.span()
  662.         start += self._index
  663.         end += self._index
  664.         self._index = end
  665.         return lluuid.UUID(self._buffer[start:end])
  666.     def _skip_alpha(self):
  667.         match = re.match(alpha_regex, self._buffer[self._index:])
  668.         if match:
  669.             self._index += match.end()
  670.             
  671.     def _parse_date(self):
  672.         delim = self._buffer[self._index]
  673.         self._index += 1
  674.         datestr = self._parse_string(delim)
  675.         return parse_datestr(datestr)
  676.     def _parse_real(self):
  677.         match = re.match(real_regex, self._buffer[self._index:])
  678.         if not match:
  679.             raise LLSDParseError("invalid real token at index %d." % self._index)
  680.         (start, end) = match.span()
  681.         start += self._index
  682.         end += self._index
  683.         self._index = end
  684.         return float( self._buffer[start:end] )
  685.     def _parse_integer(self):
  686.         match = re.match(int_regex, self._buffer[self._index:])
  687.         if not match:
  688.             raise LLSDParseError("invalid integer token at index %d." % self._index)
  689.         (start, end) = match.span()
  690.         start += self._index
  691.         end += self._index
  692.         self._index = end
  693.         return int( self._buffer[start:end] )
  694.     def _parse_string(self, delim):
  695.         """ string: "g'day" | 'have a "nice" day' | s(size)"raw data" """
  696.         rv = ""
  697.         if delim in ("'", '"'):
  698.             rv = self._parse_string_delim(delim)
  699.         elif delim == 's':
  700.             rv = self._parse_string_raw()
  701.         else:
  702.             raise LLSDParseError("invalid string token at index %d." % self._index)
  703.         return rv
  704.     def _parse_string_delim(self, delim):
  705.         """ string: "g'day 'un" | 'have a "nice" day' """
  706.         list = []
  707.         found_escape = False
  708.         found_hex = False
  709.         found_digit = False
  710.         byte = 0
  711.         while True:
  712.             cc = self._buffer[self._index]
  713.             self._index += 1
  714.             if found_escape:
  715.                 if found_hex:
  716.                     if found_digit:
  717.                         found_escape = False
  718.                         found_hex = False
  719.                         found_digit = False
  720.                         byte <<= 4
  721.                         byte |= _hex_as_nybble(cc)
  722.                         list.append(chr(byte))
  723.                         byte = 0
  724.                     else:
  725.                         found_digit = True
  726.                         byte = _hex_as_nybble(cc)
  727.                 elif cc == 'x':
  728.                     found_hex = True
  729.                 else:
  730.                     if cc == 'a':
  731.                         list.append('a')
  732.                     elif cc == 'b':
  733.                         list.append('b')
  734.                     elif cc == 'f':
  735.                         list.append('f')
  736.                     elif cc == 'n':
  737.                         list.append('n')
  738.                     elif cc == 'r':
  739.                         list.append('r')
  740.                     elif cc == 't':
  741.                         list.append('t')
  742.                     elif cc == 'v':
  743.                         list.append('v')
  744.                     else:
  745.                         list.append(cc)
  746.                     found_escape = False
  747.             elif cc == '\':
  748.                 found_escape = True
  749.             elif cc == delim:
  750.                 break
  751.             else:
  752.                 list.append(cc)
  753.         return ''.join(list)
  754.     def _parse_string_raw(self):
  755.         """ string: s(size)"raw data" """
  756.         # Read the (size) portion.
  757.         cc = self._buffer[self._index]
  758.         self._index += 1
  759.         if cc != '(':
  760.             raise LLSDParseError("invalid string token at index %d." % self._index)
  761.         rparen = self._buffer.find(')', self._index)
  762.         if rparen == -1:
  763.             raise LLSDParseError("invalid string token at index %d." % self._index)
  764.         size = int(self._buffer[self._index:rparen])
  765.         self._index = rparen + 1
  766.         delim = self._buffer[self._index]
  767.         self._index += 1
  768.         if delim not in ("'", '"'):
  769.             raise LLSDParseError("invalid string token at index %d." % self._index)
  770.         rv = self._buffer[self._index:(self._index + size)]
  771.         self._index += size
  772.         cc = self._buffer[self._index]
  773.         self._index += 1
  774.         if cc != delim:
  775.             raise LLSDParseError("invalid string token at index %d." % self._index)
  776.         return rv
  777.         
  778. def format_binary(something):
  779.     return '<?llsd/binary?>n' + _format_binary_recurse(something)
  780. def _format_binary_recurse(something):
  781.     def _format_list(something):
  782.         array_builder = []
  783.         array_builder.append('[' + struct.pack('!i', len(something)))
  784.         for item in something:
  785.             array_builder.append(_format_binary_recurse(item))
  786.         array_builder.append(']')
  787.         return ''.join(array_builder)
  788.     if something is None:
  789.         return '!'
  790.     elif isinstance(something, LLSD):
  791.         return _format_binary_recurse(something.thing)
  792.     elif isinstance(something, bool):
  793.         if something:
  794.             return '1'
  795.         else:
  796.             return '0'
  797.     elif isinstance(something, (int, long)):
  798.         return 'i' + struct.pack('!i', something)
  799.     elif isinstance(something, float):
  800.         return 'r' + struct.pack('!d', something)
  801.     elif isinstance(something, lluuid.UUID):
  802.         return 'u' + something._bits
  803.     elif isinstance(something, binary):
  804.         return 'b' + struct.pack('!i', len(something)) + something
  805.     elif isinstance(something, str):
  806.         return 's' + struct.pack('!i', len(something)) + something
  807.     elif isinstance(something, unicode):
  808.         something = something.encode('utf-8')
  809.         return 's' + struct.pack('!i', len(something)) + something
  810.     elif isinstance(something, uri):
  811.         return 'l' + struct.pack('!i', len(something)) + something
  812.     elif isinstance(something, datetime.datetime):
  813.         seconds_since_epoch = time.mktime(something.timetuple())
  814.         return 'd' + struct.pack('!d', seconds_since_epoch)
  815.     elif isinstance(something, (list, tuple)):
  816.         return _format_list(something)
  817.     elif isinstance(something, dict):
  818.         map_builder = []
  819.         map_builder.append('{' + struct.pack('!i', len(something)))
  820.         for key, value in something.items():
  821.             if isinstance(key, unicode):
  822.                 key = key.encode('utf-8')
  823.             map_builder.append('k' + struct.pack('!i', len(key)) + key)
  824.             map_builder.append(_format_binary_recurse(value))
  825.         map_builder.append('}')
  826.         return ''.join(map_builder)
  827.     else:
  828.         try:
  829.             return _format_list(list(something))
  830.         except TypeError:
  831.             raise LLSDSerializationError(
  832.                 "Cannot serialize unknown type: %s (%s)" %
  833.                 (type(something), something))
  834. def parse_binary(binary):
  835.     if binary.startswith('<?llsd/binary?>'):
  836.         just_binary = binary.split('n', 1)[1]
  837.     else:
  838.         just_binary = binary
  839.     return LLSDBinaryParser().parse(just_binary)
  840. def parse_xml(something):
  841.     try:
  842.         return to_python(fromstring(something)[0])
  843.     except ElementTreeError, err:
  844.         raise LLSDParseError(*err.args)
  845. def parse_notation(something):
  846.     return LLSDNotationParser().parse(something)
  847. def parse(something):
  848.     try:
  849.         something = string.lstrip(something)   #remove any pre-trailing whitespace
  850.         if something.startswith('<?llsd/binary?>'):
  851.             return parse_binary(something)
  852.         # This should be better.
  853.         elif something.startswith('<'):
  854.             return parse_xml(something)
  855.         else:
  856.             return parse_notation(something)
  857.     except KeyError, e:
  858.         raise Exception('LLSD could not be parsed: %s' % (e,))
  859. class LLSD(object):
  860.     def __init__(self, thing=None):
  861.         self.thing = thing
  862.     def __str__(self):
  863.         return self.toXML(self.thing)
  864.     parse = staticmethod(parse)
  865.     toXML = staticmethod(format_xml)
  866.     toPrettyXML = staticmethod(format_pretty_xml)
  867.     toBinary = staticmethod(format_binary)
  868.     toNotation = staticmethod(format_notation)
  869. undef = LLSD(None)
  870. XML_MIME_TYPE = 'application/llsd+xml'
  871. BINARY_MIME_TYPE = 'application/llsd+binary'
  872. # register converters for llsd in mulib, if it is available
  873. try:
  874.     from mulib import stacked, mu
  875.     stacked.NoProducer()  # just to exercise stacked
  876.     mu.safe_load(None)    # just to exercise mu
  877. except:
  878.     # mulib not available, don't print an error message since this is normal
  879.     pass
  880. else:
  881.     mu.add_parser(parse, XML_MIME_TYPE)
  882.     mu.add_parser(parse, 'application/llsd+binary')
  883.     def llsd_convert_xml(llsd_stuff, request):
  884.         request.write(format_xml(llsd_stuff))
  885.     def llsd_convert_binary(llsd_stuff, request):
  886.         request.write(format_binary(llsd_stuff))
  887.     for typ in [LLSD, dict, list, tuple, str, int, long, float, bool, unicode, type(None)]:
  888.         stacked.add_producer(typ, llsd_convert_xml, XML_MIME_TYPE)
  889.         stacked.add_producer(typ, llsd_convert_xml, 'application/xml')
  890.         stacked.add_producer(typ, llsd_convert_xml, 'text/xml')
  891.         stacked.add_producer(typ, llsd_convert_binary, 'application/llsd+binary')
  892.     stacked.add_producer(LLSD, llsd_convert_xml, '*/*')
  893.     # in case someone is using the legacy mu.xml wrapper, we need to
  894.     # tell mu to produce application/xml or application/llsd+xml
  895.     # (based on the accept header) from raw xml. Phoenix 2008-07-21
  896.     stacked.add_producer(mu.xml, mu.produce_raw, XML_MIME_TYPE)
  897.     stacked.add_producer(mu.xml, mu.produce_raw, 'application/xml')
  898. # mulib wsgi stuff
  899. # try:
  900. #     from mulib import mu, adapters
  901. #
  902. #     # try some known attributes from mulib to be ultra-sure we've imported it
  903. #     mu.get_current
  904. #     adapters.handlers
  905. # except:
  906. #     # mulib not available, don't print an error message since this is normal
  907. #     pass
  908. # else:
  909. #     def llsd_xml_handler(content_type):
  910. #         def handle_llsd_xml(env, start_response):
  911. #             llsd_stuff, _ = mu.get_current(env)
  912. #             result = format_xml(llsd_stuff)
  913. #             start_response("200 OK", [('Content-Type', content_type)])
  914. #             env['mu.negotiated_type'] = content_type
  915. #             yield result
  916. #         return handle_llsd_xml
  917. #    
  918. #     def llsd_binary_handler(content_type):
  919. #         def handle_llsd_binary(env, start_response):
  920. #             llsd_stuff, _ = mu.get_current(env)
  921. #             result = format_binary(llsd_stuff)
  922. #             start_response("200 OK", [('Content-Type', content_type)])
  923. #             env['mu.negotiated_type'] = content_type
  924. #             yield result
  925. #         return handle_llsd_binary
  926. #
  927. #     adapters.DEFAULT_PARSERS[XML_MIME_TYPE] = parse
  928.     
  929. #     for typ in [LLSD, dict, list, tuple, str, int, float, bool, unicode, type(None)]:
  930. #         for content_type in (XML_MIME_TYPE, 'application/xml'):
  931. #             adapters.handlers.set_handler(typ, llsd_xml_handler(content_type), content_type)
  932. #
  933. #         adapters.handlers.set_handler(typ, llsd_binary_handler(BINARY_MIME_TYPE), BINARY_MIME_TYPE)
  934. #
  935. #     adapters.handlers.set_handler(LLSD, llsd_xml_handler(XML_MIME_TYPE), '*/*')