first commit
[bitcoin:spesmilo.git] / jsonrpc / json.py
1
2 """
3   Copyright (c) 2007 Jan-Klaas Kollhof
4
5   This file is part of jsonrpc.
6
7   jsonrpc is free software; you can redistribute it and/or modify
8   it under the terms of the GNU Lesser General Public License as published by
9   the Free Software Foundation; either version 2.1 of the License, or
10   (at your option) any later version.
11
12   This software is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU Lesser General Public License for more details.
16
17   You should have received a copy of the GNU Lesser General Public License
18   along with this software; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 """
21
22 from types import *
23 import re
24
25 CharReplacements ={
26         '\t': '\\t',
27         '\b': '\\b',
28         '\f': '\\f',
29         '\n': '\\n',
30         '\r': '\\r',
31         '\\': '\\\\',
32         '/': '\\/',
33         '"': '\\"'}
34
35 EscapeCharToChar = {
36         't': '\t',
37         'b': '\b',
38         'f': '\f',
39         'n': '\n',
40         'r': '\r',
41         '\\': '\\',
42         '/': '/',
43         '"' : '"'}
44
45 StringEscapeRE= re.compile(r'[\x00-\x19\\"/\b\f\n\r\t]')
46 Digits = ['0', '1', '2','3','4','5','6','7','8','9']
47
48
49 class JSONEncodeException(Exception):
50     def __init__(self, obj):
51         Exception.__init__(self)
52         self.obj = obj
53
54     def __str__(self):
55        return "Object not encodeable: %s" % self.obj
56
57        
58 class JSONDecodeException(Exception):
59     def __init__(self, message):
60         Exception.__init__(self)
61         self.message = message
62
63     def __str__(self):
64        return self.message
65
66     
67 def escapeChar(match):
68     c=match.group(0)
69     try:
70         replacement = CharReplacements[c]
71         return replacement
72     except KeyError:
73         d = ord(c)
74         if d < 32:
75             return '\\u%04x' % d
76         else:
77             return c
78
79 def dumps(obj):
80     return unicode("".join([part for part in dumpParts (obj)]))
81
82 def dumpParts (obj):
83     objType = type(obj)
84     if obj == None:
85        yield u'null'
86     elif objType is BooleanType:
87         if obj:
88             yield u'true'
89         else:
90             yield u'false'
91     elif objType is DictionaryType:
92         yield u'{'
93         isFirst=True
94         for (key, value) in obj.items():
95             if isFirst:
96                 isFirst=False
97             else:
98                 yield u","
99             yield u'"' + StringEscapeRE.sub(escapeChar, key) +u'":'
100             for part in dumpParts (value):
101                 yield part
102         yield u'}'
103     elif objType in StringTypes:
104         yield u'"' + StringEscapeRE.sub(escapeChar, obj) +u'"'
105
106     elif objType in [TupleType, ListType, GeneratorType]:
107         yield u'['
108         isFirst=True
109         for item in obj:
110             if isFirst:
111                 isFirst=False
112             else:
113                 yield u","
114             for part in dumpParts (item):
115                 yield part
116         yield u']'
117     elif objType in [IntType, LongType, FloatType]:
118         yield unicode(obj)
119     else:
120         raise JSONEncodeException(obj)
121     
122
123 def loads(s):
124     stack = []
125     chars = iter(s)
126     value = None
127     currCharIsNext=False
128
129     try:
130         while(1):
131             skip = False
132             if not currCharIsNext:
133                 c = chars.next()
134             while(c in [' ', '\t', '\r','\n']):
135                 c = chars.next()
136             currCharIsNext=False
137             if c=='"':
138                 value = ''
139                 try:
140                     c=chars.next()
141                     while c != '"':
142                         if c == '\\':
143                             c=chars.next()
144                             try:
145                                 value+=EscapeCharToChar[c]
146                             except KeyError:
147                                 if c == 'u':
148                                     hexCode = chars.next() + chars.next() + chars.next() + chars.next()
149                                     value += unichr(int(hexCode,16))
150                                 else:
151                                     raise JSONDecodeException("Bad Escape Sequence Found")
152                         else:
153                             value+=c
154                         c=chars.next()
155                 except StopIteration:
156                     raise JSONDecodeException("Expected end of String")
157             elif c == '{':
158                 stack.append({})
159                 skip=True
160             elif c =='}':
161                 value = stack.pop()
162             elif c == '[':
163                 stack.append([])
164                 skip=True
165             elif c == ']':
166                 value = stack.pop()
167             elif c in [',',':']:
168                 skip=True
169             elif c in Digits or c == '-':
170                 digits=[c]
171                 c = chars.next()
172                 numConv = int
173                 try:
174                     while c in Digits:
175                         digits.append(c)
176                         c = chars.next()
177                     if c == ".":
178                         numConv=float
179                         digits.append(c)
180                         c = chars.next()
181                         while c in Digits:
182                             digits.append(c)
183                             c = chars.next()
184                         if c.upper() == 'E':
185                             digits.append(c)
186                             c = chars.next()
187                             if c in ['+','-']:
188                                 digits.append(c)
189                                 c = chars.next()
190                                 while c in Digits:
191                                     digits.append(c)
192                                     c = chars.next()
193                             else:
194                                 raise JSONDecodeException("Expected + or -")
195                 except StopIteration:
196                     pass
197                 value = numConv("".join(digits))
198                 currCharIsNext=True
199
200             elif c in ['t','f','n']:
201                 kw = c+ chars.next() + chars.next() + chars.next()
202                 if kw == 'null':
203                     value = None
204                 elif kw == 'true':
205                     value = True
206                 elif kw == 'fals' and chars.next() == 'e':
207                     value = False
208                 else:
209                     raise JSONDecodeException('Expected Null, False or True')
210             else:
211                 raise JSONDecodeException('Expected []{}," or Number, Null, False or True')
212
213             if not skip:
214                 if len(stack):
215                     top = stack[-1]
216                     if type(top) is ListType:
217                         top.append(value)
218                     elif type(top) is DictionaryType:
219                         stack.append(value)
220                     elif type(top)  in StringTypes:
221                         key = stack.pop()
222                         stack[-1][key] = value
223                     else:
224                         raise JSONDecodeException("Expected dictionary key, or start of a value")
225                 else:
226                     return value
227     except StopIteration:
228          raise JSONDecodeException("Unexpected end of JSON source")
229
230