/rust/registry/src/index.crates.io-1949cf8c6b5b557f/der-parser-8.2.0/src/ber/print.rs
Line | Count | Source |
1 | | use crate::ber::BitStringObject; |
2 | | use crate::ber::{BerObject, BerObjectContent}; |
3 | | use alloc::string::{String, ToString}; |
4 | | use alloc::vec; |
5 | | use alloc::vec::Vec; |
6 | | use asn1_rs::{Class, Header, Length, Tag}; |
7 | | use core::fmt; |
8 | | use core::iter::FromIterator; |
9 | | use core::str; |
10 | | use debug::HexSlice; |
11 | | |
12 | | use rusticata_macros::debug; |
13 | | |
14 | | #[derive(Clone, Copy, Debug, PartialEq)] |
15 | | pub enum PrettyPrinterFlag { |
16 | | Recursive, |
17 | | ShowHeader, |
18 | | } |
19 | | |
20 | | /// Pretty-print BER object |
21 | | /// |
22 | | /// This method is recursive by default. To prevent that, unset the `Recursive` flag. |
23 | | pub struct PrettyBer<'a> { |
24 | | obj: &'a BerObject<'a>, |
25 | | indent: usize, |
26 | | inc: usize, |
27 | | |
28 | | flags: Vec<PrettyPrinterFlag>, |
29 | | } |
30 | | |
31 | | impl<'a> BerObject<'a> { |
32 | 0 | pub fn as_pretty(&'a self, indent: usize, increment: usize) -> PrettyBer<'a> { |
33 | 0 | PrettyBer::new(self, vec![PrettyPrinterFlag::Recursive], indent, increment) |
34 | 0 | } |
35 | | } |
36 | | |
37 | | impl<'a> PrettyBer<'a> { |
38 | 0 | pub const fn new( |
39 | 0 | obj: &'a BerObject<'a>, |
40 | 0 | flags: Vec<PrettyPrinterFlag>, |
41 | 0 | indent: usize, |
42 | 0 | increment: usize, |
43 | 0 | ) -> Self { |
44 | 0 | Self { |
45 | 0 | obj, |
46 | 0 | indent, |
47 | 0 | inc: increment, |
48 | 0 | flags, |
49 | 0 | } |
50 | 0 | } |
51 | | |
52 | | pub fn set_flag(&mut self, flag: PrettyPrinterFlag) { |
53 | | if !self.flags.contains(&flag) { |
54 | | self.flags.push(flag); |
55 | | } |
56 | | } |
57 | | |
58 | | pub fn unset_flag(&mut self, flag: PrettyPrinterFlag) { |
59 | 0 | self.flags.retain(|&f| f != flag); |
60 | | } |
61 | | |
62 | | pub fn is_flag_set(&self, flag: PrettyPrinterFlag) -> bool { |
63 | | self.flags.contains(&flag) |
64 | | } |
65 | | |
66 | | pub fn next_indent<'b>(&self, obj: &'b BerObject) -> PrettyBer<'b> { |
67 | | PrettyBer { |
68 | | obj, |
69 | | indent: self.indent + self.inc, |
70 | | inc: self.inc, |
71 | | flags: self.flags.to_vec(), |
72 | | } |
73 | | } |
74 | | |
75 | | #[inline] |
76 | | fn is_recursive(&self) -> bool { |
77 | | self.is_flag_set(PrettyPrinterFlag::Recursive) |
78 | | } |
79 | | } |
80 | | |
81 | | fn dbg_header(header: &Header, f: &mut fmt::Formatter) -> fmt::Result { |
82 | | let s_constructed = if header.is_constructed() { "+" } else { "" }; |
83 | | let l = match header.length() { |
84 | | Length::Definite(sz) => sz.to_string(), |
85 | | Length::Indefinite => "Indefinite".to_string(), |
86 | | }; |
87 | | match header.class() { |
88 | | Class::Universal => { |
89 | | write!(f, "[{}]{} {}", header.tag(), s_constructed, l)?; |
90 | | } |
91 | | Class::ContextSpecific => { |
92 | | write!(f, "[{}]{} {}", header.tag().0, s_constructed, l)?; |
93 | | } |
94 | | |
95 | | class => { |
96 | | write!(f, "[{} {}]{} {}", class, header.tag().0, s_constructed, l)?; |
97 | | } |
98 | | } |
99 | | Ok(()) |
100 | | } |
101 | | |
102 | | impl<'a> fmt::Debug for PrettyBer<'a> { |
103 | | #[rustfmt::skip] |
104 | | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
105 | | if self.indent > 0 { |
106 | | write!(f, "{:1$}", " ", self.indent)?; |
107 | | }; |
108 | | if self.flags.contains(&PrettyPrinterFlag::ShowHeader) { |
109 | | dbg_header(&self.obj.header, f)?; |
110 | | write!(f, " ")?; |
111 | | }; |
112 | | fn print_utf32_string_with_type(f: &mut fmt::Formatter, s: &[u8], ty: &str) -> fmt::Result { |
113 | | let chars: Option<Vec<char>> = s |
114 | | .chunks_exact(4) |
115 | 0 | .map(|a| core::char::from_u32(u32::from_be_bytes([a[0], a[1], a[2], a[3]]))) |
116 | | .collect(); |
117 | | |
118 | | match chars { |
119 | | Some(b) => writeln!(f, "{}(\"{}\")", ty, String::from_iter(b)), |
120 | | None => writeln!(f, "{}({:?}) <error decoding utf32 string>", ty, s), |
121 | | } |
122 | | } |
123 | | match self.obj.content { |
124 | | BerObjectContent::EndOfContent => write!(f, "EndOfContent"), |
125 | | BerObjectContent::Boolean(b) => write!(f, "Boolean({:?})", b), |
126 | | BerObjectContent::Integer(i) => write!(f, "Integer({:?})", HexSlice(i)), |
127 | | BerObjectContent::Enum(i) => write!(f, "Enum({})", i), |
128 | | BerObjectContent::OID(ref v) => write!(f, "OID({:?})", v), |
129 | | BerObjectContent::RelativeOID(ref v) => write!(f, "RelativeOID({:?})", v), |
130 | | BerObjectContent::Null => write!(f, "Null"), |
131 | | BerObjectContent::OctetString(v) => write!(f, "OctetString({:?})", HexSlice(v)), |
132 | | BerObjectContent::BitString(u,BitStringObject{data:v}) |
133 | | => write!(f, "BitString({},{:?})", u, HexSlice(v)), |
134 | | BerObjectContent::GeneralizedTime(ref time) => write!(f, "GeneralizedTime(\"{}\")", time), |
135 | | BerObjectContent::UTCTime(ref time) => write!(f, "UTCTime(\"{}\")", time), |
136 | | BerObjectContent::VisibleString(s) => write!(f, "VisibleString(\"{}\")", s), |
137 | | BerObjectContent::GeneralString(s) => write!(f, "GeneralString(\"{}\")", s), |
138 | | BerObjectContent::GraphicString(s) => write!(f, "GraphicString(\"{}\")", s), |
139 | | BerObjectContent::PrintableString(s) => write!(f, "PrintableString(\"{}\")", s), |
140 | | BerObjectContent::NumericString(s) => write!(f, "NumericString(\"{}\")", s), |
141 | | BerObjectContent::UTF8String(s) => write!(f, "UTF8String(\"{}\")", s), |
142 | | BerObjectContent::IA5String(s) => write!(f, "IA5String(\"{}\")", s), |
143 | | BerObjectContent::T61String(s) => write!(f, "T61String({})", s), |
144 | | BerObjectContent::VideotexString(s) => write!(f, "VideotexString({})", s), |
145 | | BerObjectContent::ObjectDescriptor(s) => write!(f, "ObjectDescriptor(\"{}\")", s), |
146 | | BerObjectContent::BmpString(s) => write!(f, "BmpString(\"{}\")", s), |
147 | | BerObjectContent::UniversalString(s) => print_utf32_string_with_type(f, s, "UniversalString"), |
148 | | BerObjectContent::Optional(ref o) => { |
149 | | match o { |
150 | | Some(obj) => write!(f, "OPTION {:?}", obj), |
151 | | None => write!(f, "NONE"), |
152 | | } |
153 | | } |
154 | | BerObjectContent::Tagged(class, tag, ref obj) => { |
155 | | writeln!(f, "ContextSpecific [{} {}] {{", class, tag.0)?; |
156 | | write!(f, "{:?}", self.next_indent(obj))?; |
157 | | if self.indent > 0 { |
158 | | write!(f, "{:1$}", " ", self.indent)?; |
159 | | }; |
160 | | write!(f, "}}")?; |
161 | | Ok(()) |
162 | | }, |
163 | | BerObjectContent::Set(ref v) | |
164 | | BerObjectContent::Sequence(ref v) => { |
165 | | let ty = if self.obj.header.tag() == Tag::Sequence { "Sequence" } else { "Set" }; |
166 | | if self.is_recursive() { |
167 | | writeln!(f, "{}[", ty)?; |
168 | | for o in v { |
169 | | write!(f, "{:?}", self.next_indent(o))?; |
170 | | }; |
171 | | if self.indent > 0 { |
172 | | write!(f, "{:1$}", " ", self.indent)?; |
173 | | }; |
174 | | write!(f, "]")?; |
175 | | } else { |
176 | | write!(f, "{}", ty)?; |
177 | | } |
178 | | Ok(()) |
179 | | }, |
180 | | BerObjectContent::Unknown(ref any) => { |
181 | | write!(f, "Unknown {:x?}", HexSlice(any.data)) |
182 | | }, |
183 | | } |
184 | | } |
185 | | } |
186 | | |
187 | | #[cfg(test)] |
188 | | mod tests { |
189 | | use super::PrettyPrinterFlag; |
190 | | use crate::ber::*; |
191 | | |
192 | | #[test] |
193 | | fn test_pretty_print() { |
194 | | let d = BerObject::from_obj(BerObjectContent::Sequence(vec![ |
195 | | BerObject::from_int_slice(b"\x01\x00\x01"), |
196 | | BerObject::from_int_slice(b"\x01\x00\x01"), |
197 | | BerObject::from_obj(BerObjectContent::Set(vec![ |
198 | | BerObject::from_int_slice(b"\x01"), |
199 | | BerObject::from_int_slice(b"\x02"), |
200 | | ])), |
201 | | ])); |
202 | | |
203 | | println!("{:?}", d.as_pretty(0, 2)); |
204 | | |
205 | | let mut pp = d.as_pretty(0, 4); |
206 | | pp.set_flag(PrettyPrinterFlag::ShowHeader); |
207 | | println!("{:?}", pp); |
208 | | } |
209 | | } |