lzfse 0.0.1.pre.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 07b55f339ef7d623c2e3c5805f354a6e9b2152e9699d34d8b5fc4fc39e3b177a
4
+ data.tar.gz: '074309076709dc4772b82de24f005a34c9ab9fa7640ce915ea4086afe0b44f33'
5
+ SHA512:
6
+ metadata.gz: 4f594884e1eb6d0efe2e04e79544307b1671c27ab2ad65414088e596c88b4cbaad1a4100c30428aa6a75cd9e19c5b5db7ec5e46788380ecfebfba9e447b2a10e
7
+ data.tar.gz: ba5c1b9c9357dc6776fda37537175ffdc8191cd4ac8f914221c27aa460f4d4d9ecd783a6e5bc22e86775a7e03d4f98e81346e4e615d0d99891374da1ce5aac9a
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --no-private --markup-provider=redcarpet --markup=markdown - README.md LICENSE ext/lzfse/LICENSE
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 William Woodruff <william @ yossarian.net>
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.
data/README.md ADDED
@@ -0,0 +1,38 @@
1
+ lzfse.rb
2
+ ========
3
+
4
+ [![CI](https://github.com/woodruffw/lzfse.rb/actions/workflows/ci.yml/badge.svg)](https://github.com/woodruffw/lzfse.rb/actions/workflows/ci.yml)
5
+
6
+ Ruby bindings for Apple's reference implementation of [LZFSE](https://github.com/lzfse/lzfse).
7
+
8
+ Bindings are also provided for the internal LZVN APIs.
9
+
10
+ ## Usage
11
+
12
+ You'll need the gem:
13
+
14
+ ```bash
15
+ gem install lzfse
16
+ ```
17
+
18
+ Then, use the four public APIs:
19
+
20
+ ```ruby
21
+ require "lzfse"
22
+
23
+ # LZFSE
24
+ compressed = LZFSE.lzfse_compress "please compress this string"
25
+ LZFSE.lzfse_decompress compressed
26
+
27
+ # LZVN
28
+ compressed = LZFSE.lzvn_compress "please also compress this string!"
29
+ LZFSE.lzvn_compress compressed
30
+ ```
31
+
32
+ Each API takes a single string and returns a string.
33
+
34
+ ## License
35
+
36
+ *lzfse.rb* is licensed under the MIT license.
37
+
38
+ Apple's reference implementation of LZFSE is licensed under the 3-clause BSD license.
data/ext/lzfse/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2015-2016, Apple Inc. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without modification,
4
+ are permitted provided that the following conditions are met:
5
+
6
+ 1. Redistributions of source code must retain the above copyright notice,
7
+ this list of conditions and the following disclaimer.
8
+
9
+ 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+
13
+ 3. Neither the name of the copyright holder(s) nor the names of any contributors
14
+ may be used to endorse or promote products derived from this software without
15
+ specific prior written permission.
16
+
17
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
18
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
20
+ SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
26
+ OF SUCH DAMAGE.
27
+
data/ext/lzfse/ext.c ADDED
@@ -0,0 +1,194 @@
1
+ #include "ext.h"
2
+
3
+ VALUE mLZFSE = Qnil;
4
+ VALUE cEncodeError = Qnil;
5
+ VALUE cDecodeError = Qnil;
6
+
7
+ static VALUE mLZFSE_lzfse_encode_intern(VALUE self, VALUE input) {
8
+ Check_Type(input, T_STRING);
9
+
10
+ size_t input_len = RSTRING_LEN(input);
11
+ uint8_t *input_buf = (uint8_t *)RSTRING_PTR(input);
12
+
13
+ if (input_len <= 0) {
14
+ rb_raise(cEncodeError, "input buffer must not be empty");
15
+ }
16
+
17
+ size_t output_len = input_len + 4096;
18
+ uint8_t *output_buf = malloc(output_len);
19
+
20
+ output_len = lzfse_encode_buffer(output_buf, output_len, input_buf, input_len, NULL);
21
+
22
+ if (output_len <= 0) {
23
+ rb_raise(cEncodeError, "encode failed (output buffer possibly too small)");
24
+ }
25
+
26
+ VALUE output_str = rb_str_new((char *)output_buf, output_len);
27
+ free(output_buf);
28
+
29
+ return output_str;
30
+ }
31
+
32
+ static VALUE mLZFSE_lzfse_decode_intern(VALUE self, VALUE input) {
33
+ Check_Type(input, T_STRING);
34
+
35
+ size_t input_len = RSTRING_LEN(input);
36
+ uint8_t *input_buf = (uint8_t *)RSTRING_PTR(input);
37
+
38
+ if (input_len <= 0) {
39
+ rb_raise(cDecodeError, "input buffer must not be empty");
40
+ }
41
+
42
+ // Educated guess: start with a decompression buffer twice as large and work
43
+ // from there.
44
+ size_t output_len = input_len * 2;
45
+ uint8_t *output_buf = malloc(output_len);
46
+
47
+ // NOTE(ww): The public `lzfse_decode_buffer` API is a little bit braindead,
48
+ // so we use the "internal" `lzfse_decode` API instead. This requires
49
+ // us to set the decoder state up for ourselves.
50
+ void *scratch_buffer = malloc(lzfse_decode_scratch_size() + 1);
51
+ lzfse_decoder_state *state = (lzfse_decoder_state *)scratch_buffer;
52
+
53
+ // NOTE(ww): It would be nice if there was an allocate-on-demand API, but
54
+ // there isn't. So we do things the bad way.
55
+ do {
56
+ // We have to update each of these fields with every try, to avoid
57
+ // mixing-and-matching decompression states between attempts.
58
+ memset(state, 0x00, sizeof(lzfse_decoder_state));
59
+ state->src = input_buf;
60
+ state->src_begin = input_buf;
61
+ state->src_end = input_buf + input_len;
62
+ state->dst = output_buf;
63
+ state->dst_begin = output_buf;
64
+ state->dst_end = output_buf + output_len;
65
+
66
+ int status = lzfse_decode(state);
67
+ if (status == LZFSE_STATUS_OK) {
68
+ break;
69
+ } else if (status == LZFSE_STATUS_DST_FULL) {
70
+ // Try again. There is almost certainly a better way of doing this
71
+ // that involves preserving the decoder state and reusing the partially
72
+ // decoded buffer, but this suffices for now.
73
+ output_len *= 2;
74
+ output_buf = realloc(output_buf, output_len);
75
+ } else {
76
+ rb_raise(cDecodeError, "internal error while decoding (%d)", status);
77
+ }
78
+ } while (true);
79
+
80
+ free(scratch_buffer);
81
+
82
+ VALUE output_str = rb_str_new((char *)output_buf, state->dst - output_buf);
83
+ free(output_buf);
84
+
85
+ return output_str;
86
+ }
87
+
88
+ static VALUE mLZFSE_lzvn_encode_intern(VALUE self, VALUE input) {
89
+ Check_Type(input, T_STRING);
90
+
91
+ size_t input_len = RSTRING_LEN(input);
92
+ uint8_t *input_buf = (uint8_t *)RSTRING_PTR(input);
93
+
94
+ if (input_len <= 0) {
95
+ rb_raise(cEncodeError, "input buffer must not be empty");
96
+ }
97
+
98
+ if (input_len < LZVN_ENCODE_MIN_SRC_SIZE) {
99
+ rb_raise(cEncodeError, "input is too small for LZVN (%zu < %zu)", input_len,
100
+ LZVN_ENCODE_MIN_SRC_SIZE);
101
+ }
102
+
103
+ size_t output_len = input_len + 4096;
104
+ uint8_t *output_buf = malloc(output_len);
105
+
106
+ // NOTE(ww): lzvn_encode_buffer takes the same scratch buffer as the LZFSE
107
+ // APIs. See lzfse_encode_buffer_with_scratch in lzfse_encode.c.
108
+ void *scratch_buffer = malloc(lzfse_encode_scratch_size() + 1);
109
+
110
+ output_len = lzvn_encode_buffer(output_buf, output_len, input_buf, input_len, scratch_buffer);
111
+ if (output_len <= 0) {
112
+ rb_raise(cEncodeError, "encode failed (output buffer possibly too small)");
113
+ }
114
+
115
+ free(scratch_buffer);
116
+ VALUE output_str = rb_str_new((char *)output_buf, output_len);
117
+ free(output_buf);
118
+
119
+ return output_str;
120
+ }
121
+
122
+ static VALUE mLZFSE_lzvn_decode_intern(VALUE self, VALUE input) {
123
+ Check_Type(input, T_STRING);
124
+
125
+ size_t input_len = RSTRING_LEN(input);
126
+ uint8_t *input_buf = (uint8_t *)RSTRING_PTR(input);
127
+
128
+ if (input_len <= 0) {
129
+ rb_raise(cDecodeError, "input buffer must not be empty");
130
+ }
131
+
132
+ // Educated guess: start with a decompression buffer twice as large and work
133
+ // from there.
134
+ size_t output_len = input_len * 2;
135
+ uint8_t *output_buf = malloc(output_len);
136
+
137
+ // NOTE(ww): Very similar to LZFSE decoding above; the main difference is that
138
+ // our decoder state is a stack object instead.
139
+ lzvn_decoder_state state;
140
+ do {
141
+ memset(&state, 0x00, sizeof(lzvn_decoder_state));
142
+ state.src = input_buf;
143
+ state.src_end = input_buf + input_len;
144
+ state.dst = output_buf;
145
+ state.dst_begin = output_buf;
146
+ state.dst_end = output_buf + output_len;
147
+
148
+ lzvn_decode(&state);
149
+
150
+ // NOTE(ww): Unlike `lzfse_decode`, `lzvn_decode` doesn't provide a status
151
+ // API. We need to check various decoder states to determine our next step.
152
+ // Below is mostly ripped from the internals of `lzfse_decode`, case
153
+ // `LZFSE_COMPRESSEDLZVN_BLOCK_MAGIC`.
154
+ size_t src_used = state.src - input_buf;
155
+ size_t dst_used = state.dst - output_buf;
156
+
157
+ // Sanity check: we shouldn't have overrun either buffer.
158
+ if (src_used > input_len || dst_used > output_len) {
159
+ rb_raise(cDecodeError, "decode failed: internal buffer mismatch");
160
+ }
161
+
162
+ // If we're in a valid state and we've consumed the entire input, we're
163
+ // done. Observe that we can't check the validity of dst_used here, since a
164
+ // raw LZVN stream doesn't include its raw output size.
165
+ if (src_used == input_len && state.end_of_stream) {
166
+ break;
167
+ }
168
+
169
+ // If we're in an invalid state, die.
170
+ if (src_used == input_len || state.end_of_stream) {
171
+ rb_raise(cDecodeError, "internal error while decoding (lzvn, %zu, %zu)", src_used, dst_used);
172
+ }
173
+
174
+ // Otherwise, our output buffer was too small. Retry.
175
+ output_len *= 2;
176
+ output_buf = realloc(output_buf, output_len);
177
+ } while (true);
178
+
179
+ VALUE output_str = rb_str_new((char *)output_buf, state.dst - output_buf);
180
+ free(output_buf);
181
+
182
+ return output_str;
183
+ }
184
+
185
+ __attribute__((visibility("default"))) void Init_lzfse() {
186
+ mLZFSE = rb_define_module("LZFSE");
187
+ cEncodeError = rb_const_get(mLZFSE, rb_intern("EncodeError"));
188
+ cDecodeError = rb_const_get(mLZFSE, rb_intern("DecodeError"));
189
+
190
+ rb_define_singleton_method(mLZFSE, "lzfse_encode_intern", mLZFSE_lzfse_encode_intern, 1);
191
+ rb_define_singleton_method(mLZFSE, "lzfse_decode_intern", mLZFSE_lzfse_decode_intern, 1);
192
+ rb_define_singleton_method(mLZFSE, "lzvn_encode_intern", mLZFSE_lzvn_encode_intern, 1);
193
+ rb_define_singleton_method(mLZFSE, "lzvn_decode_intern", mLZFSE_lzvn_decode_intern, 1);
194
+ }
data/ext/lzfse/ext.h ADDED
@@ -0,0 +1,14 @@
1
+ #ifndef LZFSE_RB
2
+ #define LZFSE_RB
3
+
4
+ #include <ruby.h>
5
+ #include <stdbool.h>
6
+ #include <stdio.h>
7
+
8
+ #include "lzfse.h"
9
+ #include "lzfse_internal.h"
10
+ #include "lzvn_decode_base.h"
11
+
12
+ extern VALUE mLZFSE;
13
+
14
+ #endif
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mkmf"
4
+
5
+ RbConfig::MAKEFILE_CONFIG["CC"] = ENV["CC"] if ENV["CC"]
6
+
7
+ append_cflags %w[-Os -Wno-unknown-pragmas -Wno-unused-variable -DNDEBUG -D_POSIX_C_SOURCE
8
+ -std=c99 -fvisibility=hidden -g]
9
+
10
+ create_makefile "lzfse"
data/ext/lzfse/lzfse.h ADDED
@@ -0,0 +1,136 @@
1
+ /*
2
+ Copyright (c) 2015-2016, Apple Inc. All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
+
6
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
+
8
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
9
+ in the documentation and/or other materials provided with the distribution.
10
+
11
+ 3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
12
+ from this software without specific prior written permission.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
15
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
16
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
18
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
19
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20
+ */
21
+
22
+ #ifndef LZFSE_H
23
+ #define LZFSE_H
24
+
25
+ #include <stddef.h>
26
+ #include <stdint.h>
27
+
28
+ #ifdef __cplusplus
29
+ extern "C" {
30
+ #endif
31
+
32
+ #if defined(_MSC_VER) && !defined(__clang__)
33
+ # define __attribute__(X)
34
+ # pragma warning(disable : 4068)
35
+ #endif
36
+
37
+ #if defined(LZFSE_DLL)
38
+ # if defined(_WIN32) || defined(__CYGWIN__)
39
+ # if defined(LZFSE_DLL_EXPORTS)
40
+ # define LZFSE_API __declspec(dllexport)
41
+ # else
42
+ # define LZFSE_API __declspec(dllimport)
43
+ # endif
44
+ # endif
45
+ #endif
46
+
47
+ #if !defined(LZFSE_API)
48
+ # if __GNUC__ >= 4
49
+ # define LZFSE_API __attribute__((visibility("default")))
50
+ # else
51
+ # define LZFSE_API
52
+ # endif
53
+ #endif
54
+
55
+ /*! @abstract Get the required scratch buffer size to compress using LZFSE. */
56
+ LZFSE_API size_t lzfse_encode_scratch_size();
57
+
58
+ /*! @abstract Compress a buffer using LZFSE.
59
+ *
60
+ * @param dst_buffer
61
+ * Pointer to the first byte of the destination buffer.
62
+ *
63
+ * @param dst_size
64
+ * Size of the destination buffer in bytes.
65
+ *
66
+ * @param src_buffer
67
+ * Pointer to the first byte of the source buffer.
68
+ *
69
+ * @param src_size
70
+ * Size of the source buffer in bytes.
71
+ *
72
+ * @param scratch_buffer
73
+ * If non-NULL, a pointer to scratch space for the routine to use as workspace;
74
+ * the routine may use up to lzfse_encode_scratch_size( ) bytes of workspace
75
+ * during its operation, and will not perform any internal allocations. If
76
+ * NULL, the routine may allocate its own memory to use during operation via
77
+ * a single call to malloc( ), and will release it by calling free( ) prior
78
+ * to returning. For most use, passing NULL is perfectly satisfactory, but if
79
+ * you require strict control over allocation, you will want to pass an
80
+ * explicit scratch buffer.
81
+ *
82
+ * @return
83
+ * The number of bytes written to the destination buffer if the input is
84
+ * successfully compressed. If the input cannot be compressed to fit into
85
+ * the provided buffer, or an error occurs, zero is returned, and the
86
+ * contents of dst_buffer are unspecified. */
87
+ LZFSE_API size_t lzfse_encode_buffer(uint8_t *__restrict dst_buffer,
88
+ size_t dst_size,
89
+ const uint8_t *__restrict src_buffer,
90
+ size_t src_size,
91
+ void *__restrict scratch_buffer);
92
+
93
+ /*! @abstract Get the required scratch buffer size to decompress using LZFSE. */
94
+ LZFSE_API size_t lzfse_decode_scratch_size();
95
+
96
+ /*! @abstract Decompress a buffer using LZFSE.
97
+ *
98
+ * @param dst_buffer
99
+ * Pointer to the first byte of the destination buffer.
100
+ *
101
+ * @param dst_size
102
+ * Size of the destination buffer in bytes.
103
+ *
104
+ * @param src_buffer
105
+ * Pointer to the first byte of the source buffer.
106
+ *
107
+ * @param src_size
108
+ * Size of the source buffer in bytes.
109
+ *
110
+ * @param scratch_buffer
111
+ * If non-NULL, a pointer to scratch space for the routine to use as workspace;
112
+ * the routine may use up to lzfse_decode_scratch_size( ) bytes of workspace
113
+ * during its operation, and will not perform any internal allocations. If
114
+ * NULL, the routine may allocate its own memory to use during operation via
115
+ * a single call to malloc( ), and will release it by calling free( ) prior
116
+ * to returning. For most use, passing NULL is perfectly satisfactory, but if
117
+ * you require strict control over allocation, you will want to pass an
118
+ * explicit scratch buffer.
119
+ *
120
+ * @return
121
+ * The number of bytes written to the destination buffer if the input is
122
+ * successfully decompressed. If there is not enough space in the destination
123
+ * buffer to hold the entire expanded output, only the first dst_size bytes
124
+ * will be written to the buffer and dst_size is returned. Note that this
125
+ * behavior differs from that of lzfse_encode_buffer. */
126
+ LZFSE_API size_t lzfse_decode_buffer(uint8_t *__restrict dst_buffer,
127
+ size_t dst_size,
128
+ const uint8_t *__restrict src_buffer,
129
+ size_t src_size,
130
+ void *__restrict scratch_buffer);
131
+
132
+ #ifdef __cplusplus
133
+ } /* extern "C" */
134
+ #endif
135
+
136
+ #endif /* LZFSE_H */