From 098724d99d1f964ee1856a19ce17b8d7ae668266 Mon Sep 17 00:00:00 2001 From: Alex Potsides Date: Fri, 7 Aug 2020 12:16:16 +0100 Subject: [PATCH] feat: support ascii encoding (#2) For better or for worse, sometimes you want to covert between a Uint8Array and a string where each character of the string is created from the character code of the corresponding byte from the array. Adds an `ascii` encoding which is similar to `binary` as used by node buffers. It's not called `binary` as people confuse this with `base2`. --- README.md | 2 ++ from-string.js | 25 +++++++++++++++++++++++++ test/from-string.spec.js | 13 +++++++++++++ test/to-string.spec.js | 13 +++++++++++++ to-string.js | 32 +++++++++++++++++++++++++++----- 5 files changed, 80 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index be23fe0..71f515a 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ const fromString = require('uint8arrays/from-string') console.info(fromString('hello world')) // Uint8Array[104, 101 ... console.info(fromString('00010203aabbcc', 'base16')) // Uint8Array[0, 1 ... console.info(fromString('AAECA6q7zA', 'base64')) // Uint8Array[0, 1 ... +console.info(fromString('01234', 'ascii')) // Uint8Array[48, 49 ... ``` ### toString(array, encoding = 'utf8') @@ -109,4 +110,5 @@ const fromString = require('uint8arrays/from-string') console.info(toString(Uint8Array.from([104, 101...]))) // 'hello world' console.info(toString(Uint8Array.from([0, 1, 2...]), 'base16')) // '00010203aabbcc' console.info(toString(Uint8Array.from([0, 1, 2...]), 'base64')) // 'AAECA6q7zA' +console.info(toString(Uint8Array.from([48, 49, 50...]), 'ascii')) // '01234' ``` diff --git a/from-string.js b/from-string.js index d26790b..63e4604 100644 --- a/from-string.js +++ b/from-string.js @@ -4,9 +4,30 @@ const { names } = require('multibase/src/constants') const { TextEncoder } = require('web-encoding') const utf8Encoder = new TextEncoder() +/** + * Interperets each character in a string as a byte and + * returns a Uint8Array of those bytes. + * + * @param {String} string The string to turn into an array + * @returns {Uint8Array} + */ +function asciiStringToUint8Array (string) { + const array = new Uint8Array(string.length) + + for (let i = 0; i < string.length; i++) { + array[i] = string.charCodeAt(i) + } + + return array +} + /** * Create a `Uint8Array` from the passed string * + * Supports `utf8`, `utf-8` and any encoding supported by the multibase module. + * + * Also `ascii` which is similar to node's 'binary' encoding. + * * @param {String} string * @param {String} [encoding=utf8] utf8, base16, base64, base64urlpad, etc * @returns {Uint8Array} @@ -17,6 +38,10 @@ function fromString (string, encoding = 'utf8') { return utf8Encoder.encode(string) } + if (encoding === 'ascii') { + return asciiStringToUint8Array(string) + } + const codec = names[encoding] if (!codec) { diff --git a/test/from-string.spec.js b/test/from-string.spec.js index 777ae36..9ed0fc5 100644 --- a/test/from-string.spec.js +++ b/test/from-string.spec.js @@ -27,6 +27,19 @@ describe('Uint8Array fromString', () => { expect(fromString(str, 'base64')).to.deep.equal(arr) }) + it('creates a Uint8Array from an ascii string', () => { + const str = [ + String.fromCharCode(0), + String.fromCharCode(1), + String.fromCharCode(2), + String.fromCharCode(3), + String.fromCharCode(4) + ].join('') + const arr = Uint8Array.from([0, 1, 2, 3, 4]) + + expect(fromString(str, 'ascii')).to.deep.equal(arr) + }) + it('throws when an unknown base is passed', () => { const str = 'hello world' diff --git a/test/to-string.spec.js b/test/to-string.spec.js index ef50090..0761eae 100644 --- a/test/to-string.spec.js +++ b/test/to-string.spec.js @@ -27,6 +27,19 @@ describe('Uint8Array toString', () => { expect(toString(arr, 'base64')).to.deep.equal(str) }) + it('creates an ascii string from a Uint8Array', () => { + const str = [ + String.fromCharCode(0), + String.fromCharCode(1), + String.fromCharCode(2), + String.fromCharCode(3), + String.fromCharCode(4) + ].join('') + const arr = Uint8Array.from([0, 1, 2, 3, 4]) + + expect(toString(arr, 'ascii')).to.deep.equal(str) + }) + it('throws when an unknown base is passed', () => { const arr = Uint8Array.from([0, 1, 2, 3, 170, 187, 204]) diff --git a/to-string.js b/to-string.js index ffad895..e5941d3 100644 --- a/to-string.js +++ b/to-string.js @@ -4,19 +4,41 @@ const { names } = require('multibase/src/constants') const { TextDecoder } = require('web-encoding') const utf8Decoder = new TextDecoder('utf8') +/** + * Turns a Uint8Array of bytes into a string with each + * character being the char code of the corresponding byte + * + * @param {Uint8Array} array The array to turn into a string + * @returns {String} + */ +function uint8ArrayToAsciiString (array) { + let string = '' + + for (let i = 0; i < array.length; i++) { + string += String.fromCharCode(array[i]) + } + return string +} + /** * Turns a `Uint8Array` into a string. * - * Supports `utf8` and any encoding supported by the multibase module + * Supports `utf8`, `utf-8` and any encoding supported by the multibase module. + * + * Also `ascii` which is similar to node's 'binary' encoding. * - * @param {Uint8Array} buf The array to turn into a string + * @param {Uint8Array} array The array to turn into a string * @param {String} [encoding=utf8] The encoding to use * @returns {String} * @see {@link https://www.npmjs.com/package/multibase|multibase} for supported encodings other than `utf8` */ -function toString (buf, encoding = 'utf8') { +function toString (array, encoding = 'utf8') { if (encoding === 'utf8' || encoding === 'utf-8') { - return utf8Decoder.decode(buf) + return utf8Decoder.decode(array) + } + + if (encoding === 'ascii') { + return uint8ArrayToAsciiString(array) } const codec = names[encoding] @@ -25,7 +47,7 @@ function toString (buf, encoding = 'utf8') { throw new Error('Unknown base') } - return codec.encode(buf) + return codec.encode(array) } module.exports = toString