decode input bytes. `forced` overrides auto-detect
| 269 | |
| 270 | // decode input bytes. `forced` overrides auto-detect |
| 271 | std::vector<std::uint8_t> decode_input(std::vector<std::uint8_t> raw, InputFormat forced, const char** fmt_out) { |
| 272 | if (forced == InputFormat::Raw) { *fmt_out = "raw forced"; return raw; } |
| 273 | |
| 274 | std::size_t bom = 0; |
| 275 | const bool is_text = looks_like_text(raw, bom); |
| 276 | const std::string_view s(reinterpret_cast<const char*>(raw.data() + bom), raw.size() - bom); |
| 277 | |
| 278 | auto fail = [&](const char* fmt_name) -> std::vector<std::uint8_t> { |
| 279 | throw mkpivm::Error(std::string("--input-format ") + fmt_name + ": input doesn't decode as that format"); |
| 280 | }; |
| 281 | |
| 282 | switch (forced) { |
| 283 | case InputFormat::EscX: { |
| 284 | auto v = extract_backslash_x(s); |
| 285 | if (v.empty()) return fail("escape"); |
| 286 | *fmt_out = "\\xHH forced"; return v; |
| 287 | } |
| 288 | case InputFormat::ZeroX: { |
| 289 | auto v = extract_0x(s); |
| 290 | if (v.empty()) return fail("0x"); |
| 291 | *fmt_out = "0xHH forced"; return v; |
| 292 | } |
| 293 | case InputFormat::Hex: { |
| 294 | auto v = try_bare_hex(s); |
| 295 | if (v.empty()) return fail("hex"); |
| 296 | *fmt_out = "hex forced"; return v; |
| 297 | } |
| 298 | case InputFormat::B64: { |
| 299 | auto v = try_base64(s); |
| 300 | if (v.empty()) return fail("b64"); |
| 301 | *fmt_out = "base64 forced"; return v; |
| 302 | } |
| 303 | default: break; |
| 304 | } |
| 305 | |
| 306 | // auto path |
| 307 | if (!is_text) { *fmt_out = "raw"; return raw; } |
| 308 | |
| 309 | if (auto v = extract_backslash_x(s); !v.empty()) { *fmt_out = "\\xHH"; return v; } |
| 310 | if (auto v = extract_0x(s); !v.empty()) { *fmt_out = "0xHH"; return v; } |
| 311 | |
| 312 | // continuous hex is a valid base64 alphabet subset, so use the presence |
| 313 | // of b64-only chars +, /, = to disambiguate |
| 314 | bool b64_marker = false; |
| 315 | for (char ch : s) if (ch == '+' || ch == '/' || ch == '=') { b64_marker = true; break; } |
| 316 | |
| 317 | if (b64_marker) { |
| 318 | if (auto v = try_base64(s); !v.empty()) { *fmt_out = "base64"; return v; } |
| 319 | } |
| 320 | |
| 321 | if (auto v = try_bare_hex(s); !v.empty()) { *fmt_out = "hex"; return v; } |
| 322 | if (auto v = try_base64(s); !v.empty()) { *fmt_out = "base64"; return v; } |
| 323 | throw mkpivm::Error( |
| 324 | "input looks textual but no hex or base64 content found. " |
| 325 | "use --input-format raw to force binary interpretation." |
| 326 | ); |
| 327 | } |
| 328 |
no test coverage detected