ruby-lzws 1.1.5 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/ext/lzws_ext/io.c CHANGED
@@ -1,16 +1,18 @@
1
1
  // Ruby bindings for lzws library.
2
2
  // Copyright (c) 2019 AUTHORS, MIT License.
3
3
 
4
- #include "ruby/io.h"
4
+ #include "lzws_ext/io.h"
5
5
 
6
- #include <lzws/common.h>
7
6
  #include <lzws/file.h>
8
7
 
9
8
  #include "lzws_ext/error.h"
10
- #include "lzws_ext/io.h"
9
+ #include "lzws_ext/gvl.h"
11
10
  #include "lzws_ext/macro.h"
12
11
  #include "lzws_ext/option.h"
13
12
  #include "ruby.h"
13
+ #include "ruby/io.h"
14
+
15
+ // -- utils --
14
16
 
15
17
  #define GET_FILE(target) \
16
18
  Check_Type(target, T_FILE); \
@@ -48,22 +50,52 @@ static inline lzws_ext_result_t get_file_error(lzws_result_t result)
48
50
  }
49
51
  }
50
52
 
53
+ // -- compress --
54
+
55
+ typedef struct
56
+ {
57
+ FILE* source_file;
58
+ size_t source_buffer_length;
59
+ FILE* destination_file;
60
+ size_t destination_buffer_length;
61
+ lzws_compressor_options_t* compressor_options_ptr;
62
+ lzws_result_t result;
63
+ } compress_args_t;
64
+
65
+ static inline void* compress_wrapper(void* data)
66
+ {
67
+ compress_args_t* args = data;
68
+
69
+ args->result = lzws_compress_file(
70
+ args->source_file,
71
+ args->source_buffer_length,
72
+ args->destination_file,
73
+ args->destination_buffer_length,
74
+ args->compressor_options_ptr);
75
+
76
+ return NULL;
77
+ }
78
+
51
79
  VALUE lzws_ext_compress_io(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE destination, VALUE options)
52
80
  {
53
81
  GET_FILE(source);
54
82
  GET_FILE(destination);
55
83
  Check_Type(options, T_HASH);
84
+ LZWS_EXT_GET_SIZE_OPTION(options, source_buffer_length);
85
+ LZWS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
86
+ LZWS_EXT_GET_BOOL_OPTION(options, gvl);
56
87
  LZWS_EXT_GET_COMPRESSOR_OPTIONS(options);
57
- LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, source_buffer_length);
58
- LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
59
88
 
60
- lzws_result_t result = lzws_compress_file(
61
- source_file, source_buffer_length,
62
- destination_file, destination_buffer_length,
63
- without_magic_header, max_code_bit_length, block_mode, msb, unaligned_bit_groups, quiet);
89
+ compress_args_t args = {
90
+ .source_file = source_file,
91
+ .source_buffer_length = source_buffer_length,
92
+ .destination_file = destination_file,
93
+ .destination_buffer_length = destination_buffer_length,
94
+ .compressor_options_ptr = &compressor_options};
64
95
 
65
- if (result != 0) {
66
- lzws_ext_raise_error(get_file_error(result));
96
+ LZWS_EXT_GVL_WRAP(gvl, compress_wrapper, &args);
97
+ if (args.result != 0) {
98
+ lzws_ext_raise_error(get_file_error(args.result));
67
99
  }
68
100
 
69
101
  // Ruby itself won't flush stdio file before closing fd, flush is required.
@@ -72,22 +104,52 @@ VALUE lzws_ext_compress_io(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE dest
72
104
  return Qnil;
73
105
  }
74
106
 
107
+ // -- decompress --
108
+
109
+ typedef struct
110
+ {
111
+ FILE* source_file;
112
+ size_t source_buffer_length;
113
+ FILE* destination_file;
114
+ size_t destination_buffer_length;
115
+ lzws_decompressor_options_t* decompressor_options_ptr;
116
+ lzws_result_t result;
117
+ } decompress_args_t;
118
+
119
+ static inline void* decompress_wrapper(void* data)
120
+ {
121
+ decompress_args_t* args = data;
122
+
123
+ args->result = lzws_decompress_file(
124
+ args->source_file,
125
+ args->source_buffer_length,
126
+ args->destination_file,
127
+ args->destination_buffer_length,
128
+ args->decompressor_options_ptr);
129
+
130
+ return NULL;
131
+ }
132
+
75
133
  VALUE lzws_ext_decompress_io(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE destination, VALUE options)
76
134
  {
77
135
  GET_FILE(source);
78
136
  GET_FILE(destination);
79
137
  Check_Type(options, T_HASH);
138
+ LZWS_EXT_GET_SIZE_OPTION(options, source_buffer_length);
139
+ LZWS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
140
+ LZWS_EXT_GET_BOOL_OPTION(options, gvl);
80
141
  LZWS_EXT_GET_DECOMPRESSOR_OPTIONS(options);
81
- LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, source_buffer_length);
82
- LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
83
142
 
84
- lzws_result_t result = lzws_decompress_file(
85
- source_file, source_buffer_length,
86
- destination_file, destination_buffer_length,
87
- without_magic_header, msb, unaligned_bit_groups, quiet);
143
+ decompress_args_t args = {
144
+ .source_file = source_file,
145
+ .source_buffer_length = source_buffer_length,
146
+ .destination_file = destination_file,
147
+ .destination_buffer_length = destination_buffer_length,
148
+ .decompressor_options_ptr = &decompressor_options};
88
149
 
89
- if (result != 0) {
90
- lzws_ext_raise_error(get_file_error(result));
150
+ LZWS_EXT_GVL_WRAP(gvl, decompress_wrapper, &args);
151
+ if (args.result != 0) {
152
+ lzws_ext_raise_error(get_file_error(args.result));
91
153
  }
92
154
 
93
155
  // Ruby itself won't flush stdio file before closing fd, flush is required.
@@ -96,6 +158,8 @@ VALUE lzws_ext_decompress_io(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE de
96
158
  return Qnil;
97
159
  }
98
160
 
161
+ // -- exports --
162
+
99
163
  void lzws_ext_io_exports(VALUE root_module)
100
164
  {
101
165
  rb_define_module_function(root_module, "_native_compress_io", RUBY_METHOD_FUNC(lzws_ext_compress_io), 3);
data/ext/lzws_ext/main.c CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  #include "lzws_ext/buffer.h"
5
5
  #include "lzws_ext/io.h"
6
+ #include "lzws_ext/option.h"
6
7
  #include "lzws_ext/stream/compressor.h"
7
8
  #include "lzws_ext/stream/decompressor.h"
8
9
  #include "lzws_ext/string.h"
@@ -14,6 +15,7 @@ void Init_lzws_ext()
14
15
 
15
16
  lzws_ext_buffer_exports(root_module);
16
17
  lzws_ext_io_exports(root_module);
18
+ lzws_ext_option_exports(root_module);
17
19
  lzws_ext_compressor_exports(root_module);
18
20
  lzws_ext_decompressor_exports(root_module);
19
21
  lzws_ext_string_exports(root_module);
@@ -6,15 +6,15 @@
6
6
  #include "lzws_ext/error.h"
7
7
  #include "ruby.h"
8
8
 
9
- static inline VALUE get_raw_option_value(VALUE options, const char* name)
9
+ // -- values --
10
+
11
+ static inline VALUE get_raw_value(VALUE options, const char* name)
10
12
  {
11
13
  return rb_funcall(options, rb_intern("[]"), 1, ID2SYM(rb_intern(name)));
12
14
  }
13
15
 
14
- bool lzws_ext_get_bool_option_value(VALUE options, const char* name)
16
+ static inline bool get_bool_value(VALUE raw_value)
15
17
  {
16
- VALUE raw_value = get_raw_option_value(options, name);
17
-
18
18
  int raw_type = TYPE(raw_value);
19
19
  if (raw_type != T_TRUE && raw_type != T_FALSE) {
20
20
  lzws_ext_raise_error(LZWS_EXT_ERROR_VALIDATE_FAILED);
@@ -23,20 +23,56 @@ bool lzws_ext_get_bool_option_value(VALUE options, const char* name)
23
23
  return raw_type == T_TRUE;
24
24
  }
25
25
 
26
- unsigned int lzws_ext_get_uint_option_value(VALUE options, const char* name)
26
+ static inline unsigned int get_uint_value(VALUE raw_value)
27
27
  {
28
- VALUE raw_value = get_raw_option_value(options, name);
29
-
30
28
  Check_Type(raw_value, T_FIXNUM);
31
29
 
32
30
  return NUM2UINT(raw_value);
33
31
  }
34
32
 
35
- size_t lzws_ext_get_size_option_value(VALUE options, const char* name)
33
+ static inline size_t get_size_value(VALUE raw_value)
36
34
  {
37
- VALUE raw_value = get_raw_option_value(options, name);
38
-
39
35
  Check_Type(raw_value, T_FIXNUM);
40
36
 
41
37
  return NUM2SIZET(raw_value);
42
38
  }
39
+
40
+ void lzws_ext_resolve_bool_option(VALUE options, bool* option, const char* name)
41
+ {
42
+ VALUE raw_value = get_raw_value(options, name);
43
+ if (raw_value != Qnil) {
44
+ *option = get_bool_value(raw_value);
45
+ }
46
+ }
47
+
48
+ void lzws_ext_resolve_max_code_bit_length_option(VALUE options, lzws_byte_fast_t* option, const char* name)
49
+ {
50
+ VALUE raw_value = get_raw_value(options, name);
51
+ if (raw_value != Qnil) {
52
+ *option = get_uint_value(raw_value);
53
+ }
54
+ }
55
+
56
+ bool lzws_ext_get_bool_option_value(VALUE options, const char* name)
57
+ {
58
+ VALUE raw_value = get_raw_value(options, name);
59
+
60
+ return get_bool_value(raw_value);
61
+ }
62
+
63
+ size_t lzws_ext_get_size_option_value(VALUE options, const char* name)
64
+ {
65
+ VALUE raw_value = get_raw_value(options, name);
66
+
67
+ return get_size_value(raw_value);
68
+ }
69
+
70
+ // -- exports --
71
+
72
+ void lzws_ext_option_exports(VALUE root_module)
73
+ {
74
+ VALUE module = rb_define_module_under(root_module, "Option");
75
+
76
+ rb_define_const(module, "LOWEST_MAX_CODE_BIT_LENGTH", UINT2NUM(LZWS_LOWEST_MAX_CODE_BIT_LENGTH));
77
+ rb_define_const(module, "BIGGEST_MAX_CODE_BIT_LENGTH", UINT2NUM(LZWS_BIGGEST_MAX_CODE_BIT_LENGTH));
78
+ }
@@ -4,40 +4,46 @@
4
4
  #if !defined(LZWS_EXT_OPTIONS_H)
5
5
  #define LZWS_EXT_OPTIONS_H
6
6
 
7
+ #include <lzws/compressor/common.h>
8
+ #include <lzws/decompressor/common.h>
7
9
  #include <stdbool.h>
8
10
  #include <stdlib.h>
9
11
 
10
- #include "lzws_ext/common.h"
11
12
  #include "ruby.h"
12
13
 
13
- bool lzws_ext_get_bool_option_value(VALUE options, const char* name);
14
- unsigned int lzws_ext_get_uint_option_value(VALUE options, const char* name);
15
- size_t lzws_ext_get_size_option_value(VALUE options, const char* name);
14
+ void lzws_ext_resolve_bool_option(VALUE options, bool* option, const char* name);
15
+ void lzws_ext_resolve_max_code_bit_length_option(VALUE options, lzws_byte_fast_t* option, const char* name);
16
16
 
17
- #define LZWS_EXT_GET_BOOL_OPTION(options, name) \
18
- bool name = lzws_ext_get_bool_option_value(options, #name);
17
+ #define LZWS_EXT_RESOLVE_BOOL_OPTION(options, target_options, name) \
18
+ lzws_ext_resolve_bool_option(options, &target_options.name, #name);
19
19
 
20
- #define LZWS_EXT_GET_UINT_OPTION(options, type, name) \
21
- type name = lzws_ext_get_uint_option_value(options, #name);
20
+ #define LZWS_EXT_RESOLVE_MAX_CODE_BIT_LENGTH_OPTION(options, target_options, name) \
21
+ lzws_ext_resolve_max_code_bit_length_option(options, &target_options.name, #name);
22
22
 
23
- #define LZWS_EXT_GET_SIZE_OPTION(options, name) \
24
- size_t name = lzws_ext_get_size_option_value(options, #name);
23
+ #define LZWS_EXT_GET_COMPRESSOR_OPTIONS(options) \
24
+ lzws_compressor_options_t compressor_options = LZWS_COMPRESSOR_DEFAULT_OPTIONS; \
25
+ \
26
+ LZWS_EXT_RESOLVE_BOOL_OPTION(options, compressor_options, without_magic_header); \
27
+ LZWS_EXT_RESOLVE_MAX_CODE_BIT_LENGTH_OPTION(options, compressor_options, max_code_bit_length); \
28
+ LZWS_EXT_RESOLVE_BOOL_OPTION(options, compressor_options, block_mode); \
29
+ LZWS_EXT_RESOLVE_BOOL_OPTION(options, compressor_options, msb); \
30
+ LZWS_EXT_RESOLVE_BOOL_OPTION(options, compressor_options, unaligned_bit_groups); \
31
+ LZWS_EXT_RESOLVE_BOOL_OPTION(options, compressor_options, quiet);
25
32
 
26
- #define LZWS_EXT_GET_COMPRESSOR_OPTIONS(options) \
27
- LZWS_EXT_GET_BOOL_OPTION(options, without_magic_header); \
28
- LZWS_EXT_GET_UINT_OPTION(options, lzws_ext_byte_fast_t, max_code_bit_length); \
29
- LZWS_EXT_GET_BOOL_OPTION(options, block_mode); \
30
- LZWS_EXT_GET_BOOL_OPTION(options, msb); \
31
- LZWS_EXT_GET_BOOL_OPTION(options, unaligned_bit_groups); \
32
- LZWS_EXT_GET_BOOL_OPTION(options, quiet);
33
+ #define LZWS_EXT_GET_DECOMPRESSOR_OPTIONS(options) \
34
+ lzws_decompressor_options_t decompressor_options = LZWS_DECOMPRESSOR_DEFAULT_OPTIONS; \
35
+ \
36
+ LZWS_EXT_RESOLVE_BOOL_OPTION(options, decompressor_options, without_magic_header); \
37
+ LZWS_EXT_RESOLVE_BOOL_OPTION(options, decompressor_options, msb); \
38
+ LZWS_EXT_RESOLVE_BOOL_OPTION(options, decompressor_options, unaligned_bit_groups); \
39
+ LZWS_EXT_RESOLVE_BOOL_OPTION(options, decompressor_options, quiet);
33
40
 
34
- #define LZWS_EXT_GET_DECOMPRESSOR_OPTIONS(options) \
35
- LZWS_EXT_GET_BOOL_OPTION(options, without_magic_header); \
36
- LZWS_EXT_GET_BOOL_OPTION(options, msb); \
37
- LZWS_EXT_GET_BOOL_OPTION(options, unaligned_bit_groups); \
38
- LZWS_EXT_GET_BOOL_OPTION(options, quiet);
41
+ bool lzws_ext_get_bool_option_value(VALUE options, const char* name);
42
+ size_t lzws_ext_get_size_option_value(VALUE options, const char* name);
39
43
 
40
- #define LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, name) \
41
- LZWS_EXT_GET_SIZE_OPTION(options, name);
44
+ #define LZWS_EXT_GET_BOOL_OPTION(options, name) bool name = lzws_ext_get_bool_option_value(options, #name);
45
+ #define LZWS_EXT_GET_SIZE_OPTION(options, name) size_t name = lzws_ext_get_size_option_value(options, #name);
46
+
47
+ void lzws_ext_option_exports(VALUE root_module);
42
48
 
43
49
  #endif // LZWS_EXT_OPTIONS_H
@@ -4,15 +4,16 @@
4
4
  #include "lzws_ext/stream/compressor.h"
5
5
 
6
6
  #include <lzws/buffer.h>
7
- #include <lzws/common.h>
8
- #include <lzws/compressor/common.h>
9
7
  #include <lzws/compressor/main.h>
10
8
  #include <lzws/compressor/state.h>
11
9
 
12
10
  #include "lzws_ext/error.h"
11
+ #include "lzws_ext/gvl.h"
13
12
  #include "lzws_ext/option.h"
14
13
  #include "ruby.h"
15
14
 
15
+ // -- initialization --
16
+
16
17
  static void free_compressor(lzws_ext_compressor_t* compressor_ptr)
17
18
  {
18
19
  lzws_compressor_state_t* state_ptr = compressor_ptr->state_ptr;
@@ -31,14 +32,14 @@ static void free_compressor(lzws_ext_compressor_t* compressor_ptr)
31
32
  VALUE lzws_ext_allocate_compressor(VALUE klass)
32
33
  {
33
34
  lzws_ext_compressor_t* compressor_ptr;
34
-
35
- VALUE self = Data_Make_Struct(klass, lzws_ext_compressor_t, NULL, free_compressor, compressor_ptr);
35
+ VALUE self = Data_Make_Struct(klass, lzws_ext_compressor_t, NULL, free_compressor, compressor_ptr);
36
36
 
37
37
  compressor_ptr->state_ptr = NULL;
38
38
  compressor_ptr->destination_buffer = NULL;
39
39
  compressor_ptr->destination_buffer_length = 0;
40
40
  compressor_ptr->remaining_destination_buffer = NULL;
41
41
  compressor_ptr->remaining_destination_buffer_length = 0;
42
+ compressor_ptr->gvl = false;
42
43
 
43
44
  return self;
44
45
  }
@@ -51,15 +52,13 @@ VALUE lzws_ext_initialize_compressor(VALUE self, VALUE options)
51
52
  {
52
53
  GET_COMPRESSOR(self);
53
54
  Check_Type(options, T_HASH);
55
+ LZWS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
56
+ LZWS_EXT_GET_BOOL_OPTION(options, gvl);
54
57
  LZWS_EXT_GET_COMPRESSOR_OPTIONS(options);
55
- LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
56
58
 
57
59
  lzws_compressor_state_t* state_ptr;
58
60
 
59
- lzws_result_t result = lzws_compressor_get_initial_state(
60
- &state_ptr,
61
- without_magic_header, max_code_bit_length, block_mode, msb, unaligned_bit_groups, quiet);
62
-
61
+ lzws_result_t result = lzws_compressor_get_initial_state(&state_ptr, &compressor_options);
63
62
  if (result != 0) {
64
63
  switch (result) {
65
64
  case LZWS_COMPRESSOR_ALLOCATE_FAILED:
@@ -73,7 +72,9 @@ VALUE lzws_ext_initialize_compressor(VALUE self, VALUE options)
73
72
 
74
73
  lzws_ext_byte_t* destination_buffer;
75
74
 
76
- result = lzws_create_destination_buffer_for_compressor(&destination_buffer, &destination_buffer_length, quiet);
75
+ result = lzws_create_destination_buffer_for_compressor(
76
+ &destination_buffer, &destination_buffer_length, compressor_options.quiet);
77
+
77
78
  if (result != 0) {
78
79
  lzws_compressor_free_state(state_ptr);
79
80
  lzws_ext_raise_error(LZWS_EXT_ERROR_ALLOCATE_FAILED);
@@ -84,66 +85,106 @@ VALUE lzws_ext_initialize_compressor(VALUE self, VALUE options)
84
85
  compressor_ptr->destination_buffer_length = destination_buffer_length;
85
86
  compressor_ptr->remaining_destination_buffer = destination_buffer;
86
87
  compressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
88
+ compressor_ptr->gvl = gvl;
87
89
 
88
90
  return Qnil;
89
91
  }
90
92
 
93
+ // -- compress --
94
+
91
95
  #define DO_NOT_USE_AFTER_CLOSE(compressor_ptr) \
92
96
  if (compressor_ptr->state_ptr == NULL || compressor_ptr->destination_buffer == NULL) { \
93
97
  lzws_ext_raise_error(LZWS_EXT_ERROR_USED_AFTER_CLOSE); \
94
98
  }
95
99
 
96
- #define GET_SOURCE_DATA(source_value) \
97
- Check_Type(source_value, T_STRING); \
98
- \
99
- const char* source = RSTRING_PTR(source_value); \
100
- size_t source_length = RSTRING_LEN(source_value); \
101
- lzws_ext_byte_t* remaining_source = (lzws_ext_byte_t*)source; \
102
- size_t remaining_source_length = source_length;
100
+ typedef struct
101
+ {
102
+ lzws_ext_compressor_t* compressor_ptr;
103
+ lzws_ext_byte_t* remaining_source;
104
+ size_t* remaining_source_length_ptr;
105
+ lzws_result_t result;
106
+ } compress_args_t;
107
+
108
+ static inline void* compress_wrapper(void* data)
109
+ {
110
+ compress_args_t* args = data;
111
+ lzws_ext_compressor_t* compressor_ptr = args->compressor_ptr;
112
+
113
+ args->result = lzws_compress(
114
+ compressor_ptr->state_ptr,
115
+ &args->remaining_source,
116
+ args->remaining_source_length_ptr,
117
+ &compressor_ptr->remaining_destination_buffer,
118
+ &compressor_ptr->remaining_destination_buffer_length);
119
+
120
+ return NULL;
121
+ }
103
122
 
104
123
  VALUE lzws_ext_compress(VALUE self, VALUE source_value)
105
124
  {
106
125
  GET_COMPRESSOR(self);
107
126
  DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
108
- GET_SOURCE_DATA(source_value);
127
+ Check_Type(source_value, T_STRING);
109
128
 
110
- lzws_result_t result = lzws_compress(
111
- compressor_ptr->state_ptr,
112
- &remaining_source, &remaining_source_length,
113
- &compressor_ptr->remaining_destination_buffer, &compressor_ptr->remaining_destination_buffer_length);
129
+ const char* source = RSTRING_PTR(source_value);
130
+ size_t source_length = RSTRING_LEN(source_value);
131
+ lzws_ext_byte_t* remaining_source = (lzws_ext_byte_t*) source;
132
+ size_t remaining_source_length = source_length;
133
+
134
+ compress_args_t args = {
135
+ .compressor_ptr = compressor_ptr,
136
+ .remaining_source = remaining_source,
137
+ .remaining_source_length_ptr = &remaining_source_length};
114
138
 
115
- if (
116
- result != 0 &&
117
- result != LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION) {
139
+ LZWS_EXT_GVL_WRAP(compressor_ptr->gvl, compress_wrapper, &args);
140
+ if (args.result != 0 && args.result != LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION) {
118
141
  lzws_ext_raise_error(LZWS_EXT_ERROR_UNEXPECTED);
119
142
  }
120
143
 
121
144
  VALUE bytes_written = SIZET2NUM(source_length - remaining_source_length);
122
- VALUE needs_more_destination = result == LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION ? Qtrue : Qfalse;
145
+ VALUE needs_more_destination = args.result == LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION ? Qtrue : Qfalse;
123
146
 
124
147
  return rb_ary_new_from_args(2, bytes_written, needs_more_destination);
125
148
  }
126
149
 
150
+ // -- compressor finish --
151
+
152
+ typedef struct
153
+ {
154
+ lzws_ext_compressor_t* compressor_ptr;
155
+ lzws_result_t result;
156
+ } compressor_finish_args_t;
157
+
158
+ static inline void* compressor_finish_wrapper(void* data)
159
+ {
160
+ compressor_finish_args_t* args = data;
161
+ lzws_ext_compressor_t* compressor_ptr = args->compressor_ptr;
162
+
163
+ args->result = lzws_compressor_finish(
164
+ compressor_ptr->state_ptr,
165
+ &compressor_ptr->remaining_destination_buffer,
166
+ &compressor_ptr->remaining_destination_buffer_length);
167
+
168
+ return NULL;
169
+ }
170
+
127
171
  VALUE lzws_ext_compressor_finish(VALUE self)
128
172
  {
129
173
  GET_COMPRESSOR(self);
130
174
  DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
131
175
 
132
- lzws_result_t result = lzws_compressor_finish(
133
- compressor_ptr->state_ptr,
134
- &compressor_ptr->remaining_destination_buffer, &compressor_ptr->remaining_destination_buffer_length);
176
+ compressor_finish_args_t args = {.compressor_ptr = compressor_ptr};
135
177
 
136
- if (
137
- result != 0 &&
138
- result != LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION) {
178
+ LZWS_EXT_GVL_WRAP(compressor_ptr->gvl, compressor_finish_wrapper, &args);
179
+ if (args.result != 0 && args.result != LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION) {
139
180
  lzws_ext_raise_error(LZWS_EXT_ERROR_UNEXPECTED);
140
181
  }
141
182
 
142
- VALUE needs_more_destination = result == LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION ? Qtrue : Qfalse;
143
-
144
- return needs_more_destination;
183
+ return args.result == LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION ? Qtrue : Qfalse;
145
184
  }
146
185
 
186
+ // -- other --
187
+
147
188
  VALUE lzws_ext_compressor_read_result(VALUE self)
148
189
  {
149
190
  GET_COMPRESSOR(self);
@@ -153,10 +194,9 @@ VALUE lzws_ext_compressor_read_result(VALUE self)
153
194
  size_t destination_buffer_length = compressor_ptr->destination_buffer_length;
154
195
  size_t remaining_destination_buffer_length = compressor_ptr->remaining_destination_buffer_length;
155
196
 
156
- const char* result = (const char*)destination_buffer;
197
+ const char* result = (const char*) destination_buffer;
157
198
  size_t result_length = destination_buffer_length - remaining_destination_buffer_length;
158
-
159
- VALUE result_value = rb_str_new(result, result_length);
199
+ VALUE result_value = rb_str_new(result, result_length);
160
200
 
161
201
  compressor_ptr->remaining_destination_buffer = destination_buffer;
162
202
  compressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
@@ -164,6 +204,8 @@ VALUE lzws_ext_compressor_read_result(VALUE self)
164
204
  return result_value;
165
205
  }
166
206
 
207
+ // -- cleanup --
208
+
167
209
  VALUE lzws_ext_compressor_close(VALUE self)
168
210
  {
169
211
  GET_COMPRESSOR(self);
@@ -183,12 +225,14 @@ VALUE lzws_ext_compressor_close(VALUE self)
183
225
  compressor_ptr->destination_buffer = NULL;
184
226
  }
185
227
 
186
- // It is possible to keep "destination_buffer_length", "remaining_destination_buffer"
187
- // and "remaining_destination_buffer_length" as is.
228
+ // It is possible to keep "destination_buffer_length", "remaining_destination_buffer",
229
+ // "remaining_destination_buffer_length" and "gvl" as is.
188
230
 
189
231
  return Qnil;
190
232
  }
191
233
 
234
+ // -- exports --
235
+
192
236
  void lzws_ext_compressor_exports(VALUE root_module)
193
237
  {
194
238
  VALUE module = rb_define_module_under(root_module, "Stream");