Skip to main content

gix_object/
encode.rs

1//! Encoding utilities
2use 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}
12/// Generates a loose header buffer
13pub 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
68/// Serialize a header field. Values containing newlines are retained as `input` bytes in the I/O error.
69/// After [wrapping](gix_error::Error::from_error()), inspect them with [metadata](gix_error::Error::metadata()).
70pub(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" ";