b_encode 0.0.1

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
+ SHA1:
3
+ metadata.gz: 03f9d43b091e021486f8290606ff0d11f032bc2d
4
+ data.tar.gz: fffa952a1d86fcbbe34d4fe5339019d507aaca02
5
+ SHA512:
6
+ metadata.gz: 7fd573cfe2a7162fc4733b70e04389294bb4e3250c3fdf4fc6b3bf31e1083efa5fbd988db4c4424694588411aa67d617715ad09fccabd33ed715b108e8a8f0f3
7
+ data.tar.gz: c6bdadc918f6d09a1adc27a90d2135277bc4be655dc8527a2dd5a2f3038b707ce8829ed97fa887462984040405f30b90152eb97ee7be61de839fc6305b3c59df
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+
16
+ *.gem
17
+ *.my
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in b_encode.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 August
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # BEncode
2
+
3
+ A bencode encoder/decoder.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'b_encode'
11
+ ```
12
+
13
+ Or install it yourself:
14
+
15
+ ```sh
16
+ $ gem install b_encode
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ #### Encoding
22
+
23
+ ```ruby
24
+ "foo".bencode # => "3:foo"
25
+ 123.bencode # => "i123e"
26
+
27
+ ["foo", 123].bencode # => "l3:fooi123ee"
28
+ {"foo" => 123}.bencode # => "d3:fooi123ee"
29
+ ```
30
+
31
+ #### Decoding
32
+ ```ruby
33
+ BEncode.decode "3:foo" # => "foo"
34
+ BEncode.decode "i123e" # => 123
35
+
36
+ BEncode.decode "l3:fooi123ee" # => ["foo", 123]
37
+ BEncode.decode "d3:fooi123ee" # => {"foo" => 123}
38
+ ```
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require "rake/extensiontask"
4
+
5
+ Rake::ExtensionTask.new("b_encode") do |ext|
6
+ ext.lib_dir = "lib/b_encode"
7
+ end
data/b_encode.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'b_encode/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "b_encode"
8
+ spec.version = BEncode::VERSION
9
+ spec.authors = ["August"]
10
+ spec.email = ["augustt198@gmail.com"]
11
+ spec.extensions = ["ext/b_encode/extconf.rb"]
12
+ spec.summary = %q{Bencode encoder/decoder}
13
+ spec.homepage = "http://github.com/augustt198/b_encode"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rake-compiler"
24
+ end
data/benchmark.rb ADDED
@@ -0,0 +1,77 @@
1
+ require "b_encode"
2
+ require "benchmark"
3
+
4
+ TESTS = 1_000_000
5
+
6
+ Benchmark.bm(30) do |bm|
7
+ bm.report("b_encode: encoding integers") do
8
+ TESTS.times { |x| x.bencode }
9
+ end
10
+ bm.report("b_encode: encoding strings") do
11
+ TESTS.times { |x| x.to_s.bencode }
12
+ end
13
+ bm.report("b_encode: encoding lists") do
14
+ TESTS.times { |x| [x, x.to_s, [], {}].bencode }
15
+ end
16
+ bm.report("b_encode: encoding dicts") do
17
+ TESTS.times { |x| {x.to_s => x}.bencode }
18
+ end
19
+ bm.report("b_encode: decoding integers") do
20
+ TESTS.times { |x| BEncode.decode "i#{x}e" }
21
+ end
22
+ bm.report("b_encode: decoding strings") do
23
+ TESTS.times do |x|
24
+ s = x.to_s
25
+ BEncode.decode "#{s.length}:#{s}"
26
+ end
27
+ end
28
+ bm.report("b_encode: decoding lists") do
29
+ TESTS.times do |x|
30
+ BEncode.decode "li123e3:fooli10eed1:a1:bee"
31
+ end
32
+ end
33
+ bm.report("b_encode: decoding hashes") do
34
+ TESTS.times do |x|
35
+ BEncode.decode "d3:fooi123e1:ali123ed3:abc3:defeee"
36
+ end
37
+ end
38
+ end
39
+
40
+ # suppress warnings
41
+ $VERBOSE = nil
42
+
43
+ require "bencode"
44
+
45
+ Benchmark.bm(30) do |bm|
46
+ bm.report("bencode: encoding integers") do
47
+ TESTS.times { |x| x.bencode }
48
+ end
49
+ bm.report("bencode: encoding strings") do
50
+ TESTS.times { |x| x.to_s.bencode }
51
+ end
52
+ bm.report("bencode: encoding lists") do
53
+ TESTS.times { |x| [x, x.to_s, [], {}].bencode }
54
+ end
55
+ bm.report("bencode: encoding dicts") do
56
+ TESTS.times { |x| {x.to_s => x}.bencode }
57
+ end
58
+ bm.report("bencode: decoding integers") do
59
+ TESTS.times { |x| BEncode.load "i#{x}e" }
60
+ end
61
+ bm.report("bencode: decoding strings") do
62
+ TESTS.times do |x|
63
+ s = x.to_s
64
+ BEncode.load "#{s.length}:#{s}"
65
+ end
66
+ end
67
+ bm.report("bencode: decoding lists") do
68
+ TESTS.times do |x|
69
+ BEncode.load "li123e3:fooli10eed1:a1:bee"
70
+ end
71
+ end
72
+ bm.report("bencode: decoding hashes") do
73
+ TESTS.times do |x|
74
+ BEncode.load "d3:fooi123e1:ali123ed3:abc3:defeee"
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,317 @@
1
+ #include "b_encode.h"
2
+
3
+ VALUE rb_mBEncode;
4
+
5
+ int digit_count(int n) {
6
+ if (n == 0)
7
+ return 1;
8
+
9
+ n = abs(n);
10
+ int c = 0;
11
+ for (; n > 0; c++)
12
+ n /= 10;
13
+
14
+ return c;
15
+ }
16
+
17
+ static VALUE
18
+ rb_str_bencode_bang(VALUE str) {
19
+ int strlen = RSTRING_LEN(str);
20
+ // length prefix + ":" + str
21
+ int dc = digit_count(strlen);
22
+ int newlen = dc + 1 + strlen;
23
+
24
+ rb_str_resize(str, newlen);
25
+
26
+ char *ptr = RSTRING_PTR(str);
27
+
28
+ memmove(ptr + dc + 1, ptr, strlen);
29
+ if (strlen == 0) {
30
+ ptr[0] = '0';
31
+ } else {
32
+ int n = strlen;
33
+ for (int i = 0; n > 0; n /= 10, i++)
34
+ ptr[dc - i - 1] = (n % 10) + '0';
35
+ }
36
+ ptr[dc] = ':';
37
+
38
+ return str;
39
+ }
40
+
41
+ static VALUE
42
+ rb_str_bencode(VALUE str) {
43
+ str = rb_str_dup(str);
44
+ rb_str_bencode_bang(str);
45
+ return str;
46
+ }
47
+
48
+ static VALUE
49
+ rb_integer_bencode(VALUE rb_num) {
50
+ long num = NUM2LONG(rb_num);
51
+ int c = 0;
52
+ if (num == 0) {
53
+ c = 1;
54
+ } else {
55
+ if (num < 0)
56
+ c++; // minus sign
57
+ for (int n = labs(num); n > 0; c++)
58
+ n /= 10;
59
+ }
60
+
61
+ // "i"<integer>"e"
62
+ int strlen = c + 2;
63
+ VALUE str = rb_str_new(NULL, strlen);
64
+ char *ptr = RSTRING_PTR(str);
65
+
66
+ ptr[0] = 'i';
67
+ if (num == 0) {
68
+ ptr[1] = '0';
69
+ } else {
70
+ if (num < 0) {
71
+ ptr[1] = '-';
72
+ }
73
+ int i = 0;
74
+ for (int n = labs(num); n > 0; n /= 10, i++)
75
+ ptr[c - i] = (n % 10) + '0';
76
+ }
77
+ ptr[c + 1] = 'e';
78
+
79
+ return str;
80
+ }
81
+
82
+ static VALUE
83
+ rb_ary_bencode(VALUE ary) {
84
+ long len = RARRAY_LEN(ary);
85
+ VALUE b_entries[len];
86
+
87
+ int total_len = 0;
88
+ ID bencode_method_sym = rb_intern("bencode");
89
+ for (int i = 0; i < len; i++) {
90
+ VALUE val = rb_ary_entry(ary, i);
91
+ VALUE bencoded = rb_funcall(val, bencode_method_sym, 0);
92
+ total_len += RSTRING_LEN(bencoded);
93
+ b_entries[i] = bencoded;
94
+ }
95
+
96
+ // "l"<contents>"e"
97
+ VALUE str = rb_str_new(NULL, total_len + 2);
98
+ char *ptr = RSTRING_PTR(str);
99
+
100
+ ptr[0] = 'l';
101
+
102
+ int offset = 1;
103
+ for (int i = 0; i < len; i++) {
104
+ VALUE entry = b_entries[i];
105
+ int e_len = RSTRING_LEN(entry);
106
+ memcpy(ptr + offset, RSTRING_PTR(entry), e_len);
107
+ offset += e_len;
108
+ }
109
+
110
+ ptr[total_len + 1] = 'e';
111
+
112
+ return str;
113
+ }
114
+
115
+ struct foreach_info {
116
+ int *idx_ptr;
117
+ VALUE *base;
118
+ };
119
+
120
+ static int
121
+ rb_hash_bencode_entry(VALUE key, VALUE value, VALUE arg) {
122
+ if (!RB_TYPE_P(key, T_STRING))
123
+ rb_raise(rb_eTypeError, "All hash keys must be strings");
124
+
125
+ VALUE key_bencode = rb_str_bencode(key);
126
+
127
+ ID bencode_method_sym = rb_intern("bencode");
128
+ VALUE val_bencode = rb_funcall(value, bencode_method_sym, 0);
129
+
130
+ struct foreach_info *info = (struct foreach_info*) arg;
131
+
132
+ int idx = *(info->idx_ptr);
133
+ VALUE *base = info->base;
134
+
135
+ *((VALUE*) base + idx) = key_bencode;
136
+ *((VALUE*) base + idx + 1) = val_bencode;
137
+
138
+ *info->idx_ptr += 2;
139
+
140
+ return ST_CONTINUE;
141
+ }
142
+
143
+ static VALUE
144
+ rb_hash_bencode(VALUE hash) {
145
+ int hash_size = RHASH_SIZE(hash);
146
+ VALUE pieces[hash_size * 2];
147
+
148
+ int idx = 0;
149
+ struct foreach_info info = {&idx, pieces};
150
+
151
+ rb_hash_foreach(hash, rb_hash_bencode_entry, (VALUE) &info);
152
+
153
+ int total_len = 0;
154
+ for (int i = 0; i < hash_size * 2; i++) {
155
+ total_len += RSTRING_LEN(pieces[i]);
156
+ }
157
+
158
+ VALUE str = rb_str_new(NULL, total_len + 2);
159
+ char *ptr = RSTRING_PTR(str);
160
+
161
+ ptr[0] = 'd';
162
+
163
+ int offset = 1;
164
+ for (int i = 0; i < hash_size * 2; i++) {
165
+ int entry_len = RSTRING_LEN(pieces[i]);
166
+ memcpy(ptr + offset, RSTRING_PTR(pieces[i]), entry_len);
167
+ offset += entry_len;
168
+ }
169
+
170
+ ptr[total_len + 1] = 'e';
171
+
172
+ return str;
173
+ }
174
+
175
+ #define EOF_CHECK(ptr, len)\
176
+ if (*(ptr) >= (len))\
177
+ rb_raise(rb_eIOError, "Unexpected EOF");
178
+
179
+ VALUE decode_any(char *str, int *idx_ptr, int len);
180
+
181
+ VALUE decode_integer(char *str, int *idx_ptr, int len) {
182
+ int strlen = 2; // "i"<integer>"e"
183
+
184
+ EOF_CHECK(idx_ptr, len);
185
+ int neg = 0; // bool
186
+ if (str[*idx_ptr] == '-') {
187
+ neg = 1;
188
+
189
+ strlen++;
190
+ *idx_ptr += 1;
191
+ EOF_CHECK(idx_ptr, len);
192
+ }
193
+
194
+ long num = 0;
195
+ while (rb_isdigit(str[*idx_ptr])) {
196
+ num = num * 10 + (str[*idx_ptr] - '0');
197
+ strlen++;
198
+
199
+ *idx_ptr += 1;
200
+ EOF_CHECK(idx_ptr, len);
201
+ }
202
+
203
+ if (neg)
204
+ num = -num;
205
+
206
+ if (str[*idx_ptr] != 'e')
207
+ rb_raise(rb_eRuntimeError, "Expected 'e'");
208
+ *idx_ptr += 1;
209
+
210
+ return LONG2NUM(num);
211
+ }
212
+
213
+ VALUE decode_string(char *str, int *idx_ptr, int len, char dig) {
214
+ EOF_CHECK(idx_ptr, len);
215
+ int strlen = dig - '0';
216
+
217
+ while (rb_isdigit(str[*idx_ptr])) {
218
+ strlen = strlen * 10 + (str[*idx_ptr] - '0');
219
+ strlen++;
220
+ *idx_ptr += 1;
221
+ EOF_CHECK(idx_ptr, len);
222
+ }
223
+
224
+ if (str[*idx_ptr] != ':')
225
+ rb_raise(rb_eRuntimeError, "Expected ':', got '%c'", str[*idx_ptr]);
226
+ *idx_ptr += 1;
227
+
228
+ if (*idx_ptr + strlen > len)
229
+ rb_raise(rb_eIOError, "Unexpected EOF");
230
+
231
+ VALUE rb_str = rb_str_new(NULL, strlen);
232
+
233
+ memcpy(RSTRING_PTR(rb_str), str + *idx_ptr, strlen);
234
+ *idx_ptr += strlen;
235
+
236
+ return rb_str;
237
+ }
238
+
239
+ VALUE decode_list(char *str, int *idx_ptr, int len) {
240
+ EOF_CHECK(idx_ptr, len);
241
+
242
+ VALUE ary = rb_ary_new();
243
+
244
+ while (str[*idx_ptr] != 'e') {
245
+ VALUE elem = decode_any(str, idx_ptr, len);
246
+ rb_ary_push(ary, elem);
247
+ EOF_CHECK(idx_ptr, len);
248
+ }
249
+ *idx_ptr += 1;
250
+
251
+ return ary;
252
+ }
253
+
254
+ VALUE decode_dict(char *str, int *idx_ptr, int len) {
255
+ EOF_CHECK(idx_ptr, len);
256
+
257
+ VALUE hash = rb_hash_new();
258
+
259
+ while (str[*idx_ptr] != 'e') {
260
+ VALUE key = decode_any(str, idx_ptr, len);
261
+ EOF_CHECK(idx_ptr, len);
262
+ VALUE val = decode_any(str, idx_ptr, len);
263
+ EOF_CHECK(idx_ptr, len);
264
+
265
+ rb_hash_aset(hash, key, val);
266
+ }
267
+ *idx_ptr += 1;
268
+
269
+ return hash;
270
+ }
271
+
272
+ VALUE decode_any(char *str, int *idx_ptr, int len) {
273
+ EOF_CHECK(idx_ptr, len);
274
+ char prefix = str[*idx_ptr];
275
+ *idx_ptr += 1;
276
+
277
+ switch (prefix) {
278
+ case 'i':
279
+ return decode_integer(str, idx_ptr, len);
280
+ case 'l':
281
+ return decode_list(str, idx_ptr, len);
282
+ case 'd':
283
+ return decode_dict(str, idx_ptr, len);
284
+ default:
285
+ if (rb_isdigit(prefix)) {
286
+ return decode_string(str, idx_ptr, len, prefix);
287
+ }
288
+ rb_raise(rb_eRuntimeError, "Unexpected character '%c'", prefix);
289
+ }
290
+
291
+ return Qnil;
292
+ }
293
+
294
+ VALUE rb_bencode_decode(VALUE mod, VALUE str) {
295
+ int idx = 0;
296
+
297
+ return decode_any(RSTRING_PTR(str), &idx, RSTRING_LEN(str));
298
+ }
299
+
300
+ void Init_b_encode(void) {
301
+ rb_mBEncode = rb_define_module("BEncode");
302
+
303
+ // String#bencode and String#bencode!
304
+ rb_define_method(rb_cString, "bencode", rb_str_bencode, 0);
305
+ rb_define_method(rb_cString, "bencode!", rb_str_bencode_bang, 0);
306
+
307
+ // Integer#bencode
308
+ rb_define_method(rb_cInteger, "bencode", rb_integer_bencode, 0);
309
+
310
+ // Array#bencode
311
+ rb_define_method(rb_cArray, "bencode", rb_ary_bencode, 0);
312
+
313
+ // Hash#bencode
314
+ rb_define_method(rb_cHash, "bencode", rb_hash_bencode, 0);
315
+
316
+ rb_define_singleton_method(rb_mBEncode, "decode", rb_bencode_decode, 1);
317
+ }
@@ -0,0 +1,6 @@
1
+ #ifndef B_ENCODE_H
2
+ #define B_ENCODE_H 1
3
+
4
+ #include "ruby.h"
5
+
6
+ #endif /* B_ENCODE_H */
@@ -0,0 +1,3 @@
1
+ require "mkmf"
2
+
3
+ create_makefile("b_encode/b_encode")
@@ -0,0 +1,3 @@
1
+ module BEncode
2
+ VERSION = "0.0.1"
3
+ end
data/lib/b_encode.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "b_encode/version"
2
+ require "b_encode/b_encode"
3
+
4
+ module BEncode
5
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: b_encode
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - August
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake-compiler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description:
56
+ email:
57
+ - augustt198@gmail.com
58
+ executables: []
59
+ extensions:
60
+ - ext/b_encode/extconf.rb
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - b_encode.gemspec
69
+ - benchmark.rb
70
+ - ext/b_encode/b_encode.c
71
+ - ext/b_encode/b_encode.h
72
+ - ext/b_encode/extconf.rb
73
+ - lib/b_encode.rb
74
+ - lib/b_encode/version.rb
75
+ homepage: http://github.com/augustt198/b_encode
76
+ licenses:
77
+ - MIT
78
+ metadata: {}
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 2.4.3
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: Bencode encoder/decoder
99
+ test_files: []