| 1 | use crate::{Error, MaxDepthExceeded, Result}; |
| 2 | |
| 3 | // We take the limits from the D-Bus specification for gvariant as well. |
| 4 | // |
| 5 | // The GVariant specification removed all the limits, from the D-Bus specification but that turned |
| 6 | // out to be a [mistake]. Although glib went for a higher limit (128) but we'll stick to the D-Bus |
| 7 | // limits and expand if/when needed. |
| 8 | // |
| 9 | // [mistake]: https://gitlab.gnome.org/GNOME/glib/-/commit/7c4e6e9fbe473de0401c778c6b0c4aad27d5145a |
| 10 | const MAX_STRUCT_DEPTH: u8 = 32; |
| 11 | const MAX_ARRAY_DEPTH: u8 = 32; |
| 12 | const MAX_TOTAL_DEPTH: u8 = 64; |
| 13 | |
| 14 | // Represents the current depth of all container being (de)serialized. |
| 15 | #[derive (Debug, Default, Clone, Copy)] |
| 16 | pub(crate) struct ContainerDepths { |
| 17 | structure: u8, |
| 18 | array: u8, |
| 19 | variant: u8, |
| 20 | #[cfg (feature = "gvariant" )] |
| 21 | maybe: u8, |
| 22 | } |
| 23 | |
| 24 | impl ContainerDepths { |
| 25 | pub fn inc_structure(mut self) -> Result<Self> { |
| 26 | self.structure += 1; |
| 27 | self.check() |
| 28 | } |
| 29 | |
| 30 | pub fn dec_structure(mut self) -> Self { |
| 31 | self.structure -= 1; |
| 32 | self |
| 33 | } |
| 34 | |
| 35 | pub fn inc_array(mut self) -> Result<Self> { |
| 36 | self.array += 1; |
| 37 | self.check() |
| 38 | } |
| 39 | |
| 40 | pub fn dec_array(mut self) -> Self { |
| 41 | self.array -= 1; |
| 42 | self |
| 43 | } |
| 44 | |
| 45 | pub fn inc_variant(mut self) -> Result<Self> { |
| 46 | self.variant += 1; |
| 47 | self.check() |
| 48 | } |
| 49 | |
| 50 | #[cfg (all(feature = "gvariant" , not(feature = "option-as-array" )))] |
| 51 | pub fn inc_maybe(mut self) -> Result<Self> { |
| 52 | self.maybe += 1; |
| 53 | self.check() |
| 54 | } |
| 55 | |
| 56 | #[cfg (all(feature = "gvariant" , not(feature = "option-as-array" )))] |
| 57 | pub fn dec_maybe(mut self) -> Self { |
| 58 | self.maybe -= 1; |
| 59 | self |
| 60 | } |
| 61 | |
| 62 | fn check(self) -> Result<Self> { |
| 63 | if self.structure > MAX_STRUCT_DEPTH { |
| 64 | return Err(Error::MaxDepthExceeded(MaxDepthExceeded::Structure)); |
| 65 | } |
| 66 | |
| 67 | if self.array > MAX_ARRAY_DEPTH { |
| 68 | return Err(Error::MaxDepthExceeded(MaxDepthExceeded::Array)); |
| 69 | } |
| 70 | |
| 71 | #[cfg (not(feature = "gvariant" ))] |
| 72 | let total = self.structure + self.array + self.variant; |
| 73 | #[cfg (feature = "gvariant" )] |
| 74 | let total = self.structure + self.array + self.variant + self.maybe; |
| 75 | |
| 76 | if total > MAX_TOTAL_DEPTH { |
| 77 | return Err(Error::MaxDepthExceeded(MaxDepthExceeded::Container)); |
| 78 | } |
| 79 | |
| 80 | Ok(self) |
| 81 | } |
| 82 | } |
| 83 | |