use dc_bundle::definition_file::decode_dcd_with_header;
use protobuf::CodedInputStream;
use serde::{Deserialize, Serialize};
use std::fs::File;
use std::io::Read;
use std::path::Path;
#[derive(Debug, Serialize, Deserialize)]
pub struct DcfInfo {
pub dc_version: u32,
pub document_id: String,
pub figma_version: String,
pub name: String,
pub last_modified: String,
pub dcd_length: u64,
}
#[derive(Debug)]
pub enum DcfError {
Io(std::io::Error),
DcBundle(dc_bundle::Error),
Parse(String),
}
impl From<std::io::Error> for DcfError {
fn from(e: std::io::Error) -> Self {
DcfError::Io(e)
}
}
impl From<dc_bundle::Error> for DcfError {
fn from(e: dc_bundle::Error) -> Self {
DcfError::DcBundle(e)
}
}
pub fn parse_dcf_info(file_path: &Path) -> Result<DcfInfo, DcfError> {
let mut file = File::open(file_path)?;
let mut buffer = Vec::new();
file.read_to_end(&mut buffer)?;
let decode_result = decode_dcd_with_header(&buffer);
match decode_result {
Ok((header, _doc)) => {
let mut cis = CodedInputStream::from_bytes(&buffer);
let header_len = cis.read_raw_varint32().map_err(|e| DcfError::Parse(e.to_string()))?;
cis.skip_raw_bytes(header_len).map_err(|e| DcfError::Parse(e.to_string()))?;
let dcd_length =
cis.read_raw_varint32().map_err(|e| DcfError::Parse(e.to_string()))? as u64;
Ok(DcfInfo {
dc_version: header.dc_version,
document_id: header.id,
figma_version: header.response_version,
name: header.name,
last_modified: header.last_modified,
dcd_length,
})
}
Err(_) => {
if buffer.len() >= 4 {
let version_bytes: [u8; 4] = buffer[0..4].try_into().unwrap();
let version = u32::from_le_bytes(version_bytes);
if version < 27 {
return Err(DcfError::Parse(format!(
"DCF version {} < 27, not supported for detailed info",
version
)));
}
}
Err(DcfError::Parse(format!("Failed to load file {:?}", file_path)))
}
}
}