]>
git.proxmox.com Git - ovs.git/blob - python/ovs/json.py
1 # Copyright (c) 2010, 2011, 2012 Nicira, Inc.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at:
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 from __future__
import absolute_import
30 __pychecker__
= 'no-stringiter'
33 dumper
= functools
.partial(json
.dumps
, separators
=(",", ":"))
36 def to_stream(obj
, stream
, pretty
=False, sort_keys
=True):
37 stream
.write(dumper(obj
, indent
=SPACES_PER_LEVEL
if pretty
else None,
41 def to_file(obj
, name
, pretty
=False, sort_keys
=True):
42 with
open(name
, "w") as stream
:
43 to_stream(obj
, stream
, pretty
, sort_keys
)
46 def to_string(obj
, pretty
=False, sort_keys
=True):
47 return dumper(obj
, indent
=SPACES_PER_LEVEL
if pretty
else None,
51 def from_stream(stream
):
52 p
= Parser(check_trailer
=True)
54 buf
= stream
.read(4096)
55 if buf
== "" or p
.feed(buf
) != len(buf
):
61 stream
= open(name
, "r")
63 return from_stream(stream
)
69 if not isinstance(s
, str):
70 # We assume the input is a string. We will only hit this case for a
71 # str in Python 2 which is not unicode, so we need to go ahead and
75 except UnicodeDecodeError as e
:
76 seq
= ' '.join(["0x%2x" % ord(c
)
77 for c
in e
.object[e
.start
:e
.end
] if ord(c
) >= 0x80])
78 return "not a valid UTF-8 string: invalid UTF-8 sequence %s" % seq
79 p
= Parser(check_trailer
=True)
85 # Maximum height of parsing stack. #
88 def __new__(cls
, *args
, **kwargs
):
89 if PARSER
== PARSER_C
:
90 return ovs
._json
.Parser(*args
, **kwargs
)
91 return super(Parser
, cls
).__new
__(cls
)
93 def __init__(self
, check_trailer
=False):
94 self
.check_trailer
= check_trailer
97 self
.lex_state
= Parser
.__lex
_start
100 self
.column_number
= 0
104 self
.parse_state
= Parser
.__parse
_start
106 self
.member_name
= None
112 def __lex_start_space(self
, c
):
115 def __lex_start_alpha(self
, c
):
117 self
.lex_state
= Parser
.__lex
_keyword
119 def __lex_start_token(self
, c
):
120 self
.__parser
_input
(c
)
122 def __lex_start_number(self
, c
):
124 self
.lex_state
= Parser
.__lex
_number
126 def __lex_start_string(self
, _
):
127 self
.lex_state
= Parser
.__lex
_string
129 def __lex_start_error(self
, c
):
130 if ord(c
) >= 32 and ord(c
) < 128:
131 self
.__error
("invalid character '%s'" % c
)
133 self
.__error
("invalid character U+%04x" % ord(c
))
135 __lex_start_actions
= {}
137 __lex_start_actions
[c
] = __lex_start_space
138 for c
in "abcdefghijklmnopqrstuvwxyz":
139 __lex_start_actions
[c
] = __lex_start_alpha
141 __lex_start_actions
[c
] = __lex_start_token
142 for c
in "-0123456789":
143 __lex_start_actions
[c
] = __lex_start_number
144 __lex_start_actions
['"'] = __lex_start_string
146 def __lex_start(self
, c
):
147 Parser
.__lex
_start
_actions
.get(
148 c
, Parser
.__lex
_start
_error
)(self
, c
)
152 for c
in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ":
153 __lex_alpha
[c
] = True
155 def __lex_finish_keyword(self
):
156 if self
.buffer == "false":
157 self
.__parser
_input
(False)
158 elif self
.buffer == "true":
159 self
.__parser
_input
(True)
160 elif self
.buffer == "null":
161 self
.__parser
_input
(None)
163 self
.__error
("invalid keyword '%s'" % self
.buffer)
165 def __lex_keyword(self
, c
):
166 if c
in Parser
.__lex
_alpha
:
170 self
.__lex
_finish
_keyword
()
173 __number_re
= re
.compile("(-)?(0|[1-9][0-9]*)"
174 r
"(?:\.([0-9]+))?(?:[eE]([-+]?[0-9]+))?$")
176 def __lex_finish_number(self
):
178 m
= Parser
.__number
_re
.match(s
)
180 sign
, integer
, fraction
, exp
= m
.groups()
181 if (exp
is not None and
182 (int(exp
) > sys
.maxsize
or int(exp
) < -sys
.maxsize
- 1)):
183 self
.__error
("exponent outside valid range")
186 if fraction
is not None and len(fraction
.lstrip('0')) == 0:
190 if fraction
is not None:
191 sig_string
+= fraction
192 significand
= int(sig_string
)
195 if fraction
is not None:
196 pow10
-= len(fraction
)
201 self
.__parser
_input
(0)
203 elif significand
<= 2 ** 63:
204 while pow10
> 0 and significand
<= 2 ** 63:
207 while pow10
< 0 and significand
% 10 == 0:
211 ((not sign
and significand
< 2 ** 63) or
212 (sign
and significand
<= 2 ** 63))):
214 self
.__parser
_input
(-significand
)
216 self
.__parser
_input
(significand
)
220 if value
== float("inf") or value
== float("-inf"):
221 self
.__error
("number outside valid range")
224 # Suppress negative zero.
226 self
.__parser
_input
(value
)
227 elif re
.match("-?0[0-9]", s
):
228 self
.__error
("leading zeros not allowed")
229 elif re
.match("-([^0-9]|$)", s
):
230 self
.__error
("'-' must be followed by digit")
231 elif re
.match(r
"-?(0|[1-9][0-9]*)\.([^0-9]|$)", s
):
232 self
.__error
("decimal point must be followed by digit")
233 elif re
.search("e[-+]?([^0-9]|$)", s
):
234 self
.__error
("exponent must contain at least one digit")
236 self
.__error
("syntax error in number")
238 def __lex_number(self
, c
):
239 if c
in ".0123456789eE-+":
243 self
.__lex
_finish
_number
()
246 __4hex_re
= re
.compile("[0-9a-fA-F]{4}")
248 def __lex_4hex(self
, s
):
250 self
.__error
("quoted string ends within \\u escape")
251 elif not Parser
.__4hex
_re
.match(s
):
252 self
.__error
("malformed \\u escape")
254 self
.__error
("null bytes not supported in quoted strings")
259 def __is_leading_surrogate(c
):
260 """Returns true if 'c' is a Unicode code point for a leading
262 return c
>= 0xd800 and c
<= 0xdbff
265 def __is_trailing_surrogate(c
):
266 """Returns true if 'c' is a Unicode code point for a trailing
268 return c
>= 0xdc00 and c
<= 0xdfff
271 def __utf16_decode_surrogate_pair(leading
, trailing
):
272 """Returns the unicode code point corresponding to leading surrogate
273 'leading' and trailing surrogate 'trailing'. The return value will not
274 make any sense if 'leading' or 'trailing' are not in the correct ranges
275 for leading or trailing surrogates."""
276 # Leading surrogate: 110110wwwwxxxxxx
277 # Trailing surrogate: 110111xxxxxxxxxx
278 # Code point: 000uuuuuxxxxxxxxxxxxxxxx
279 w
= (leading
>> 6) & 0xf
282 x1
= trailing
& 0x3ff
283 return (u
<< 16) |
(x0
<< 10) | x1
284 __unescape
= {'"': u
'"',
293 def __lex_finish_string(self
):
297 backslash
= inp
.find('\\')
301 out
+= inp
[:backslash
]
302 inp
= inp
[backslash
+ 1:]
304 self
.__error
("quoted string may not end with backslash")
307 replacement
= Parser
.__unescape
.get(inp
[0])
308 if replacement
is not None:
313 self
.__error
("bad escape \\%s" % inp
[0])
316 c0
= self
.__lex
_4hex
(inp
[1:5])
321 if Parser
.__is
_leading
_surrogate
(c0
):
322 if inp
[:2] != u
'\\u':
323 self
.__error
("malformed escaped surrogate pair")
325 c1
= self
.__lex
_4hex
(inp
[2:6])
328 if not Parser
.__is
_trailing
_surrogate
(c1
):
329 self
.__error
("second half of escaped surrogate pair is "
330 "not trailing surrogate")
332 code_point
= Parser
.__utf
16_decode
_surrogate
_pair
(c0
, c1
)
336 out
+= chr(code_point
)
337 self
.__parser
_input
('string', out
)
339 def __lex_string_escape(self
, c
):
341 self
.lex_state
= Parser
.__lex
_string
344 def __lex_string(self
, c
):
347 self
.lex_state
= Parser
.__lex
_string
_escape
349 self
.__lex
_finish
_string
()
353 self
.__error
("U+%04X must be escaped in quoted string" % ord(c
))
356 def __lex_input(self
, c
):
357 eat
= self
.lex_state(self
, c
)
358 assert eat
is True or eat
is False
361 def __parse_start(self
, token
, unused_string
):
367 self
.__error
("syntax error at beginning of input")
369 def __parse_end(self
, unused_token
, unused_string
):
370 self
.__error
("trailing garbage at end of input")
372 def __parse_object_init(self
, token
, string
):
376 self
.__parse
_object
_name
(token
, string
)
378 def __parse_object_name(self
, token
, string
):
379 if token
== 'string':
380 self
.member_name
= string
381 self
.parse_state
= Parser
.__parse
_object
_colon
383 self
.__error
("syntax error parsing object expecting string")
385 def __parse_object_colon(self
, token
, unused_string
):
387 self
.parse_state
= Parser
.__parse
_object
_value
389 self
.__error
("syntax error parsing object expecting ':'")
391 def __parse_object_value(self
, token
, string
):
392 self
.__parse
_value
(token
, string
, Parser
.__parse
_object
_next
)
394 def __parse_object_next(self
, token
, unused_string
):
396 self
.parse_state
= Parser
.__parse
_object
_name
400 self
.__error
("syntax error expecting '}' or ','")
402 def __parse_array_init(self
, token
, string
):
406 self
.__parse
_array
_value
(token
, string
)
408 def __parse_array_value(self
, token
, string
):
409 self
.__parse
_value
(token
, string
, Parser
.__parse
_array
_next
)
411 def __parse_array_next(self
, token
, unused_string
):
413 self
.parse_state
= Parser
.__parse
_array
_value
417 self
.__error
("syntax error expecting ']' or ','")
419 def __parser_input(self
, token
, string
=None):
420 self
.lex_state
= Parser
.__lex
_start
422 self
.parse_state(self
, token
, string
)
424 def __put_value(self
, value
):
426 if isinstance(top
, dict):
427 top
[self
.member_name
] = value
431 def __parser_push(self
, new_json
, next_state
):
432 if len(self
.stack
) < Parser
.MAX_HEIGHT
:
433 if len(self
.stack
) > 0:
434 self
.__put
_value
(new_json
)
435 self
.stack
.append(new_json
)
436 self
.parse_state
= next_state
438 self
.__error
("input exceeds maximum nesting depth %d" %
441 def __push_object(self
):
442 self
.__parser
_push
({}, Parser
.__parse
_object
_init
)
444 def __push_array(self
):
445 self
.__parser
_push
([], Parser
.__parse
_array
_init
)
447 def __parser_pop(self
):
448 if len(self
.stack
) == 1:
449 self
.parse_state
= Parser
.__parse
_end
450 if not self
.check_trailer
:
455 if isinstance(top
, list):
456 self
.parse_state
= Parser
.__parse
_array
_next
458 self
.parse_state
= Parser
.__parse
_object
_next
460 def __parse_value(self
, token
, string
, next_state
):
462 number_types
.extend([float])
463 number_types
= tuple(number_types
)
464 if token
in [False, None, True] or isinstance(token
, number_types
):
465 self
.__put
_value
(token
)
466 elif token
== 'string':
467 self
.__put
_value
(string
)
474 self
.__error
("syntax error expecting value")
476 self
.parse_state
= next_state
478 def __error(self
, message
):
479 if self
.error
is None:
480 self
.error
= ("line %d, column %d, byte %d: %s"
481 % (self
.line_number
, self
.column_number
,
482 self
.byte_number
, message
))
488 if self
.done
or i
>= len(s
):
492 if self
.__lex
_input
(c
):
493 self
.byte_number
+= 1
495 self
.column_number
= 0
496 self
.line_number
+= 1
498 self
.column_number
+= 1
506 if self
.lex_state
== Parser
.__lex
_start
:
508 elif self
.lex_state
in (Parser
.__lex
_string
,
509 Parser
.__lex
_string
_escape
):
510 self
.__error
("unexpected end of input in quoted string")
512 self
.__lex
_input
(" ")
514 if self
.parse_state
== Parser
.__parse
_start
:
515 self
.__error
("empty input stream")
516 elif self
.parse_state
!= Parser
.__parse
_end
:
517 self
.__error
("unexpected end of input")
519 if self
.error
is None:
520 assert len(self
.stack
) == 1
521 return self
.stack
.pop()