ffi-yajl 2.7.5-universal-mingw-ucrt

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +118 -0
  4. data/bin/ffi-yajl-bench +36 -0
  5. data/ext/ffi_yajl/ext/dlopen/dlopen.c +40 -0
  6. data/ext/ffi_yajl/ext/dlopen/extconf.rb +16 -0
  7. data/ext/ffi_yajl/ext/dlopen/yajl.sym +18 -0
  8. data/ext/ffi_yajl/ext/encoder/encoder.c +395 -0
  9. data/ext/ffi_yajl/ext/encoder/extconf.rb +86 -0
  10. data/ext/ffi_yajl/ext/parser/extconf.rb +86 -0
  11. data/ext/ffi_yajl/ext/parser/parser.c +240 -0
  12. data/lib/ffi_yajl/benchmark/MIT-LICENSE +20 -0
  13. data/lib/ffi_yajl/benchmark/encode.rb +82 -0
  14. data/lib/ffi_yajl/benchmark/encode_json_and_marshal.rb +42 -0
  15. data/lib/ffi_yajl/benchmark/encode_json_and_yaml.rb +47 -0
  16. data/lib/ffi_yajl/benchmark/encode_profile.rb +34 -0
  17. data/lib/ffi_yajl/benchmark/http.rb +28 -0
  18. data/lib/ffi_yajl/benchmark/parse.rb +93 -0
  19. data/lib/ffi_yajl/benchmark/parse_json_and_marshal.rb +50 -0
  20. data/lib/ffi_yajl/benchmark/parse_json_and_yaml.rb +55 -0
  21. data/lib/ffi_yajl/benchmark/parse_profile.rb +33 -0
  22. data/lib/ffi_yajl/benchmark/parse_profile_ruby_prof.rb +34 -0
  23. data/lib/ffi_yajl/benchmark/parse_stream.rb +54 -0
  24. data/lib/ffi_yajl/benchmark/subjects/item.json +1 -0
  25. data/lib/ffi_yajl/benchmark/subjects/ohai.json +1216 -0
  26. data/lib/ffi_yajl/benchmark/subjects/ohai.marshal_dump +0 -0
  27. data/lib/ffi_yajl/benchmark/subjects/ohai.yml +975 -0
  28. data/lib/ffi_yajl/benchmark/subjects/twitter_search.json +1 -0
  29. data/lib/ffi_yajl/benchmark/subjects/twitter_stream.json +430 -0
  30. data/lib/ffi_yajl/benchmark/subjects/unicode.json +1 -0
  31. data/lib/ffi_yajl/benchmark.rb +27 -0
  32. data/lib/ffi_yajl/encoder.rb +94 -0
  33. data/lib/ffi_yajl/ext/.keep +0 -0
  34. data/lib/ffi_yajl/ext.rb +49 -0
  35. data/lib/ffi_yajl/ffi/encoder.rb +262 -0
  36. data/lib/ffi_yajl/ffi/parser.rb +163 -0
  37. data/lib/ffi_yajl/ffi.rb +153 -0
  38. data/lib/ffi_yajl/map_library_name.rb +109 -0
  39. data/lib/ffi_yajl/parser.rb +91 -0
  40. data/lib/ffi_yajl/platform.rb +29 -0
  41. data/lib/ffi_yajl/version.rb +25 -0
  42. data/lib/ffi_yajl.rb +50 -0
  43. metadata +128 -0
@@ -0,0 +1 @@
1
+ {"results":[{"text":"#ruby \u732e\u672c\u30ad\u30bf\u30fc\u30fc\u30fc\u30fc\u30fc\u30fc\uff08\u309c\u2200\u309c\uff09\u30fc\u30fc\u30fc\u30fc\u30fc\u30fc\uff01\uff01 http:\/\/www.amazon.co.jp\/gp\/product\/4863540221","to_user_id":null,"from_user":"rubikitch","id":1843394737,"from_user_id":847295,"iso_language_code":"ja","source":"<a href="http:\/\/www.misuzilla.org\/dist\/net\/twitterircgateway\/">TwitterIrcGateway<\/a>","profile_image_url":"http:\/\/static.twitter.com\/images\/default_profile_normal.png","created_at":"Tue, 19 May 2009 03:12:47 +0000"},{"text":"Ruby on Rails\u3068CakePHP\u3001\u3069\u3063\u3061\u3067\u88fd\u9020\u3057\u3088\u3046\u304b\u3057\u3089","to_user_id":null,"from_user":"takkada","id":1842694220,"from_user_id":412519,"iso_language_code":"ja","source":"<a href="http:\/\/twitterfox.net\/">TwitterFox<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/16301882\/62305_4124481745_normal.jpg","created_at":"Tue, 19 May 2009 02:00:08 +0000"},{"text":"Ruby on Rails \u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u306f\u30fc\u3058\u307e\u30fc\u308b\u3088\u30fc","to_user_id":null,"from_user":"Tomohiro","id":1842375120,"from_user_id":38704,"iso_language_code":"ja","source":"<a href="http:\/\/www.misuzilla.org\/dist\/net\/twitterircgateway\/">TwitterIrcGateway<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/20970892\/578576_3772887925_normal.jpg","created_at":"Tue, 19 May 2009 01:27:18 +0000"},{"text":"ruby winole.rb\u3067\u547c\u3073\u51fa\u3057\u305f\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306e\u30e1\u30e2\u30ea\u304c\u9069\u5207\u306b\u958b\u653e\u3055\u308c\u3066\u306a\u304b\u3063\u305f\u3002","to_user_id":null,"from_user":"tomofusa","id":1841955169,"from_user_id":35354,"iso_language_code":"ja","source":"<a href="http:\/\/cheebow.info\/chemt\/archives\/2007\/04\/twitterwindowst.html">Twit<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/18213412\/fusa2.0_about53_normal.png","created_at":"Tue, 19 May 2009 00:43:20 +0000"},{"text":"Ruby HTTP\u4e26\u5217\u3092\u51e6\u7406\u3092\u9ad8\u901f\u5316\u3001"Typhoeus"\u767b\u5834 | \u30a8\u30f3\u30bf\u30fc\u30d7\u30e9\u30a4\u30ba | \u30de\u30a4\u30b3\u30df\u30b8\u30e3\u30fc\u30ca\u30eb http:\/\/ff.im\/-31cez","to_user_id":null,"from_user":"MyGReaderFeed","id":1841206557,"from_user_id":11923042,"iso_language_code":"ja","source":"<a href="http:\/\/friendfeed.com\/">FriendFeed<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/141487706\/3379573163_e79dab7511_normal.bmp","created_at":"Mon, 18 May 2009 23:22:26 +0000"},{"text":"\u3044\u305a\u308c\u306b\u3057\u3066\u3082\u3069\u3053\u304b\u306b Ruby 1.9.1 \u74b0\u5883\u306f\u4f5c\u3089\u306a\u3044\u3068\u30c0\u30e1\u304b\u306a\u3041\u3002Debian lenny \u4efb\u305b\u3060\u3068 1.9.0 \u3057\u304b\u8a66\u305b\u306a\u3044\u3063\u307d\u3044\u3057\u3002","to_user_id":null,"from_user":"wtnabe","id":1840166013,"from_user_id":32040,"iso_language_code":"ja","source":"<a href="http:\/\/www.misuzilla.org\/dist\/net\/twitterircgateway\/">TwitterIrcGateway<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/59828670\/200805-wtnabe-film_normal.png","created_at":"Mon, 18 May 2009 21:26:17 +0000"},{"text":"Ruby 1.9 \u3067\u306f URI#decode \u3060\u3051\u3058\u3083\u610f\u5473\u304c\u306a\u3044\u306e\u304b\u306a\uff1f \u3053\u306e\u8fba\u304b\u3089\u5206\u304b\u3089\u306a\u304f\u306a\u3063\u3066\u304f\u308b\u306a\u3002","to_user_id":null,"from_user":"wtnabe","id":1839967007,"from_user_id":32040,"iso_language_code":"ja","source":"<a href="http:\/\/www.misuzilla.org\/dist\/net\/twitterircgateway\/">TwitterIrcGateway<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/59828670\/200805-wtnabe-film_normal.png","created_at":"Mon, 18 May 2009 21:06:06 +0000"},{"text":"Star Ruby \u3067\u30d5\u30ec\u30fc\u30e0\u30b9\u30ad\u30c3\u30d7\u304c\u5b9f\u88c5\u3057\u306b\u304f\u3044\u7406\u7531\u306e\u3072\u3068\u3064\u306b\u3001\u30b9\u30af\u30ea\u30fc\u30f3\u3078\u306e\u63cf\u753b\u304c\u9045\u5ef6\u3067\u304d\u306a\u3044\u3068\u3044\u3046\u306e\u304c\u3042\u308b\u3002 Texture#[] \u306a\u3069\u3067\u30d4\u30af\u30bb\u30eb\u306e\u5024\u3092\u8aad\u307f\u53d6\u3089\u308c\u308b\u53ef\u80fd\u6027\u304c\u3042\u308b\u305f\u3081\u3002\u8aad\u307f\u53d6\u3089\u308c\u308b\u30ae\u30ea\u30ae\u30ea\u307e\u3067\u9045\u5ef6\u3059\u308b\u306e\u3082\u30a2\u30ea\u3060\u304c\u3001\u5b9f\u88c5\u306f\u9762\u5012\u3067\u3042\u308b\u3002","to_user_id":null,"from_user":"hajimehoshi","id":1837784833,"from_user_id":7543,"iso_language_code":"ja","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/14446892\/michael_normal.jpg","created_at":"Mon, 18 May 2009 17:21:16 +0000"},{"text":"ruby-gem\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u3066\u3001rails\u306b\u30c1\u30e3\u30ec\u30f3\u30b8","to_user_id":null,"from_user":"tom_a","id":1837459653,"from_user_id":366098,"iso_language_code":"ja","source":"<a href="http:\/\/twitterfox.net\/">TwitterFox<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/16661182\/DSC02701_normal.jpg","created_at":"Mon, 18 May 2009 16:46:36 +0000"},{"text":"@saronpasu \u4e2d\u8eab\u306b\u30a2\u30af\u30bb\u30b9\u3057\u306b\u304f\u3044\u3057\u3001\u4f55\u3088\u308a\u4e0d\u5b89\u5b9a\u3059\u304e\u3067\u3059\u306d\u2026\u4f8b\u5916\u3063\u3066\u30ec\u30d9\u30eb\u3058\u3083\u306a\u304f\u3066 ruby \u5dfb\u304d\u8fbc\u3093\u3067\u843d\u3061\u308b\u306e\u3067\u2026","to_user_id":28082,"to_user":"saronpasu","from_user":"negaton","id":1836710607,"from_user_id":5893,"iso_language_code":"ja","source":"<a href="http:\/\/cheebow.info\/chemt\/archives\/2007\/04\/twitterwindowst.html">Twit<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/35934732\/DSC00338_icon_normal.jpg","created_at":"Mon, 18 May 2009 15:28:25 +0000"},{"text":"\u6628\u65e5 CaboCha-Ruby \u306e token \u306e surface \u3092\u53e9\u3044\u305f\u3089\u843d\u3061\u305f\u306e\u306b\u4eca\u65e5\u306f\u5168\u304f\u540c\u3058\u30b3\u30fc\u30c9\u52d5\u304b\u3057\u3066\u3066\u843d\u3061\u306a\u3044\u3068\u304b\u306a\u3093\u306a\u306e\u2026","to_user_id":null,"from_user":"negaton","id":1836267822,"from_user_id":5893,"iso_language_code":"ja","source":"<a href="http:\/\/cheebow.info\/chemt\/archives\/2007\/04\/twitterwindowst.html">Twit<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/35934732\/DSC00338_icon_normal.jpg","created_at":"Mon, 18 May 2009 14:41:26 +0000"},{"text":"ruby.snippets \u3092\u773a\u3081\u3066\u307f\u3066\u3001\u3053\u308c\u306f\u81ea\u5206\u304c\u4f7f\u3044\u3053\u306a\u305b\u308b\u3082\u306e\u3067\u306f\u306a\u3044\u3068\u308f\u304b\u3063\u305f","to_user_id":null,"from_user":"ursm","id":1835699306,"from_user_id":41919,"iso_language_code":"ja","source":"<a href="http:\/\/www.nambu.com">Nambu<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/28792412\/1153147983506_normal.jpg","created_at":"Mon, 18 May 2009 13:33:59 +0000"},{"text":"\u3068\u3053\u308d\u3067\u3001PHP \u304b\u3089\u306f Ruby \u3063\u3066\u547c\u3079\u308b\u306e\uff1f","to_user_id":null,"from_user":"nov","id":1835354604,"from_user_id":76705,"iso_language_code":"ja","source":"<a href="http:\/\/twitterfon.net\/">TwitterFon<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/60572614\/nov_normal.gif","created_at":"Mon, 18 May 2009 12:47:52 +0000"},{"text":"\u3067\u304d\u3042\u304c\u3063\u305f\u3053\u308d shindig ruby ver. \u51fa\u3066\u305f\u308a\u3057\u305f\u3089\u6ce3\u304f\u3002","to_user_id":null,"from_user":"nov","id":1835155373,"from_user_id":76705,"iso_language_code":"ja","source":"<a href="http:\/\/twitterfon.net\/">TwitterFon<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/60572614\/nov_normal.gif","created_at":"Mon, 18 May 2009 12:17:17 +0000"},{"text":"@papiron ruby-dev\u3067ruby1.9\u306bsqlite\u30e9\u30a4\u30d6\u30e9\u30ea\u3092\u6a19\u6e96\u6dfb\u4ed8\u3057\u3088\u3046\u3068\u3044\u3046\u8b70\u8ad6\u304c\u3055\u308c\u3066\u307e\u3059\u3002http:\/\/bit.ly\/Limi9","to_user_id":10226526,"to_user":"papiron","from_user":"taigou","id":1834625775,"from_user_id":3915244,"iso_language_code":"ja","source":"<a href="http:\/\/twitterfox.net\/">TwitterFox<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/95583044\/me_normal.png","created_at":"Mon, 18 May 2009 10:38:40 +0000"}],"since_id":1769782474,"max_id":1843394737,"refresh_url":"?since_id=1843394737&q=ruby","results_per_page":15,"next_page":"?page=2&max_id=1843394737&lang=ja&q=ruby","warning":"adjusted since_id, it was older than allowedsince_id removed for pagination.","completed_in":0.052502,"page":1,"query":"ruby"}
@@ -0,0 +1,27 @@
1
+ # Copyright (c) 2015 Lamont Granquist
2
+ # Copyright (c) 2015 Chef Software, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require "ffi_yajl/benchmark/encode"
24
+ require "ffi_yajl/benchmark/encode_profile"
25
+ require "ffi_yajl/benchmark/parse"
26
+ require "ffi_yajl/benchmark/parse_profile"
27
+ require "ffi_yajl/benchmark/parse_profile_ruby_prof"
@@ -0,0 +1,94 @@
1
+ # Copyright (c) 2015 Lamont Granquist
2
+ # Copyright (c) 2015 Chef Software, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ module FFI_Yajl
24
+ class EncodeError < StandardError; end
25
+
26
+ class Encoder
27
+ attr_accessor :opts
28
+
29
+ def encode(obj)
30
+ # initialization that we can do in pure ruby
31
+ yajl_gen_opts = {}
32
+
33
+ yajl_gen_opts[:yajl_gen_validate_utf8] = @opts[:validate_utf8] == false ? false : true
34
+ yajl_gen_opts[:yajl_gen_beautify] = false
35
+ yajl_gen_opts[:yajl_gen_indent_string] = " "
36
+
37
+ if opts[:pretty]
38
+ yajl_gen_opts[:yajl_gen_beautify] = true
39
+ yajl_gen_opts[:yajl_gen_indent_string] = opts[:indent] || " "
40
+ end
41
+
42
+ # call either the ext or ffi hook
43
+ str = do_yajl_encode(obj, yajl_gen_opts, opts)
44
+ # we can skip cleaning the whole string for utf-8 issues if we have yajl validate as we go
45
+
46
+ str.force_encoding("UTF-8")
47
+ unless yajl_gen_opts[:yajl_gen_validate_utf8]
48
+ if str.respond_to?(:scrub)
49
+ str.scrub!
50
+ else
51
+ str.encode!("UTF-16le", undef: :replace, invalid: :replace).encode!("UTF-8")
52
+ end
53
+ end
54
+ str
55
+ end
56
+
57
+ def self.encode(obj, *args)
58
+ new(*args).encode(obj)
59
+ end
60
+
61
+ def initialize(opts = {})
62
+ @opts = opts
63
+ @opts ||= {}
64
+ end
65
+
66
+ def self.raise_error_for_status(status, token = nil)
67
+ # scrub token to valid utf-8 since we may be issuing an exception on an invalid utf-8 token
68
+ token = token.to_s.force_encoding("UTF-8")
69
+ if token.respond_to?(:scrub)
70
+ token.scrub!
71
+ else
72
+ token.encode!("UTF-16le", undef: :replace, invalid: :replace).encode!("UTF-8")
73
+ end
74
+ case status
75
+ when 1 # yajl_gen_keys_must_be_strings
76
+ raise FFI_Yajl::EncodeError, "YAJL internal error: attempted use of non-string object as key"
77
+ when 2 # yajl_max_depth_exceeded
78
+ raise FFI_Yajl::EncodeError, "Max nesting depth exceeded"
79
+ when 3 # yajl_gen_in_error_state
80
+ raise FFI_Yajl::EncodeError, "YAJL internal error: a generator function (yajl_gen_XXX) was called while in an error state"
81
+ when 4 # yajl_gen_generation_complete
82
+ raise FFI_Yajl::EncodeError, "YAJL internal error: attempted to encode to an already-complete document"
83
+ when 5 # yajl_gen_invalid_number
84
+ raise FFI_Yajl::EncodeError, "Invalid number: cannot encode Infinity, -Infinity, or NaN"
85
+ when 6 # yajl_gen_no_buf
86
+ 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"
87
+ when 7 # yajl_gen_invalid_string
88
+ raise FFI_Yajl::EncodeError, "Invalid UTF-8 string '#{token}': cannot encode to UTF-8"
89
+ else
90
+ raise FFI_Yajl::EncodeError, "Unknown YAJL Error (#{status}), please report this as a bug"
91
+ end
92
+ end
93
+ end
94
+ end
File without changes
@@ -0,0 +1,49 @@
1
+ # Copyright (c) 2015 Lamont Granquist
2
+ # Copyright (c) 2015 Chef Software, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require "rubygems" unless defined?(Gem)
24
+
25
+ require_relative "encoder"
26
+ require_relative "parser"
27
+ require "ffi_yajl/ext/dlopen"
28
+ require_relative "map_library_name"
29
+
30
+ # needed so the encoder c-code can find these symbols
31
+ require "stringio" unless defined?(StringIO)
32
+ require "date"
33
+
34
+ module FFI_Yajl
35
+ extend FFI_Yajl::MapLibraryName
36
+ extend FFI_Yajl::Ext::Dlopen
37
+
38
+ dlopen_yajl_library
39
+
40
+ class Parser
41
+ require "ffi_yajl/ext/parser"
42
+ include FFI_Yajl::Ext::Parser
43
+ end
44
+
45
+ class Encoder
46
+ require "ffi_yajl/ext/encoder"
47
+ include FFI_Yajl::Ext::Encoder
48
+ end
49
+ end
@@ -0,0 +1,262 @@
1
+ # Copyright (c) 2015 Lamont Granquist
2
+ # Copyright (c) 2015-2017, Chef Software Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require "date"
24
+ require "stringio" unless defined?(StringIO)
25
+
26
+ module FFI_Yajl
27
+ module FFI
28
+ module Encoder
29
+ def do_yajl_encode(obj, yajl_gen_opts, opts)
30
+ yajl_gen = FFI_Yajl.yajl_gen_alloc(nil)
31
+
32
+ # configure the yajl encoder
33
+ if yajl_gen_opts[:yajl_gen_beautify]
34
+ FFI_Yajl.yajl_gen_config(yajl_gen, :yajl_gen_beautify, :int, 1)
35
+ end
36
+ if yajl_gen_opts[:yajl_gen_validate_utf8]
37
+ FFI_Yajl.yajl_gen_config(yajl_gen, :yajl_gen_validate_utf8, :int, 1)
38
+ end
39
+ indent = yajl_gen_opts[:yajl_gen_indent_string] || " "
40
+ FFI_Yajl.yajl_gen_config(yajl_gen, :yajl_gen_indent_string, :string, indent)
41
+
42
+ # setup our own state
43
+ state = {
44
+ json_opts: opts,
45
+ processing_key: false,
46
+ }
47
+
48
+ # do the encoding
49
+ obj.ffi_yajl(yajl_gen, state)
50
+
51
+ # get back our encoded JSON
52
+ string_ptr = ::FFI::MemoryPointer.new(:string)
53
+ length_ptr = ::FFI::MemoryPointer.new(:int)
54
+ if ( status = FFI_Yajl.yajl_gen_get_buf(yajl_gen, string_ptr, length_ptr) ) != 0
55
+ FFI_Yajl::Encoder.raise_error_for_status(status)
56
+ end
57
+ string = string_ptr.get_pointer(0).read_string
58
+
59
+ FFI_Yajl.yajl_gen_free(yajl_gen)
60
+
61
+ string
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ class Hash
68
+ def ffi_yajl(yajl_gen, state)
69
+ if state[:processing_key]
70
+ str = to_s
71
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize) ) != 0
72
+ FFI_Yajl::Encoder.raise_error_for_status(status, str)
73
+ end
74
+ else
75
+ if ( status = FFI_Yajl.yajl_gen_map_open(yajl_gen) ) != 0
76
+ FFI_Yajl::Encoder.raise_error_for_status(status, "{")
77
+ end
78
+ each do |key, value|
79
+ # Perf Fix: mutate state hash rather than creating new copy
80
+ state[:processing_key] = true
81
+ key.ffi_yajl(yajl_gen, state)
82
+ state[:processing_key] = false
83
+ value.ffi_yajl(yajl_gen, state)
84
+ end
85
+ if ( status = FFI_Yajl.yajl_gen_map_close(yajl_gen) ) != 0
86
+ FFI_Yajl::Encoder.raise_error_for_status(status, "}")
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ class Array
93
+ def ffi_yajl(yajl_gen, state)
94
+ if state[:processing_key]
95
+ str = to_s
96
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize) ) != 0
97
+ FFI_Yajl::Encoder.raise_error_for_status(status, str)
98
+ end
99
+ else
100
+ if ( status = FFI_Yajl.yajl_gen_array_open(yajl_gen) ) != 0
101
+ FFI_Yajl::Encoder.raise_error_for_status(status, "[")
102
+ end
103
+ each do |value|
104
+ value.ffi_yajl(yajl_gen, state)
105
+ end
106
+ if ( status = FFI_Yajl.yajl_gen_array_close(yajl_gen) ) != 0
107
+ FFI_Yajl::Encoder.raise_error_for_status(status, "]")
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ class NilClass
114
+ def ffi_yajl(yajl_gen, state)
115
+ str = to_s
116
+ if state[:processing_key]
117
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize) ) != 0
118
+ FFI_Yajl::Encoder.raise_error_for_status(status, str)
119
+ end
120
+ else
121
+ if ( status = FFI_Yajl.yajl_gen_null(yajl_gen) ) != 0
122
+ FFI_Yajl::Encoder.raise_error_for_status(status, str)
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ class TrueClass
129
+ def ffi_yajl(yajl_gen, state)
130
+ str = to_s
131
+ if state[:processing_key]
132
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize) ) != 0
133
+ FFI_Yajl::Encoder.raise_error_for_status(status, str)
134
+ end
135
+ else
136
+ if ( status = FFI_Yajl.yajl_gen_bool(yajl_gen, 1) ) != 0
137
+ FFI_Yajl::Encoder.raise_error_for_status(status, str)
138
+ end
139
+ end
140
+ end
141
+ end
142
+
143
+ class FalseClass
144
+ def ffi_yajl(yajl_gen, state)
145
+ str = to_s
146
+ if state[:processing_key]
147
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize) ) != 0
148
+ FFI_Yajl::Encoder.raise_error_for_status(status, str)
149
+ end
150
+ else
151
+ if ( status = FFI_Yajl.yajl_gen_bool(yajl_gen, 0) ) != 0
152
+ FFI_Yajl::Encoder.raise_error_for_status(status, str)
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ class Integer
159
+ def ffi_yajl(yajl_gen, state)
160
+ str = to_s
161
+ if str == "NaN" || str == "Infinity" || str == "-Infinity"
162
+ raise ::FFI_Yajl::EncodeError, "'#{str}' is an invalid number"
163
+ end
164
+
165
+ if state[:processing_key]
166
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize) ) != 0
167
+ FFI_Yajl::Encoder.raise_error_for_status(status, str)
168
+ end
169
+ else
170
+ if ( status = FFI_Yajl.yajl_gen_number(yajl_gen, str, str.bytesize) ) != 0
171
+ FFI_Yajl::Encoder.raise_error_for_status(status, str)
172
+ end
173
+ end
174
+ end
175
+ end
176
+
177
+ class Float
178
+ def ffi_yajl(yajl_gen, state)
179
+ str = to_s
180
+ if str == "NaN" || str == "Infinity" || str == "-Infinity"
181
+ raise ::FFI_Yajl::EncodeError, "'#{str}' is an invalid number"
182
+ end
183
+
184
+ if state[:processing_key]
185
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize) ) != 0
186
+ FFI_Yajl::Encoder.raise_error_for_status(status, str)
187
+ end
188
+ else
189
+ if ( status = FFI_Yajl.yajl_gen_number(yajl_gen, str, str.bytesize) ) != 0
190
+ FFI_Yajl::Encoder.raise_error_for_status(status, str)
191
+ end
192
+ end
193
+ end
194
+ end
195
+
196
+ class Symbol
197
+ def ffi_yajl(yajl_gen, state)
198
+ str = to_s
199
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize) ) != 0
200
+ FFI_Yajl::Encoder.raise_error_for_status(status, str)
201
+ end
202
+ end
203
+ end
204
+
205
+ class String
206
+ def ffi_yajl(yajl_gen, state)
207
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, self, bytesize) ) != 0
208
+ FFI_Yajl::Encoder.raise_error_for_status(status, self)
209
+ end
210
+ end
211
+ end
212
+
213
+ class StringIO
214
+ def ffi_yajl(yajl_gen, state)
215
+ str = read
216
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize) ) != 0
217
+ FFI_Yajl::Encoder.raise_error_for_status(status, str)
218
+ end
219
+ end
220
+ end
221
+
222
+ class Date
223
+ def ffi_yajl(yajl_gen, state)
224
+ str = to_s
225
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize) ) != 0
226
+ FFI_Yajl::Encoder.raise_error_for_status(status, str)
227
+ end
228
+ end
229
+ end
230
+
231
+ class Time
232
+ def ffi_yajl(yajl_gen, state)
233
+ str = strftime "%Y-%m-%d %H:%M:%S %z"
234
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize) ) != 0
235
+ FFI_Yajl::Encoder.raise_error_for_status(status, str)
236
+ end
237
+ end
238
+ end
239
+
240
+ class DateTime
241
+ def ffi_yajl(yajl_gen, state)
242
+ str = to_s
243
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize) ) != 0
244
+ FFI_Yajl::Encoder.raise_error_for_status(status, str)
245
+ end
246
+ end
247
+ end
248
+
249
+ # I feel dirty
250
+ class Object
251
+ def ffi_yajl(yajl_gen, state)
252
+ if !state[:processing_key] && respond_to?(:to_json)
253
+ str = to_json(state[:json_opts])
254
+ # #yajl_gen_number outputs a string without quotes around it
255
+ status = FFI_Yajl.yajl_gen_number(yajl_gen, str, str.bytesize)
256
+ else
257
+ str = to_s
258
+ status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize)
259
+ end
260
+ FFI_Yajl::Encoder.raise_error_for_status(status, str) if ( status ) != 0
261
+ end
262
+ end
@@ -0,0 +1,163 @@
1
+ # Copyright (c) 2015 Lamont Granquist
2
+ # Copyright (c) 2015-2018, Chef Software Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ module FFI_Yajl
24
+ module FFI
25
+ module Parser
26
+ def set_value(val) # rubocop:disable Naming/AccessorMethodName
27
+ case stack.last
28
+ when Hash
29
+ raise FFI_Yajl::ParseError, "internal error: missing key in parse" if key.nil?
30
+ if @opts[:unique_key_checking] && stack.last.key?(key)
31
+ raise FFI_Yajl::ParseError, "repeated key: #{key}"
32
+ end
33
+
34
+ stack.last[key] = val
35
+ when Array
36
+ stack.last.push(val)
37
+ else
38
+ stack.push(val)
39
+ end
40
+ end
41
+
42
+ def stack_pop
43
+ set_value( stack.pop ) if stack.length > 1
44
+ end
45
+
46
+ def key_push
47
+ key_stack.push(key)
48
+ end
49
+
50
+ def key_pop
51
+ @key = key_stack.pop
52
+ end
53
+
54
+ def setup_callbacks
55
+ @null_callback = ::FFI::Function.new(:int, [:pointer]) do |ctx|
56
+ set_value(nil)
57
+ 1
58
+ end
59
+ @boolean_callback = ::FFI::Function.new(:int, %i{pointer int}) do |ctx, boolval|
60
+ set_value(boolval == 1 ? true : false)
61
+ 1
62
+ end
63
+ @integer_callback = ::FFI::Function.new(:int, %i{pointer long_long}) do |ctx, intval|
64
+ set_value(intval)
65
+ 1
66
+ end
67
+ @number_callback = ::FFI::Function.new(:int, %i{pointer string size_t}) do |ctx, stringval, stringlen|
68
+ s = stringval.slice(0, stringlen)
69
+ s.force_encoding("UTF-8") if defined? Encoding
70
+ # XXX: I can't think of a better way to do this right now. need to call to_f if and only if its a float.
71
+ v = ( s =~ /[\.eE]/ ) ? s.to_f : s.to_i
72
+ set_value(v)
73
+ 1
74
+ end
75
+ @double_callback = ::FFI::Function.new(:int, %i{pointer double}) do |ctx, doubleval|
76
+ set_value(doubleval)
77
+ 1
78
+ end
79
+ @string_callback = ::FFI::Function.new(:int, %i{pointer string size_t}) do |ctx, stringval, stringlen|
80
+ s = stringval.slice(0, stringlen)
81
+ s.force_encoding("UTF-8") if defined? Encoding
82
+ set_value(s)
83
+ 1
84
+ end
85
+ @start_map_callback = ::FFI::Function.new(:int, [:pointer]) do |ctx|
86
+ key_push # for key => { } case, save the key
87
+ stack.push({})
88
+ 1
89
+ end
90
+ @map_key_callback = ::FFI::Function.new(:int, %i{pointer string size_t}) do |ctx, key, keylen|
91
+ s = key.slice(0, keylen)
92
+ s.force_encoding("UTF-8") if defined? Encoding
93
+ self.key = @opts[:symbolize_keys] ? s.to_sym : s
94
+ 1
95
+ end
96
+ @end_map_callback = ::FFI::Function.new(:int, [:pointer]) do |ctx|
97
+ key_pop
98
+ stack_pop
99
+ 1
100
+ end
101
+ @start_array_callback = ::FFI::Function.new(:int, [:pointer]) do |ctx|
102
+ key_push # for key => [ ] case, save the key
103
+ stack.push([])
104
+ 1
105
+ end
106
+ @end_array_callback = ::FFI::Function.new(:int, [:pointer]) do |ctx|
107
+ key_pop
108
+ stack_pop
109
+ 1
110
+ end
111
+ end
112
+
113
+ def do_yajl_parse(str, yajl_opts = {})
114
+ setup_callbacks
115
+ callback_ptr = ::FFI::MemoryPointer.new(::FFI_Yajl::YajlCallbacks)
116
+ callbacks = ::FFI_Yajl::YajlCallbacks.new(callback_ptr)
117
+ callbacks[:yajl_null] = @null_callback
118
+ callbacks[:yajl_boolean] = @boolean_callback
119
+ callbacks[:yajl_integer] = @integer_callback
120
+ callbacks[:yajl_double] = @double_callback
121
+ callbacks[:yajl_number] = @number_callback
122
+ callbacks[:yajl_string] = @string_callback
123
+ callbacks[:yajl_start_map] = @start_map_callback
124
+ callbacks[:yajl_map_key] = @map_key_callback
125
+ callbacks[:yajl_end_map] = @end_map_callback
126
+ callbacks[:yajl_start_array] = @start_array_callback
127
+ callbacks[:yajl_end_array] = @end_array_callback
128
+ yajl_handle = ::FFI_Yajl.yajl_alloc(callback_ptr, nil, nil)
129
+
130
+ # configure the yajl parser
131
+ if yajl_opts[:yajl_allow_comments]
132
+ ::FFI_Yajl.yajl_config(yajl_handle, :yajl_allow_comments, :int, 1)
133
+ end
134
+ if yajl_opts[:yajl_dont_validate_strings]
135
+ ::FFI_Yajl.yajl_config(yajl_handle, :yajl_dont_validate_strings, :int, 1)
136
+ end
137
+ if yajl_opts[:yajl_allow_trailing_garbage]
138
+ ::FFI_Yajl.yajl_config(yajl_handle, :yajl_allow_trailing_garbage, :int, 1)
139
+ end
140
+ if yajl_opts[:yajl_allow_multiple_values]
141
+ ::FFI_Yajl.yajl_config(yajl_handle, :yajl_allow_multiple_values, :int, 1)
142
+ end
143
+ if yajl_opts[:yajl_allow_partial_values]
144
+ ::FFI_Yajl.yajl_config(yajl_handle, :yajl_allow_partial_values, :int, 1)
145
+ end
146
+
147
+ if ::FFI_Yajl.yajl_parse(yajl_handle, str, str.bytesize) != :yajl_status_ok
148
+ # FIXME: dup the error and call yajl_free_error?
149
+ error = ::FFI_Yajl.yajl_get_error(yajl_handle, 1, str, str.bytesize)
150
+ raise ::FFI_Yajl::ParseError, error
151
+ end
152
+ if ::FFI_Yajl.yajl_complete_parse(yajl_handle) != :yajl_status_ok
153
+ # FIXME: dup the error and call yajl_free_error?
154
+ error = ::FFI_Yajl.yajl_get_error(yajl_handle, 1, str, str.bytesize)
155
+ raise ::FFI_Yajl::ParseError, error
156
+ end
157
+ stack.pop
158
+ ensure
159
+ ::FFI_Yajl.yajl_free(yajl_handle) if yajl_handle
160
+ end
161
+ end
162
+ end
163
+ end