summaryrefslogtreecommitdiff
path: root/lib/json/pure/parser.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/json/pure/parser.rb')
-rw-r--r--lib/json/pure/parser.rb144
1 files changed, 89 insertions, 55 deletions
diff --git a/lib/json/pure/parser.rb b/lib/json/pure/parser.rb
index d612018..e24aac1 100644
--- a/lib/json/pure/parser.rb
+++ b/lib/json/pure/parser.rb
@@ -68,42 +68,12 @@ module JSON
# defaults to true.
# * *object_class*: Defaults to Hash
# * *array_class*: Defaults to Array
+ # * *quirks_mode*: Enables quirks_mode for parser, that is for example
+ # parsing single JSON values instead of documents is possible.
def initialize(source, opts = {})
opts ||= {}
- if defined?(::Encoding)
- if source.encoding == ::Encoding::ASCII_8BIT
- b = source[0, 4].bytes.to_a
- source = case
- when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
- source.dup.force_encoding(::Encoding::UTF_32BE).encode!(::Encoding::UTF_8)
- when b.size >= 4 && b[0] == 0 && b[2] == 0
- source.dup.force_encoding(::Encoding::UTF_16BE).encode!(::Encoding::UTF_8)
- when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
- source.dup.force_encoding(::Encoding::UTF_32LE).encode!(::Encoding::UTF_8)
-
- when b.size >= 4 && b[1] == 0 && b[3] == 0
- source.dup.force_encoding(::Encoding::UTF_16LE).encode!(::Encoding::UTF_8)
- else
- source.dup
- end
- else
- source = source.encode(::Encoding::UTF_8)
- end
- source.force_encoding(::Encoding::ASCII_8BIT)
- else
- b = source
- source = case
- when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
- JSON.iconv('utf-8', 'utf-32be', b)
- when b.size >= 4 && b[0] == 0 && b[2] == 0
- JSON.iconv('utf-8', 'utf-16be', b)
- when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
- JSON.iconv('utf-8', 'utf-32le', b)
- when b.size >= 4 && b[1] == 0 && b[3] == 0
- JSON.iconv('utf-8', 'utf-16le', b)
- else
- b
- end
+ unless @quirks_mode = opts[:quirks_mode]
+ source = determine_encoding source
end
super source
if !opts.key?(:max_nesting) # defaults to 19
@@ -113,44 +83,108 @@ module JSON
else
@max_nesting = 0
end
- @allow_nan = !!opts[:allow_nan]
- @symbolize_names = !!opts[:symbolize_names]
- @create_additions = opts.key?(:create_additions) ? !!opts[:create_additions] : true
- @create_id = opts[:create_id] || JSON.create_id
- @object_class = opts[:object_class] || Hash
- @array_class = opts[:array_class] || Array
- @match_string = opts[:match_string]
+ @allow_nan = !!opts[:allow_nan]
+ @symbolize_names = !!opts[:symbolize_names]
+ if opts.key?(:create_additions)
+ @create_additions = !!opts[:create_additions]
+ else
+ @create_additions = true
+ end
+ @create_id = @create_additions ? JSON.create_id : nil
+ @object_class = opts[:object_class] || Hash
+ @array_class = opts[:array_class] || Array
+ @match_string = opts[:match_string]
end
alias source string
+ def quirks_mode?
+ !!@quirks_mode
+ end
+
+ def reset
+ super
+ @current_nesting = 0
+ end
+
# Parses the current JSON string _source_ and returns the complete data
# structure as a result.
def parse
reset
obj = nil
- until eos?
- case
- when scan(OBJECT_OPEN)
- obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
- @current_nesting = 1
- obj = parse_object
- when scan(ARRAY_OPEN)
- obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
- @current_nesting = 1
- obj = parse_array
- when skip(IGNORE)
- ;
+ if @quirks_mode
+ while !eos? && skip(IGNORE)
+ end
+ if eos?
+ raise ParserError, "source did not contain any JSON!"
else
- raise ParserError, "source '#{peek(20)}' not in JSON!"
+ obj = parse_value
+ obj == UNPARSED and raise ParserError, "source did not contain any JSON!"
end
+ else
+ until eos?
+ case
+ when scan(OBJECT_OPEN)
+ obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
+ @current_nesting = 1
+ obj = parse_object
+ when scan(ARRAY_OPEN)
+ obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
+ @current_nesting = 1
+ obj = parse_array
+ when skip(IGNORE)
+ ;
+ else
+ raise ParserError, "source '#{peek(20)}' not in JSON!"
+ end
+ end
+ obj or raise ParserError, "source did not contain any JSON!"
end
- obj or raise ParserError, "source did not contain any JSON!"
obj
end
private
+ def determine_encoding(source)
+ if defined?(::Encoding)
+ if source.encoding == ::Encoding::ASCII_8BIT
+ b = source[0, 4].bytes.to_a
+ source =
+ case
+ when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
+ source.dup.force_encoding(::Encoding::UTF_32BE).encode!(::Encoding::UTF_8)
+ when b.size >= 4 && b[0] == 0 && b[2] == 0
+ source.dup.force_encoding(::Encoding::UTF_16BE).encode!(::Encoding::UTF_8)
+ when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
+ source.dup.force_encoding(::Encoding::UTF_32LE).encode!(::Encoding::UTF_8)
+ when b.size >= 4 && b[1] == 0 && b[3] == 0
+ source.dup.force_encoding(::Encoding::UTF_16LE).encode!(::Encoding::UTF_8)
+ else
+ source.dup
+ end
+ else
+ source = source.encode(::Encoding::UTF_8)
+ end
+ source.force_encoding(::Encoding::ASCII_8BIT)
+ else
+ b = source
+ source =
+ case
+ when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
+ JSON.iconv('utf-8', 'utf-32be', b)
+ when b.size >= 4 && b[0] == 0 && b[2] == 0
+ JSON.iconv('utf-8', 'utf-16be', b)
+ when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
+ JSON.iconv('utf-8', 'utf-32le', b)
+ when b.size >= 4 && b[1] == 0 && b[3] == 0
+ JSON.iconv('utf-8', 'utf-16le', b)
+ else
+ b
+ end
+ end
+ source
+ end
+
# Unescape characters in strings.
UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr }
UNESCAPE_MAP.update({