ascii85_native 1.0.0 → 1.0.1
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.
- checksums.yaml +4 -4
- data/ext/ascii85_native/ascii85_native.c +65 -48
- data/ext/ascii85_native/ascii85_native.h +14 -13
- data/lib/ascii85_native.rb +73 -19
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5fbe80d98b9dc9e8d4a04542b578609ce16839be238ad35dd238a001dc02aaa8
|
4
|
+
data.tar.gz: 817069f8f96a4b699f0e8f31bc66ece1f79b190678334dcad478aac0fa910590
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b6161b062e5a9641c394d31331a79f6fa4bf96d6fc9e65460f3025c71a0eb09fa5b43faf06f7e973920a0454e864672b2ce395a4afd621899ee95752627ebae
|
7
|
+
data.tar.gz: db9217c98eca4134c50c2d9a01f509dbbc089610165bc062ccbe54d347488b54a9269831d7f3fa8761bfb4e6662fa0dd98be93bfb16cb54e2fc98b39659d613c
|
@@ -1,77 +1,94 @@
|
|
1
|
-
//
|
2
|
-
//
|
3
|
-
// Ascii85 C++ implementation pulled from https://github.com/larskholte/a85
|
4
|
-
// Original C++ Code License: Copy and use as you please. No attribution necessary.
|
5
|
-
//
|
6
|
-
// Adapted to C language
|
1
|
+
// ascii85_native.c
|
7
2
|
|
3
|
+
#include "stdlib.h"
|
8
4
|
#include "ascii85_native.h"
|
9
5
|
|
10
|
-
int
|
11
|
-
return (
|
6
|
+
int a85_encoded_size(int input_length, bool append_null) {
|
7
|
+
return (input_length * 5 + 3) / 4 + !!append_null;
|
12
8
|
}
|
13
9
|
|
14
|
-
void
|
15
|
-
// Go to end of
|
16
|
-
|
17
|
-
|
10
|
+
void a85_encode(const u8* input, int input_length, char* output, bool append_null) {
|
11
|
+
// Go to end of input and output buffers
|
12
|
+
input += input_length;
|
13
|
+
output += a85_encoded_size(input_length,append_null);
|
18
14
|
// Append null if requested
|
19
15
|
if (append_null) {
|
20
|
-
*(--
|
16
|
+
*(--output) = 0;
|
21
17
|
}
|
22
18
|
// If number of bytes is not divisible by 4, act as if null bytes were added to end of buffer
|
23
|
-
int rem =
|
19
|
+
int rem = input_length & 3;
|
24
20
|
if (rem) {
|
25
21
|
u32 val = 0;
|
26
22
|
for (int i = 4 - rem; i < 4; i++) {
|
27
|
-
val |= *(--
|
23
|
+
val |= *(--input) << (8 * i);
|
28
24
|
}
|
29
25
|
int i;
|
30
26
|
for (i = 0; i < 4 - rem; i++) {
|
31
27
|
val /= 85;
|
32
28
|
}
|
33
29
|
for (; i <= 4; i++) {
|
34
|
-
*(--
|
30
|
+
*(--output) = val % 85 + 33;
|
35
31
|
val /= 85;
|
36
32
|
}
|
37
|
-
|
33
|
+
input_length &= ~3;
|
38
34
|
}
|
39
|
-
while (
|
35
|
+
while (input_length) {
|
40
36
|
// Process chunks of 4 bytes as 32-bit values
|
41
|
-
u32 val = *(--
|
42
|
-
val |= *(--
|
43
|
-
val |= *(--
|
44
|
-
val |= *(--
|
37
|
+
u32 val = *(--input);
|
38
|
+
val |= *(--input) << 8;
|
39
|
+
val |= *(--input) << 16;
|
40
|
+
val |= *(--input) << 24;
|
45
41
|
// Convert to base 85
|
46
|
-
*(--
|
42
|
+
*(--output) = val % 85 + 33;
|
47
43
|
val /= 85;
|
48
|
-
*(--
|
44
|
+
*(--output) = val % 85 + 33;
|
49
45
|
val /= 85;
|
50
|
-
*(--
|
46
|
+
*(--output) = val % 85 + 33;
|
51
47
|
val /= 85;
|
52
|
-
*(--
|
48
|
+
*(--output) = val % 85 + 33;
|
53
49
|
val /= 85;
|
54
|
-
*(--
|
55
|
-
|
50
|
+
*(--output) = val % 85 + 33;
|
51
|
+
input_length -= 4;
|
56
52
|
}
|
57
53
|
}
|
58
54
|
|
59
|
-
int
|
60
|
-
return (
|
55
|
+
int a85_decoded_size(int input_length) {
|
56
|
+
return ((input_length * 4) / 5);
|
61
57
|
}
|
62
58
|
|
63
|
-
void
|
64
|
-
|
59
|
+
void a85_filter_before_decode(const char* input, int input_length, char* output) {
|
60
|
+
int input_remaining = input_length;
|
61
|
+
while (input_remaining) {
|
62
|
+
if ( !(*input == 0 || (*input >= 10 && *input <= 13)) ) {
|
63
|
+
*output = *input;
|
64
|
+
output++;
|
65
|
+
}
|
66
|
+
input++;
|
67
|
+
input_remaining--;
|
68
|
+
}
|
69
|
+
//*output = '\0';
|
70
|
+
}
|
71
|
+
|
72
|
+
void a85_decode(const char* input, int input_length, u8* output) {
|
73
|
+
// this is now done from the ruby side
|
74
|
+
//char* filtered_input;
|
75
|
+
//filtered_input = (char*)malloc(input_length*sizeof(char));
|
76
|
+
//a85_filter_before_decode(input, input_length, filtered_input);
|
77
|
+
//int filtered_length = strlen(filtered_input);
|
78
|
+
|
79
|
+
while (input_length) {
|
80
|
+
|
81
|
+
if (*input == 0) { break; }
|
65
82
|
|
66
|
-
|
83
|
+
if (*input >= 10 && *input <= 13) { input++; input_length--; continue; }
|
67
84
|
|
68
|
-
if (
|
85
|
+
if (input_length < 5) {
|
69
86
|
// Determine represented value in base 85
|
70
87
|
u32 val = 0;
|
71
88
|
int factor = 52200625; // 85^4
|
72
89
|
int i;
|
73
|
-
for (i = 0; i <
|
74
|
-
val += (*(
|
90
|
+
for (i = 0; i < input_length; i++) {
|
91
|
+
val += (*(input++) - 33) * factor;
|
75
92
|
factor /= 85;
|
76
93
|
}
|
77
94
|
for (; i < 5; i++) {
|
@@ -79,25 +96,25 @@ void from_a85(const char* text, int textlen, u8* data) {
|
|
79
96
|
factor /= 85;
|
80
97
|
}
|
81
98
|
int shift = 24;
|
82
|
-
for (i = 0; i <
|
83
|
-
*(
|
99
|
+
for (i = 0; i < input_length - 1; i++) {
|
100
|
+
*(output++) = val >> shift;
|
84
101
|
shift -= 8;
|
85
102
|
}
|
86
103
|
break;
|
87
104
|
}
|
88
105
|
|
89
106
|
// Determine represented value in base 85
|
90
|
-
u32 val = (*(
|
91
|
-
val += (*(
|
92
|
-
val += (*(
|
93
|
-
val += (*(
|
94
|
-
val += (*(
|
107
|
+
u32 val = (*(input++) - 33) * 52200625; // 85^4
|
108
|
+
val += (*(input++) - 33) * 614125; // 85^3
|
109
|
+
val += (*(input++) - 33) * 7225; // 85^2
|
110
|
+
val += (*(input++) - 33) * 85; // 85^1
|
111
|
+
val += (*(input++) - 33); // 85^0
|
95
112
|
|
96
113
|
// Write out in big-endian order
|
97
|
-
*(
|
98
|
-
*(
|
99
|
-
*(
|
100
|
-
*(
|
101
|
-
|
114
|
+
*(output++) = val >> 24;
|
115
|
+
*(output++) = val >> 16;
|
116
|
+
*(output++) = val >> 8;
|
117
|
+
*(output++) = val;
|
118
|
+
input_length -= 5;
|
102
119
|
}
|
103
120
|
}
|
@@ -1,9 +1,4 @@
|
|
1
|
-
//
|
2
|
-
//
|
3
|
-
// Ascii85 C++ implementation pulled from https://github.com/larskholte/a85
|
4
|
-
// Original C++ Code License: Copy and use as you please. No attribution necessary.
|
5
|
-
//
|
6
|
-
// Adapted to C language
|
1
|
+
// ascii85_native.h
|
7
2
|
|
8
3
|
#include <stdint.h>
|
9
4
|
|
@@ -11,17 +6,23 @@ typedef _Bool bool;
|
|
11
6
|
typedef uint8_t u8;
|
12
7
|
typedef uint32_t u32;
|
13
8
|
|
14
|
-
// Returns size of buffer required for
|
15
|
-
int
|
9
|
+
// Returns size of char buffer required for output of a85_encode().
|
10
|
+
int a85_encoded_size(int input_length, bool append_null);
|
16
11
|
|
17
12
|
// Translates the given binary data of the given size to Ascii85.
|
18
13
|
// Can translate in-place.
|
19
14
|
// Optionally appends a null character.
|
20
|
-
void
|
15
|
+
void a85_encode(const u8* input, int input_length, char* output, bool append_null);
|
21
16
|
|
22
|
-
// Returns the size of buffer required for
|
23
|
-
|
17
|
+
// Returns the size of u8 buffer required for the output of a85_decode().
|
18
|
+
// In reality, the number of decoded characters could be far less due to
|
19
|
+
// ignored characters being thrown out (see a85_filter_before_decode())
|
20
|
+
int a85_decoded_size(int input_length);
|
24
21
|
|
25
|
-
// Translates the given Ascii85
|
22
|
+
// Translates the given Ascii85 input to binary output.
|
26
23
|
// Can translate in-place.
|
27
|
-
void
|
24
|
+
void a85_decode(const char* input, int input_length, u8* output);
|
25
|
+
|
26
|
+
// Removes unused / ignored characters from the ascii85 input
|
27
|
+
// TODO: identify and remove <~ and ~> delimiters
|
28
|
+
void a85_filter_before_decode(const char* input, int input_length, char* output);
|
data/lib/ascii85_native.rb
CHANGED
@@ -5,23 +5,28 @@ require 'ffi'
|
|
5
5
|
module Ascii85Native
|
6
6
|
extend FFI::Library
|
7
7
|
|
8
|
+
ffi_lib 'c'
|
8
9
|
ffi_lib File.join(File.dirname(__FILE__), 'ascii85_native.so')
|
9
10
|
|
10
|
-
#void
|
11
|
-
attach_function :
|
11
|
+
#void a85_encode(const u8* data, int binlen, char* text, bool append_null);
|
12
|
+
attach_function :a85_encode, [:buffer_in, :int, :buffer_out, :bool], :void
|
12
13
|
|
13
|
-
#int
|
14
|
-
attach_function :
|
14
|
+
#int a85_encoded_size(int binlen, bool append_null);
|
15
|
+
attach_function :a85_encoded_size, [:int, :bool], :int
|
15
16
|
|
16
|
-
#
|
17
|
-
attach_function :
|
17
|
+
#int a85_decoded_size(int textlen)
|
18
|
+
attach_function :a85_decoded_size, [:int], :int
|
18
19
|
|
19
|
-
#
|
20
|
-
attach_function :
|
20
|
+
#void a85_decode(const char* text, int textlen, u8* data);
|
21
|
+
attach_function :a85_filter_before_decode, [:buffer_in, :int, :buffer_out], :void
|
21
22
|
|
23
|
+
#void a85_decode(const char* text, int textlen, u8* data);
|
24
|
+
attach_function :a85_decode, [:buffer_in, :int, :buffer_out], :void
|
25
|
+
|
26
|
+
attach_function :strlen, [:string], :int
|
22
27
|
|
23
28
|
def self.encode(input, include_delimiter=false)
|
24
|
-
if input.nil?
|
29
|
+
if input.nil? || input.size == 0
|
25
30
|
return '<~~>' if include_delimiter
|
26
31
|
return ''
|
27
32
|
end
|
@@ -35,10 +40,10 @@ module Ascii85Native
|
|
35
40
|
|
36
41
|
FFI::MemoryPointer.new(:uint8, input_data.size) do |in_uint8|
|
37
42
|
in_uint8.write_array_of_type(FFI::TYPE_UINT8, :put_uint8, input_data)
|
38
|
-
out_size = self.
|
43
|
+
out_size = self.a85_encoded_size(input_data.size, true)
|
39
44
|
|
40
45
|
FFI::MemoryPointer.new(:uint8, out_size) do |output|
|
41
|
-
self.
|
46
|
+
self.a85_encode(in_uint8, input_data.size, output, true)
|
42
47
|
if include_delimiter
|
43
48
|
return '<~' + (output.read_string() || '') + '~>'
|
44
49
|
else
|
@@ -49,21 +54,70 @@ module Ascii85Native
|
|
49
54
|
end
|
50
55
|
|
51
56
|
|
52
|
-
def self.decode(input)
|
53
|
-
return "" if input.nil?
|
57
|
+
def self.decode(input, force_delimiter=true)
|
58
|
+
return "" if input.nil? || input.size == 0
|
54
59
|
|
55
|
-
if
|
60
|
+
if force_delimiter
|
56
61
|
input = input[2..-3]
|
62
|
+
else
|
63
|
+
start_slice = find_start_slice(input)
|
64
|
+
end_slice = find_end_slice(input)
|
65
|
+
input = input[start_slice..end_slice] if start_slice != 0 || end_slice != -1
|
57
66
|
end
|
58
67
|
|
59
68
|
FFI::MemoryPointer.new(:char, input.size) do |in_char|
|
60
|
-
|
61
|
-
|
69
|
+
FFI::MemoryPointer.new(:char, input.size) do |filtered_char|
|
70
|
+
in_char.write_string(input)
|
62
71
|
|
63
|
-
|
64
|
-
self.
|
65
|
-
|
72
|
+
self.a85_filter_before_decode(in_char, input.size, filtered_char)
|
73
|
+
filtered_length = self.strlen(filtered_char.read_string())
|
74
|
+
puts "filtered_length: #{filtered_length}"
|
75
|
+
|
76
|
+
out_size = self.a85_decoded_size(filtered_length)
|
77
|
+
|
78
|
+
FFI::MemoryPointer.new(:uint8, out_size) do |output|
|
79
|
+
self.a85_decode(filtered_char, filtered_length, output)
|
80
|
+
return output.read_string()
|
81
|
+
end
|
66
82
|
end
|
67
83
|
end
|
68
84
|
end
|
85
|
+
|
86
|
+
def self.find_start_slice(input)
|
87
|
+
start_slice = 0
|
88
|
+
cursor = 0
|
89
|
+
|
90
|
+
input.size.times do |i|
|
91
|
+
if ['\n', '\r', ' '].include?(input[cursor])
|
92
|
+
cursor += 1
|
93
|
+
next
|
94
|
+
elsif input[cursor] == '<' && input[cursor+1] == '~'
|
95
|
+
start_slice = cursor + 2
|
96
|
+
break
|
97
|
+
else
|
98
|
+
break # input is not delimited
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
return start_slice
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.find_end_slice(input)
|
106
|
+
end_slice = -1
|
107
|
+
cursor = -1
|
108
|
+
|
109
|
+
input.size.times do |i|
|
110
|
+
if ['\n', '\r', ' '].include?(input[cursor])
|
111
|
+
cursor -= 1
|
112
|
+
next
|
113
|
+
elsif input[cursor] == '>' && input[cursor-1] == '~'
|
114
|
+
end_slice = cursor - 2
|
115
|
+
break
|
116
|
+
else
|
117
|
+
break # input is not delimited
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
return end_slice
|
122
|
+
end
|
69
123
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ascii85_native
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Crossfield
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-06-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|
@@ -82,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '0'
|
84
84
|
requirements: []
|
85
|
-
rubygems_version: 3.
|
85
|
+
rubygems_version: 3.2.15
|
86
86
|
signing_key:
|
87
87
|
specification_version: 4
|
88
88
|
summary: Ascii85 Encoder / Decoder with Native C Extensions
|