@@ -2,6 +2,8 @@ package base45
22
33import (
44 "fmt"
5+ "unsafe"
6+ "reflect"
57 "strings"
68 "encoding/binary"
79)
@@ -18,7 +20,7 @@ type InvalidLengthError struct {
1820}
1921
2022func (e InvalidLengthError ) Error () string {
21- return fmt .Sprintf ("invalid length n=%d. It should be n mod 3 = [0, 2] NOT n mod 3 = %d" , e .length , e .mod )
23+ return fmt .Sprintf ("go-encoding/base45: invalid length n=%d. It should be n mod 3 = [0, 2] NOT n mod 3 = %d" , e .length , e .mod )
2224}
2325
2426type InvalidCharacterError struct {
@@ -27,15 +29,15 @@ type InvalidCharacterError struct {
2729}
2830
2931func (e InvalidCharacterError ) Error () string {
30- return fmt .Sprintf ("invalid character %s at position: %d\n " , string (e .char ), e .position )
32+ return fmt .Sprintf ("go-encoding/base45: invalid character %s at position: %d\n " , string (e .char ), e .position )
3133}
3234
3335type IllegalBase45ByteError struct {
3436 position int
3537}
3638
3739func (e IllegalBase45ByteError ) Error () string {
38- return fmt .Sprintf ("illegal base45 data at byte position %d\n " , e .position )
40+ return fmt .Sprintf ("go-encoding/base45: illegal base45 data at byte position %d\n " , e .position )
3941}
4042
4143// encodingMap
@@ -59,102 +61,53 @@ func (e IllegalBase45ByteError) Error() string {
5961// 09 9 21 L 33 X
6062// 10 A 22 M 34 Y
6163// 11 B 23 N 35 Z
62- var encodingMap = map [byte ]rune {
63- byte (0 ): '0' ,
64- byte (1 ): '1' ,
65- byte (2 ): '2' ,
66- byte (3 ): '3' ,
67- byte (4 ): '4' ,
68- byte (5 ): '5' ,
69- byte (6 ): '6' ,
70- byte (7 ): '7' ,
71- byte (8 ): '8' ,
72- byte (9 ): '9' ,
73- byte (10 ): 'A' ,
74- byte (11 ): 'B' ,
75- byte (12 ): 'C' ,
76- byte (13 ): 'D' ,
77- byte (14 ): 'E' ,
78- byte (15 ): 'F' ,
79- byte (16 ): 'G' ,
80- byte (17 ): 'H' ,
81- byte (18 ): 'I' ,
82- byte (19 ): 'J' ,
83- byte (20 ): 'K' ,
84- byte (21 ): 'L' ,
85- byte (22 ): 'M' ,
86- byte (23 ): 'N' ,
87- byte (24 ): 'O' ,
88- byte (25 ): 'P' ,
89- byte (26 ): 'Q' ,
90- byte (27 ): 'R' ,
91- byte (28 ): 'S' ,
92- byte (29 ): 'T' ,
93- byte (30 ): 'U' ,
94- byte (31 ): 'V' ,
95- byte (32 ): 'W' ,
96- byte (33 ): 'X' ,
97- byte (34 ): 'Y' ,
98- byte (35 ): 'Z' ,
99- byte (36 ): ' ' ,
100- byte (37 ): '$' ,
101- byte (38 ): '%' ,
102- byte (39 ): '*' ,
103- byte (40 ): '+' ,
104- byte (41 ): '-' ,
105- byte (42 ): '.' ,
106- byte (43 ): '/' ,
107- byte (44 ): ':' ,
64+ const encodeStd = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"
65+
66+ // StdEncoding is the standard base62 encoding.
67+ var StdEncoding = NewEncoding (encodeStd )
68+
69+ /*
70+ * Encodings
71+ */
72+
73+ // An Encoding is a radix 45 encoding/decoding scheme, defined by a 45-character alphabet.
74+ type Encoding struct {
75+ encode [45 ]byte
76+ decodeMap [256 ]byte
10877}
10978
110- var decodingMap = map [rune ]byte {
111- '0' : byte (0 ),
112- '1' : byte (1 ),
113- '2' : byte (2 ),
114- '3' : byte (3 ),
115- '4' : byte (4 ),
116- '5' : byte (5 ),
117- '6' : byte (6 ),
118- '7' : byte (7 ),
119- '8' : byte (8 ),
120- '9' : byte (9 ),
121- 'A' : byte (10 ),
122- 'B' : byte (11 ),
123- 'C' : byte (12 ),
124- 'D' : byte (13 ),
125- 'E' : byte (14 ),
126- 'F' : byte (15 ),
127- 'G' : byte (16 ),
128- 'H' : byte (17 ),
129- 'I' : byte (18 ),
130- 'J' : byte (19 ),
131- 'K' : byte (20 ),
132- 'L' : byte (21 ),
133- 'M' : byte (22 ),
134- 'N' : byte (23 ),
135- 'O' : byte (24 ),
136- 'P' : byte (25 ),
137- 'Q' : byte (26 ),
138- 'R' : byte (27 ),
139- 'S' : byte (28 ),
140- 'T' : byte (29 ),
141- 'U' : byte (30 ),
142- 'V' : byte (31 ),
143- 'W' : byte (32 ),
144- 'X' : byte (33 ),
145- 'Y' : byte (34 ),
146- 'Z' : byte (35 ),
147- ' ' : byte (36 ),
148- '$' : byte (37 ),
149- '%' : byte (38 ),
150- '*' : byte (39 ),
151- '+' : byte (40 ),
152- '-' : byte (41 ),
153- '.' : byte (42 ),
154- '/' : byte (43 ),
155- ':' : byte (44 ),
79+ // NewEncoding returns a new padded Encoding defined by the given alphabet,
80+ // which must be a 45-byte string that does not contain the padding character
81+ // or CR / LF ('\r', '\n').
82+ func NewEncoding (encoder string ) * Encoding {
83+ if len (encoder ) != 45 {
84+ panic ("go-encoding/base45: encoding alphabet is not 45-bytes long" )
85+ }
86+
87+ for i := 0 ; i < len (encoder ); i ++ {
88+ if encoder [i ] == '\n' || encoder [i ] == '\r' {
89+ panic ("go-encoding/base45: encoding alphabet contains newline character" )
90+ }
91+ }
92+
93+ e := new (Encoding )
94+ copy (e .encode [:], encoder )
95+
96+ for i := 0 ; i < len (e .decodeMap ); i ++ {
97+ e .decodeMap [i ] = 0xFF
98+ }
99+
100+ for i := 0 ; i < len (encoder ); i ++ {
101+ e.decodeMap [encoder [i ]] = byte (i )
102+ }
103+
104+ return e
156105}
157106
107+ /*
108+ * Encoder
109+ */
110+
158111// Encode
159112// 4. The Base45 Encoding
160113// A 45-character subset of US-ASCII is used; the 45 characters usable
@@ -188,68 +141,89 @@ var decodingMap = map[rune]byte{
188141//
189142// For decoding a Base45 encoded string the inverse operations are
190143// performed.
191- func Encode (in string ) string {
192- bytes := []byte (in )
144+ func (enc * Encoding ) Encode (bytes []byte ) []byte {
193145 pairs := encodePairs (bytes )
146+
194147 var builder strings.Builder
195148 for i , pair := range pairs {
196149 res := encodeBase45 (pair )
197150 if i + 1 == len (pairs ) && res [2 ] == 0 {
198151 for _ , b := range res [:2 ] {
199- if c , ok := encodingMap [ b ]; ok {
200- builder .WriteRune ( c )
152+ if len ( enc . encode ) > int ( b ) {
153+ builder .WriteByte ( enc . encode [ b ] )
201154 }
202155 }
203156 } else {
204157 for _ , b := range res {
205- if c , ok := encodingMap [ b ]; ok {
206- builder .WriteRune ( c )
158+ if len ( enc . encode ) > int ( b ) {
159+ builder .WriteByte ( enc . encode [ b ] )
207160 }
208161 }
209162 }
210163 }
211- return builder .String ()
164+
165+ return []byte (builder .String ())
166+ }
167+
168+ // EncodeToString returns the base62 encoding of src.
169+ func (enc * Encoding ) EncodeToString (src []byte ) string {
170+ buf := enc .Encode (src )
171+ return string (buf )
212172}
213173
174+ /*
175+ * Decoder
176+ */
177+
214178// Decode
215179// Decoding example 1: The string "QED8WEX0" represents, when looked up
216180// in Table 1, the values [26 14 13 8 32 14 33 0]. We arrange the
217181// numbers in chunks of three, except for the last one which can be two,
218182// and get [[26 14 13] [8 32 14] [33 0]]. In base 45 we get [26981
219183// 29798 33] where the bytes are [[105 101] [116 102] [33]]. If we look
220184// at the ASCII values we get the string "ietf!".
221- func Decode (in string ) (string , error ) {
185+ func ( enc * Encoding ) Decode (in [] byte ) ([] byte , error ) {
222186 size := len (in )
187+
223188 mod := size % 3
224189 if mod != 0 && mod != 2 {
225- return "" , InvalidLengthError {
190+ return nil , InvalidLengthError {
226191 length : size ,
227192 mod : mod ,
228193 }
229194 }
195+
230196 bytes := make ([]byte , 0 , size )
231197 for pos , char := range in {
232- v , ok := decodingMap [char ]
233- if ! ok {
234- return "" , InvalidCharacterError {
235- char : char ,
236- position : pos ,
198+ if len (enc .decodeMap ) > int (char ) {
199+ v := enc .decodeMap [char ]
200+
201+ if int (v ) == 255 {
202+ return nil , InvalidCharacterError {
203+ char : rune (char ),
204+ position : pos ,
205+ }
237206 }
207+
208+ bytes = append (bytes , v )
238209 }
239- bytes = append (bytes , v )
240210 }
211+
241212 chunks := decodeChunks (bytes )
242213 triplets , err := decodeTriplets (chunks )
243214 if err != nil {
244- return "" , err
215+ return nil , err
245216 }
217+
246218 tripletsLength := len (triplets )
247219 decoded := make ([]byte , 0 , tripletsLength * 2 )
220+
248221 for i := 0 ; i < tripletsLength - 1 ; i ++ {
249222 bytes := uint16ToBytes (triplets [i ])
250223 decoded = append (decoded , bytes [0 ])
251224 decoded = append (decoded , bytes [1 ])
252225 }
226+
253227 if mod == 2 {
254228 bytes := uint16ToBytes (triplets [tripletsLength - 1 ])
255229 decoded = append (decoded , bytes [1 ])
@@ -258,7 +232,15 @@ func Decode(in string) (string, error) {
258232 decoded = append (decoded , bytes [0 ])
259233 decoded = append (decoded , bytes [1 ])
260234 }
261- return string (decoded ), nil
235+
236+ return decoded , nil
237+ }
238+
239+ // DecodeString returns the bytes represented by the base62 string s.
240+ func (enc * Encoding ) DecodeString (s string ) ([]byte , error ) {
241+ sh := (* reflect .StringHeader )(unsafe .Pointer (& s ))
242+ bh := reflect.SliceHeader {Data : sh .Data , Len : sh .Len , Cap : sh .Len }
243+ return enc .Decode (* (* []byte )(unsafe .Pointer (& bh )))
262244}
263245
264246func uint16ToBytes (in uint16 ) []byte {
@@ -297,8 +279,10 @@ func encodePairs(in []byte) [][]byte {
297279 } else {
298280 low = in [i ]
299281 }
282+
300283 ret = append (ret , []byte {high , low })
301284 }
285+
302286 return ret
303287}
304288
@@ -313,18 +297,22 @@ func encodeBase45(in []byte) []byte {
313297func decodeTriplets (in [][]byte ) ([]uint16 , error ) {
314298 size := len (in )
315299 ret := make ([]uint16 , 0 , size )
300+
316301 for pos , chunk := range in {
317302 if len (chunk ) == 3 {
318303 // n = c + (d*45) + (e*45*45)
319304 c := int (chunk [0 ])
320305 d := int (chunk [1 ])
321306 e := int (chunk [2 ])
322307 n := c + (d * base ) + (e * baseSquare )
308+
323309 if n > maxUint16 {
324310 return nil , IllegalBase45ByteError {position : pos }
325311 }
312+
326313 ret = append (ret , uint16 (n ))
327314 }
315+
328316 if len (chunk ) == 2 {
329317 // n = c + (d*45)
330318 c := uint16 (chunk [0 ])
@@ -333,5 +321,6 @@ func decodeTriplets(in [][]byte) ([]uint16, error) {
333321 ret = append (ret , n )
334322 }
335323 }
324+
336325 return ret , nil
337326}
0 commit comments