happy_cracking/crypto/
strtools.rs1use anyhow::Result;
2use clap::Subcommand;
3
4#[derive(Subcommand)]
5pub enum StrToolsAction {
6 #[command(about = "Reverse a string")]
7 Reverse {
8 #[arg(help = "Input text")]
9 input: String,
10 },
11 #[command(about = "Show ASCII/Unicode code points for each character")]
12 Ord {
13 #[arg(help = "Input text")]
14 input: String,
15 },
16 #[command(about = "Convert space-separated code points to characters")]
17 Chr {
18 #[arg(help = "Space-separated code points (e.g. \"72 101 108 108 111\")")]
19 input: String,
20 },
21}
22
23pub fn run(action: StrToolsAction) -> Result<()> {
24 match action {
25 StrToolsAction::Reverse { input } => {
26 println!("{}", reverse(&input));
27 }
28 StrToolsAction::Ord { input } => {
29 println!("{}", ord(&input));
30 }
31 StrToolsAction::Chr { input } => {
32 println!("{}", chr(&input)?);
33 }
34 }
35 Ok(())
36}
37
38pub fn reverse(input: &str) -> String {
40 input.chars().rev().collect()
41}
42
43pub fn ord(input: &str) -> String {
45 if input.is_empty() {
46 return String::new();
47 }
48
49 let mut out = String::with_capacity(input.len() * 10);
53 let mut first = true;
54
55 for c in input.chars() {
56 if !first {
57 out.push(' ');
58 }
59 first = false;
60
61 out.push(c);
62 out.push('=');
63
64 let mut n = c as u32;
65 if n == 0 {
66 out.push('0');
67 } else {
68 let mut buf = [0u8; 10];
69 let mut i = 10;
70 while n > 0 {
71 i -= 1;
72 buf[i] = (n % 10) as u8 + b'0';
73 n /= 10;
74 }
75 out.push_str(unsafe { std::str::from_utf8_unchecked(&buf[i..]) });
77 }
78 }
79
80 out
81}
82
83pub fn chr(input: &str) -> Result<String> {
85 if input.is_empty() {
86 return Ok(String::new());
87 }
88
89 input
90 .split_whitespace()
91 .map(|s| {
92 let n: u32 = s
93 .parse()
94 .map_err(|_| anyhow::anyhow!("Invalid code point: {}", s))?;
95 char::from_u32(n).ok_or_else(|| anyhow::anyhow!("Invalid Unicode code point: {}", n))
96 })
97 .collect()
98}