#![forbid(unsafe_code)]
use std::fs::File;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
const UTF8_BOM: [u8; 3] = [0xEF, 0xBB, 0xBF];
fn main() -> io::Result<()> {
let mut args = std::env::args_os().skip(1);
let out_dir = args
.next()
.map_or_else(|| PathBuf::from("tests/fixtures"), PathBuf::from);
#[allow(clippy::disallowed_methods)]
std::fs::create_dir_all(&out_dir)?;
let stdout = io::stdout();
let mut log = stdout.lock();
write_file(
&out_dir,
"ascii.txt",
b"The quick brown fox jumps over the lazy dog.\n",
&mut log,
)?;
let multilingual = "Grüße — 日本語 — 😊 — Здравствуйте — 한국어\n";
write_file(
&out_dir,
"utf8_multilingual.txt",
multilingual.as_bytes(),
&mut log,
)?;
let mut utf8_bom = UTF8_BOM.to_vec();
utf8_bom.extend_from_slice("UTF-8 with BOM: grüße 😊\n".as_bytes());
write_file(&out_dir, "utf8_bom.txt", &utf8_bom, &mut log)?;
let sample16 = "UTF-16 sample: grüße 😊\n";
write_file(
&out_dir,
"utf16le_bom.txt",
&utf16_bytes(sample16, Endian::Little),
&mut log,
)?;
write_file(
&out_dir,
"utf16be_bom.txt",
&utf16_bytes(sample16, Endian::Big),
&mut log,
)?;
write_file(
&out_dir,
"utf32le_bom.bin",
&utf32le_bytes("UTF-32 😊\n"),
&mut log,
)?;
let latin1: &[u8] = b"Caf\xE9 d\xE9j\xE0 vu\n";
write_file(&out_dir, "latin1.txt", latin1, &mut log)?;
write_file(&out_dir, "truncated_utf8.bin", b"abc\xF0", &mut log)?;
write_file(&out_dir, "lone_continuation.bin", b"\x80", &mut log)?;
writeln!(log, "Done. Fixtures written to {}", out_dir.display())?;
Ok(())
}
#[derive(Clone, Copy)]
enum Endian {
Little,
Big,
}
fn utf16_bytes(text: &str, endian: Endian) -> Vec<u8> {
let mut units = vec![0xFEFF_u16];
units.extend(text.encode_utf16());
let mut bytes = Vec::with_capacity(units.len().saturating_mul(2));
for unit in units {
match endian {
Endian::Little => bytes.extend_from_slice(&unit.to_le_bytes()),
Endian::Big => bytes.extend_from_slice(&unit.to_be_bytes()),
}
}
bytes
}
fn utf32le_bytes(text: &str) -> Vec<u8> {
let mut bytes = 0xFEFF_u32.to_le_bytes().to_vec();
for ch in text.chars() {
bytes.extend_from_slice(&u32::from(ch).to_le_bytes());
}
bytes
}
fn write_file<W: Write>(dir: &Path, name: &str, bytes: &[u8], log: &mut W) -> io::Result<()> {
let path = dir.join(name);
let mut file = File::create(&path)?;
file.write_all(bytes)?;
file.flush()?;
writeln!(log, "wrote {name:>22} ({} bytes)", bytes.len())?;
Ok(())
}