Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 0 additions & 15 deletions .eslintrc.js

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
.vscode
*.tgz
38 changes: 26 additions & 12 deletions __tests__/encodeDecode.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable no-undef */
const { encode, decode } = require('../lib/base45')
import { describe, test } from 'node:test'
import * as base45 from '../lib/base45.js'

const cases = [
['Hello!!', '%69 VD92EX0'],
['AB', 'BB8'],
Expand All @@ -12,28 +13,41 @@ const cases = [
]
]

const invalidCases = [
'NCFOXN%TSMAHN-H/RCMPQ5GE5I00H9GBH3QNAD6.LQLX85ZS GJTSJ4NKP1HCV4*XUA2PSGH.+H$NI4L6F$S-N1FYBRR1$Q1+GOF+P$HQPHQHTQ.SQ6$PUKRN95404.W7UX4795L*KDYPWGO+9AZDOHCRL35IWMSDOP7OQ+M70AK$8 96XY4SBLU96:/6N9R%EPL8RY9DOA60-K.IA.C8KRDL4O54O4IGUJKJGI0JAXD15IAXMFU*GSHGRKMXGG6DBYCBMQN:HG5PAHGG8KES/F-1JW-K%B3A9ENO4B-S-*O4-G1FD/U47HAE1MI4OE0G1:HHD4AB874MM-6B:HKJSQ.TAG3CR1638W9AV88G64PB4VHRY2EK03NFJL4M10KP3AT2VK LT5GGFV85I0*10W2ZXJSBTMFW*+KM2T8-CXR32BMF7RAEAYKMWHE/NH UP4SNGENEWUY97 -3YM0.HAM:D:00ZY35XRT1100MFKWEWYHKCZIZJ0CAQYIKOZIZJ0DAQCDQGAE62ORR7HL0POYQCGMGBBEQFCBCDCT4VYFQZEPYFXK69ZRV9T8IY6NWAYEJF0VXVKNFCG/X9UIG5HFWRPEDW2EPW00S1K83I3900:919FUCKYOUALLGPSUPPORTERS9IKM24N21AW7ZUR2L013300EUISGOEINGDOWNNAZZYFUCKERS666I3AK96XYR01300STOREMYCODEMUTHERFUCKERANDGOTOHELLI5340XRT09SHUZVB33IR0IPUTAVIRUSHERE83H73KFI280I23KL0YRZT91Y0WITHLOVEFROMHA1*PWEOXCI/QXRLOZKN0LM*03I2RWT0Z',
]

const textEncoder = new TextEncoder()
const textDecoder = new TextDecoder()

describe('decoding', () => {
test('all test cases', () => {
test('all test cases', (t) => {
cases.forEach(([expected, encoded]) => {
const result = decode(encoded).toString('utf-8')
expect(result).toEqual(expected)
const result = base45.decode(encoded)
t.assert.strictEqual(textDecoder.decode(result), expected)
})
})

test('first encode and then decode the test cases', () => {
test('first encode and then decode the test cases', (t) => {
cases.forEach(([text]) => {
const encoded = encode(text)
const result = decode(encoded).toString('utf-8')
expect(result).toEqual(text)
const encoded = base45.encode(textEncoder.encode(text))
const result = base45.decode(encoded)
t.assert.strictEqual(textDecoder.decode(result), text)
})
})

test('rejects invalid input', (t) => {
invalidCases.forEach((input) => {
t.assert.throws(() => base45.decode(input), { message: /Invalid base45 string/ })
})
})
})

describe('encoding', () => {
test('all test cases', () => {
test('all test cases', (t) => {
cases.forEach(([text, encoded]) => {
const result = encode(text)
expect(result).toEqual(encoded)
const result = base45.encode(textEncoder.encode(text))
t.assert.strictEqual(result, encoded)
})
})
})
5 changes: 5 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import neostandard from 'neostandard'

export default neostandard({
env: ['browser', 'node'],
})
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
module.exports = require('./lib/base45')
export * from './lib/base45.js'
44 changes: 22 additions & 22 deletions lib/base45.js
Original file line number Diff line number Diff line change
@@ -1,47 +1,47 @@
const charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:'
const divmod = (x, y) => [Math.floor(x / y), x % y]

// Encode a buffer (or uint8array) to base45-encoded string
const encode = (buffer) => {
if (typeof (buffer) === 'string') buffer = Buffer.from(buffer)
/**
* Encode data into a base45-encoded string.
* @param {Uint8Array} data
*/
export function encode(data) {
let res = ''
for (let i = 0; i < buffer.length; i = i + 2) {
if (buffer.length - i > 1) {
const x = (buffer[i] << 8) + buffer[i + 1]
for (let i = 0; i < data.length; i = i + 2) {
if (data.length - i > 1) {
const x = (data[i] << 8) + data[i + 1]
const [e, rest] = divmod(x, 45 * 45)
const [d, c] = divmod(rest, 45)
res += charset[c] + charset[d] + charset[e]
} else {
const [d, c] = divmod(buffer[i], 45)
const [d, c] = divmod(data[i], 45)
res += charset[c] + charset[d]
}
}
return res
}

// Decode base45-encoded input
const decode = (input) => {
const buffer = Array.from(input).map(c => charset.indexOf(c))
/**
* Decode base45-encoded input.
* @param {string} input
*/
export function decode(input) {
const data = Array.from(input, (c) => charset.indexOf(c))
const res = []
for (let i = 0; i < buffer.length; i = i + 3) {
if (buffer.length - i >= 3) {
const x = buffer[i] + buffer[i + 1] * 45 + buffer[i + 2] * 45 * 45
for (let i = 0; i < data.length; i = i + 3) {
if (data.length - i >= 3) {
const x = data[i] + data[i + 1] * 45 + data[i + 2] * 45 * 45
if (x > 0xFFFF) {
throw new Error("Invalid base45 string")
throw new Error('Invalid base45 string')
}
res.push(...divmod(x, 256))
} else {
const x = buffer[i] + buffer[i + 1] * 45
const x = data[i] + data[i + 1] * 45
if (x > 0xFF) {
throw new Error("Invalid base45 string")
throw new Error('Invalid base45 string')
}
res.push(x)
}
}
return Buffer.from(res)
}

module.exports = {
encode,
decode
return new Uint8Array(res)
}
Loading