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+ table [ alphabet . charCodeAt ( i ) ] = i
9+ }
10+ return table
11+ } ) ( )
412
5- function indexOf ( char : string ) : number {
6- const index = alphabet . indexOf ( char )
7- if ( index === - 1 ) {
8- throw new Error ( `Non-base45 character: ${ char } ` )
13+ function decodeChar ( input : string , i : number ) : number {
14+ const v = decodeTable [ input . charCodeAt ( i ) ]
15+ if ( v === INVALID ) {
16+ throw new Error ( `Non-base45 character: ${ input [ i ] } ` )
917 }
10- return index
18+ return v
1119}
1220
1321export const base45 = from ( {
@@ -18,33 +26,35 @@ export const base45 = from({
1826 for ( let i = 0 ; i < input . length ; i += 2 ) {
1927 if ( i + 1 === input . length ) {
2028 const v = input [ i ]
21- const a = v / 45 | 0
22- const b = v % 45 | 0
23- ret += alphabet [ b ] + alphabet [ a ]
29+ ret += alphabet [ v % 45 ] + alphabet [ ( v / 45 ) | 0 ]
2430 break
2531 }
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 ]
32+ const v = ( input [ i ] << 8 ) | input [ i + 1 ]
33+ ret += alphabet [ v % 45 ] + alphabet [ ( ( v / 45 ) | 0 ) % 45 ] + alphabet [ ( v / 2025 ) | 0 ]
3134 }
3235 return ret
3336 } ,
3437 decode : ( input : string ) : Uint8Array < ArrayBuffer > => {
3538 if ( ( input . length * 2 ) % 3 === 2 ) {
3639 throw new Error ( 'Unexpected end of data' )
3740 }
38- const out = new Uint8Array ( Math . floor ( input . length * 2 / 3 ) )
41+ const out = new Uint8Array ( ( ( input . length * 2 ) / 3 ) | 0 )
42+ let o = 0
3943 for ( let i = 0 ; i < input . length ; i += 3 ) {
4044 if ( i + 2 === input . length ) {
41- const v = indexOf ( input [ i ] ) + indexOf ( input [ i + 1 ] ) * 45
42- out [ i / 3 * 2 ] = v
45+ const v = decodeChar ( input , i ) + decodeChar ( input , i + 1 ) * 45
46+ if ( v > 0xff ) {
47+ throw new Error ( 'Invalid base45 encoding: trailing chunk out of range' )
48+ }
49+ out [ o ++ ] = v
4350 break
4451 }
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
52+ const v = decodeChar ( input , i ) + decodeChar ( input , i + 1 ) * 45 + decodeChar ( input , i + 2 ) * 2025
53+ if ( v > 0xffff ) {
54+ throw new Error ( 'Invalid base45 encoding: chunk out of range' )
55+ }
56+ out [ o ++ ] = v >> 8
57+ out [ o ++ ] = v & 0xff
4858 }
4959 return out
5060 }
0 commit comments