ob64 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +9 -0
  3. data/.github/workflows/main.yml +77 -16
  4. data/.standard.yml +1 -2
  5. data/CHANGELOG.md +14 -1
  6. data/README.md +57 -19
  7. data/benchmark.rb +60 -95
  8. data/ext/ob64/extconf.rb +0 -42
  9. data/ext/ob64/ob64.h +3 -1
  10. data/ext/ob64/ob64_ext.c +80 -23
  11. data/ext/ob64/ob64_pack.c +228 -0
  12. data/ext/ob64/pack_base64.c +5182 -0
  13. data/ext/ob64/pack_base64.h +33 -0
  14. data/ext/ob64/pack_generic.h +151 -0
  15. data/ext/ob64/pack_simd.h +22 -0
  16. data/ext/ob64/pack_uuencode.c +1741 -0
  17. data/ext/ob64/pack_uuencode.h +18 -0
  18. data/lib/ob64/core_ext.rb +2 -25
  19. data/lib/ob64/version.rb +1 -1
  20. data/lib/ob64.rb +149 -70
  21. data/ob64.gemspec +3 -5
  22. metadata +17 -73
  23. data/.gitmodules +0 -3
  24. data/ext/ob64/libbase64.h +0 -1
  25. data/vendor/libbase64/.gitignore +0 -12
  26. data/vendor/libbase64/.travis.yml +0 -71
  27. data/vendor/libbase64/CMakeLists.txt +0 -264
  28. data/vendor/libbase64/LICENSE +0 -28
  29. data/vendor/libbase64/Makefile +0 -93
  30. data/vendor/libbase64/README.md +0 -474
  31. data/vendor/libbase64/base64-benchmarks.png +0 -0
  32. data/vendor/libbase64/bin/base64.c +0 -132
  33. data/vendor/libbase64/cmake/Modules/TargetArch.cmake +0 -29
  34. data/vendor/libbase64/cmake/Modules/TargetSIMDInstructionSet.cmake +0 -34
  35. data/vendor/libbase64/cmake/base64-config.cmake.in +0 -5
  36. data/vendor/libbase64/cmake/config.h.in +0 -25
  37. data/vendor/libbase64/cmake/test-arch.c +0 -35
  38. data/vendor/libbase64/include/libbase64.h +0 -145
  39. data/vendor/libbase64/lib/arch/avx/codec.c +0 -42
  40. data/vendor/libbase64/lib/arch/avx2/codec.c +0 -42
  41. data/vendor/libbase64/lib/arch/avx2/dec_loop.c +0 -110
  42. data/vendor/libbase64/lib/arch/avx2/dec_reshuffle.c +0 -34
  43. data/vendor/libbase64/lib/arch/avx2/enc_loop.c +0 -89
  44. data/vendor/libbase64/lib/arch/avx2/enc_reshuffle.c +0 -83
  45. data/vendor/libbase64/lib/arch/avx2/enc_translate.c +0 -30
  46. data/vendor/libbase64/lib/arch/generic/32/dec_loop.c +0 -86
  47. data/vendor/libbase64/lib/arch/generic/32/enc_loop.c +0 -73
  48. data/vendor/libbase64/lib/arch/generic/64/enc_loop.c +0 -77
  49. data/vendor/libbase64/lib/arch/generic/codec.c +0 -39
  50. data/vendor/libbase64/lib/arch/generic/dec_head.c +0 -37
  51. data/vendor/libbase64/lib/arch/generic/dec_tail.c +0 -91
  52. data/vendor/libbase64/lib/arch/generic/enc_head.c +0 -24
  53. data/vendor/libbase64/lib/arch/generic/enc_tail.c +0 -34
  54. data/vendor/libbase64/lib/arch/neon32/codec.c +0 -72
  55. data/vendor/libbase64/lib/arch/neon32/dec_loop.c +0 -106
  56. data/vendor/libbase64/lib/arch/neon32/enc_loop.c +0 -58
  57. data/vendor/libbase64/lib/arch/neon32/enc_reshuffle.c +0 -54
  58. data/vendor/libbase64/lib/arch/neon32/enc_translate.c +0 -57
  59. data/vendor/libbase64/lib/arch/neon64/codec.c +0 -70
  60. data/vendor/libbase64/lib/arch/neon64/dec_loop.c +0 -129
  61. data/vendor/libbase64/lib/arch/neon64/enc_loop.c +0 -66
  62. data/vendor/libbase64/lib/arch/neon64/enc_reshuffle.c +0 -54
  63. data/vendor/libbase64/lib/arch/sse41/codec.c +0 -42
  64. data/vendor/libbase64/lib/arch/sse42/codec.c +0 -42
  65. data/vendor/libbase64/lib/arch/ssse3/codec.c +0 -42
  66. data/vendor/libbase64/lib/arch/ssse3/dec_loop.c +0 -173
  67. data/vendor/libbase64/lib/arch/ssse3/dec_reshuffle.c +0 -33
  68. data/vendor/libbase64/lib/arch/ssse3/enc_loop.c +0 -67
  69. data/vendor/libbase64/lib/arch/ssse3/enc_reshuffle.c +0 -48
  70. data/vendor/libbase64/lib/arch/ssse3/enc_translate.c +0 -33
  71. data/vendor/libbase64/lib/codec_choose.c +0 -281
  72. data/vendor/libbase64/lib/codecs.h +0 -65
  73. data/vendor/libbase64/lib/env.h +0 -67
  74. data/vendor/libbase64/lib/exports.txt +0 -7
  75. data/vendor/libbase64/lib/lib.c +0 -164
  76. data/vendor/libbase64/lib/lib_openmp.c +0 -149
  77. data/vendor/libbase64/lib/tables/.gitignore +0 -1
  78. data/vendor/libbase64/lib/tables/Makefile +0 -17
  79. data/vendor/libbase64/lib/tables/table_dec_32bit.h +0 -393
  80. data/vendor/libbase64/lib/tables/table_enc_12bit.h +0 -1031
  81. data/vendor/libbase64/lib/tables/table_enc_12bit.py +0 -45
  82. data/vendor/libbase64/lib/tables/table_generator.c +0 -184
  83. data/vendor/libbase64/lib/tables/tables.c +0 -40
  84. data/vendor/libbase64/lib/tables/tables.h +0 -23
data/ext/ob64/ob64_ext.c CHANGED
@@ -2,55 +2,82 @@
2
2
  #include "ob64.h"
3
3
 
4
4
  VALUE mOb64 = Qnil;
5
- VALUE mOb64_LibBase64 = Qnil;
5
+ VALUE mOb64_Ext = Qnil;
6
6
 
7
- VALUE Ob64_encode_string(VALUE self, VALUE bin);
8
- VALUE Ob64_decode_string(VALUE self, VALUE string);
7
+ /* Indexed by enum pack_codec */
8
+ static const char *const codec_names[PACK_CODECS] = { "scalar", "avx2", "avx512", "neon64" };
9
+ static ID codec_ids[PACK_CODECS];
10
+
11
+ VALUE Ob64_encode_string(VALUE self, VALUE bin, VALUE urlsafe, VALUE padding);
12
+ VALUE Ob64_decode_string(VALUE self, VALUE string, VALUE urlsafe, VALUE loose);
9
13
  VALUE Ob64_encoded_length_of(VALUE self, VALUE bin, VALUE withPadding);
10
14
  VALUE Ob64_decoded_length_of(VALUE self, VALUE string);
15
+ VALUE Ob64_codec(VALUE self);
16
+ VALUE Ob64_set_codec(VALUE self, VALUE codec);
17
+ VALUE Ob64_codecs(VALUE self);
11
18
 
12
- size_t __encoded_length_of(VALUE string, bool withPadding);
19
+ size_t __encoded_length_of(size_t bin_len, bool withPadding);
13
20
  size_t __decoded_length_of(VALUE string);
14
21
 
15
22
  void
16
23
  Init_ob64_ext(void)
17
24
  {
25
+ rb_ext_ractor_safe(true);
26
+ pack_base64_init();
27
+ for (int i = 0; i < PACK_CODECS; i++) {
28
+ codec_ids[i] = rb_intern(codec_names[i]);
29
+ }
30
+
18
31
  mOb64 = rb_define_module("Ob64");
19
- mOb64_LibBase64 = rb_define_module_under(mOb64, "LibBase64");
32
+ mOb64_Ext = rb_define_module_under(mOb64, "Ext");
20
33
 
21
- rb_define_private_method(mOb64_LibBase64, "__encode", Ob64_encode_string, 1);
22
- rb_define_private_method(mOb64_LibBase64, "__decode", Ob64_decode_string, 1);
23
- rb_define_private_method(mOb64_LibBase64, "__encoded_length_of", Ob64_encoded_length_of, 2);
24
- rb_define_private_method(mOb64_LibBase64, "__decoded_length_of", Ob64_decoded_length_of, 1);
34
+ rb_define_private_method(mOb64_Ext, "__encode", Ob64_encode_string, 3);
35
+ rb_define_private_method(mOb64_Ext, "__decode", Ob64_decode_string, 3);
36
+ rb_define_private_method(mOb64_Ext, "__encoded_length_of", Ob64_encoded_length_of, 2);
37
+ rb_define_private_method(mOb64_Ext, "__decoded_length_of", Ob64_decoded_length_of, 1);
38
+ rb_define_private_method(mOb64_Ext, "__codec", Ob64_codec, 0);
39
+ rb_define_private_method(mOb64_Ext, "__set_codec", Ob64_set_codec, 1);
40
+ rb_define_private_method(mOb64_Ext, "__codecs", Ob64_codecs, 0);
41
+
42
+ Init_ob64_pack(mOb64_Ext);
25
43
  }
26
44
 
27
- VALUE Ob64_encode_string(VALUE self, VALUE bin)
45
+ VALUE Ob64_encode_string(VALUE self, VALUE bin, VALUE urlsafe, VALUE padding)
28
46
  {
29
- VALUE result = rb_str_buf_new(__encoded_length_of(bin, true));
30
- size_t nout;
47
+ StringValue(bin);
48
+ size_t bin_len = RSTRING_LEN(bin);
49
+ VALUE result = rb_str_buf_new(__encoded_length_of(bin_len, true));
50
+ int flags = RTEST(urlsafe) ? PACK_BASE64_URL_SAFE : 0;
31
51
 
32
- base64_encode(StringValuePtr(bin), RSTRING_LEN(bin), StringValuePtr(result), &nout, 0);
33
- rb_str_set_len(result, nout);
52
+ pack_base64_encode(RSTRING_PTR(bin), bin_len, RSTRING_PTR(result), flags);
53
+ rb_str_set_len(result, __encoded_length_of(bin_len, RTEST(padding)));
54
+ RB_GC_GUARD(bin);
34
55
 
35
56
  return result;
36
57
  }
37
58
 
38
- VALUE Ob64_decode_string(VALUE self, VALUE string)
59
+ VALUE Ob64_decode_string(VALUE self, VALUE string, VALUE urlsafe, VALUE loose)
39
60
  {
40
- VALUE result = rb_str_buf_new(__decoded_length_of(string));
61
+ StringValue(string);
62
+ size_t string_len = RSTRING_LEN(string);
63
+ /* Room for unpadded input */
64
+ VALUE result = rb_str_buf_new((string_len + 3) / 4 * 3);
65
+ int flags = (RTEST(urlsafe) ? PACK_BASE64_URL_SAFE : 0) | (RTEST(loose) ? PACK_BASE64_LOOSE : 0);
41
66
  size_t nout;
42
67
 
43
- if (!base64_decode(StringValuePtr(string), RSTRING_LEN(string), StringValuePtr(result), &nout, 0)) {
68
+ if (!pack_base64_decode(RSTRING_PTR(string), string_len, RSTRING_PTR(result), &nout, flags)) {
44
69
  rb_raise(rb_eArgError, "invalid base64");
45
70
  }
46
71
  rb_str_set_len(result, nout);
72
+ RB_GC_GUARD(string);
47
73
 
48
74
  return result;
49
75
  }
50
76
 
51
77
  VALUE Ob64_encoded_length_of(VALUE self, VALUE bin, VALUE withPadding)
52
78
  {
53
- return ULONG2NUM((unsigned long)__encoded_length_of(bin, withPadding != Qnil && withPadding != Qfalse ? true : false));
79
+ StringValue(bin);
80
+ return ULONG2NUM((unsigned long)__encoded_length_of(RSTRING_LEN(bin), RTEST(withPadding)));
54
81
  }
55
82
 
56
83
  VALUE Ob64_decoded_length_of(VALUE self, VALUE string)
@@ -58,12 +85,12 @@ VALUE Ob64_decoded_length_of(VALUE self, VALUE string)
58
85
  return ULONG2NUM((unsigned long)__decoded_length_of(string));
59
86
  }
60
87
 
61
- size_t __encoded_length_of(VALUE bin, bool withPadding)
88
+ size_t __encoded_length_of(size_t bin_len, bool withPadding)
62
89
  {
63
90
  if (withPadding) {
64
- return (RSTRING_LEN(bin) + 2) / 3 * 4;
91
+ return (bin_len + 2) / 3 * 4;
65
92
  } else {
66
- return ((RSTRING_LEN(bin) * 8) + 5) / 6;
93
+ return ((bin_len * 8) + 5) / 6;
67
94
  }
68
95
  }
69
96
 
@@ -72,8 +99,8 @@ size_t __decoded_length_of(VALUE string)
72
99
  char *string_ptr = StringValuePtr(string);
73
100
  size_t string_len = RSTRING_LEN(string);
74
101
  size_t padding = 0;
75
- if (string_ptr[string_len - 1] == '=') padding++;
76
- if (string_ptr[string_len - 2] == '=') padding++;
102
+ if (string_len >= 1 && string_ptr[string_len - 1] == '=') padding++;
103
+ if (string_len >= 2 && string_ptr[string_len - 2] == '=') padding++;
77
104
 
78
105
  if ((string_len - padding) % 4 == 1) {
79
106
  rb_raise(rb_eArgError, "invalid base64");
@@ -81,3 +108,33 @@ size_t __decoded_length_of(VALUE string)
81
108
 
82
109
  return (3 * (string_len - padding)) / 4;
83
110
  }
111
+
112
+ VALUE Ob64_codec(VALUE self)
113
+ {
114
+ return ID2SYM(codec_ids[pack_codec_current()]);
115
+ }
116
+
117
+ VALUE Ob64_set_codec(VALUE self, VALUE codec)
118
+ {
119
+ for (int i = 0; i < PACK_CODECS; i++) {
120
+ if (codec == ID2SYM(codec_ids[i])) {
121
+ if (!pack_codec_runnable(i)) {
122
+ rb_raise(rb_eArgError, "%s is not supported by this CPU", codec_names[i]);
123
+ }
124
+ pack_codec_set(i);
125
+ return codec;
126
+ }
127
+ }
128
+ rb_raise(rb_eArgError, "unknown codec: %+"PRIsVALUE, codec);
129
+ }
130
+
131
+ VALUE Ob64_codecs(VALUE self)
132
+ {
133
+ VALUE codecs = rb_ary_new();
134
+
135
+ for (int i = 0; i < PACK_CODECS; i++) {
136
+ if (pack_codec_runnable(i)) rb_ary_push(codecs, ID2SYM(codec_ids[i]));
137
+ }
138
+
139
+ return codecs;
140
+ }
@@ -0,0 +1,228 @@
1
+ #include <limits.h>
2
+ #include "ob64.h"
3
+ #include "pack_uuencode.h"
4
+ #include "ruby/encoding.h"
5
+
6
+ #define COUNT_STAR (-1)
7
+
8
+ /*
9
+ * Returns 'm' or 'u' if fmt is a String matching \A[mu](\d{1,9}|\*)?\z in an
10
+ * ASCII-compatible encoding, 0 otherwise. *count: 1 if absent, COUNT_STAR for '*'.
11
+ */
12
+ static int
13
+ parse_format(VALUE fmt, long *count)
14
+ {
15
+ if (!RB_TYPE_P(fmt, T_STRING) || !rb_enc_str_asciicompat_p(fmt)) return 0;
16
+
17
+ const char *p = RSTRING_PTR(fmt);
18
+ long len = RSTRING_LEN(fmt);
19
+
20
+ if (len < 1 || len > 10 || (p[0] != 'm' && p[0] != 'u')) return 0;
21
+ if (len == 1) {
22
+ *count = 1;
23
+ }
24
+ else if (len == 2 && p[1] == '*') {
25
+ *count = COUNT_STAR;
26
+ }
27
+ else {
28
+ *count = 0;
29
+ for (long i = 1; i < len; i++) {
30
+ if (p[i] < '0' || p[i] > '9') return 0;
31
+ *count = *count * 10 + (p[i] - '0');
32
+ }
33
+ }
34
+
35
+ return p[0];
36
+ }
37
+
38
+ /* Sets res's length to n and makes it a US-ASCII String, as native pack does */
39
+ static VALUE
40
+ ascii_result(VALUE res, size_t n)
41
+ {
42
+ rb_str_set_len(res, (long)n);
43
+ ENCODING_CODERANGE_SET(res, rb_usascii_encindex(), ENC_CODERANGE_7BIT);
44
+
45
+ return res;
46
+ }
47
+
48
+ static VALUE
49
+ uuencode(VALUE from, long line_len)
50
+ {
51
+ long plen = RSTRING_LEN(from);
52
+ /* A length byte and a newline per line */
53
+ long lines = (plen + line_len - 1) / line_len;
54
+ VALUE res = rb_str_buf_new((plen + 2) / 3 * 4 + lines * 2);
55
+ const char *src = RSTRING_PTR(from);
56
+ char *out = RSTRING_PTR(res);
57
+ size_t n = pack_uuencode_lines(src, (size_t)plen, out, (size_t)line_len);
58
+ RB_GC_GUARD(from);
59
+
60
+ return ascii_result(res, n);
61
+ }
62
+
63
+ static VALUE
64
+ Ob64_pack(int argc, VALUE *argv, VALUE ary)
65
+ {
66
+ long count, plen;
67
+ int type;
68
+ VALUE from;
69
+
70
+ if (argc != 1 || rb_keyword_given_p() || rb_block_given_p() ||
71
+ !(type = parse_format(argv[0], &count)) ||
72
+ RARRAY_LEN(ary) < 1 || !RB_TYPE_P(from = RARRAY_AREF(ary, 0), T_STRING) ||
73
+ /* Bound plen so the output size below cannot overflow */
74
+ (plen = RSTRING_LEN(from)) > LONG_MAX / 4) {
75
+ return rb_call_super_kw(argc, argv, RB_PASS_CALLED_KEYWORDS);
76
+ }
77
+
78
+ VALUE res;
79
+ size_t n;
80
+
81
+ if (type == 'm' && count == 0) {
82
+ res = rb_str_buf_new((plen + 2) / 3 * 4);
83
+ n = pack_base64_encode(RSTRING_PTR(from), (size_t)plen, RSTRING_PTR(res), 0);
84
+ }
85
+ else {
86
+ long len = count;
87
+
88
+ /* '*' gets 45, as natively */
89
+ if (len <= 2) len = 45;
90
+ else if (len > 63 && type == 'u') len = 63;
91
+ else len = len / 3 * 3;
92
+
93
+ if (type == 'u') return uuencode(from, len);
94
+
95
+ /* A newline per line */
96
+ long lines = (plen + len - 1) / len;
97
+ res = rb_str_buf_new((plen + 2) / 3 * 4 + lines);
98
+ n = pack_base64_encode_rfc2045(RSTRING_PTR(from), (size_t)plen, RSTRING_PTR(res), (int)len);
99
+ }
100
+ RB_GC_GUARD(from);
101
+
102
+ return ascii_result(res, n);
103
+ }
104
+
105
+ static VALUE
106
+ uudecode(VALUE str)
107
+ {
108
+ long len = RSTRING_LEN(str);
109
+ /* +3: the decoder stores up to 3 bytes past a line's decoded length */
110
+ VALUE buf = rb_str_buf_new((long)pack_uudecode_cap((size_t)len) + 3);
111
+ size_t total = pack_uudecode_lines(RSTRING_PTR(str), (size_t)len, RSTRING_PTR(buf));
112
+ RB_GC_GUARD(str);
113
+
114
+ rb_str_set_len(buf, (long)total);
115
+
116
+ return buf;
117
+ }
118
+
119
+ static VALUE
120
+ base64_decode(VALUE str, long count)
121
+ {
122
+ long len = RSTRING_LEN(str);
123
+ /* Room for unpadded input and decoder overruns */
124
+ VALUE buf = rb_str_buf_new(len / 4 * 3 + 3);
125
+ size_t n;
126
+
127
+ if (count == 0) {
128
+ if (!pack_base64_decode(RSTRING_PTR(str), (size_t)len, RSTRING_PTR(buf), &n, 0)) {
129
+ rb_raise(rb_eArgError, "invalid base64");
130
+ }
131
+ }
132
+ else {
133
+ n = pack_base64_decode_rfc2045(RSTRING_PTR(str), (size_t)len, RSTRING_PTR(buf));
134
+ }
135
+ RB_GC_GUARD(str);
136
+
137
+ rb_str_set_len(buf, (long)n);
138
+
139
+ return buf;
140
+ }
141
+
142
+ /* Returns the decoded String, or Qundef when native Ruby must handle the call */
143
+ static VALUE
144
+ unpack_fast(int argc, VALUE *argv, VALUE str)
145
+ {
146
+ long count;
147
+ int type;
148
+
149
+ if (argc != 1 || rb_keyword_given_p() || rb_block_given_p() ||
150
+ !(type = parse_format(argv[0], &count))) {
151
+ return Qundef;
152
+ }
153
+
154
+ return type == 'm' ? base64_decode(str, count) : uudecode(str);
155
+ }
156
+
157
+ static VALUE
158
+ Ob64_unpack(int argc, VALUE *argv, VALUE str)
159
+ {
160
+ VALUE res = unpack_fast(argc, argv, str);
161
+
162
+ if (RB_UNDEF_P(res)) return rb_call_super_kw(argc, argv, RB_PASS_CALLED_KEYWORDS);
163
+
164
+ return rb_ary_new_from_values(1, &res);
165
+ }
166
+
167
+ static VALUE
168
+ Ob64_unpack1(int argc, VALUE *argv, VALUE str)
169
+ {
170
+ VALUE res = unpack_fast(argc, argv, str);
171
+
172
+ if (RB_UNDEF_P(res)) return rb_call_super_kw(argc, argv, RB_PASS_CALLED_KEYWORDS);
173
+
174
+ return res;
175
+ }
176
+
177
+ static VALUE
178
+ Ob64_uuencode(VALUE self, VALUE bin)
179
+ {
180
+ StringValue(bin);
181
+
182
+ return uuencode(bin, 45);
183
+ }
184
+
185
+ static VALUE
186
+ Ob64_uudecode(VALUE self, VALUE string)
187
+ {
188
+ StringValue(string);
189
+
190
+ return uudecode(string);
191
+ }
192
+
193
+ static VALUE
194
+ Ob64_uuencoded_length_of(VALUE self, VALUE bin)
195
+ {
196
+ StringValue(bin);
197
+ long plen = RSTRING_LEN(bin);
198
+ /* Per line: a length byte, 4 chars per 3 bytes and a newline */
199
+ long full = plen / 45, rest = plen % 45;
200
+
201
+ return LONG2NUM(full * 62 + (rest ? (rest + 2) / 3 * 4 + 2 : 0));
202
+ }
203
+
204
+ static VALUE
205
+ Ob64_uudecoded_length_of(VALUE self, VALUE string)
206
+ {
207
+ StringValue(string);
208
+ size_t total = pack_uudecode_lines(RSTRING_PTR(string), (size_t)RSTRING_LEN(string), NULL);
209
+ RB_GC_GUARD(string);
210
+
211
+ return LONG2NUM((long)total);
212
+ }
213
+
214
+ void
215
+ Init_ob64_pack(VALUE mExt)
216
+ {
217
+ VALUE mPack = rb_define_module_under(mExt, "Pack");
218
+ VALUE mUnpack = rb_define_module_under(mExt, "Unpack");
219
+
220
+ rb_define_method(mPack, "pack", Ob64_pack, -1);
221
+ rb_define_method(mUnpack, "unpack", Ob64_unpack, -1);
222
+ rb_define_method(mUnpack, "unpack1", Ob64_unpack1, -1);
223
+
224
+ rb_define_private_method(mExt, "__uuencode", Ob64_uuencode, 1);
225
+ rb_define_private_method(mExt, "__uudecode", Ob64_uudecode, 1);
226
+ rb_define_private_method(mExt, "__uuencoded_length_of", Ob64_uuencoded_length_of, 1);
227
+ rb_define_private_method(mExt, "__uudecoded_length_of", Ob64_uudecoded_length_of, 1);
228
+ }