#![allow(non_upper_case_globals)] use { crate::pipewire::pw_pod::{ PW_CHOICE_None, PW_TYPE_Array, PW_TYPE_Bitmap, PW_TYPE_Bool, PW_TYPE_Bytes, PW_TYPE_Choice, PW_TYPE_Double, PW_TYPE_Fd, PW_TYPE_Float, PW_TYPE_Fraction, PW_TYPE_Id, PW_TYPE_Int, PW_TYPE_Long, PW_TYPE_None, PW_TYPE_Object, PW_TYPE_Pod, PW_TYPE_Pointer, PW_TYPE_Rectangle, PW_TYPE_Sequence, PW_TYPE_String, PW_TYPE_Struct, PwChoiceType, PwControlType, PwPod, PwPodArray, PwPodChoice, PwPodControl, PwPodFraction, PwPodObject, PwPodObjectType, PwPodPointer, PwPodRectangle, PwPodSequence, PwPodStruct, PwPodType, PwPointerType, PwProp, PwPropFlag, }, ahash::AHashMap, bstr::{BStr, BString, ByteSlice}, std::{ fmt::Debug, mem::{self, MaybeUninit}, rc::Rc, }, thiserror::Error, uapi::{OwnedFd, Pod}, }; #[derive(Debug, Error)] pub enum PwParserError { #[error("Unexpected EOF")] UnexpectedEof, #[error("Message references an FD that is out of bounds")] MissingFd, #[error("Array element type has size of 0")] ZeroSizedArrayElementType, #[error("Unknown POD type: {0:?}")] UnknownType(PwPodType), #[error("Unexpected POD type: Expected {0:?}, got {1:?}")] UnexpectedPodType(PwPodType, PwPodType), } #[derive(Copy, Clone)] pub struct PwParser<'a> { data: &'a [u8], fds: &'a [Rc], pos: usize, } impl<'a> PwParser<'a> { pub fn new(data: &'a [u8], fds: &'a [Rc]) -> Self { Self { data, fds, pos: 0 } } pub fn reset(&mut self) { self.pos = 0; } fn read_raw(&mut self, offset: usize) -> Result { if self.pos + offset + mem::size_of::() <= self.data.len() { unsafe { let mut res = MaybeUninit::uninit(); let src = self.data[self.pos + offset..].as_ptr(); std::ptr::copy_nonoverlapping(src, res.as_mut_ptr() as _, mem::size_of::()); Ok(res.assume_init()) } } else { Err(PwParserError::UnexpectedEof) } } pub fn len(&self) -> usize { self.data.len() - self.pos } pub fn pos(&self) -> usize { self.pos } fn read_array(&mut self, offset: usize, len: usize) -> Result, PwParserError> { let child_len = self.read_raw::(offset)? as usize; if child_len == 0 { return Err(PwParserError::ZeroSizedArrayElementType); } let ty = PwPodType(self.read_raw(offset + 4)?); Ok(PwPodArray { ty, child_len, n_elements: (len - 8) / child_len, elements: PwParser::new( &self.data[self.pos + offset + 8..self.pos + offset + len], self.fds, ), }) } pub fn read_dict_struct(&mut self) -> Result, PwParserError> { let s2 = self.read_struct()?; let mut p3 = s2.fields; let num_dict_entries = p3.read_int()?; let mut de = AHashMap::new(); for _ in 0..num_dict_entries { de.insert(p3.read_string()?.to_owned(), p3.read_string()?.to_owned()); } Ok(de) } pub fn read_struct(&mut self) -> Result, PwParserError> { match self.read_pod()? { PwPod::Struct(s) => Ok(s), v => Err(PwParserError::UnexpectedPodType(PW_TYPE_Struct, v.ty())), } } pub fn read_uint(&mut self) -> Result { self.read_int().map(|v| v as u32) } pub fn read_int(&mut self) -> Result { match self.read_value()? { PwPod::Int(s) => Ok(s), v => Err(PwParserError::UnexpectedPodType(PW_TYPE_Int, v.ty())), } } pub fn read_object_opt(&mut self) -> Result, PwParserError> { match self.read_pod()? { PwPod::Object(p) => Ok(Some(p)), PwPod::None => Ok(None), v => Err(PwParserError::UnexpectedPodType(PW_TYPE_Object, v.ty())), } } pub fn read_object(&mut self) -> Result { match self.read_object_opt()? { Some(p) => Ok(p), _ => Err(PwParserError::UnexpectedPodType( PW_TYPE_Object, PW_TYPE_None, )), } } pub fn read_id(&mut self) -> Result { match self.read_value()? { PwPod::Id(s) => Ok(s), v => Err(PwParserError::UnexpectedPodType(PW_TYPE_Id, v.ty())), } } pub fn read_fd_opt(&mut self) -> Result>, PwParserError> { match self.read_pod()? { PwPod::Fd(idx) if idx == !0 => Ok(None), PwPod::Fd(idx) => match self.fds.get(idx as usize) { Some(fd) => Ok(Some(fd.clone())), _ => Err(PwParserError::MissingFd), }, v => Err(PwParserError::UnexpectedPodType(PW_TYPE_Id, v.ty())), } } pub fn read_fd(&mut self) -> Result, PwParserError> { match self.read_fd_opt()? { Some(fd) => Ok(fd), _ => Err(PwParserError::MissingFd), } } pub fn read_ulong(&mut self) -> Result { self.read_long().map(|l| l as _) } pub fn read_long(&mut self) -> Result { match self.read_value()? { PwPod::Long(s) => Ok(s), v => Err(PwParserError::UnexpectedPodType(PW_TYPE_Long, v.ty())), } } pub fn read_string(&mut self) -> Result<&'a BStr, PwParserError> { match self.read_value()? { PwPod::String(s) => Ok(s), v => Err(PwParserError::UnexpectedPodType(PW_TYPE_String, v.ty())), } } pub fn read_value(&mut self) -> Result, PwParserError> { let mut v = self.read_pod(); if let Ok(PwPod::Choice(v)) = &mut v { if v.ty == PW_CHOICE_None && v.elements.n_elements > 0 { return v .elements .elements .read_pod_body_packed(v.elements.ty, v.elements.child_len); } } v } pub fn read_pod(&mut self) -> Result, PwParserError> { let len = self.read_raw::(0)? as usize; let ty = PwPodType(self.read_raw(4)?); self.pos += 8; self.read_pod_body(ty, len) } pub fn read_pod_body_packed( &mut self, ty: PwPodType, len: usize, ) -> Result, PwParserError> { self.read_pod_body2(ty, len, true) } pub fn read_pod_body(&mut self, ty: PwPodType, len: usize) -> Result, PwParserError> { self.read_pod_body2(ty, len, false) } fn read_pod_body2( &mut self, ty: PwPodType, len: usize, packed: bool, ) -> Result, PwParserError> { let size = if packed { len } else { (len + 7) & !7 }; if self.len() < size { return Err(PwParserError::UnexpectedEof); } let val = match ty { PW_TYPE_None => PwPod::None, PW_TYPE_Bool => PwPod::Bool(self.read_raw::(0)? != 0), PW_TYPE_Id => PwPod::Id(self.read_raw(0)?), PW_TYPE_Int => PwPod::Int(self.read_raw(0)?), PW_TYPE_Long => PwPod::Long(self.read_raw(0)?), PW_TYPE_Float => PwPod::Float(self.read_raw(0)?), PW_TYPE_Double => PwPod::Double(self.read_raw(0)?), PW_TYPE_String => { let s = if len == 0 { &[][..] } else { &self.data[self.pos..self.pos + len - 1] }; PwPod::String(s.as_bstr()) } PW_TYPE_Bytes => PwPod::Bytes(&self.data[self.pos..self.pos + len]), PW_TYPE_Rectangle => PwPod::Rectangle(PwPodRectangle { width: self.read_raw(0)?, height: self.read_raw(4)?, }), PW_TYPE_Fraction => PwPod::Fraction(PwPodFraction { num: self.read_raw(0)?, denom: self.read_raw(4)?, }), PW_TYPE_Bitmap => PwPod::Bitmap(&self.data[self.pos..self.pos + len]), PW_TYPE_Array => PwPod::Array(self.read_array(0, len)?), PW_TYPE_Struct => PwPod::Struct(PwPodStruct { fields: PwParser::new(&self.data[self.pos..self.pos + len], self.fds), }), PW_TYPE_Object => PwPod::Object(PwPodObject { ty: PwPodObjectType(self.read_raw(0)?), id: self.read_raw(4)?, probs: PwParser::new(&self.data[self.pos + 8..self.pos + len], self.fds), }), PW_TYPE_Sequence => PwPod::Sequence(PwPodSequence { unit: self.read_raw(0)?, controls: PwParser::new(&self.data[self.pos + 8..self.pos + len], self.fds), }), PW_TYPE_Pointer => PwPod::Pointer(PwPodPointer { ty: PwPointerType(self.read_raw(0)?), value: self.read_raw(8)?, }), PW_TYPE_Fd => PwPod::Fd(self.read_raw(0)?), PW_TYPE_Choice => PwPod::Choice(PwPodChoice { ty: PwChoiceType(self.read_raw(0)?), flags: self.read_raw(4)?, elements: self.read_array(8, len - 8)?, }), PW_TYPE_Pod => { let pos = self.pos; let pod = self.read_pod()?; self.pos = pos; pod } _ => return Err(PwParserError::UnknownType(ty)), }; self.pos += size; Ok(val) } pub fn read_prop(&mut self) -> Result, PwParserError> { let key = self.read_raw(0)?; let flags = PwPropFlag(self.read_raw(4)?); self.pos += 8; Ok(PwProp { key, flags, pod: self.read_pod()?, }) } pub fn read_control(&mut self) -> Result, PwParserError> { let offset = self.read_raw(0)?; let ty = PwControlType(self.read_raw(4)?); self.pos += 8; Ok(PwPodControl { offset, ty, value: self.read_pod()?, }) } pub fn skip(&mut self) -> Result<(), PwParserError> { let size = self.read_raw::(0)? as usize; if self.len() < size + 8 { return Err(PwParserError::UnexpectedEof); } self.pos += size + 8; Ok(()) } }