Skip to content

Instantly share code, notes, and snippets.

@Ephellon
Last active January 4, 2019 08:14
Show Gist options
  • Save Ephellon/ac53809b19c47e26fb381d786b35df52 to your computer and use it in GitHub Desktop.
Save Ephellon/ac53809b19c47e26fb381d786b35df52 to your computer and use it in GitHub Desktop.
Shuffle.js: An Encoding/Decoding Library (with LZW compression support)
var destruct, construct, roll, unroll, compress, decompress;
/* DO NOT USE for secure projects, there are only 32 possible outputs */
/* The input (de/con)structors */
/** Destructs (attempts to flatten) the input
* @parameter input: the input to flatten
*/
destruct = (input) => {
if(input === undefined || input === null)
return;
let output = [],
times = -1;
for(let index = 0, length = (input += '').length, code; index < length; index++) {
code = input.charCodeAt(index);
output.push(('00000000' + code.toString(2)).slice(-8));
}
output = output.join('');
for(let max = 0, len, best = -1; best < 32; best++) {
len = roll(output, best).replace(/([01]{8})/g, '$1,').split(/([01]{8},)\1+/).length;
if(len > max) {
max = len;
times = best;
}
}
output = roll(output, times);
output = output.replace(/([01]{8})/g, ($0, $1, $$, $_) => String.fromCharCode(+('0b' + $1)));
return String.fromCharCode(times) + output;
};
/** Constructs (attempts to inflate) the input
* @parameter input: the input to inflate
*/
construct = (input) => {
if(input === undefined || input === null)
return;
let output = [],
times = input.charCodeAt(0);
input = input.slice(1, input.length);
for(let index = 0, length = (input += '').length, code; index < length; index++) {
code = input.charCodeAt(index);
output.push(('00000000' + code.toString(2)).slice(-8));
}
output = output.join('');
output = unroll(output, times);
output = output.replace(/([01]{8})/g, ($0, $1, $$, $_) => String.fromCharCode(+('0b' + $1)));
return output;
};
/* The (un)rollers */
/** Roll input x number of times
* @parameter input: the binary string/array to roll
* @parameter times: the number of times to roll the input (zero-indexed, i.e. '-1' won't roll the input) [default: 6]
*/
roll = (input, times = 6) => {
let output = [];
for(let index = 0, length = input.length, A, B; index < length; index++) {
A = input[index - 1];
B = input[index + 0];
if(A !== undefined && A !== null)
output.push( +(A === B) );
else
output.push(B);
}
output = output.join('');
times &= 31;
if(times > 0)
return roll(output, --times);
return output;
};
/** Unroll the input, using x as the number of times the input was rolled
* @parameter input: the binary string/array to unroll
* @parameter times: the number of times to unroll the input (zero-indexed, i.e. '-1' won't unroll the input) [default: 6]
*/
unroll = (input, times = 6) => {
let output = [];
for(let index = 0, length = input.length, A, B, C; index < length; index++) {
A = input[index - 1];
B = input[index + 0];
if(A !== undefined && A !== null)
output.push( !!+B? C: C = +!(+C) );
else
output.push(C = B);
}
output = output.join('');
times &= 31;
if(times > 0)
return unroll(output, --times);
return output;
};
/* The (de)compressors */
/** Compresses a string (via LZW format)
* @parameter string: the string to compress
*/
compress = (string) => {
let dictionary = {},
paragraph = (string + ''), // phrases
word = paragraph[0], // phrase
media = [],
output = [],
index = 256,
character;
let item = (w = word, d = dictionary) =>
(w.length > 1)?
d['@' + w]:
w.charCodeAt(0);
for(let i = 1, l = paragraph.length, c, d; i < l; i++)
if(dictionary['@' + word + (character = paragraph[i])] !== undefined)
word += character;
else
media.push(item(word)),
dictionary['@' + word + character] = index++,
word = character;
media.push(item(word));
for(let i = 0, l = media.length; i < l; i++)
output.push(String.fromCharCode(media[i]));
return output.join('');
};
/** Decompresses an LZW-formatted string
* @parameter string: the string to decompress
*/
decompress = (string) => {
let dictionary = {},
paragraph = (string + ''), // phrases,
character = paragraph[0],
word = {
now: '', // phrase
last: character // old-phrase
},
output = [character],
index = 256;
for(let i = 1, l = paragraph.length, code, pass; i < l; i++) {
code = paragraph.charCodeAt(i);
if(code < 256)
word.now = paragraph[i];
else if((word.now = dictionary['@' + code]) === undefined)
word.now = word.last + character;
output.push(word.now);
character = word.now[0];
dictionary['@' + index++] = word.last + character;
word.last = word.now;
}
return output.join('');
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment