CyberChefのCLIがほしい Hex編
CyberChef CLI計画
昨日に引き続き、CyberChef的なCLIツールの話です。
記事をPublishしてから体裁を整えたりURLのDecoderを書いたりしていました。
今日はURLの次によく使うHexを書きます。
From Hex
基本的にAutoで使っているので、自動でDelimiterを判定したい。
実装としては、全部のDelimiterでパーサを回して、パースできた長さが最大のものを返す方針。
ここで最近やってたClamAVのシグネチャをパースする時に学んだnomが活きるワケ。
…
と思ったけど、そんなややこしい事しなくてもDelimiterとPrefix全部消してから2文字ずつパースすればいいじゃん。
use anyhow::{anyhow, Result};
pub fn decode(input: &str) -> Result<String> {
let delimiters = &[",", "\r", "\n", ";", ":", " ", "\t"];
let prefixes = &["%", "0x", "x", "\\"];
let mut cleaned_input = input.to_string();
for delim in delimiters {
cleaned_input = cleaned_input.replace(delim, "");
}
for prefix in prefixes {
cleaned_input = cleaned_input.replace(prefix, "");
}
if cleaned_input.len() % 2 != 0 {
return Err(anyhow!("Input length is not even: '{}'", cleaned_input));
}
let mut bytes = Vec::new();
for (i, chunk) in cleaned_input.as_bytes().chunks(2).enumerate() {
let hex_str = std::str::from_utf8(chunk)
.map_err(|e| anyhow!("Failed to read chunk: {}", e))?;
let byte = u8::from_str_radix(hex_str, 16)
.map_err(|_| anyhow!("Failed to parse '{}' at index: {}. Successfully converted part: '{}'", hex_str, i, String::from_utf8(bytes.clone()).unwrap()))?;
bytes.push(byte);
}
match String::from_utf8(bytes.clone()) {
Ok(string) => Ok(string),
Err(e) => {
let valid_up_to = e.utf8_error().valid_up_to();
let successful_string = String::from_utf8(bytes[0..valid_up_to].to_vec())
.unwrap_or_default();
Err(anyhow!(
"UTF-8 conversion error: {}. Successfully converted part: '{}'",
e,
successful_string
))
}
}
}
こだわりポイントとしてはとにかくパースできた部分だけでも抽出できるようにした点ですね。
From Hexはこんな感じで良いとして、To Hexいるかな…
xxdとawkでなんとかなってるのであまりモチベは無いです。需要があればやります。
終わりに
この記事はn01e0 Advent Calendar 2024の22日目の記事とします。
Comments