diff options
-rw-r--r-- | lib/ffi_yajl.rb | 58 | ||||
-rw-r--r-- | lib/ffi_yajl/ffi/encoder.rb | 57 | ||||
-rw-r--r-- | spec/ffi_yajl/json_gem_spec.rb | 1 |
3 files changed, 82 insertions, 34 deletions
diff --git a/lib/ffi_yajl.rb b/lib/ffi_yajl.rb index 40c26e4..05090d7 100644 --- a/lib/ffi_yajl.rb +++ b/lib/ffi_yajl.rb @@ -30,6 +30,25 @@ module FFI_Yajl @opts = opts end + def self.raise_error_for_status(status) + case status + when 1 # yajl_gen_keys_must_be_strings + raise FFI_Yajl::EncodeError, "YAJL internal error: attempted use of non-string object as key" + when 2 # yajl_max_depth_exceeded + raise FFI_Yajl::EncodeError, "Max nesting depth exceeded" + when 3 # yajl_gen_in_error_state + raise FFI_Yajl::EncodeError, "YAJL internal error: a generator function (yajl_gen_XXX) was called while in an error state" + when 4 # yajl_gen_generation_complete + raise FFI_Yajl::EncodeError, "YAJL internal error: attempted to encode to an already-complete document" + when 5 # yajl_gen_invalid_number + raise FFI_Yajl::EncodeError, "Invalid number: cannot encode Infinity, -Infinity, or NaN" + when 6 # yajl_gen_no_buf + raise FFI_Yajl::EncodeError, "YAJL internal error: yajl_gen_get_buf was called, but a print callback was specified, so no internal buffer is available" + else + raise FFI_Yajl::EncodeError, "Unknown YAJL Error, please report this as a bug" + end + end + if ENV['FORCE_FFI_YAJL'] == "ext" require 'ffi_yajl/ext' include FFI_Yajl::Ext::Encoder @@ -86,15 +105,15 @@ module FFI_Yajl :yajl_status_error, ] - enum :yajl_gen_status, [ - :yajl_gen_status_ok, - :yajl_gen_keys_must_be_strings, - :yajl_max_depth_exceeded, - :yajl_gen_in_error_state, - :yajl_gen_generation_complete, - :yajl_gen_invalid_number, - :yajl_gen_no_buf, - ] +# enum :yajl_gen_status, [ +# :yajl_gen_status_ok, +# :yajl_gen_keys_must_be_strings, +# :yajl_max_depth_exceeded, +# :yajl_gen_in_error_state, +# :yajl_gen_generation_complete, +# :yajl_gen_invalid_number, +# :yajl_gen_no_buf, +# ] enum :yajl_option, [ :yajl_allow_comments, 0x01, @@ -145,18 +164,19 @@ module FFI_Yajl # void yajl_gen_free (yajl_gen handle) attach_function :yajl_gen_free, [:yajl_gen], :void - attach_function :yajl_gen_integer, [:yajl_gen, :long_long], :yajl_gen_status - attach_function :yajl_gen_double, [:yajl_gen, :double], :yajl_gen_status - attach_function :yajl_gen_number, [:yajl_gen, :ustring, :int], :yajl_gen_status + # FFI::Enums are slower than :ints + attach_function :yajl_gen_integer, [:yajl_gen, :long_long], :int + attach_function :yajl_gen_double, [:yajl_gen, :double], :int + attach_function :yajl_gen_number, [:yajl_gen, :ustring, :int], :int attach_function :yajl_gen_string, [:yajl_gen, :ustring, :int], :int # XXX: FFI Enums are slow? - attach_function :yajl_gen_null, [:yajl_gen], :yajl_gen_status - attach_function :yajl_gen_bool, [:yajl_gen, :int], :yajl_gen_status - attach_function :yajl_gen_map_open, [:yajl_gen], :yajl_gen_status - attach_function :yajl_gen_map_close, [:yajl_gen], :yajl_gen_status - attach_function :yajl_gen_array_open, [:yajl_gen], :yajl_gen_status - attach_function :yajl_gen_array_close, [:yajl_gen], :yajl_gen_status + attach_function :yajl_gen_null, [:yajl_gen], :int + attach_function :yajl_gen_bool, [:yajl_gen, :int], :int + attach_function :yajl_gen_map_open, [:yajl_gen], :int + attach_function :yajl_gen_map_close, [:yajl_gen], :int + attach_function :yajl_gen_array_open, [:yajl_gen], :int + attach_function :yajl_gen_array_close, [:yajl_gen], :int # yajl_gen_status yajl_gen_get_buf (yajl_gen hand, const unsigned char **buf, unsigned int *len) - attach_function :yajl_gen_get_buf, [:yajl_gen, :pointer ,:pointer], :yajl_gen_status + attach_function :yajl_gen_get_buf, [:yajl_gen, :pointer ,:pointer], :int # void yajl_gen_clear (yajl_gen hand) attach_function :yajl_gen_clear, [:yajl_gen], :void diff --git a/lib/ffi_yajl/ffi/encoder.rb b/lib/ffi_yajl/ffi/encoder.rb index 42725b0..058fc2b 100644 --- a/lib/ffi_yajl/ffi/encoder.rb +++ b/lib/ffi_yajl/ffi/encoder.rb @@ -31,7 +31,9 @@ module FFI_Yajl # get back our encoded JSON string_ptr = ::FFI::MemoryPointer.new(:string) length_ptr = ::FFI::MemoryPointer.new(:int) - FFI_Yajl.yajl_gen_get_buf(yajl_gen, string_ptr, length_ptr) + if ( status = FFI_Yajl.yajl_gen_get_buf(yajl_gen, string_ptr, length_ptr) ) != 0 + FFI_Yajl::Encoder.raise_error_for_status(status) + end length = length_ptr.read_int string = string_ptr.get_pointer(0).read_string @@ -39,13 +41,16 @@ module FFI_Yajl return string end + end end end class Hash def ffi_yajl(yajl_gen, state) - FFI_Yajl.yajl_gen_map_open(yajl_gen) + if ( status = FFI_Yajl.yajl_gen_map_open(yajl_gen) ) != 0 + FFI_Yajl::Encoder.raise_error_for_status(status) + end self.each do |key, value| # Perf Fix: mutate state hash rather than creating new copy state[:processing_key] = true @@ -53,35 +58,47 @@ class Hash state[:processing_key] = false value.ffi_yajl(yajl_gen, state) end - FFI_Yajl.yajl_gen_map_close(yajl_gen) + if ( status = FFI_Yajl.yajl_gen_map_close(yajl_gen) ) != 0 + FFI_Yajl::Encoder.raise_error_for_status(status) + end end end class Array def ffi_yajl(yajl_gen, state) - FFI_Yajl.yajl_gen_array_open(yajl_gen) + if ( status = FFI_Yajl.yajl_gen_array_open(yajl_gen) ) != 0 + FFI_Yajl::Encoder.raise_error_for_status(status) + end self.each do |value| value.ffi_yajl(yajl_gen, state) end - FFI_Yajl.yajl_gen_array_close(yajl_gen) + if ( status = FFI_Yajl.yajl_gen_array_close(yajl_gen) ) != 0 + FFI_Yajl::Encoder.raise_error_for_status(status) + end end end class NilClass def ffi_yajl(yajl_gen, state) - FFI_Yajl.yajl_gen_null(yajl_gen) + if ( status = FFI_Yajl.yajl_gen_null(yajl_gen) ) != 0 + FFI_Yajl::Encoder.raise_error_for_status(status) + end end end class TrueClass def ffi_yajl(yajl_gen, state) - FFI_Yajl.yajl_gen_bool(yajl_gen, 0) + if ( status = FFI_Yajl.yajl_gen_bool(yajl_gen, 0) ) != 0 + FFI_Yajl::Encoder.raise_error_for_status(status) + end end end class FalseClass def ffi_yajl(yajl_gen, state) - FFI_Yajl.yajl_gen_bool(yajl_gen, 1) + if ( status = FFI_Yajl.yajl_gen_bool(yajl_gen, 1) ) != 0 + FFI_Yajl::Encoder.raise_error_for_status(status) + end end end @@ -89,9 +106,13 @@ class Fixnum def ffi_yajl(yajl_gen, state) if state[:processing_key] str = self.to_s - FFI_Yajl.yajl_gen_string(yajl_gen, str, str.length) + if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.length) ) != 0 + FFI_Yajl::Encoder.raise_error_for_status(status) + end else - FFI_Yajl.yajl_gen_integer(yajl_gen, self) + if ( status = FFI_Yajl.yajl_gen_integer(yajl_gen, self) ) != 0 + FFI_Yajl::Encoder.raise_error_for_status(status) + end end end end @@ -99,19 +120,25 @@ end class Bignum def ffi_yajl(yajl_gen, state) str = self.to_s - FFI_Yajl.yajl_gen_number(yajl_gen, str, str.length) + if ( status = FFI_Yajl.yajl_gen_number(yajl_gen, str, str.length) ) != 0 + FFI_Yajl::Encoder.raise_error_for_status(status) + end end end class Float def ffi_yajl(yajl_gen, state) - FFI_Yajl.yajl_gen_double(yajl_gen, self) + if ( status = FFI_Yajl.yajl_gen_double(yajl_gen, self) ) != 0 + FFI_Yajl::Encoder.raise_error_for_status(status) + end end end class String def ffi_yajl(yajl_gen, state) - FFI_Yajl.yajl_gen_string(yajl_gen, self, self.length) + if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, self, self.length) ) != 0 + FFI_Yajl::Encoder.raise_error_for_status(status) + end end end @@ -125,7 +152,9 @@ class Object def ffi_yajl(yajl_gen, state) json = self.to_json(state[:json_opts]) - FFI_Yajl.yajl_gen_number(yajl_gen, json, json.length) + if ( status = FFI_Yajl.yajl_gen_number(yajl_gen, json, json.length) ) != 0 + FFI_Yajl::Encoder.raise_error_for_status(status) + end end end diff --git a/spec/ffi_yajl/json_gem_spec.rb b/spec/ffi_yajl/json_gem_spec.rb index 1b614e4..d28f9f6 100644 --- a/spec/ffi_yajl/json_gem_spec.rb +++ b/spec/ffi_yajl/json_gem_spec.rb @@ -164,7 +164,6 @@ describe "JSON Gem Compat API" do expect{ JSON.parse("blah") }.to raise_error(JSON::ParserError) end it "should raise JSON::GeneratorError on encoding NaN" do - pending("fix NaN encoding issue") expect{ JSON.generate(0.0/0.0) }.to raise_error(JSON::GeneratorError) end it "should raise JSON::GeneratorError on encoding a partial UTF-8 character" do |