]>
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
32 __pychecker__
= 'no-stringiter'
35 _dumper
= functools
.partial(json
.dumps
, separators
=(",", ":"))
38 def dumper(*args
, **kwargs
):
39 return _dumper(*args
, **kwargs
).decode('raw-unicode-escape')
44 def to_stream(obj
, stream
, pretty
=False, sort_keys
=True):
45 stream
.write(dumper(obj
, indent
=SPACES_PER_LEVEL
if pretty
else None,
49 def to_file(obj
, name
, pretty
=False, sort_keys
=True):
50 with
open(name
, "w") as stream
:
51 to_stream(obj
, stream
, pretty
, sort_keys
)
54 def to_string(obj
, pretty
=False, sort_keys
=True):
55 return dumper(obj
, indent
=SPACES_PER_LEVEL
if pretty
else None,
59 def from_stream(stream
):
60 p
= Parser(check_trailer
=True)
62 buf
= stream
.read(4096)
63 if buf
== "" or p
.feed(buf
) != len(buf
):
69 stream
= open(name
, "r")
71 return from_stream(stream
)
77 if not isinstance(s
, six
.text_type
):
78 # We assume the input is a string. We will only hit this case for a
79 # str in Python 2 which is not unicode, so we need to go ahead and
82 s
= six
.text_type(s
, 'utf-8')
83 except UnicodeDecodeError as e
:
84 seq
= ' '.join(["0x%2x" % ord(c
)
85 for c
in e
.object[e
.start
:e
.end
] if ord(c
) >= 0x80])
86 return "not a valid UTF-8 string: invalid UTF-8 sequence %s" % seq
87 p
= Parser(check_trailer
=True)
93 # Maximum height of parsing stack. #
96 def __new__(cls
, *args
, **kwargs
):
97 if PARSER
== PARSER_C
:
98 return ovs
._json
.Parser(*args
, **kwargs
)
99 return super(Parser
, cls
).__new
__(cls
)
101 def __init__(self
, check_trailer
=False):
102 self
.check_trailer
= check_trailer
105 self
.lex_state
= Parser
.__lex
_start
108 self
.column_number
= 0
112 self
.parse_state
= Parser
.__parse
_start
114 self
.member_name
= None
120 def __lex_start_space(self
, c
):
123 def __lex_start_alpha(self
, c
):
125 self
.lex_state
= Parser
.__lex
_keyword
127 def __lex_start_token(self
, c
):
128 self
.__parser
_input
(c
)
130 def __lex_start_number(self
, c
):
132 self
.lex_state
= Parser
.__lex
_number
134 def __lex_start_string(self
, _
):
135 self
.lex_state
= Parser
.__lex
_string
137 def __lex_start_error(self
, c
):
138 if ord(c
) >= 32 and ord(c
) < 128:
139 self
.__error
("invalid character '%s'" % c
)
141 self
.__error
("invalid character U+%04x" % ord(c
))
143 __lex_start_actions
= {}
145 __lex_start_actions
[c
] = __lex_start_space
146 for c
in "abcdefghijklmnopqrstuvwxyz":
147 __lex_start_actions
[c
] = __lex_start_alpha
149 __lex_start_actions
[c
] = __lex_start_token
150 for c
in "-0123456789":
151 __lex_start_actions
[c
] = __lex_start_number
152 __lex_start_actions
['"'] = __lex_start_string
154 def __lex_start(self
, c
):
155 Parser
.__lex
_start
_actions
.get(
156 c
, Parser
.__lex
_start
_error
)(self
, c
)
160 for c
in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ":
161 __lex_alpha
[c
] = True
163 def __lex_finish_keyword(self
):
164 if self
.buffer == "false":
165 self
.__parser
_input
(False)
166 elif self
.buffer == "true":
167 self
.__parser
_input
(True)
168 elif self
.buffer == "null":
169 self
.__parser
_input
(None)
171 self
.__error
("invalid keyword '%s'" % self
.buffer)
173 def __lex_keyword(self
, c
):
174 if c
in Parser
.__lex
_alpha
:
178 self
.__lex
_finish
_keyword
()
181 __number_re
= re
.compile("(-)?(0|[1-9][0-9]*)"
182 "(?:\.([0-9]+))?(?:[eE]([-+]?[0-9]+))?$")
184 def __lex_finish_number(self
):
186 m
= Parser
.__number
_re
.match(s
)
188 sign
, integer
, fraction
, exp
= m
.groups()
189 if (exp
is not None and
190 (int(exp
) > sys
.maxsize
or int(exp
) < -sys
.maxsize
- 1)):
191 self
.__error
("exponent outside valid range")
194 if fraction
is not None and len(fraction
.lstrip('0')) == 0:
198 if fraction
is not None:
199 sig_string
+= fraction
200 significand
= int(sig_string
)
203 if fraction
is not None:
204 pow10
-= len(fraction
)
209 self
.__parser
_input
(0)
211 elif significand
<= 2 ** 63:
212 while pow10
> 0 and significand
<= 2 ** 63:
215 while pow10
< 0 and significand
% 10 == 0:
219 ((not sign
and significand
< 2 ** 63) or
220 (sign
and significand
<= 2 ** 63))):
222 self
.__parser
_input
(-significand
)
224 self
.__parser
_input
(significand
)
228 if value
== float("inf") or value
== float("-inf"):
229 self
.__error
("number outside valid range")
232 # Suppress negative zero.
234 self
.__parser
_input
(value
)
235 elif re
.match("-?0[0-9]", s
):
236 self
.__error
("leading zeros not allowed")
237 elif re
.match("-([^0-9]|$)", s
):
238 self
.__error
("'-' must be followed by digit")
239 elif re
.match("-?(0|[1-9][0-9]*)\.([^0-9]|$)", s
):
240 self
.__error
("decimal point must be followed by digit")
241 elif re
.search("e[-+]?([^0-9]|$)", s
):
242 self
.__error
("exponent must contain at least one digit")
244 self
.__error
("syntax error in number")
246 def __lex_number(self
, c
):
247 if c
in ".0123456789eE-+":
251 self
.__lex
_finish
_number
()
254 __4hex_re
= re
.compile("[0-9a-fA-F]{4}")
256 def __lex_4hex(self
, s
):
258 self
.__error
("quoted string ends within \\u escape")
259 elif not Parser
.__4hex
_re
.match(s
):
260 self
.__error
("malformed \\u escape")
262 self
.__error
("null bytes not supported in quoted strings")
267 def __is_leading_surrogate(c
):
268 """Returns true if 'c' is a Unicode code point for a leading
270 return c
>= 0xd800 and c
<= 0xdbff
273 def __is_trailing_surrogate(c
):
274 """Returns true if 'c' is a Unicode code point for a trailing
276 return c
>= 0xdc00 and c
<= 0xdfff
279 def __utf16_decode_surrogate_pair(leading
, trailing
):
280 """Returns the unicode code point corresponding to leading surrogate
281 'leading' and trailing surrogate 'trailing'. The return value will not
282 make any sense if 'leading' or 'trailing' are not in the correct ranges
283 for leading or trailing surrogates."""
284 # Leading surrogate: 110110wwwwxxxxxx
285 # Trailing surrogate: 110111xxxxxxxxxx
286 # Code point: 000uuuuuxxxxxxxxxxxxxxxx
287 w
= (leading
>> 6) & 0xf
290 x1
= trailing
& 0x3ff
291 return (u
<< 16) |
(x0
<< 10) | x1
292 __unescape
= {'"': u
'"',
301 def __lex_finish_string(self
):
305 backslash
= inp
.find('\\')
309 out
+= inp
[:backslash
]
310 inp
= inp
[backslash
+ 1:]
312 self
.__error
("quoted string may not end with backslash")
315 replacement
= Parser
.__unescape
.get(inp
[0])
316 if replacement
is not None:
321 self
.__error
("bad escape \\%s" % inp
[0])
324 c0
= self
.__lex
_4hex
(inp
[1:5])
329 if Parser
.__is
_leading
_surrogate
(c0
):
330 if inp
[:2] != u
'\\u':
331 self
.__error
("malformed escaped surrogate pair")
333 c1
= self
.__lex
_4hex
(inp
[2:6])
336 if not Parser
.__is
_trailing
_surrogate
(c1
):
337 self
.__error
("second half of escaped surrogate pair is "
338 "not trailing surrogate")
340 code_point
= Parser
.__utf
16_decode
_surrogate
_pair
(c0
, c1
)
344 out
+= six
.unichr(code_point
)
345 self
.__parser
_input
('string', out
)
347 def __lex_string_escape(self
, c
):
349 self
.lex_state
= Parser
.__lex
_string
352 def __lex_string(self
, c
):
355 self
.lex_state
= Parser
.__lex
_string
_escape
357 self
.__lex
_finish
_string
()
361 self
.__error
("U+%04X must be escaped in quoted string" % ord(c
))
364 def __lex_input(self
, c
):
365 eat
= self
.lex_state(self
, c
)
366 assert eat
is True or eat
is False
369 def __parse_start(self
, token
, unused_string
):
375 self
.__error
("syntax error at beginning of input")
377 def __parse_end(self
, unused_token
, unused_string
):
378 self
.__error
("trailing garbage at end of input")
380 def __parse_object_init(self
, token
, string
):
384 self
.__parse
_object
_name
(token
, string
)
386 def __parse_object_name(self
, token
, string
):
387 if token
== 'string':
388 self
.member_name
= string
389 self
.parse_state
= Parser
.__parse
_object
_colon
391 self
.__error
("syntax error parsing object expecting string")
393 def __parse_object_colon(self
, token
, unused_string
):
395 self
.parse_state
= Parser
.__parse
_object
_value
397 self
.__error
("syntax error parsing object expecting ':'")
399 def __parse_object_value(self
, token
, string
):
400 self
.__parse
_value
(token
, string
, Parser
.__parse
_object
_next
)
402 def __parse_object_next(self
, token
, unused_string
):
404 self
.parse_state
= Parser
.__parse
_object
_name
408 self
.__error
("syntax error expecting '}' or ','")
410 def __parse_array_init(self
, token
, string
):
414 self
.__parse
_array
_value
(token
, string
)
416 def __parse_array_value(self
, token
, string
):
417 self
.__parse
_value
(token
, string
, Parser
.__parse
_array
_next
)
419 def __parse_array_next(self
, token
, unused_string
):
421 self
.parse_state
= Parser
.__parse
_array
_value
425 self
.__error
("syntax error expecting ']' or ','")
427 def __parser_input(self
, token
, string
=None):
428 self
.lex_state
= Parser
.__lex
_start
430 self
.parse_state(self
, token
, string
)
432 def __put_value(self
, value
):
434 if isinstance(top
, dict):
435 top
[self
.member_name
] = value
439 def __parser_push(self
, new_json
, next_state
):
440 if len(self
.stack
) < Parser
.MAX_HEIGHT
:
441 if len(self
.stack
) > 0:
442 self
.__put
_value
(new_json
)
443 self
.stack
.append(new_json
)
444 self
.parse_state
= next_state
446 self
.__error
("input exceeds maximum nesting depth %d" %
449 def __push_object(self
):
450 self
.__parser
_push
({}, Parser
.__parse
_object
_init
)
452 def __push_array(self
):
453 self
.__parser
_push
([], Parser
.__parse
_array
_init
)
455 def __parser_pop(self
):
456 if len(self
.stack
) == 1:
457 self
.parse_state
= Parser
.__parse
_end
458 if not self
.check_trailer
:
463 if isinstance(top
, list):
464 self
.parse_state
= Parser
.__parse
_array
_next
466 self
.parse_state
= Parser
.__parse
_object
_next
468 def __parse_value(self
, token
, string
, next_state
):
469 number_types
= list(six
.integer_types
)
470 number_types
.extend([float])
471 number_types
= tuple(number_types
)
472 if token
in [False, None, True] or isinstance(token
, number_types
):
473 self
.__put
_value
(token
)
474 elif token
== 'string':
475 self
.__put
_value
(string
)
482 self
.__error
("syntax error expecting value")
484 self
.parse_state
= next_state
486 def __error(self
, message
):
487 if self
.error
is None:
488 self
.error
= ("line %d, column %d, byte %d: %s"
489 % (self
.line_number
, self
.column_number
,
490 self
.byte_number
, message
))
496 if self
.done
or i
>= len(s
):
500 if self
.__lex
_input
(c
):
501 self
.byte_number
+= 1
503 self
.column_number
= 0
504 self
.line_number
+= 1
506 self
.column_number
+= 1
514 if self
.lex_state
== Parser
.__lex
_start
:
516 elif self
.lex_state
in (Parser
.__lex
_string
,
517 Parser
.__lex
_string
_escape
):
518 self
.__error
("unexpected end of input in quoted string")
520 self
.__lex
_input
(" ")
522 if self
.parse_state
== Parser
.__parse
_start
:
523 self
.__error
("empty input stream")
524 elif self
.parse_state
!= Parser
.__parse
_end
:
525 self
.__error
("unexpected end of input")
527 if self
.error
is None:
528 assert len(self
.stack
) == 1
529 return self
.stack
.pop()