comparison mod_s2s_v6mesh/base32.lib.lua @ 6472:9f43226c7de1

mod_s2s_v6mesh: DNS-less federation for IPv6 networks
author Matthew Wild <mwild1@gmail.com>
date Tue, 17 Mar 2026 16:37:04 +0000
parents
children
comparison
equal deleted inserted replaced
6471:be2f75957552 6472:9f43226c7de1
1 --[[
2 borrowed from basexx library for Lua, under MIT License (MIT)
3 Copyright (c) 2013 aiq
4 The MIT License (MIT)
5
6 Copyright (c) 2013 aiq
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12 the Software, and to permit persons to whom the Software is furnished to do so,
13 subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
20 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
21 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 ----------------------------------------------------------------------------]]
25
26 local function ignore_set( str, set )
27 if set then
28 str = str:gsub( "["..set.."]", "" )
29 end
30 return str
31 end
32
33 local function divide_string( str, max )
34 local result = {}
35
36 local start = 1
37 for i = 1, #str do
38 if i % max == 0 then
39 table.insert( result, str:sub( start, i ) )
40 start = i + 1
41 elseif i == #str then
42 table.insert( result, str:sub( start, i ) )
43 end
44 end
45
46 return result
47 end
48
49 function to_bit( str )
50 return ( str:gsub( '.', function ( c )
51 local byte = string.byte( c )
52 local bits = {}
53 for _ = 1,8 do
54 table.insert( bits, byte % 2 )
55 byte = math.floor( byte / 2 )
56 end
57 return table.concat( bits ):reverse()
58 end ) )
59 end
60
61 local function number_to_bit( num, length )
62 local bits = {}
63
64 while num > 0 do
65 local rest = math.floor( math.fmod( num, 2 ) )
66 table.insert( bits, rest )
67 num = ( num - rest ) / 2
68 end
69
70 while #bits < length do
71 table.insert( bits, "0" )
72 end
73
74 return string.reverse( table.concat( bits ) )
75 end
76
77 local function pure_from_bit( str )
78 return ( str:gsub( '........', function ( cc )
79 return string.char( tonumber( cc, 2 ) )
80 end ) )
81 end
82
83 local function unexpected_char_error( str, pos )
84 local c = string.sub( str, pos, pos )
85 return string.format( "unexpected character at position %d: '%s'", pos, c )
86 end
87
88 local function from_basexx( str, alphabet, bits )
89 local result = {}
90 for i = 1, #str do
91 local c = string.sub( str, i, i )
92 if c ~= '=' then
93 local index = string.find( alphabet, c, 1, true )
94 if not index then
95 return nil, unexpected_char_error( str, i )
96 end
97 table.insert( result, number_to_bit( index - 1, bits ) )
98 end
99 end
100
101 local value = table.concat( result )
102 local pad = #value % 8
103 return pure_from_bit( string.sub( value, 1, #value - pad ) )
104 end
105
106 local function to_basexx( str, alphabet, bits, pad )
107 local bitString = to_bit( str )
108
109 local chunks = divide_string( bitString, bits )
110 local result = {}
111 for _,value in ipairs( chunks ) do
112 if ( #value < bits ) then
113 value = value .. string.rep( '0', bits - #value )
114 end
115 local pos = tonumber( value, 2 ) + 1
116 table.insert( result, alphabet:sub( pos, pos ) )
117 end
118
119 table.insert( result, pad )
120 return table.concat( result )
121 end
122
123 local base32Alphabet = "abcdefghijklmnopqrstuvwxyz234567"
124 local base32PadMap = { "", "======", "====", "===", "=" }
125
126 local function from_base32( str, ignore )
127 str = ignore_set( str, ignore )
128 return from_basexx( string.lower( str ), base32Alphabet, 5 )
129 end
130
131 function to_base32( str )
132 return to_basexx( str, base32Alphabet, 5, base32PadMap[ #str % 5 + 1 ] )
133 end
134
135 return {
136 decode = from_base32;
137 encode = to_base32;
138 };