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 (feature = "gvariant" )] |
51 | pub fn inc_maybe(mut self) -> Result<Self> { |
52 | self.maybe += 1; |
53 | self.check() |
54 | } |
55 | |
56 | #[cfg (feature = "gvariant" )] |
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 | |