11import { from } from './base.ts'
22
33const alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:'
4+ const INVALID = 0xff
5+ const decodeTable = ( ( ) => {
6+ const table = new Uint8Array ( 256 ) . fill ( INVALID )
7+ for ( let i = 0 ; i < alphabet . length ; i ++ ) {
8+ const code = alphabet . charCodeAt ( i )
9+ table [ code ] = i
10+ if ( code >= 0x41 && code <= 0x5a ) {
11+ table [ code + 0x20 ] = i
12+ }
13+ }
14+ return table
15+ } ) ( )
416
5- function indexOf ( char : string ) : number {
6- const index = alphabet . indexOf ( char )
7- if ( index === - 1 ) {
8- throw new Error ( `Non-base45 character: ${ char } ` )
17+ function decodeChar ( input : string , i : number ) : number {
18+ const v = decodeTable [ input . charCodeAt ( i ) ]
19+ if ( v === INVALID ) {
20+ throw new Error ( `Non-base45 character: ${ input [ i ] } ` )
921 }
10- return index
22+ return v
1123}
1224
1325export const base45 = from ( {
@@ -18,33 +30,35 @@ export const base45 = from({
1830 for ( let i = 0 ; i < input . length ; i += 2 ) {
1931 if ( i + 1 === input . length ) {
2032 const v = input [ i ]
21- const a = v / 45 | 0
22- const b = v % 45 | 0
23- ret += alphabet [ b ] + alphabet [ a ]
33+ ret += alphabet [ v % 45 ] + alphabet [ ( v / 45 ) | 0 ]
2434 break
2535 }
26- const v = input [ i ] << 8 | input [ i + 1 ]
27- const a = v / 45 ** 2 | 0
28- const b = v / 45 % 45 | 0
29- const c = v % 45
30- ret += alphabet [ c ] + alphabet [ b ] + alphabet [ a ]
36+ const v = ( input [ i ] << 8 ) | input [ i + 1 ]
37+ ret += alphabet [ v % 45 ] + alphabet [ ( ( v / 45 ) | 0 ) % 45 ] + alphabet [ ( v / 2025 ) | 0 ]
3138 }
3239 return ret
3340 } ,
3441 decode : ( input : string ) : Uint8Array < ArrayBuffer > => {
3542 if ( ( input . length * 2 ) % 3 === 2 ) {
3643 throw new Error ( 'Unexpected end of data' )
3744 }
38- const out = new Uint8Array ( Math . floor ( input . length * 2 / 3 ) )
45+ const out = new Uint8Array ( ( ( input . length * 2 ) / 3 ) | 0 )
46+ let o = 0
3947 for ( let i = 0 ; i < input . length ; i += 3 ) {
4048 if ( i + 2 === input . length ) {
41- const v = indexOf ( input [ i ] ) + indexOf ( input [ i + 1 ] ) * 45
42- out [ i / 3 * 2 ] = v
49+ const v = decodeChar ( input , i ) + decodeChar ( input , i + 1 ) * 45
50+ if ( v > 0xff ) {
51+ throw new Error ( 'Invalid base45 encoding: trailing chunk out of range' )
52+ }
53+ out [ o ++ ] = v
4354 break
4455 }
45- const v = indexOf ( input [ i ] ) + indexOf ( input [ i + 1 ] ) * 45 + indexOf ( input [ i + 2 ] ) * 45 ** 2
46- out [ i / 3 * 2 ] = v >> 8
47- out [ i / 3 * 2 + 1 ] = v & 0xff
56+ const v = decodeChar ( input , i ) + decodeChar ( input , i + 1 ) * 45 + decodeChar ( input , i + 2 ) * 2025
57+ if ( v > 0xffff ) {
58+ throw new Error ( 'Invalid base45 encoding: chunk out of range' )
59+ }
60+ out [ o ++ ] = v >> 8
61+ out [ o ++ ] = v & 0xff
4862 }
4963 return out
5064 }
0 commit comments