Coverage Report

Created: 2026-04-14 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}