PageRenderTime 59ms CodeModel.GetById 10ms app.highlight 43ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/lib/python/indra/ipc/xml_rpc.py

https://bitbucket.org/lindenlab/viewer-beta/
Python | 273 lines | 264 code | 0 blank | 9 comment | 0 complexity | a1f9cb481b3c9dd01a6b2fc2f03969ad MD5 | raw file
  1"""\
  2@file xml_rpc.py
  3@brief An implementation of a parser/generator for the XML-RPC xml format.
  4
  5$LicenseInfo:firstyear=2006&license=mit$
  6
  7Copyright (c) 2006-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
 29
 30from greenlet import greenlet
 31
 32from mulib import mu
 33
 34from xml.sax import handler
 35from xml.sax import parseString
 36
 37
 38# States
 39class Expected(object):
 40    def __init__(self, tag):
 41        self.tag = tag
 42
 43    def __getattr__(self, name):
 44        return type(self)(name)
 45
 46    def __repr__(self):
 47        return '%s(%r)' % (
 48            type(self).__name__, self.tag)
 49
 50
 51class START(Expected):
 52    pass
 53
 54
 55class END(Expected):
 56    pass
 57
 58
 59class STR(object):
 60    tag = ''
 61
 62
 63START = START('')
 64END = END('')
 65
 66
 67class Malformed(Exception):
 68    pass
 69
 70
 71class XMLParser(handler.ContentHandler):
 72    def __init__(self, state_machine, next_states):
 73        handler.ContentHandler.__init__(self)
 74        self.state_machine = state_machine
 75        if not isinstance(next_states, tuple):
 76            next_states = (next_states, )
 77        self.next_states = next_states
 78        self._character_buffer = ''
 79
 80    def assertState(self, state, name, *rest):
 81        if not isinstance(self.next_states, tuple):
 82            self.next_states = (self.next_states, )
 83        for next in self.next_states:
 84            if type(state) == type(next):
 85                if next.tag and next.tag != name:
 86                    raise Malformed(
 87                        "Expected %s, got %s %s %s" % (
 88                            next, state, name, rest))
 89                break
 90        else:
 91            raise Malformed(
 92                "Expected %s, got %s %s %s" % (
 93                    self.next_states, state, name, rest))
 94
 95    def startElement(self, name, attrs):
 96        self.assertState(START, name.lower(), attrs)
 97        self.next_states = self.state_machine.switch(START, (name.lower(), dict(attrs)))
 98
 99    def endElement(self, name):
100        if self._character_buffer.strip():
101            characters = self._character_buffer.strip()
102            self._character_buffer = ''
103            self.assertState(STR, characters)
104            self.next_states = self.state_machine.switch(characters)
105        self.assertState(END, name.lower())
106        self.next_states = self.state_machine.switch(END, name.lower())
107
108    def error(self, exc):
109        self.bozo = 1
110        self.exc = exc
111
112    def fatalError(self, exc):
113        self.error(exc)
114        raise exc
115
116    def characters(self, characters):
117        self._character_buffer += characters
118
119
120def parse(what):
121    child = greenlet(xml_rpc)
122    me = greenlet.getcurrent()
123    startup_states = child.switch(me)
124    parser = XMLParser(child, startup_states)
125    try:
126        parseString(what, parser)
127    except Malformed:
128        print what
129        raise
130    return child.switch()
131
132
133def xml_rpc(yielder):
134    yielder.switch(START.methodcall)
135    yielder.switch(START.methodname)
136    methodName = yielder.switch(STR)
137    yielder.switch(END.methodname)
138
139    yielder.switch(START.params)
140
141    root = None
142    params = []
143    while True:
144        state, _ = yielder.switch(START.param, END.params)
145        if state == END:
146            break
147
148        yielder.switch(START.value)
149        
150        params.append(
151            handle(yielder))
152
153        yielder.switch(END.value)
154        yielder.switch(END.param)
155
156    yielder.switch(END.methodcall)
157    ## Resume parse
158    yielder.switch()
159    ## Return result to parse
160    return methodName.strip(), params
161
162
163def handle(yielder):
164    _, (tag, attrs) = yielder.switch(START)
165    if tag in ['int', 'i4']:
166        result = int(yielder.switch(STR))
167    elif tag == 'boolean':
168        result = bool(int(yielder.switch(STR)))
169    elif tag == 'string':
170        result = yielder.switch(STR)
171    elif tag == 'double':
172        result = float(yielder.switch(STR))
173    elif tag == 'datetime.iso8601':
174        result = yielder.switch(STR)
175    elif tag == 'base64':
176        result = base64.b64decode(yielder.switch(STR))
177    elif tag == 'struct':
178        result = {}
179        while True:
180            state, _ = yielder.switch(START.member, END.struct)
181            if state == END:
182                break
183
184            yielder.switch(START.name)
185            key = yielder.switch(STR)
186            yielder.switch(END.name)
187
188            yielder.switch(START.value)
189            result[key] = handle(yielder)
190            yielder.switch(END.value)
191
192            yielder.switch(END.member)
193        ## We already handled </struct> above, don't want to handle it below
194        return result
195    elif tag == 'array':
196        result = []
197        yielder.switch(START.data)
198        while True:
199            state, _ = yielder.switch(START.value, END.data)
200            if state == END:
201                break
202
203            result.append(handle(yielder))
204
205            yielder.switch(END.value)
206
207    yielder.switch(getattr(END, tag))
208
209    return result
210
211
212VALUE = mu.tag_factory('value')
213BOOLEAN = mu.tag_factory('boolean')
214INT = mu.tag_factory('int')
215STRUCT = mu.tag_factory('struct')
216MEMBER = mu.tag_factory('member')
217NAME = mu.tag_factory('name')
218ARRAY = mu.tag_factory('array')
219DATA = mu.tag_factory('data')
220STRING = mu.tag_factory('string')
221DOUBLE = mu.tag_factory('double')
222METHODRESPONSE = mu.tag_factory('methodResponse')
223PARAMS = mu.tag_factory('params')
224PARAM = mu.tag_factory('param')
225
226mu.inline_elements['string'] = True
227mu.inline_elements['boolean'] = True
228mu.inline_elements['name'] = True
229
230
231def _generate(something):
232    if isinstance(something, dict):
233        result = STRUCT()
234        for key, value in something.items():
235            result[
236                MEMBER[
237                    NAME[key], _generate(value)]]
238        return VALUE[result]
239    elif isinstance(something, list):
240        result = DATA()
241        for item in something:
242            result[_generate(item)]
243        return VALUE[ARRAY[[result]]]
244    elif isinstance(something, basestring):
245        return VALUE[STRING[something]]
246    elif isinstance(something, bool):
247        if something:
248            return VALUE[BOOLEAN['1']]
249        return VALUE[BOOLEAN['0']]
250    elif isinstance(something, int):
251        return VALUE[INT[something]]
252    elif isinstance(something, float):
253        return VALUE[DOUBLE[something]]
254
255def generate(*args):
256    params = PARAMS()
257    for arg in args:
258        params[PARAM[_generate(arg)]]
259    return METHODRESPONSE[params]
260
261
262if __name__ == '__main__':
263    print parse("""<?xml version="1.0"?> <methodCall>  <methodName>examples.getStateName</methodName>  <params>  <param>  <value><i4>41</i4></value>  </param>  </params>  </methodCall>
264""")
265    
266        
267        
268        
269        
270        
271        
272        
273