use super::*;
use crate::upgrade::CdnzUpgradeError;
use std::io::{self, Read};
const CURRENT_VERSION: &'static str = env!("CARGO_PKG_VERSION");
#[derive(Debug, thiserror::Error)]
pub enum CdnzDeError {
#[error("IO error: {0}")]
IoError(#[from] io::Error),
#[error("Error upgrading file: {0}")]
UpgradeError(#[from] CdnzUpgradeError),
}
#[derive(Serialize, Deserialize)]
struct CborContainer {
version: String,
#[serde(with = "serde_bytes")]
payload: Vec<u8>,
}
impl Project {
pub fn to_cdnz(&self) -> Result<Vec<u8>, io::Error> {
self.serialize(true)
}
pub fn to_cdnx(&self) -> Result<Vec<u8>, io::Error> {
self.serialize(false)
}
fn serialize(&self, compress: bool) -> Result<Vec<u8>, io::Error> {
let magic = if compress { b"CDNZ" } else { b"CDNX" };
let mut inner_bytes = Vec::new();
ciborium::ser::into_writer(self, &mut inner_bytes)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
let payload = if compress {
zstd::encode_all(&inner_bytes[..], 3)?
} else {
inner_bytes
};
let container = CborContainer {
version: CURRENT_VERSION.to_string(),
payload,
};
let mut output = Vec::from(*magic);
ciborium::ser::into_writer(&container, &mut output)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
Ok(output)
}
pub fn from_bytes(data: &[u8]) -> Result<Self, CdnzDeError> {
let reader = std::io::Cursor::new(data);
Self::from_reader(reader)
}
pub fn from_reader<R: Read>(mut reader: R) -> Result<Self, CdnzDeError> {
let mut magic = [0u8; 4];
reader.read_exact(&mut magic)?;
let is_compressed = match &magic {
b"CDNZ" => true,
b"CDNX" => false,
_ => return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid Magic").into()),
};
let container: CborContainer = ciborium::de::from_reader(reader)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
let inner_cbor_bytes = if is_compressed {
zstd::decode_all(&container.payload[..])?
} else {
container.payload
};
let project: Project = ciborium::de::from_reader(&inner_cbor_bytes[..])
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
Ok(project)
}
}