This commit is contained in:
nora 2022-08-03 16:17:35 +02:00
commit 04728bfdb4
4 changed files with 191 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
/target
.idea
.vscode

16
Cargo.lock generated Normal file
View file

@ -0,0 +1,16 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "anyhow"
version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142"
[[package]]
name = "jsfck"
version = "0.1.0"
dependencies = [
"anyhow",
]

9
Cargo.toml Normal file
View file

@ -0,0 +1,9 @@
[package]
name = "jsfck"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0.60"

163
src/main.rs Normal file
View file

@ -0,0 +1,163 @@
use std::fmt::{self, Display, Formatter};
use std::io::{self, Read, Write};
fn main() -> anyhow::Result<()> {
let stdin = std::io::stdin().lock();
let mut stdin = io::BufReader::new(stdin);
let stdout = std::io::stdout().lock();
let mut stdout = io::BufWriter::new(stdout);
let mut buf = vec![0; 4096];
let mut string = String::with_capacity(8192);
loop {
let read = stdin.read(&mut buf)?;
if read == 0 {
return Ok(());
}
let next_data = &buf[0..read];
js_fuck(next_data, &mut string)?;
stdout.write_all(string.as_bytes())?;
string.clear();
}
}
fn js_fuck<W: fmt::Write>(code: &[u8], mut f: W) -> fmt::Result {
write!(
f,
"(()=>{{}})[{}]({})()",
FromString(b"constructor"),
FromString(code)
)
}
const ZERO: &str = "+[]";
const ONE: &str = "+!![]";
struct Number(u8);
impl Display for Number {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if self.0 == 0 {
f.write_str(ZERO)?;
return Ok(());
}
let mut first = true;
for _ in 0..self.0 {
if !first {
f.write_str(" + ")?;
}
first = false;
f.write_str(ONE)?;
}
Ok(())
}
}
struct FromString<'a>(&'a [u8]);
impl Display for FromString<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
js_fuck_from_string(self.0, f)
}
}
fn js_fuck_from_string<W: fmt::Write>(str: &[u8], mut f: W) -> fmt::Result {
let mut first = true;
str.iter().try_for_each(|char| {
if !first {
f.write_str("+")?;
}
first = false;
js_fuck_from_char(*char, &mut f)
})
}
fn js_fuck_from_char<W: fmt::Write>(char: u8, mut f: W) -> fmt::Result {
if js_fuck_trivial(char, &mut f)? {
return Ok(());
}
write!(
f,
"([]+[])[{}][{}]({})",
FromString(b"constructor"),
FromString(b"fromCharCode"),
Number(char)
)
}
fn js_fuck_trivial<W: fmt::Write>(data: u8, mut f: W) -> Result<bool, fmt::Error> {
match data {
b'a' => write!(f, "(+{{}}+[])[{}]", Number(1)),
b'b' => write!(f, "({{}}+[])[{}]", Number(2)),
b'o' => write!(f, "({{}}+[])[{}]", Number(1)),
b'e' => write!(f, "({{}}+[])[{}]", Number(4)),
b'c' => write!(f, "({{}}+[])[{}]", Number(5)),
b't' => write!(f, "({{}}+[])[{}]", Number(6)),
b' ' => write!(f, "({{}}+[])[{}]", Number(7)),
b'f' => write!(f, "(![]+[])[{}]", Number(0)),
b's' => write!(f, "(![]+[])[{}]", Number(3)),
b'r' => write!(f, "(!![]+[])[{}]", Number(1)),
b'u' => write!(f, "(!![]+[])[{}]", Number(2)),
b'i' => write!(f, "((+!![]/+[])+[])[{}]", Number(3)),
b'n' => write!(f, "((+!![]/+[])+[])[{}]", Number(4)),
b'S' => write!(
f,
"([]+([]+[])[{}])[{}]",
FromString(b"constructor"),
Number(9)
),
b'g' => write!(
f,
"([]+([]+[])[{}])[{}]",
FromString(b"constructor"),
Number(14)
),
b'p' => write!(
f,
"([]+(/-/)[{}])[{}]",
FromString(b"constructor"),
Number(14)
),
b'\\' => write!(f, "(/\\\\/+[])[{}]", Number(1)),
b'd' => write!(
f,
"({})[{}]({})",
Number(13),
FromString(b"toString"),
Number(14)
),
b'h' => write!(
f,
"({})[{}]({})",
Number(17),
FromString(b"toString"),
Number(18)
),
b'm' => write!(
f,
"({})[{}]({})",
Number(22),
FromString(b"toString"),
Number(23)
),
b'C' => write!(
f,
"((()=>{{}})[{}]({})()((/\\\\/+[])[{}]))[{}]",
FromString(b"constructor"),
FromString(b"return escape"),
Number(1),
Number(2)
),
_ => return Ok(false),
}?;
Ok(true)
}