1use crate::ber::BitStringObject;
2use crate::ber::{BerObject, BerObjectContent};
3use alloc::string::{String, ToString};
4use alloc::vec;
5use alloc::vec::Vec;
6use asn1_rs::{Class, Header, Length, Tag};
7use core::fmt;
8use core::iter::FromIterator;
9use core::str;
10use debug::HexSlice;
11
12use rusticata_macros::debug;
13
14#[derive(Clone, Copy, Debug, PartialEq)]
15pub enum PrettyPrinterFlag {
16 Recursive,
17 ShowHeader,
18}
19
20pub struct PrettyBer<'a> {
24 obj: &'a BerObject<'a>,
25 indent: usize,
26 inc: usize,
27
28 flags: Vec<PrettyPrinterFlag>,
29}
30
31impl<'a> BerObject<'a> {
32 pub fn as_pretty(&'a self, indent: usize, increment: usize) -> PrettyBer<'a> {
33 PrettyBer::new(self, vec![PrettyPrinterFlag::Recursive], indent, increment)
34 }
35}
36
37impl<'a> PrettyBer<'a> {
38 pub const fn new(
39 obj: &'a BerObject<'a>,
40 flags: Vec<PrettyPrinterFlag>,
41 indent: usize,
42 increment: usize,
43 ) -> Self {
44 Self {
45 obj,
46 indent,
47 inc: increment,
48 flags,
49 }
50 }
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 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
81fn 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
102impl fmt::Debug for PrettyBer<'_> {
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_utf16_string_with_type(f: &mut fmt::Formatter, s: &[u8], ty: &str) -> fmt::Result {
113 let v: Vec<_> = s
114 .chunks_exact(2)
115 .map(|a| u16::from_be_bytes([a[0], a[1]]))
116 .collect();
117 let s = String::from_utf16(&v);
118
119 match s {
120 Ok(s) => writeln!(f, "{}(\"{}\")", ty, s),
121 Err(_) => writeln!(f, "{}({:?}) <error decoding utf32 string>", ty, s),
122 }
123 }
124 fn print_utf32_string_with_type(f: &mut fmt::Formatter, s: &[u8], ty: &str) -> fmt::Result {
125 let chars: Option<Vec<char>> = s
126 .chunks_exact(4)
127 .map(|a| core::char::from_u32(u32::from_be_bytes([a[0], a[1], a[2], a[3]])))
128 .collect();
129
130 match chars {
131 Some(b) => writeln!(f, "{}(\"{}\")", ty, String::from_iter(b)),
132 None => writeln!(f, "{}({:?}) <error decoding utf32 string>", ty, s),
133 }
134 }
135 match self.obj.content {
136 BerObjectContent::EndOfContent => write!(f, "EndOfContent"),
137 BerObjectContent::Boolean(b) => write!(f, "Boolean({:?})", b),
138 BerObjectContent::Integer(i) => write!(f, "Integer({:?})", HexSlice(i)),
139 BerObjectContent::Enum(i) => write!(f, "Enum({})", i),
140 BerObjectContent::OID(ref v) => write!(f, "OID({:?})", v),
141 BerObjectContent::RelativeOID(ref v) => write!(f, "RelativeOID({:?})", v),
142 BerObjectContent::Null => write!(f, "Null"),
143 BerObjectContent::OctetString(v) => write!(f, "OctetString({:?})", HexSlice(v)),
144 BerObjectContent::BitString(u,BitStringObject{data:v})
145 => write!(f, "BitString({},{:?})", u, HexSlice(v)),
146 BerObjectContent::GeneralizedTime(ref time) => write!(f, "GeneralizedTime(\"{}\")", time),
147 BerObjectContent::UTCTime(ref time) => write!(f, "UTCTime(\"{}\")", time),
148 BerObjectContent::VisibleString(s) => write!(f, "VisibleString(\"{}\")", s),
149 BerObjectContent::GeneralString(s) => write!(f, "GeneralString(\"{}\")", s),
150 BerObjectContent::GraphicString(s) => write!(f, "GraphicString(\"{}\")", s),
151 BerObjectContent::PrintableString(s) => write!(f, "PrintableString(\"{}\")", s),
152 BerObjectContent::NumericString(s) => write!(f, "NumericString(\"{}\")", s),
153 BerObjectContent::UTF8String(s) => write!(f, "UTF8String(\"{}\")", s),
154 BerObjectContent::IA5String(s) => write!(f, "IA5String(\"{}\")", s),
155 BerObjectContent::T61String(s) => write!(f, "T61String({})", s),
156 BerObjectContent::VideotexString(s) => write!(f, "VideotexString({})", s),
157 BerObjectContent::ObjectDescriptor(s) => write!(f, "ObjectDescriptor(\"{}\")", s),
158 BerObjectContent::BmpString(s) => print_utf16_string_with_type(f, s, "BmpString"),
159 BerObjectContent::UniversalString(s) => print_utf32_string_with_type(f, s, "UniversalString"),
160 BerObjectContent::Optional(ref o) => {
161 match o {
162 Some(obj) => write!(f, "OPTION {:?}", obj),
163 None => write!(f, "NONE"),
164 }
165 }
166 BerObjectContent::Tagged(class, tag, ref obj) => {
167 writeln!(f, "ContextSpecific [{} {}] {{", class, tag.0)?;
168 write!(f, "{:?}", self.next_indent(obj))?;
169 if self.indent > 0 {
170 write!(f, "{:1$}", " ", self.indent)?;
171 };
172 write!(f, "}}")?;
173 Ok(())
174 },
175 BerObjectContent::Set(ref v) |
176 BerObjectContent::Sequence(ref v) => {
177 let ty = if self.obj.header.tag() == Tag::Sequence { "Sequence" } else { "Set" };
178 if self.is_recursive() {
179 writeln!(f, "{}[", ty)?;
180 for o in v {
181 write!(f, "{:?}", self.next_indent(o))?;
182 };
183 if self.indent > 0 {
184 write!(f, "{:1$}", " ", self.indent)?;
185 };
186 write!(f, "]")?;
187 } else {
188 write!(f, "{}", ty)?;
189 }
190 Ok(())
191 },
192 BerObjectContent::Unknown(ref any) => {
193 write!(f, "Unknown {:x?}", HexSlice(any.data))
194 },
195 }
196 }
197}
198
199#[cfg(test)]
200mod 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}