Skip to content

Instantly share code, notes, and snippets.

@iczero
Last active April 21, 2021 07:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iczero/a03255b5d5de1f22cbc21e323622347e to your computer and use it in GitHub Desktop.
Save iczero/a03255b5d5de1f22cbc21e323622347e to your computer and use it in GitHub Desktop.
stupid unicode things
// @ts-check
const { Transform } = require('stream');
const zlib = require('zlib');
// abuse varwidth fonts by encoding bytes to very thin unicode characters
// for best results run calculateWidths() with different fonts and devices
/* run this on about:blank
let root = document.createElement('div');
document.body.appendChild(root);
for (let i = 0; i < 65536; i++) {
let el = document.createElement('span');
el.dataset.index = i;
el.innerText = String.fromCharCode(i);
root.appendChild(el);
}
function calculateWidths() {
let dimensions = [];
for (let el of root.children) {
let width = el.getBoundingClientRect().width;
if (width < 1) continue;
dimensions.push([width, +el.dataset.index, el.innerText]);
}
return dimensions.sort((a, b) => a[0] - b[0]);
}
*/
const CHARS = [
6211, 6130, 4170, 5194, 737, 8343, 8260, 8725,
6154, 690, 3856, 2417, 7502, 7522, 8305, 10649
].map(i => String.fromCharCode(i));
/* use the following instead for zero-width control characters:
const CHARS = [
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143
].map(i => String.fromCharCode(i));
*/
const CHARS_REVERSE = new Map(CHARS.map((char, idx) => [char, idx]));
const CHARS_SET = new Set(CHARS);
/**
* Encode byte to string
* @param {number} n
* @return {string}
*/
function encode(n) {
return CHARS[n >> 4] + CHARS[n & 0xf];
}
/**
* Decode string to byte
* @param {string|[string, string]} s
* @return {number}
*/
function decode(s) {
return (CHARS_REVERSE.get(s[0]) << 4) + CHARS_REVERSE.get(s[1]);
}
/**
* Encode buffer to string
* @param {Buffer} buf
* @return {string}
*/
function encodeBuffer(buf) {
return Array.prototype.map.call(buf, encode).join('');
}
/**
* Decode string to buffer
* @param {string} s
* @return {Buffer}
*/
function decodeBuffer(s) {
let encoded = s.split('').filter(Set.prototype.has.bind(CHARS_SET));
let decoded = [];
for (let i = 0; i < (encoded.length - encoded.length % 2); i += 2) {
decoded.push(decode(/** @type {[string, string]} */ (encoded.slice(i, i + 2))));
}
return Buffer.from(decoded);
}
/** Transform stream for encoding */
class EncodeStream extends Transform {
/**
* stream.Transform _transform method
* @param {Buffer} data
* @param {string} _encoding
* @param {(err: Error) => void} callback
*/
_transform(data, _encoding, callback) {
this.push(Buffer.from(encodeBuffer(data), 'utf-8'))
callback(null);
}
}
/** Transform stream for decoding */
class DecodeStream extends Transform {
/**
* The constructor
* @param {object} [opts]
*/
constructor(opts) {
super(opts);
this.partial = false;
this.byte = 0;
}
/**
* stream.Transform _transform method
* @param {Buffer} data
* @param {string} _encoding
* @param {(err: Error) => void} callback
*/
_transform(data, _encoding, callback) {
let dataString = data.toString('utf-8');
let out = [];
for (let i = 0; i < dataString.length; i++) {
let n = CHARS_REVERSE.get(dataString[i]);
if (typeof n === 'undefined') continue;
if (this.partial) {
out.push(this.byte | n);
this.partial = false;
} else {
this.byte = n << 4;
this.partial = true;
}
}
if (out.length) this.push(Buffer.from(out));
callback(null);
}
}
if (require.main === module) {
let args = process.argv.slice(2);
/** @type {import('stream').Stream} */
let s = process.stdin;
if (args.includes('-d')) {
s = s.pipe(new DecodeStream());
if (args.includes('-c')) s = s.pipe(zlib.createBrotliDecompress());
} else {
if (args.includes('-c')) s = s.pipe(zlib.createBrotliCompress());
s = s.pipe(new EncodeStream());
}
s.pipe(process.stdout);
}
exports.encode = encode;
exports.decode = decode;
exports.encodeBuffer = encodeBuffer;
exports.decodeBuffer = decodeBuffer;
exports.EncodeStream = EncodeStream;
exports.DecodeStream = DecodeStream;
// @ts-check
const { Transform } = require('stream');
const zlib = require('zlib');
// abuse all fonts by encoding bytes to combining diacriticals
const CHARS = [
768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783
].map(i => String.fromCharCode(i));
const CHARS_REVERSE = new Map(CHARS.map((char, idx) => [char, idx]));
const CHARS_SET = new Set(CHARS);
/**
* Encode byte to string
* @param {number} n
* @return {string}
*/
function encode(n) {
return CHARS[n >> 4] + CHARS[n & 0xf];
}
/**
* Decode string to byte
* @param {string|[string, string]} s
* @return {number}
*/
function decode(s) {
return (CHARS_REVERSE.get(s[0]) << 4) + CHARS_REVERSE.get(s[1]);
}
/**
* Encode buffer to string
* @param {Buffer} buf
* @return {string}
*/
function encodeBuffer(buf) {
return Array.prototype.map.call(buf, encode).join('');
}
/**
* Decode string to buffer
* @param {string} s
* @return {Buffer}
*/
function decodeBuffer(s) {
let encoded = s.normalize('NFKD').split('').filter(Set.prototype.has.bind(CHARS_SET));
let decoded = [];
for (let i = 0; i < (encoded.length - encoded.length % 2); i += 2) {
decoded.push(decode(/** @type {[string, string]} */ (encoded.slice(i, i + 2))));
}
return Buffer.from(decoded);
}
/** Transform stream for encoding */
class EncodeStream extends Transform {
constructor(...args) {
super(...args);
this.push('a');
}
/**
* stream.Transform _transform method
* @param {Buffer} data
* @param {string} _encoding
* @param {(err: Error) => void} callback
*/
_transform(data, _encoding, callback) {
this.push(Buffer.from(encodeBuffer(data), 'utf-8'))
callback(null);
}
}
/** Transform stream for decoding */
class DecodeStream extends Transform {
/**
* The constructor
* @param {object} [opts]
*/
constructor(opts) {
super(opts);
this.initial = true;
this.partial = false;
this.byte = 0;
}
/**
* stream.Transform _transform method
* @param {Buffer} data
* @param {string} _encoding
* @param {(err: Error) => void} callback
*/
_transform(data, _encoding, callback) {
let dataString = data.toString('utf-8');
if (this.initial) {
this.initial = false;
dataString = dataString.normalize('NFKD');
}
let out = [];
for (let i = 0; i < dataString.length; i++) {
let n = CHARS_REVERSE.get(dataString[i]);
if (typeof n === 'undefined') continue;
if (this.partial) {
out.push(this.byte | n);
this.partial = false;
} else {
this.byte = n << 4;
this.partial = true;
}
}
if (out.length) this.push(Buffer.from(out));
callback(null);
}
}
if (require.main === module) {
let args = process.argv.slice(2);
/** @type {import('stream').Stream} */
let s = process.stdin;
if (args.includes('-d')) {
s = s.pipe(new DecodeStream());
if (args.includes('-c')) s = s.pipe(zlib.createBrotliDecompress());
} else {
if (args.includes('-c')) s = s.pipe(zlib.createBrotliCompress());
s = s.pipe(new EncodeStream());
}
s.pipe(process.stdout);
}
exports.encode = encode;
exports.decode = decode;
exports.encodeBuffer = encodeBuffer;
exports.decodeBuffer = decodeBuffer;
exports.EncodeStream = EncodeStream;
exports.DecodeStream = DecodeStream;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment