├── .gitignore
├── .rspec
├── .travis.yml
├── .yardopts
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── benchmarks
├── assets
│ ├── twitter_api_response.json
│ └── wikipedia_zstandard.html
└── zstd_deflate.rake
├── bin
├── console
└── setup
├── lib
├── zstandard.rb
└── zstandard
│ ├── api.rb
│ ├── config.rb
│ ├── ffi_bindings.rb
│ └── version.rb
├── run_rspec_with_bundled_libraries.sh
├── spec
├── libzstd
│ └── x86_64
│ │ └── ubuntu
│ │ ├── 12.04
│ │ ├── libzstd.so.0.5.0
│ │ ├── libzstd.so.0.6.0
│ │ ├── libzstd.so.0.7.0
│ │ ├── libzstd.so.0.8.0
│ │ ├── libzstd.so.1.0.0
│ │ ├── libzstd.so.1.1.0
│ │ ├── libzstd.so.1.2.0
│ │ ├── libzstd.so.1.3.0
│ │ ├── libzstd.so.1.3.3
│ │ └── libzstd.so.1.3.8
│ │ ├── 14.04
│ │ ├── libzstd.so.0.5.0
│ │ ├── libzstd.so.0.6.0
│ │ ├── libzstd.so.0.7.0
│ │ ├── libzstd.so.0.8.0
│ │ ├── libzstd.so.1.0.0
│ │ ├── libzstd.so.1.1.0
│ │ ├── libzstd.so.1.2.0
│ │ ├── libzstd.so.1.3.0
│ │ └── libzstd.so.1.3.8
│ │ └── 16.04
│ │ ├── libzstd.so.0.5.0
│ │ ├── libzstd.so.0.6.0
│ │ ├── libzstd.so.0.7.0
│ │ ├── libzstd.so.0.8.0
│ │ ├── libzstd.so.1.0.0
│ │ ├── libzstd.so.1.1.0
│ │ ├── libzstd.so.1.1.3
│ │ ├── libzstd.so.1.2.0
│ │ └── libzstd.so.1.3.0
├── spec_helper.rb
└── zstandard_spec.rb
└── zstandard.gemspec
/.gitignore:
--------------------------------------------------------------------------------
1 | /.bundle/
2 | /.yardoc
3 | /Gemfile.lock
4 | /_yardoc/
5 | /coverage/
6 | /doc/
7 | /pkg/
8 | /spec/reports/
9 | /tmp/
10 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --color
2 | --format documentation
3 | --require spec_helper
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: ruby
3 | rvm:
4 | - 1.9.3
5 | - 2.0.0
6 | - 2.1.10
7 | - 2.2.9
8 | - 2.3.6
9 | - 2.4.3
10 | - 2.5.0
11 | - 2.6.0
12 | - jruby-1.7.27
13 | - jruby-9.1.17.0
14 | - jruby-9.2.6.0
15 |
16 | before_install:
17 | - gem install bundler -v 1.13.6
18 |
19 | script: bundle && ./run_rspec_with_bundled_libraries.sh
20 |
--------------------------------------------------------------------------------
/.yardopts:
--------------------------------------------------------------------------------
1 | --markup=markdown
2 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | # Specify your gem's dependencies in zstandard.gemspec
4 | gemspec
5 |
6 | group :development do
7 | gem "benchmark-ips"
8 | gem "bundler"
9 | gem "rake"
10 | gem "ruby-progressbar", "~> 1.0"
11 | gem "rspec", "~> 3.0"
12 |
13 | if RUBY_ENGINE == "ruby"
14 | gem "simplecov" if RUBY_VERSION >= "2.0.0"
15 |
16 | if !ENV["CI"]
17 | gem "pry"
18 |
19 | if RUBY_VERSION < "2.0.0"
20 | gem "pry-nav"
21 | else
22 | gem "pry-byebug"
23 | end
24 |
25 | # yard and friends
26 | gem "redcarpet"
27 | gem "github-markup"
28 | gem "yard"
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Michael Sievers
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # zstandard-ruby
2 |
3 | [](https://travis-ci.org/msievers/zstandard-ruby)
4 |
5 | * [Installation](#installation)
6 | * [Usage](#usage)
7 | * [Advanced Usage](#advanced-usage)
8 | * [Configuration](#configuration)
9 | * [Docs](#docs)
10 | * [Examples for installing `libzstd`](#examples-for-installing-libzstd)
11 | * [Contributing](#contributing)
12 | * [License](#license)
13 |
14 | This gem implements FFI based bindings to the [Zstandard](https://facebook.github.io/zstd) compression library `libzstd`. The [Zstandard](https://facebook.github.io/zstd) compression algorithm shines because it compresses data with the same or better ratio as *Zlib* but does this (much) faster, depending on the input. For the majority of cases it's **faster and better** then *Zlib*. It is tested to work with MRI from 1.9.3 to 2.6.x and with JRuby from >= 1.7.24, including 9.2.x.
15 |
16 | It **does not** ship the actual `libzstd` library but expects some version to be present on your system.
17 |
18 | This gem *is activly maintained*. The tests are updated regularly, to keep up with the latest zstd version.
19 |
20 | ## Installation
21 |
22 | Make sure you have `libzstd` installed on your system. In doubt, have a look at the [examples for installing `libzstd`](#examples-for-installing-libzstd).
23 |
24 | Add this line to your application's Gemfile:
25 |
26 | ```ruby
27 | gem "zstandard"
28 | ```
29 |
30 | And then execute:
31 |
32 | ```
33 | bundle
34 | ```
35 |
36 | Or install it yourself as:
37 |
38 | ```
39 | gem install zstandard
40 | ```
41 |
42 | ## Usage
43 |
44 | The gem provides an API which aims compatibility the with `zlib` gem. There are two module methods
45 | * `deflate(string, level)`
46 | * `inflate(compressed_string)`
47 |
48 | The only difference between this and the `zlib` gem is the interpretation of the compression level. For `zlib`, this is a value between `1..9`, whereas for `Zstandard` it's between `1..22`.
49 |
50 | For most use cases, you should try to keep the compression level (very) low for `Zstandard`, because often compression time increases without significant better compression ratios. If in doubt, *do not specify* a compression level at all, which will use the default compression level.
51 |
52 | ```ruby
53 | require "zstandard"
54 |
55 | compressed_string = Zstandard.deflate(string)
56 | decompressed_string = Zstandard.inflate(compressed_string)
57 | ```
58 |
59 | ## Advanced Usage
60 |
61 | *This is not intended to be used by regular users.*
62 |
63 | Besides the high level API which targets compatibility with the well known `zlib` gem there are two additional layers you can interact with. There is a low-level API which tries to cover differences between various `libzstd` version, e.g. different *frame header* formats. You should only use this if you know, what you are doing.
64 |
65 | ```ruby
66 | require "zstandard"
67 |
68 | compressed_string = Zstandard::API.simple_compress(string)
69 | decompressed_string = Zstandard::API.simple_decompress(compressed_string)
70 | ```
71 |
72 | The most low-level bindings are exposed via `Zstandard::FFIBindings`. If there is any reason for this, you can do the following.
73 |
74 | ```ruby
75 | require "zstandard"
76 |
77 | zstd_library_version = Zstandard::FFIBindings.zstd_version_number
78 | ```
79 |
80 | ## Configuration
81 |
82 | This gem can be configured by setting various environment variables. Please be carefull if you decide to change/overwrite any of these. The default values are carefully choosen and there should be no need to alter one of these for regular use cases.
83 |
84 | ### `ZSTANDARD_LIBRARY`
85 |
86 | If you have `libzstd` installed in some unusual location or if you want to explictly tell, which library to use, you can set `ZSTANDARD_LIBRARY` to the path of the library you want to use. This can be handy for example if you have the latest version compiled in `/usr/local/lib`, but your system has an old version in `/usr/lib`.
87 |
88 | ```
89 | ZSTANDARD_LIBRARY=/usr/local/lib/libzstd.so bundle exec rspec
90 | ```
91 |
92 | ### `ZSTANDARD_MAX_SIMPLE_DECOMPRESS_SIZE`
93 |
94 | This specifies the maximum (decompressed) size of a string for which the simple decompression approach should be used. In order minimise memory consumption, if the expected decompressed size exceeds this limit, streaming decompression is used.
95 |
96 | ### `ZSTANDARD_MAX_STREAMING_DECOMRPESS_BUFFER_SIZE`
97 |
98 | For streaming decompression, this specifies the size of the decompression bufffer.
99 |
100 | ## Docs
101 |
102 | Yard generated docs can be found at [http://www.rubydoc.info/github/msievers/zstandard-ruby](http://www.rubydoc.info/github/msievers/zstandard-ruby).
103 |
104 | ## Examples for installing `libzstd`
105 |
106 | * [Debian](#debian)
107 | * [Fedora](#fedora)
108 | * [FreeBSD](#freebsd)
109 | * [Mac](#mac)
110 | * [NetBSD](#netbsd)
111 | * [Ubuntu](#ubuntu)
112 |
113 | ### Debian
114 |
115 | #### Jessie (8.x)
116 |
117 | The package is only included in `sid`, the unstable Debian version. There are guides describing how to install unstable packages into a stable Debian, for example at [Linuxaria](https://linuxaria.com/howto/how-to-install-a-single-package-from-debian-sid-or-debian-testing) or [serverfault.com](https://serverfault.com/questions/22414/how-can-i-run-debian-stable-but-install-some-packages-from-testing).
118 |
119 | ```
120 | # run as root
121 |
122 | apt-get install zstd
123 | ```
124 |
125 | ### Fedora
126 |
127 | #### Fedora 23
128 |
129 | ```
130 | sudo dnf install libzstd
131 | ```
132 |
133 | ### FreeBSD
134 |
135 | #### FreeBSD 10
136 |
137 | ```
138 | # run as root
139 |
140 | portsnap fetch && portsnap extract
141 |
142 | cd /usr/ports/archivers/zstd
143 | make install
144 | ```
145 |
146 | ### Mac
147 |
148 | ```
149 | brew install zstd
150 | ```
151 |
152 | ### NetBSD
153 |
154 | #### NetBSD 7
155 |
156 | ```
157 | # run as root
158 |
159 | # the following assumes you are running a x86_64 system with NetBSD 7.0.x
160 |
161 | export PATH="/usr/pkg/sbin:$PATH"
162 | export PKG_PATH="ftp://ftp.netbsd.org/pub/pkgsrc/packages/NetBSD/x86_64/7.0_current/All/"
163 |
164 | pkg_add zstd
165 | ```
166 |
167 | ### Ubuntu
168 |
169 | #### Xenial Xerus (16.04) and above
170 |
171 | ```
172 | sudo apt-get install zstd
173 | ```
174 |
175 | ## Contributing
176 |
177 | Bug reports and pull requests are welcome on GitHub at [https://github.com/msievers/zstandard-ruby](https://github.com/msievers/zstandard-ruby).
178 |
179 | ## License
180 |
181 | The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
182 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require "bundler/gem_tasks"
2 | require "rspec/core/rake_task"
3 |
4 | RSpec::Core::RakeTask.new(:spec)
5 |
6 | task :default => :spec
7 |
8 | Dir.glob("benchmarks/*.rake").each do |file|
9 | import file
10 | end
11 |
12 | desc "Run benchmarks"
13 | task :benchmark => ["benchmarks:deflate"]
14 |
--------------------------------------------------------------------------------
/benchmarks/assets/twitter_api_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "statuses": [
3 | {
4 | "coordinates": null,
5 | "favorited": false,
6 | "truncated": false,
7 | "created_at": "Mon Sep 24 03:35:21 +0000 2012",
8 | "id_str": "250075927172759552",
9 | "entities": {
10 | "urls": [
11 |
12 | ],
13 | "hashtags": [
14 | {
15 | "text": "freebandnames",
16 | "indices": [
17 | 20,
18 | 34
19 | ]
20 | }
21 | ],
22 | "user_mentions": [
23 |
24 | ]
25 | },
26 | "in_reply_to_user_id_str": null,
27 | "contributors": null,
28 | "text": "Aggressive Ponytail #freebandnames",
29 | "metadata": {
30 | "iso_language_code": "en",
31 | "result_type": "recent"
32 | },
33 | "retweet_count": 0,
34 | "in_reply_to_status_id_str": null,
35 | "id": 250075927172759552,
36 | "geo": null,
37 | "retweeted": false,
38 | "in_reply_to_user_id": null,
39 | "place": null,
40 | "user": {
41 | "profile_sidebar_fill_color": "DDEEF6",
42 | "profile_sidebar_border_color": "C0DEED",
43 | "profile_background_tile": false,
44 | "name": "Sean Cummings",
45 | "profile_image_url": "http://a0.twimg.com/profile_images/2359746665/1v6zfgqo8g0d3mk7ii5s_normal.jpeg",
46 | "created_at": "Mon Apr 26 06:01:55 +0000 2010",
47 | "location": "LA, CA",
48 | "follow_request_sent": null,
49 | "profile_link_color": "0084B4",
50 | "is_translator": false,
51 | "id_str": "137238150",
52 | "entities": {
53 | "url": {
54 | "urls": [
55 | {
56 | "expanded_url": null,
57 | "url": "",
58 | "indices": [
59 | 0,
60 | 0
61 | ]
62 | }
63 | ]
64 | },
65 | "description": {
66 | "urls": [
67 |
68 | ]
69 | }
70 | },
71 | "default_profile": true,
72 | "contributors_enabled": false,
73 | "favourites_count": 0,
74 | "url": null,
75 | "profile_image_url_https": "https://si0.twimg.com/profile_images/2359746665/1v6zfgqo8g0d3mk7ii5s_normal.jpeg",
76 | "utc_offset": -28800,
77 | "id": 137238150,
78 | "profile_use_background_image": true,
79 | "listed_count": 2,
80 | "profile_text_color": "333333",
81 | "lang": "en",
82 | "followers_count": 70,
83 | "protected": false,
84 | "notifications": null,
85 | "profile_background_image_url_https": "https://si0.twimg.com/images/themes/theme1/bg.png",
86 | "profile_background_color": "C0DEED",
87 | "verified": false,
88 | "geo_enabled": true,
89 | "time_zone": "Pacific Time (US & Canada)",
90 | "description": "Born 330 Live 310",
91 | "default_profile_image": false,
92 | "profile_background_image_url": "http://a0.twimg.com/images/themes/theme1/bg.png",
93 | "statuses_count": 579,
94 | "friends_count": 110,
95 | "following": null,
96 | "show_all_inline_media": false,
97 | "screen_name": "sean_cummings"
98 | },
99 | "in_reply_to_screen_name": null,
100 | "source": "Twitter for Mac",
101 | "in_reply_to_status_id": null
102 | },
103 | {
104 | "coordinates": null,
105 | "favorited": false,
106 | "truncated": false,
107 | "created_at": "Fri Sep 21 23:40:54 +0000 2012",
108 | "id_str": "249292149810667520",
109 | "entities": {
110 | "urls": [
111 |
112 | ],
113 | "hashtags": [
114 | {
115 | "text": "FreeBandNames",
116 | "indices": [
117 | 20,
118 | 34
119 | ]
120 | }
121 | ],
122 | "user_mentions": [
123 |
124 | ]
125 | },
126 | "in_reply_to_user_id_str": null,
127 | "contributors": null,
128 | "text": "Thee Namaste Nerdz. #FreeBandNames",
129 | "metadata": {
130 | "iso_language_code": "pl",
131 | "result_type": "recent"
132 | },
133 | "retweet_count": 0,
134 | "in_reply_to_status_id_str": null,
135 | "id": 249292149810667520,
136 | "geo": null,
137 | "retweeted": false,
138 | "in_reply_to_user_id": null,
139 | "place": null,
140 | "user": {
141 | "profile_sidebar_fill_color": "DDFFCC",
142 | "profile_sidebar_border_color": "BDDCAD",
143 | "profile_background_tile": true,
144 | "name": "Chaz Martenstein",
145 | "profile_image_url": "http://a0.twimg.com/profile_images/447958234/Lichtenstein_normal.jpg",
146 | "created_at": "Tue Apr 07 19:05:07 +0000 2009",
147 | "location": "Durham, NC",
148 | "follow_request_sent": null,
149 | "profile_link_color": "0084B4",
150 | "is_translator": false,
151 | "id_str": "29516238",
152 | "entities": {
153 | "url": {
154 | "urls": [
155 | {
156 | "expanded_url": null,
157 | "url": "http://bullcityrecords.com/wnng/",
158 | "indices": [
159 | 0,
160 | 32
161 | ]
162 | }
163 | ]
164 | },
165 | "description": {
166 | "urls": [
167 |
168 | ]
169 | }
170 | },
171 | "default_profile": false,
172 | "contributors_enabled": false,
173 | "favourites_count": 8,
174 | "url": "http://bullcityrecords.com/wnng/",
175 | "profile_image_url_https": "https://si0.twimg.com/profile_images/447958234/Lichtenstein_normal.jpg",
176 | "utc_offset": -18000,
177 | "id": 29516238,
178 | "profile_use_background_image": true,
179 | "listed_count": 118,
180 | "profile_text_color": "333333",
181 | "lang": "en",
182 | "followers_count": 2052,
183 | "protected": false,
184 | "notifications": null,
185 | "profile_background_image_url_https": "https://si0.twimg.com/profile_background_images/9423277/background_tile.bmp",
186 | "profile_background_color": "9AE4E8",
187 | "verified": false,
188 | "geo_enabled": false,
189 | "time_zone": "Eastern Time (US & Canada)",
190 | "description": "You will come to Durham, North Carolina. I will sell you some records then, here in Durham, North Carolina. Fun will happen.",
191 | "default_profile_image": false,
192 | "profile_background_image_url": "http://a0.twimg.com/profile_background_images/9423277/background_tile.bmp",
193 | "statuses_count": 7579,
194 | "friends_count": 348,
195 | "following": null,
196 | "show_all_inline_media": true,
197 | "screen_name": "bullcityrecords"
198 | },
199 | "in_reply_to_screen_name": null,
200 | "source": "web",
201 | "in_reply_to_status_id": null
202 | },
203 | {
204 | "coordinates": null,
205 | "favorited": false,
206 | "truncated": false,
207 | "created_at": "Fri Sep 21 23:30:20 +0000 2012",
208 | "id_str": "249289491129438208",
209 | "entities": {
210 | "urls": [
211 |
212 | ],
213 | "hashtags": [
214 | {
215 | "text": "freebandnames",
216 | "indices": [
217 | 29,
218 | 43
219 | ]
220 | }
221 | ],
222 | "user_mentions": [
223 |
224 | ]
225 | },
226 | "in_reply_to_user_id_str": null,
227 | "contributors": null,
228 | "text": "Mexican Heaven, Mexican Hell #freebandnames",
229 | "metadata": {
230 | "iso_language_code": "en",
231 | "result_type": "recent"
232 | },
233 | "retweet_count": 0,
234 | "in_reply_to_status_id_str": null,
235 | "id": 249289491129438208,
236 | "geo": null,
237 | "retweeted": false,
238 | "in_reply_to_user_id": null,
239 | "place": null,
240 | "user": {
241 | "profile_sidebar_fill_color": "99CC33",
242 | "profile_sidebar_border_color": "829D5E",
243 | "profile_background_tile": false,
244 | "name": "Thomas John Wakeman",
245 | "profile_image_url": "http://a0.twimg.com/profile_images/2219333930/Froggystyle_normal.png",
246 | "created_at": "Tue Sep 01 21:21:35 +0000 2009",
247 | "location": "Kingston New York",
248 | "follow_request_sent": null,
249 | "profile_link_color": "D02B55",
250 | "is_translator": false,
251 | "id_str": "70789458",
252 | "entities": {
253 | "url": {
254 | "urls": [
255 | {
256 | "expanded_url": null,
257 | "url": "",
258 | "indices": [
259 | 0,
260 | 0
261 | ]
262 | }
263 | ]
264 | },
265 | "description": {
266 | "urls": [
267 |
268 | ]
269 | }
270 | },
271 | "default_profile": false,
272 | "contributors_enabled": false,
273 | "favourites_count": 19,
274 | "url": null,
275 | "profile_image_url_https": "https://si0.twimg.com/profile_images/2219333930/Froggystyle_normal.png",
276 | "utc_offset": -18000,
277 | "id": 70789458,
278 | "profile_use_background_image": true,
279 | "listed_count": 1,
280 | "profile_text_color": "3E4415",
281 | "lang": "en",
282 | "followers_count": 63,
283 | "protected": false,
284 | "notifications": null,
285 | "profile_background_image_url_https": "https://si0.twimg.com/images/themes/theme5/bg.gif",
286 | "profile_background_color": "352726",
287 | "verified": false,
288 | "geo_enabled": false,
289 | "time_zone": "Eastern Time (US & Canada)",
290 | "description": "Science Fiction Writer, sort of. Likes Superheroes, Mole People, Alt. Timelines.",
291 | "default_profile_image": false,
292 | "profile_background_image_url": "http://a0.twimg.com/images/themes/theme5/bg.gif",
293 | "statuses_count": 1048,
294 | "friends_count": 63,
295 | "following": null,
296 | "show_all_inline_media": false,
297 | "screen_name": "MonkiesFist"
298 | },
299 | "in_reply_to_screen_name": null,
300 | "source": "web",
301 | "in_reply_to_status_id": null
302 | },
303 | {
304 | "coordinates": null,
305 | "favorited": false,
306 | "truncated": false,
307 | "created_at": "Fri Sep 21 22:51:18 +0000 2012",
308 | "id_str": "249279667666817024",
309 | "entities": {
310 | "urls": [
311 |
312 | ],
313 | "hashtags": [
314 | {
315 | "text": "freebandnames",
316 | "indices": [
317 | 20,
318 | 34
319 | ]
320 | }
321 | ],
322 | "user_mentions": [
323 |
324 | ]
325 | },
326 | "in_reply_to_user_id_str": null,
327 | "contributors": null,
328 | "text": "The Foolish Mortals #freebandnames",
329 | "metadata": {
330 | "iso_language_code": "en",
331 | "result_type": "recent"
332 | },
333 | "retweet_count": 0,
334 | "in_reply_to_status_id_str": null,
335 | "id": 249279667666817024,
336 | "geo": null,
337 | "retweeted": false,
338 | "in_reply_to_user_id": null,
339 | "place": null,
340 | "user": {
341 | "profile_sidebar_fill_color": "BFAC83",
342 | "profile_sidebar_border_color": "615A44",
343 | "profile_background_tile": true,
344 | "name": "Marty Elmer",
345 | "profile_image_url": "http://a0.twimg.com/profile_images/1629790393/shrinker_2000_trans_normal.png",
346 | "created_at": "Mon May 04 00:05:00 +0000 2009",
347 | "location": "Wisconsin, USA",
348 | "follow_request_sent": null,
349 | "profile_link_color": "3B2A26",
350 | "is_translator": false,
351 | "id_str": "37539828",
352 | "entities": {
353 | "url": {
354 | "urls": [
355 | {
356 | "expanded_url": null,
357 | "url": "http://www.omnitarian.me",
358 | "indices": [
359 | 0,
360 | 24
361 | ]
362 | }
363 | ]
364 | },
365 | "description": {
366 | "urls": [
367 |
368 | ]
369 | }
370 | },
371 | "default_profile": false,
372 | "contributors_enabled": false,
373 | "favourites_count": 647,
374 | "url": "http://www.omnitarian.me",
375 | "profile_image_url_https": "https://si0.twimg.com/profile_images/1629790393/shrinker_2000_trans_normal.png",
376 | "utc_offset": -21600,
377 | "id": 37539828,
378 | "profile_use_background_image": true,
379 | "listed_count": 52,
380 | "profile_text_color": "000000",
381 | "lang": "en",
382 | "followers_count": 608,
383 | "protected": false,
384 | "notifications": null,
385 | "profile_background_image_url_https": "https://si0.twimg.com/profile_background_images/106455659/rect6056-9.png",
386 | "profile_background_color": "EEE3C4",
387 | "verified": false,
388 | "geo_enabled": false,
389 | "time_zone": "Central Time (US & Canada)",
390 | "description": "Cartoonist, Illustrator, and T-Shirt connoisseur",
391 | "default_profile_image": false,
392 | "profile_background_image_url": "http://a0.twimg.com/profile_background_images/106455659/rect6056-9.png",
393 | "statuses_count": 3575,
394 | "friends_count": 249,
395 | "following": null,
396 | "show_all_inline_media": true,
397 | "screen_name": "Omnitarian"
398 | },
399 | "in_reply_to_screen_name": null,
400 | "source": "Twitter for iPhone",
401 | "in_reply_to_status_id": null
402 | }
403 | ],
404 | "search_metadata": {
405 | "max_id": 250126199840518145,
406 | "since_id": 24012619984051000,
407 | "refresh_url": "?since_id=250126199840518145&q=%23freebandnames&result_type=mixed&include_entities=1",
408 | "next_results": "?max_id=249279667666817023&q=%23freebandnames&count=4&include_entities=1&result_type=mixed",
409 | "count": 4,
410 | "completed_in": 0.035,
411 | "since_id_str": "24012619984051000",
412 | "query": "%23freebandnames",
413 | "max_id_str": "250126199840518145"
414 | }
415 | }
416 |
--------------------------------------------------------------------------------
/benchmarks/assets/wikipedia_zstandard.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Zstandard - Wikipedia
6 |
7 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
Zstandard
38 |
39 |
From Wikipedia, the free encyclopedia
40 |
41 |
44 |
103 |
Zstandard (or Zstd ) is a lossless data compression algorithm developed by Yann Collet at Facebook . The name also refers to the reference implementation in C . Version 1 of implementation was released as Free software on 31 August 2016.[1] [2]
104 |
105 |
106 |
107 |
Contents
108 |
109 |
116 |
117 |
118 |
Features [ edit ]
119 |
Zstandard was designed to give compression comparable to that of DEFLATE (.ZIP , gzip ) with higher compression / decompression speeds.
120 |
Zstandard combines use of a dictionary-type algorithm (LZ77 ) and Finite State Entropy (tANS ) stage of entropy coding .
121 |
License [ edit ]
122 |
The reference implementation is licensed under the BSD License , published at GitHub . Since version 1.0, it has additional Grant of Patent Rights.[3]
123 |
See also [ edit ]
124 |
130 |
References [ edit ]
131 |
138 |
External links [ edit ]
139 |
146 |
167 |
188 |
189 |
190 |
191 |
192 |
193 |
194 | v
195 | t
196 | e
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 | Lossless
207 |
208 |
209 |
210 |
211 | Entropy type
212 |
213 |
241 |
242 |
243 |
244 |
245 |
246 |
247 | Dictionary type
248 |
249 |
273 |
274 |
275 |
276 |
277 |
278 |
279 | Other types
280 |
281 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 | Audio
303 |
304 |
305 |
306 |
307 | Concepts
308 |
309 |
329 |
330 |
331 |
332 |
333 |
334 |
335 | Codec parts
336 |
337 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 | Image
367 |
368 |
369 |
370 |
371 | Concepts
372 |
373 |
387 |
388 |
389 |
390 |
391 |
392 |
393 | Methods
394 |
395 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 | Video
418 |
419 |
420 |
421 |
422 | Concepts
423 |
424 |
442 |
443 |
444 |
445 |
446 |
447 |
448 | Codec parts
449 |
450 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 | Theory
468 |
469 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
493 |
494 |
495 |
496 |
497 |
498 |
512 |
513 |
514 |
531 |
532 |
545 |
546 |
548 |
550 |
551 |
552 |
553 |
554 |
Navigation menu
555 |
556 |
557 |
558 |
Personal tools
559 |
561 |
562 |
563 |
564 |
Namespaces
565 |
569 |
570 |
580 |
581 |
582 |
590 |
598 |
599 |
600 | Search
601 |
602 |
603 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
Navigation
614 |
615 |
619 |
620 |
621 |
Interaction
622 |
623 |
627 |
628 |
629 |
Tools
630 |
631 |
635 |
636 |
637 |
Print/export
638 |
639 |
643 |
644 |
645 |
Languages
646 |
647 |
651 |
652 |
653 |
654 |
677 |
678 |
679 |
680 |
--------------------------------------------------------------------------------
/benchmarks/zstd_deflate.rake:
--------------------------------------------------------------------------------
1 | require "benchmark/ips"
2 | require "ruby-progressbar"
3 | require "securerandom"
4 | require "zlib"
5 | require_relative "../lib/zstandard"
6 |
7 | namespace :benchmarks do
8 | task :deflate do
9 | [
10 | [
11 | "random string",
12 | SecureRandom.base64(1024*1024*16)[0..(1024*1024*16-1)]
13 | ],
14 | [
15 | "Wikipedia Zstandard article (html)",
16 | File.read(File.join(File.dirname(__FILE__), "assets", "wikipedia_zstandard.html"))
17 | ],
18 | [
19 | "Twitter API response (json)",
20 | File.read(File.join(File.dirname(__FILE__), "assets", "twitter_api_response.json"))
21 | ]
22 | ]
23 | .each do |description, content|
24 | [[1, 1], [6, 6]].each do |levels|
25 | zlib_compressed_size = Zlib.deflate(content, levels.first).bytesize
26 | zstd_compressed_size = Zstandard.deflate(content, levels.last).bytesize
27 |
28 | show_bar = ->(title, size, compressed_size) do
29 | ProgressBar.create(title: title, total: size, starting_at: compressed_size, format: "%t: |%B| %c byte").stop
30 | end
31 |
32 | puts ""
33 | puts "Deflate, #{description}, #{content.bytesize} bytes, zlib: level=#{levels.first || 'default'}, zstd: level=#{levels.last || 'default'}"
34 | puts ""
35 |
36 | show_bar.call("uncompressed ", content.bytesize, content.bytesize)
37 | show_bar.call("compressed (zlib)", content.bytesize, zlib_compressed_size)
38 | show_bar.call("compressed (zstd)", content.bytesize, zstd_compressed_size)
39 |
40 | puts
41 |
42 | Benchmark.ips do |x|
43 | x.config(:time => 5, :warmup => 2)
44 |
45 | x.report("zlib") { Zlib.deflate(content, levels.first) }
46 | x.report("zstd") { Zstandard.deflate(content, levels.last) }
47 |
48 | x.compare!
49 | end
50 | end
51 | end
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/bin/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require "bundler/setup"
4 | require "zstandard"
5 |
6 | # You can add fixtures and/or initialization code here to make experimenting
7 | # with your gem easier. You can also use a different console, if you like.
8 |
9 | # (If you use this, don't forget to add pry to your Gemfile!)
10 | require "pry"
11 | Pry.start
12 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -euo pipefail
3 | IFS=$'\n\t'
4 | set -vx
5 |
6 | bundle install
7 |
8 | # Do any other automated setup that you need to do here
9 |
--------------------------------------------------------------------------------
/lib/zstandard.rb:
--------------------------------------------------------------------------------
1 | require_relative "./zstandard/api"
2 | require_relative "./zstandard/config"
3 | require_relative "./zstandard/version"
4 |
5 | module Zstandard
6 | class Error < ::StandardError; end;
7 | class DecompressedSizeUnknownError < Error; end;
8 | class LibraryVersionNotSupportedError < Error; end;
9 |
10 | def self.deflate(string, level = nil)
11 | API.simple_compress(string, level: level)
12 | end
13 |
14 | def self.inflate(string)
15 | decompressed_size = API.decompressed_size(string)
16 |
17 | if decompressed_size > 0 && decompressed_size <= Config::MAX_SIMPLE_DECOMPRESS_SIZE
18 | API.simple_decompress(string)
19 | else
20 | API.streaming_decompress(string)
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/lib/zstandard/api.rb:
--------------------------------------------------------------------------------
1 | require_relative "./config"
2 | require_relative "./ffi_bindings"
3 |
4 | module Zstandard
5 | # Internal API layer to abstract different libzstd calling semantics/versions
6 | module API
7 | def self.streaming_decompress(string, options = {})
8 | dst_size = window_size(string)
9 |
10 | # The docs propose to check the dst size (windowSize), because it could be manipulated
11 | raise "Invalid dst size!" if dst_size <= 0 || dst_size > Config::MAX_STREAMING_DECOMRPESS_BUFFER_SIZE
12 |
13 | src = FFI::MemoryPointer.from_string(string) # we need the pointer for arithmetics
14 | dst = FFI::MemoryPointer.new(:char, dst_size)
15 |
16 | dst_offset = 0
17 | src_offset = 0
18 | result = []
19 |
20 | dctx = FFIBindings.zstd_create_dctx
21 | FFIBindings.zstd_decompress_begin(dctx)
22 |
23 | while (src_size = FFIBindings.zstd_next_src_size_to_deompress(dctx)) != 0
24 | nbytes = FFIBindings.zstd_decompress_continue(
25 | dctx,
26 | dst + dst_offset,
27 | (dst + dst_offset).size,
28 | src + src_offset,
29 | src_size
30 | )
31 |
32 | if FFIBindings.zstd_is_error(error_code = nbytes) > 0
33 | raise FFIBindings.zstd_get_error_name(error_code)
34 | elsif nbytes > 0
35 | result << (dst + dst_offset).read_bytes(nbytes)
36 | dst_offset += nbytes
37 | dst_offset = 0 if (dst + dst_offset).size == 0
38 | end
39 |
40 | src_offset += src_size
41 | end
42 |
43 | dst.free
44 | src.free
45 | FFIBindings.zstd_free_dctx(dctx)
46 |
47 | result.join
48 | end
49 |
50 | #
51 | # Tries to gather the size of the decompressed data.
52 | #
53 | # @param [String] string Compressed data
54 | # @return [Integer] size of the decompressed data or 0
55 | #
56 | def self.decompressed_size(string)
57 | if FFIBindings.zstd_version_number < 600
58 | parameters = FFIBindings::ZSTD_parameters.new
59 | FFIBindings.zstd_get_frame_params(parameters, string, string.bytesize)
60 | parameters[:srcSize]
61 | elsif FFIBindings.zstd_version_number < 10104
62 | frame_params = FFIBindings::ZSTD_frameParams.new
63 | FFIBindings.zstd_get_frame_params(frame_params, string, string.bytesize)
64 | frame_params[:frameContentSize]
65 | else
66 | FFIBindings.zstd_find_decompressed_size(string, string.bytesize)
67 | end
68 | end
69 |
70 | def self.simple_compress(string, options = {})
71 | level = options[:level] || 1
72 |
73 | dst_size = FFIBindings.zstd_compress_bound(string.bytesize)
74 | dst = FFI::MemoryPointer.new(:char, dst_size)
75 |
76 | error_code = number_of_bytes = FFIBindings.zstd_compress(dst, dst_size, string, string.bytesize, level)
77 |
78 | if FFIBindings.zstd_is_error(error_code) >= 0
79 | dst.read_bytes(number_of_bytes)
80 | else
81 | raise "error"
82 | end
83 | end
84 |
85 | def self.simple_decompress(string, options = {})
86 | #
87 | # The docs state, that one should be carefull when using the simple decompress API, because
88 | # it relies on the upfront knowledge of the decompressed (dst) size. This information may
89 | # by present within the frame header (or not). If it's present, it can be very large and/or
90 | # intentionally modified, so it's vital to check that this value is within the systems limits
91 | # and fallback to streaming decompression if unsure.
92 | #
93 | dst = FFI::MemoryPointer.new(:char, dst_size = API.decompressed_size(string))
94 | error_code = number_of_bytes = FFIBindings.zstd_decompress(dst, dst_size, string, string.bytesize)
95 |
96 | if FFIBindings.zstd_is_error(error_code) != 0
97 | raise FFIBindings.zstd_get_error_name(error_code).read_string
98 | else
99 | dst.read_bytes(number_of_bytes)
100 | end
101 | end
102 |
103 | def self.window_size(string)
104 | if FFIBindings.zstd_version_number < 600
105 | parameters = FFIBindings::ZSTD_parameters.new
106 | FFIBindings.zstd_get_frame_params(parameters, string, string.bytesize)
107 | 2 ** parameters[:windowLog]
108 | elsif FFIBindings.zstd_version_number < 700
109 | frame_params = FFIBindings::ZSTD_frameParams.new
110 | FFIBindings.zstd_get_frame_params(frame_params, string, string.bytesize)
111 | 2 ** frame_params[:windowLog]
112 | elsif Zstandard::FFIBindings.zstd_version_number < 10300
113 | frame_params = FFIBindings::ZSTD_frameParams.new
114 | FFIBindings.zstd_get_frame_params(frame_params, string, string.bytesize)
115 | frame_params[:windowSize]
116 | else
117 | frame_header = FFIBindings::ZSTD_frameHeader.new
118 | FFIBindings.zstd_get_frame_header(frame_header, string, string.bytesize)
119 | frame_header[:windowSize]
120 | end
121 | end
122 | end
123 | end
124 |
--------------------------------------------------------------------------------
/lib/zstandard/config.rb:
--------------------------------------------------------------------------------
1 | module Zstandard
2 | module Config
3 | LIBRARY_PATH = ENV["ZSTANDARD_LIBRARY"] || "zstd"
4 |
5 | # Threshold for switching to streaming decompression
6 | MAX_SIMPLE_DECOMPRESS_SIZE =
7 | begin
8 | default = 1024 * 1024 * 32
9 | env_param = ENV["ZSTANDARD_MAX_SIMPLE_DECOMPRESS_SIZE"].to_i
10 | env_param > 0 ? env_param : default
11 | end
12 | .freeze
13 |
14 | # Caps the window size of compressed data to prohibit abuse (e.g. by
15 | # manipulated frame headers). The docs propose to support at least 8MB.
16 | MAX_STREAMING_DECOMRPESS_BUFFER_SIZE =
17 | begin
18 | default = 1024 * 1024 * 8
19 | env_param = ENV["ZSTANDARD_MAX_STREAMING_DECOMRPESS_BUFFER_SIZE"].to_i
20 | env_param > 0 ? env_param : default
21 | end
22 | .freeze
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/lib/zstandard/ffi_bindings.rb:
--------------------------------------------------------------------------------
1 | require "ffi"
2 | require_relative "./config"
3 |
4 | module Zstandard
5 | module FFIBindings
6 | extend FFI::Library
7 | begin
8 | ffi_lib Config::LIBRARY_PATH
9 | rescue LoadError => e
10 | STDERR.puts "Could not open #{Config::LIBRARY_PATH} shared library!"
11 | STDERR.puts
12 | STDERR.puts "Please be sure you have zstd installed. This can be accomplished via"
13 | STDERR.puts "- your systems package management (e.g. apt-get install zstd)"
14 | STDERR.puts "- compiled/installed by yourself (use ZSTANDARD_LIBRARY env variable for non-default paths)"
15 | STDERR.puts
16 | raise e
17 | end
18 |
19 | # this is placed upfront because it's needed for various conditionals
20 | attach_function :zstd_version_number, :ZSTD_versionNumber, [], :uint
21 |
22 | raise Zstandard::LibraryVersionNotSupportedError if zstd_version_number < 500
23 |
24 | #
25 | # @!group Simple API
26 | #
27 |
28 | # @!method self.zstd_compress(dst, dstCapacity, src, srcSize, compressionLevel)
29 | # @param [void*] dst
30 | # @param [size_t] dstCapacity
31 | # @param [const void*] src
32 | # @param [size_t] srcSize
33 | # @param [int] compressionLevel
34 | # @return [size_t] the compressed size
35 | attach_function :zstd_compress, :ZSTD_compress, [:pointer, :size_t, :pointer, :size_t, :int], :size_t
36 |
37 |
38 | # @!method self.zstd_compress_bound(srcSize)
39 | # @param [size_t] srcSize
40 | # @return [size_t]
41 | attach_function :zstd_compress_bound, :ZSTD_compressBound, [:size_t], :size_t
42 |
43 | # @!method self.zstd_decompress(dst, dstCapacity, src, compressedSize)
44 | # @param [void*] dst
45 | # @param [size_t] dstCapacity
46 | # @param [const void*] src
47 | # @param [size_t] compressedSize
48 | # @return [size_t] the decompressed size
49 | attach_function :zstd_decompress, :ZSTD_decompress, [:pointer, :size_t, :pointer, :size_t], :size_t
50 |
51 | #
52 | # @!group Buffer-less streaming decompression
53 | #
54 |
55 | # @!method self.zstd_create_dctx
56 | # @return [ZSTD_DCtx*]
57 | attach_function :zstd_create_dctx, :ZSTD_createDCtx, [], :pointer
58 |
59 | # @!method self.zstd_decompress_begin(dctx)
60 | # @param [ZSTD_DCtx*] dctx
61 | # @return [size_t]
62 | attach_function :zstd_decompress_begin, :ZSTD_decompressBegin, [:pointer], :size_t
63 |
64 | # @!method self.zstd_decompress_continue(dctx, dst, dstCapacity, src, srcSize)
65 | # @param [ZSTD_DCtx*] dctx
66 | # @param [void*] dst
67 | # @param [size_t] dstCapacity
68 | # @param [const void*] src
69 | # @param [size_t] srcSize
70 | # @return [size_t]
71 | attach_function :zstd_decompress_continue, :ZSTD_decompressContinue, [:pointer, :pointer, :size_t, :pointer, :size_t], :size_t
72 |
73 | # @!method self.zstd_find_decompressed_size
74 | # @param [const void*] src
75 | # @param [size_t] srcSize
76 | # @return [unsigned long long]
77 | if zstd_version_number >= 10104
78 | attach_function :zstd_find_decompressed_size, :ZSTD_findDecompressedSize, [:pointer, :size_t], :uint64
79 | end
80 |
81 | # @!method self.zstd_free_dctx(dctx)
82 | # @param [ZSTD_DCtx*] dctx
83 | # @return [size_t]
84 | attach_function :zstd_free_dctx, :ZSTD_freeDCtx, [:pointer], :size_t
85 |
86 | # @!method self.zstd_get_frame_params(fparamsPtr, src, srcSize)
87 | # @param [ZSTD_parameters,ZSTD_frameParams] fparamsPtr (type depends on the version of `libzstd`, from `>= 0.6.0`, it's {ZSTD_frameParams}, before it's {ZSTD_parameters})
88 | # @param [const void*] src
89 | # @param [size_t] srcSize
90 | # @return [size_t]
91 | # size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t srcSize)
92 | if zstd_version_number < 10300
93 | attach_function :zstd_get_frame_params, :ZSTD_getFrameParams, [:pointer, :pointer, :size_t], :size_t
94 | else
95 | attach_function :zstd_get_frame_header, :ZSTD_getFrameHeader, [:pointer, :pointer, :size_t], :size_t
96 | end
97 |
98 | # @!method zstd_next_src_size_to_deompress(dctx)
99 | # @param [ZSTD_DCtx*] dctx
100 | # @return [size_t]
101 | attach_function :zstd_next_src_size_to_deompress, :ZSTD_nextSrcSizeToDecompress, [:pointer], :size_t
102 |
103 | #
104 | # @!group Helpers
105 | #
106 |
107 | # @!method zstd_get_error_name(code)
108 | # @param [size_t] code
109 | # @return [const char*]
110 | attach_function :zstd_get_error_name, :ZSTD_getErrorName, [:size_t], :pointer
111 |
112 | # @!method zstd_is_error(code)
113 | # @param [size_t] code
114 | # @return [unsigned] an integer indicating if this is an error code. A value > 0 indicates `true`.
115 | # unsigned ZSTD_isError(size_t code)
116 | attach_function :zstd_is_error, :ZSTD_isError, [:size_t], :uint
117 |
118 | # @!method zstd_version_number
119 | # @return [uint]
120 |
121 | # @!endgroup Helpers
122 |
123 | #
124 | # (Advanced) types (requires zstd_version_number to be attached for conditionals)
125 | #
126 |
127 | if zstd_version_number < 600
128 | enum :ZSTD_strategy, [:ZSTD_fast, :ZSTD_greedy, :ZSTD_lazy, :ZSTD_lazy2, :ZSTD_btlazy2]
129 | elsif zstd_version_number < 800
130 | enum :ZSTD_strategy, [:ZSTD_fast, :ZSTD_greedy, :ZSTD_lazy, :ZSTD_lazy2, :ZSTD_btlazy2, :ZSTD_btopt]
131 | else
132 | enum :ZSTD_strategy, [:ZSTD_fast, :ZSTD_dfast, :ZSTD_greedy, :ZSTD_lazy, :ZSTD_lazy2, :ZSTD_btlazy2, :ZSTD_btopt]
133 | end
134 |
135 | # The format of this struct depends on the version of `libzstd` you are using.
136 | #
137 | # `<= v0.6.x`
138 | # ```
139 | # typedef struct {
140 | # U64 frameContentSize;
141 | # U32 windowLog;
142 | # } ZSTD_frameParams;
143 | # ```
144 | #
145 | # `>= v0.7.x`
146 | # ```
147 | # typedef struct {
148 | # unsigned long long frameContentSize;
149 | # unsigned windowSize;
150 | # unsigned dictID;
151 | # unsigned checksumFlag;
152 | # } ZSTD_frameParams;
153 | # ```
154 | if Zstandard::FFIBindings.zstd_version_number < 10300
155 | class ZSTD_frameParams < FFI::Struct
156 | # @!method [](member)
157 | if Zstandard::FFIBindings.zstd_version_number < 700
158 | # `<= v0.6.x`
159 | # @overload [](member)
160 | # @param [:frameContentSize, :windowLog] member
161 | layout(
162 | frameContentSize: :uint64,
163 | windowLog: :uint32
164 | )
165 | elsif Zstandard::FFIBindings.zstd_version_number < 800
166 | # `>= v0.7.x`
167 | # @overload [](member)
168 | # @param [:frameContentSize, :windowSize, :dictID, :checksumFlag] member
169 | layout(
170 | :frameContentSize, :uint64,
171 | :windowSize, :uint32,
172 | :dictID, :uint32,
173 | :checksumFlag, :uint32
174 | )
175 | else
176 | layout(
177 | :frameContentSize, :ulong_long,
178 | :windowSize, :uint,
179 | :dictID, :uint,
180 | :checksumFlag, :uint
181 | )
182 | end
183 | end
184 | else
185 | class ZSTD_frameHeader < FFI::Struct
186 | layout(
187 | :frameContentSize, :ulong_long,
188 | :windowSize, :uint,
189 | :dictID, :uint,
190 | :checksumFlag, :uint
191 | )
192 | end
193 | end
194 |
195 | class ZSTD_parameters < FFI::Struct
196 | # @!method[](member)
197 | if Zstandard::FFIBindings.zstd_version_number < 600
198 | # `<= v0.5.x`
199 | # @overload [](member)
200 | # @param [:srcSize, :windowLog, :contentLog, :hashLog, :searchLog, :searchLength, :targetLength, :strategy]
201 | layout(
202 | :srcSize, :uint64,
203 | :windowLog, :uint32,
204 | :contentLog, :uint32,
205 | :hashLog, :uint32,
206 | :searchLog, :uint32,
207 | :searchLength, :uint32,
208 | :targetLength, :uint32,
209 | :strategy, :ZSTD_strategy
210 | )
211 | end
212 | end
213 | end
214 | end
215 |
--------------------------------------------------------------------------------
/lib/zstandard/version.rb:
--------------------------------------------------------------------------------
1 | module Zstandard
2 | VERSION = "0.1.3"
3 | end
4 |
--------------------------------------------------------------------------------
/run_rspec_with_bundled_libraries.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | PROCESSOR_TYPE=$(uname -p)
4 | DISTRIBUTOR_ID=$(lsb_release -i -s|tr '[:upper:]' '[:lower:]')
5 | RELEASE=$(lsb_release -r -s)
6 |
7 | LIBRARIES_DIRECTORY="./spec/libzstd/${PROCESSOR_TYPE}/${DISTRIBUTOR_ID}/${RELEASE}"
8 |
9 | if [ -d "$LIBRARIES_DIRECTORY" ]; then
10 | for library in ${LIBRARIES_DIRECTORY}/*
11 | do
12 | bundle exec rake ZSTANDARD_LIBRARY=$library
13 | if [ "$?" -ne "0" ]; then
14 | exit 1
15 | fi
16 | done
17 | else
18 | echo "There are no bundled libraries for the current system."
19 | exit 1
20 | fi
21 |
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.0.5.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.0.5.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.0.6.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.0.6.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.0.7.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.0.7.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.0.8.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.0.8.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.1.0.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.1.0.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.1.1.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.1.1.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.1.2.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.1.2.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.1.3.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.1.3.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.1.3.3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.1.3.3
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.1.3.8:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/12.04/libzstd.so.1.3.8
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/14.04/libzstd.so.0.5.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/14.04/libzstd.so.0.5.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/14.04/libzstd.so.0.6.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/14.04/libzstd.so.0.6.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/14.04/libzstd.so.0.7.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/14.04/libzstd.so.0.7.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/14.04/libzstd.so.0.8.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/14.04/libzstd.so.0.8.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/14.04/libzstd.so.1.0.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/14.04/libzstd.so.1.0.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/14.04/libzstd.so.1.1.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/14.04/libzstd.so.1.1.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/14.04/libzstd.so.1.2.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/14.04/libzstd.so.1.2.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/14.04/libzstd.so.1.3.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/14.04/libzstd.so.1.3.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/14.04/libzstd.so.1.3.8:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/14.04/libzstd.so.1.3.8
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/16.04/libzstd.so.0.5.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/16.04/libzstd.so.0.5.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/16.04/libzstd.so.0.6.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/16.04/libzstd.so.0.6.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/16.04/libzstd.so.0.7.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/16.04/libzstd.so.0.7.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/16.04/libzstd.so.0.8.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/16.04/libzstd.so.0.8.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/16.04/libzstd.so.1.0.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/16.04/libzstd.so.1.0.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/16.04/libzstd.so.1.1.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/16.04/libzstd.so.1.1.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/16.04/libzstd.so.1.1.3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/16.04/libzstd.so.1.1.3
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/16.04/libzstd.so.1.2.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/16.04/libzstd.so.1.2.0
--------------------------------------------------------------------------------
/spec/libzstd/x86_64/ubuntu/16.04/libzstd.so.1.3.0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msievers/zstandard-ruby/873ed5fe69f150c006d2656b9a5b0262b4033166/spec/libzstd/x86_64/ubuntu/16.04/libzstd.so.1.3.0
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2 |
3 | if RUBY_ENGINE == "ruby"
4 | if ENV["CI"]
5 | # CI stuff
6 | else
7 | begin
8 | require "pry"
9 | rescue LoadError
10 | end
11 |
12 | begin
13 | require "simplecov"
14 | SimpleCov.start
15 | rescue LoadError
16 | end
17 | end
18 | end
19 |
20 | require "zstandard"
21 |
--------------------------------------------------------------------------------
/spec/zstandard_spec.rb:
--------------------------------------------------------------------------------
1 | require "securerandom"
2 |
3 | describe Zstandard do
4 | puts "\nffi_libs #{Zstandard::FFIBindings.instance_variable_get(:@ffi_libs).map(&:name)}"
5 |
6 | def random_string(length)
7 | # Needs to be truncated because the length of the result of base64 is about 4/3 of length
8 | SecureRandom.base64(length)[0..(length - 1)]
9 | end
10 |
11 | specify ".deflate" do
12 | string = random_string(1024)
13 | compressed_string = Zstandard.deflate(string)
14 | expect(Zstandard.inflate(compressed_string)).to eq(string)
15 | end
16 |
17 | describe ".inflate" do
18 | specify "if decompressed size is <= MAX_SIMPLE_DECOMPRESS_SIZE" do
19 | string = random_string(Zstandard::Config::MAX_SIMPLE_DECOMPRESS_SIZE)
20 | compressed_string = Zstandard.deflate(string)
21 | expect(Zstandard.inflate(compressed_string)).to eq(string)
22 | end
23 |
24 | specify "if decompressed size is > MAX_SIMPLE_DECOMPRESS_SIZE" do
25 | string = random_string(Zstandard::Config::MAX_SIMPLE_DECOMPRESS_SIZE + 1)
26 | compressed_string = Zstandard.deflate(string)
27 | expect(Zstandard.inflate(compressed_string)).to eq(string)
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/zstandard.gemspec:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 | lib = File.expand_path('../lib', __FILE__)
3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4 | require 'zstandard/version'
5 |
6 | Gem::Specification.new do |spec|
7 | spec.name = "zstandard"
8 | spec.version = Zstandard::VERSION
9 | spec.authors = ["Michael Sievers"]
10 | spec.email = ["michael_sievers@web.de"]
11 | spec.summary = %q{zstd (Zstandard) compression library bindings}
12 | spec.description = %q{This gem provides FFI based Ruby bindings for the zstd (Zstandard) compression library.}
13 | spec.homepage = "https://github.com/msievers/zstandard-ruby"
14 | spec.license = "MIT"
15 |
16 | spec.files = `git ls-files -z`.split("\x0").reject do |f|
17 | f.match(%r{^(test|spec|features|bin|benchmarks|run_rspec_with_bundled_libraries.sh)/})
18 | end
19 |
20 | spec.bindir = "exe"
21 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22 | spec.require_paths = ["lib"]
23 |
24 | spec.add_dependency "ffi", "~> 1.0"
25 | end
26 |
--------------------------------------------------------------------------------