Last active
January 4, 2019 08:14
-
-
Save Ephellon/ac53809b19c47e26fb381d786b35df52 to your computer and use it in GitHub Desktop.
Shuffle.js: An Encoding/Decoding Library (with LZW compression support)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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