base45 0.1.0 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 391fbba1f795babf955ab02b30fbe0f9016cd4440d33727bf76883feeb6a341d
4
- data.tar.gz: c533882b3b041d2d5d5c5e6e68830900bc5ff63a42ea1c7c17b8d5867c5a7888
3
+ metadata.gz: 7e6b4b06a7babf7b527a48d46e3a3be28e5e9ec5bf98bc1ab2fd846fea3e173b
4
+ data.tar.gz: f759775b44c270a43fda53bb20994b374bbb458e990dcbfa70731374675bbb7d
5
5
  SHA512:
6
- metadata.gz: 86c794ec6a105a7db8a7eab5d934d9bcccb2d6d58d38d75ab75fc2ff57047363f43fed0b025947fb92418b4c138b41e87e0b1ce1e42123d7fca3d4df1e285056
7
- data.tar.gz: 937cad72b4c7b54d87f23eb8484a76a6589e029e3e8eb8afc0be86de63974f0c7bd44ecf15905d5c1253d32d3796c005cd6c20a9e0c19caba465afd0115f14df
6
+ metadata.gz: 4604ad5a6df8f8955b472c2c187010974d5fecb9cb82c91e2385d5b01aa1a2637b41be16e9f6e57326e27340e0b1aa25a6562da08507ecc7f24b486e92e0ba69
7
+ data.tar.gz: f8175d0a95a34089cbf8ae43f7a44b79f4087fb9819778ca7d28c50d9cbf388e177f47c887ba20dc0ed17d1f1aaa2fcbe763190fce0dcfc5d918e99267c0a585
data/.rubocop.yml CHANGED
@@ -11,3 +11,6 @@ Style/StringLiteralsInInterpolation:
11
11
 
12
12
  Layout/LineLength:
13
13
  Max: 120
14
+
15
+ Metrics/BlockLength:
16
+ ExcludedMethods: ['describe']
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Base45
4
+ class IllegalCharacterError < StandardError; end
5
+
6
+ class ForbiddenLengthError < StandardError; end
7
+
8
+ class OverflowError < StandardError; end
9
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Base45
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/base45.rb CHANGED
@@ -9,11 +9,10 @@
9
9
 
10
10
  require_relative "base45/version"
11
11
  require_relative "base45/encoding_table"
12
+ require_relative "base45/errors"
12
13
 
13
14
  # Exposes two methods to decode and encode in base 45
14
15
  module Base45
15
- class Error < StandardError; end
16
-
17
16
  class << self
18
17
  # Returns the Base45-encoded version of +payload+
19
18
  #
@@ -24,11 +23,14 @@ module Base45
24
23
  #
25
24
  # :Y8UPCAVC3/DH44M-DUJCLQE934AW6X0
26
25
  def encode(payload)
27
- return if payload.length.zero?
28
-
29
- return encode_for_single_char(payload) if payload.bytesize < 2
26
+ sliced_bytes = payload.each_byte.each_slice(2)
27
+ base45_bytes = sliced_bytes.flat_map do |byte_a, byte_b|
28
+ byte_b ? encode_two_bytes(byte_a, byte_b) : encode_one_byte(byte_a)
29
+ end
30
30
 
31
- encode_for_multipe_chars(payload)
31
+ base45_bytes.map do |byte45|
32
+ BASE_45_TABLE[byte45.to_s.rjust(2, "0")]
33
+ end.join
32
34
  end
33
35
 
34
36
  # Returns the Base45-decoded version of +payload+
@@ -40,50 +42,43 @@ module Base45
40
42
  #
41
43
  # Encoding in base 45 !
42
44
  def decode(payload)
43
- return if payload.length < 2
44
-
45
- lookup = sliced_payload(payload)
46
- base45_vals = lookup.map { |c, d, e| c + d * 45 + (e ? e * 45**2 : 0) }
47
-
48
- base45_vals.pack("S>*").gsub(/\x00/, "")
45
+ map45_chars(payload).each_slice(3).flat_map do |c, d, e|
46
+ c && d or raise ForbiddenLengthError
47
+ v = c + d * 45
48
+ bytes_from_base45(e, v)
49
+ end.pack("C*")
49
50
  end
50
51
 
51
52
  private
52
53
 
53
- def sliced_payload(payload)
54
- payload.chars.each_slice(3).map do |slice|
55
- slice.map { |char| INVERTED_BASE_45_TABLE[char]&.to_i }
56
- end
57
- end
54
+ def bytes_from_base45(last_triplet_byte, factor45)
55
+ return [factor45] unless last_triplet_byte
58
56
 
59
- def encode_for_single_char(payload)
60
- keys = payload.bytes[0].divmod(45).reverse
57
+ factor45 += last_triplet_byte * (45**2)
58
+ x, y = factor45.divmod(256)
59
+ raise OverflowError unless x < 256
61
60
 
62
- keys.map { |i| BASE_45_TABLE[i.to_s.rjust(2, "0")] }.join
61
+ [x, y]
63
62
  end
64
63
 
65
- def encode_for_multipe_chars(payload)
66
- # 16-bit unsigned (unsigned char) - except big endian
67
- bytes16 = payload.unpack("S>*")
68
-
69
- is_odd = payload.bytesize.odd? && payload.bytes[-1] < 256
70
- bytes16 << payload.bytes[-1] if is_odd
64
+ def encode_one_byte(byte)
65
+ byte.divmod(45).reverse
66
+ end
71
67
 
72
- modulo45_bytes = modulo45_array(bytes16)
68
+ def encode_two_bytes(first_byte, second_byte)
69
+ x = (first_byte << 8) + second_byte
70
+ e, x = x.divmod(45**2)
71
+ d, c = x.divmod(45)
73
72
 
74
- modulo45_bytes.flatten.map do |i|
75
- BASE_45_TABLE[i.to_s.rjust(2, "0")]
76
- end.join
73
+ [c, d, e]
77
74
  end
78
75
 
79
- def modulo45_array(bytes16)
80
- bytes16.map do |byte|
81
- arr = []
82
- multiplier, rest = byte.divmod(45**2)
83
- arr << multiplier if multiplier.positive?
84
- arr.push(*rest.divmod(45))
76
+ def map45_chars(string)
77
+ string.upcase.each_char.map do |c|
78
+ char_byte = INVERTED_BASE_45_TABLE[c]
79
+ raise(IllegalCharacterError, c.inspect) unless char_byte
85
80
 
86
- arr.reverse
81
+ char_byte.to_i
87
82
  end
88
83
  end
89
84
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: base45
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wattswing
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-02 00:00:00.000000000 Z
11
+ date: 2021-11-06 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Decode / encode in base 45
14
14
  email:
@@ -28,6 +28,7 @@ files:
28
28
  - bin/setup
29
29
  - lib/base45.rb
30
30
  - lib/base45/encoding_table.rb
31
+ - lib/base45/errors.rb
31
32
  - lib/base45/version.rb
32
33
  homepage: https://github.com/wattswing/base45
33
34
  licenses: