bitbottle 0.10.0

a modern archive file format
Documentation
use std::io::{Read, Write};
use crate::bottle::{BottleReader, BottleStream, BottleWriter};
use crate::bottle_error::{BottleError, BottleResult};
use crate::header::Header;


const MAGIC: [u8; 4] = [ 0xf0, 0x9f, 0x97, 0x83 ];

/// write a Header into a data stream, with armor.
pub fn write_header_stream<W: Write>(bottle_writer: &mut BottleWriter<W>, header: &Header) -> BottleResult<()> {
    // prefix with magic & CRC of the header
    let mut prefix = [0u8; 8];
    prefix[0..4].copy_from_slice(&MAGIC);
    prefix[4..8].copy_from_slice(&crc32c::crc32c(&header.data).to_le_bytes());

    bottle_writer.write_data_stream()?;
    bottle_writer.write_all(&prefix)?;
    bottle_writer.write_all(header.pack())?;
    bottle_writer.close_stream()
}

/// read a Header from a data stream, which is used for storage in some bottles.
pub fn read_header_stream<R: Read>(bottle_reader: &mut BottleReader<R>) -> BottleResult<Header> {
    bottle_reader.expect_next_stream(BottleStream::Data)?;

    let mut buffer = Vec::new();
    bottle_reader.data_stream()?.read_to_end(&mut buffer)?;
    bottle_reader.close_stream()?;

    // from v0.9.2 onward, there should be a prefix with crc
    let mut start = 0;
    if buffer[0] == 0xf0 {
        if !&buffer[0..4].eq(&MAGIC) {
            return Err(BottleError::BadMagic);
        }
        let crc = u32::from_le_bytes(buffer[4..8].try_into().unwrap());
        let my_crc = crc32c::crc32c(&buffer[8..]);
        if crc != my_crc {
            return Err(BottleError::BadCrc { expected: my_crc, got: crc });
        }
        start += 8;
    }

    let mut header = Header::new();
    header.data.extend_from_slice(&buffer[start..]);
    Ok(header)
}