/rust/registry/src/index.crates.io-1949cf8c6b5b557f/der-parser-10.0.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 | 0 | pub fn set_flag(&mut self, flag: PrettyPrinterFlag) { |
53 | 0 | if !self.flags.contains(&flag) { |
54 | 0 | self.flags.push(flag); |
55 | 0 | } |
56 | 0 | } |
57 | | |
58 | 0 | pub fn unset_flag(&mut self, flag: PrettyPrinterFlag) { |
59 | 0 | self.flags.retain(|&f| f != flag); |
60 | 0 | } |
61 | | |
62 | 0 | pub fn is_flag_set(&self, flag: PrettyPrinterFlag) -> bool { |
63 | 0 | self.flags.contains(&flag) |
64 | 0 | } |
65 | | |
66 | 0 | pub fn next_indent<'b>(&self, obj: &'b BerObject) -> PrettyBer<'b> { |
67 | 0 | PrettyBer { |
68 | 0 | obj, |
69 | 0 | indent: self.indent + self.inc, |
70 | 0 | inc: self.inc, |
71 | 0 | flags: self.flags.to_vec(), |
72 | 0 | } |
73 | 0 | } |
74 | | |
75 | | #[inline] |
76 | 0 | fn is_recursive(&self) -> bool { |
77 | 0 | self.is_flag_set(PrettyPrinterFlag::Recursive) |
78 | 0 | } |
79 | | } |
80 | | |
81 | 0 | fn dbg_header(header: &Header, f: &mut fmt::Formatter) -> fmt::Result { |
82 | 0 | let s_constructed = if header.is_constructed() { "+" } else { "" }; |
83 | 0 | let l = match header.length() { |
84 | 0 | Length::Definite(sz) => sz.to_string(), |
85 | 0 | Length::Indefinite => "Indefinite".to_string(), |
86 | | }; |
87 | 0 | match header.class() { |
88 | | Class::Universal => { |
89 | 0 | write!(f, "[{}]{} {}", header.tag(), s_constructed, l)?; |
90 | | } |
91 | | Class::ContextSpecific => { |
92 | 0 | write!(f, "[{}]{} {}", header.tag().0, s_constructed, l)?; |
93 | | } |
94 | | |
95 | 0 | class => { |
96 | 0 | write!(f, "[{} {}]{} {}", class, header.tag().0, s_constructed, l)?; |
97 | | } |
98 | | } |
99 | 0 | Ok(()) |
100 | 0 | } |
101 | | |
102 | | impl fmt::Debug for PrettyBer<'_> { |
103 | | #[rustfmt::skip] |
104 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
105 | 0 | if self.indent > 0 { |
106 | 0 | write!(f, "{:1$}", " ", self.indent)?; |
107 | 0 | }; |
108 | 0 | if self.flags.contains(&PrettyPrinterFlag::ShowHeader) { |
109 | 0 | dbg_header(&self.obj.header, f)?; |
110 | 0 | write!(f, " ")?; |
111 | 0 | }; |
112 | 0 | fn print_utf16_string_with_type(f: &mut fmt::Formatter, s: &[u8], ty: &str) -> fmt::Result { |
113 | 0 | let v: Vec<_> = s |
114 | 0 | .chunks_exact(2) |
115 | 0 | .map(|a| u16::from_be_bytes([a[0], a[1]])) |
116 | 0 | .collect(); |
117 | 0 | let s = String::from_utf16(&v); |
118 | | |
119 | 0 | match s { |
120 | 0 | Ok(s) => writeln!(f, "{}(\"{}\")", ty, s), |
121 | 0 | Err(_) => writeln!(f, "{}({:?}) <error decoding utf32 string>", ty, s), |
122 | | } |
123 | 0 | } |
124 | 0 | fn print_utf32_string_with_type(f: &mut fmt::Formatter, s: &[u8], ty: &str) -> fmt::Result { |
125 | 0 | let chars: Option<Vec<char>> = s |
126 | 0 | .chunks_exact(4) |
127 | 0 | .map(|a| core::char::from_u32(u32::from_be_bytes([a[0], a[1], a[2], a[3]]))) |
128 | 0 | .collect(); |
129 | | |
130 | 0 | match chars { |
131 | 0 | Some(b) => writeln!(f, "{}(\"{}\")", ty, String::from_iter(b)), |
132 | 0 | None => writeln!(f, "{}({:?}) <error decoding utf32 string>", ty, s), |
133 | | } |
134 | 0 | } |
135 | 0 | match self.obj.content { |
136 | 0 | BerObjectContent::EndOfContent => write!(f, "EndOfContent"), |
137 | 0 | BerObjectContent::Boolean(b) => write!(f, "Boolean({:?})", b), |
138 | 0 | BerObjectContent::Integer(i) => write!(f, "Integer({:?})", HexSlice(i)), |
139 | 0 | BerObjectContent::Enum(i) => write!(f, "Enum({})", i), |
140 | 0 | BerObjectContent::OID(ref v) => write!(f, "OID({:?})", v), |
141 | 0 | BerObjectContent::RelativeOID(ref v) => write!(f, "RelativeOID({:?})", v), |
142 | 0 | BerObjectContent::Null => write!(f, "Null"), |
143 | 0 | BerObjectContent::OctetString(v) => write!(f, "OctetString({:?})", HexSlice(v)), |
144 | 0 | BerObjectContent::BitString(u,BitStringObject{data:v}) |
145 | 0 | => write!(f, "BitString({},{:?})", u, HexSlice(v)), |
146 | 0 | BerObjectContent::GeneralizedTime(ref time) => write!(f, "GeneralizedTime(\"{}\")", time), |
147 | 0 | BerObjectContent::UTCTime(ref time) => write!(f, "UTCTime(\"{}\")", time), |
148 | 0 | BerObjectContent::VisibleString(s) => write!(f, "VisibleString(\"{}\")", s), |
149 | 0 | BerObjectContent::GeneralString(s) => write!(f, "GeneralString(\"{}\")", s), |
150 | 0 | BerObjectContent::GraphicString(s) => write!(f, "GraphicString(\"{}\")", s), |
151 | 0 | BerObjectContent::PrintableString(s) => write!(f, "PrintableString(\"{}\")", s), |
152 | 0 | BerObjectContent::NumericString(s) => write!(f, "NumericString(\"{}\")", s), |
153 | 0 | BerObjectContent::UTF8String(s) => write!(f, "UTF8String(\"{}\")", s), |
154 | 0 | BerObjectContent::IA5String(s) => write!(f, "IA5String(\"{}\")", s), |
155 | 0 | BerObjectContent::T61String(s) => write!(f, "T61String({})", s), |
156 | 0 | BerObjectContent::VideotexString(s) => write!(f, "VideotexString({})", s), |
157 | 0 | BerObjectContent::ObjectDescriptor(s) => write!(f, "ObjectDescriptor(\"{}\")", s), |
158 | 0 | BerObjectContent::BmpString(s) => print_utf16_string_with_type(f, s, "BmpString"), |
159 | 0 | BerObjectContent::UniversalString(s) => print_utf32_string_with_type(f, s, "UniversalString"), |
160 | 0 | BerObjectContent::Optional(ref o) => { |
161 | 0 | match o { |
162 | 0 | Some(obj) => write!(f, "OPTION {:?}", obj), |
163 | 0 | None => write!(f, "NONE"), |
164 | | } |
165 | | } |
166 | 0 | BerObjectContent::Tagged(class, tag, ref obj) => { |
167 | 0 | writeln!(f, "ContextSpecific [{} {}] {{", class, tag.0)?; |
168 | 0 | write!(f, "{:?}", self.next_indent(obj))?; |
169 | 0 | if self.indent > 0 { |
170 | 0 | write!(f, "{:1$}", " ", self.indent)?; |
171 | 0 | }; |
172 | 0 | write!(f, "}}")?; |
173 | 0 | Ok(()) |
174 | | }, |
175 | 0 | BerObjectContent::Set(ref v) | |
176 | 0 | BerObjectContent::Sequence(ref v) => { |
177 | 0 | let ty = if self.obj.header.tag() == Tag::Sequence { "Sequence" } else { "Set" }; |
178 | 0 | if self.is_recursive() { |
179 | 0 | writeln!(f, "{}[", ty)?; |
180 | 0 | for o in v { |
181 | 0 | write!(f, "{:?}", self.next_indent(o))?; |
182 | | }; |
183 | 0 | if self.indent > 0 { |
184 | 0 | write!(f, "{:1$}", " ", self.indent)?; |
185 | 0 | }; |
186 | 0 | write!(f, "]")?; |
187 | | } else { |
188 | 0 | write!(f, "{}", ty)?; |
189 | | } |
190 | 0 | Ok(()) |
191 | | }, |
192 | 0 | BerObjectContent::Unknown(ref any) => { |
193 | 0 | write!(f, "Unknown {:x?}", HexSlice(any.data)) |
194 | | }, |
195 | | } |
196 | 0 | } |
197 | | } |
198 | | |
199 | | #[cfg(test)] |
200 | | mod tests { |
201 | | use super::PrettyPrinterFlag; |
202 | | use crate::ber::*; |
203 | | |
204 | | #[test] |
205 | | fn test_pretty_print() { |
206 | | let d = BerObject::from_obj(BerObjectContent::Sequence(vec![ |
207 | | BerObject::from_int_slice(b"\x01\x00\x01"), |
208 | | BerObject::from_int_slice(b"\x01\x00\x01"), |
209 | | BerObject::from_obj(BerObjectContent::Set(vec![ |
210 | | BerObject::from_int_slice(b"\x01"), |
211 | | BerObject::from_int_slice(b"\x02"), |
212 | | ])), |
213 | | ])); |
214 | | |
215 | | println!("{:?}", d.as_pretty(0, 2)); |
216 | | |
217 | | let mut pp = d.as_pretty(0, 4); |
218 | | pp.set_flag(PrettyPrinterFlag::ShowHeader); |
219 | | println!("{:?}", pp); |
220 | | } |
221 | | } |