use super::{CharSpec, DescriptorTag, EntityIdentifier, ExtentDescriptor, TagIdentifier};
use crate::error::UdfResult;
use crate::time::UdfTimestamp;
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct PrimaryVolumeDescriptor {
pub tag: DescriptorTag,
pub vds_number: u32,
pub pvd_number: u32,
pub volume_identifier: [u8; 32],
pub volume_sequence_number: u16,
pub max_volume_sequence_number: u16,
pub interchange_level: u16,
pub max_interchange_level: u16,
pub character_set_list: u32,
pub max_character_set_list: u32,
pub volume_set_identifier: [u8; 128],
pub descriptor_char_set: CharSpec,
pub explanatory_char_set: CharSpec,
pub volume_abstract: ExtentDescriptor,
pub volume_copyright: ExtentDescriptor,
pub application_identifier: EntityIdentifier,
pub recording_date_time: UdfTimestamp,
pub implementation_identifier: EntityIdentifier,
pub implementation_use: [u8; 64],
pub predecessor_vds_location: u32,
pub flags: u16,
reserved: [u8; 22],
}
unsafe impl bytemuck::Zeroable for PrimaryVolumeDescriptor {}
unsafe impl bytemuck::Pod for PrimaryVolumeDescriptor {}
impl PrimaryVolumeDescriptor {
pub fn validate(&self, location: u32) -> UdfResult<()> {
self.tag
.validate(TagIdentifier::PrimaryVolumeDescriptor, location)
}
#[cfg(feature = "alloc")]
pub fn volume_id(&self) -> alloc::string::String {
decode_dstring(&self.volume_identifier)
}
}
#[cfg(feature = "alloc")]
pub fn decode_dstring(data: &[u8]) -> alloc::string::String {
if data.is_empty() {
return alloc::string::String::new();
}
let compression_id = data[0];
let len = data[data.len() - 1] as usize;
if len == 0 || len > data.len() - 1 {
return alloc::string::String::new();
}
let content = &data[1..=len.min(data.len() - 2)];
match compression_id {
8 => {
alloc::string::String::from_utf8_lossy(content).into_owned()
}
16 => {
let mut result = alloc::string::String::new();
for chunk in content.chunks(2) {
if chunk.len() == 2 {
let code_unit = u16::from_be_bytes([chunk[0], chunk[1]]);
if let Some(c) = char::from_u32(code_unit as u32) {
result.push(c);
}
}
}
result
}
_ => alloc::string::String::new(),
}
}
#[cfg(test)]
mod tests {
use super::*;
static_assertions::const_assert_eq!(size_of::<PrimaryVolumeDescriptor>(), 512);
}