1use gix_error::validation;
3use std::io::{self, Write};
4
5use bstr::ByteSlice;
6
7macro_rules! check {
8 ($e: expr) => {
9 $e.expect("Writing to a Vec should never fail.")
10 };
11}
12pub fn loose_header(kind: crate::Kind, size: u64) -> smallvec::SmallVec<[u8; 28]> {
14 let mut v = smallvec::SmallVec::new();
15 check!(v.write_all(kind.as_bytes()));
16 check!(v.write_all(SPACE));
17 check!(v.write_all(itoa::Buffer::new().format(size).as_bytes()));
18 check!(v.write_all(b"\0"));
19 v
20}
21
22pub(crate) fn header_field_multi_line(name: &[u8], value: &[u8], out: &mut dyn io::Write) -> io::Result<()> {
23 let mut lines = value.as_bstr().lines_with_terminator();
24 out.write_all(name)?;
25 out.write_all(SPACE)?;
26 if let Some(line) = lines.next() {
27 out.write_all(line)?;
28 }
29 for line in lines {
30 out.write_all(SPACE)?;
31 out.write_all(line)?;
32 }
33 if !value.ends_with_str(b"\n") {
34 out.write_all(NL)?;
35 }
36 Ok(())
37}
38
39pub(crate) fn trusted_header_field(name: &[u8], value: &[u8], out: &mut dyn io::Write) -> io::Result<()> {
40 out.write_all(name)?;
41 out.write_all(SPACE)?;
42 out.write_all(value)?;
43 out.write_all(NL)
44}
45
46pub(crate) fn trusted_header_signature(
47 name: &[u8],
48 value: &gix_actor::SignatureRef<'_>,
49 out: &mut dyn io::Write,
50) -> io::Result<()> {
51 out.write_all(name)?;
52 out.write_all(SPACE)?;
53 value.write_to(out)?;
54 out.write_all(NL)
55}
56
57pub(crate) fn trusted_header_id(
58 name: &[u8],
59 value: &gix_hash::ObjectId,
60 mut out: &mut dyn io::Write,
61) -> io::Result<()> {
62 out.write_all(name)?;
63 out.write_all(SPACE)?;
64 value.write_hex_to(&mut out)?;
65 out.write_all(NL)
66}
67
68pub(crate) fn header_field(name: &[u8], value: &[u8], out: &mut dyn io::Write) -> io::Result<()> {
71 if value.is_empty() {
72 return Err(io::Error::other(validation("Header values must not be empty")));
73 }
74 if value.contains_str(NL) {
75 return Err(io::Error::other(
76 validation("Newlines are not allowed in header values").with_input(value),
77 ));
78 }
79 trusted_header_field(name, value, out)
80}
81
82pub(crate) const NL: &[u8; 1] = b"\n";
83pub(crate) const SPACE: &[u8; 1] = b" ";