1use pyo3::prelude::*;
4use pyo3::types::PyBytes;
5
6use synta::traits::Decode;
7use synta::{Decoder, Encoding, TagClass};
8
9use super::error::SyntaErr;
10
11fn parse_tag_class(s: &str) -> PyResult<TagClass> {
12 match s {
13 "Universal" => Ok(TagClass::Universal),
14 "Context" => Ok(TagClass::ContextSpecific),
15 "Application" => Ok(TagClass::Application),
16 "Private" => Ok(TagClass::Private),
17 other => Err(pyo3::exceptions::PyValueError::new_err(format!(
18 "Unknown tag class '{other}'; expected 'Universal', 'Context', 'Application', or 'Private'",
19 ))),
20 }
21}
22
23fn tag_class_str(class: TagClass) -> &'static str {
24 match class {
25 TagClass::Universal => "Universal",
26 TagClass::Application => "Application",
27 TagClass::ContextSpecific => "Context",
28 TagClass::Private => "Private",
29 }
30}
31
32use super::types::{
33 PyBitString, PyBmpString, PyBoolean, PyGeneralString, PyGeneralizedTime, PyIA5String,
34 PyInteger, PyNull, PyNumericString, PyObjectIdentifier, PyOctetString, PyPrintableString,
35 PyReal, PyTeletexString, PyUniversalString, PyUtcTime, PyUtf8String, PyVisibleString,
36};
37use super::PyEncoding;
38
39#[pyclass(name = "Decoder")]
49pub struct PyDecoder {
50 data: Vec<u8>,
52 position: usize,
54 encoding: Encoding,
56}
57
58impl PyDecoder {
59 fn advance(&mut self, by: usize) {
61 self.position += by;
62 debug_assert!(
63 self.position <= self.data.len(),
64 "decoder position {} overshot data length {}",
65 self.position,
66 self.data.len()
67 );
68 }
69
70 fn decode_one<T>(&mut self) -> PyResult<T>
80 where
81 T: for<'a> Decode<'a>,
82 {
83 let mut decoder = Decoder::new(&self.data[self.position..], self.encoding);
84 let result = T::decode(&mut decoder).map_err(SyntaErr)?;
85 self.advance(decoder.position());
86 Ok(result)
87 }
88}
89
90#[pymethods]
91impl PyDecoder {
92 #[new]
98 fn new(data: Vec<u8>, encoding: PyEncoding) -> Self {
99 Self {
100 data,
101 position: 0,
102 encoding: encoding.into(),
103 }
104 }
105
106 fn decode_integer(&mut self) -> PyResult<PyInteger> {
108 self.decode_one::<synta::Integer>()
109 .map(|inner| PyInteger { inner })
110 }
111
112 fn decode_octet_string(&mut self) -> PyResult<PyOctetString> {
114 self.decode_one::<synta::OctetString>()
115 .map(|inner| PyOctetString { inner })
116 }
117
118 fn decode_oid(&mut self) -> PyResult<PyObjectIdentifier> {
120 self.decode_one::<synta::ObjectIdentifier>()
121 .map(PyObjectIdentifier::from_oid)
122 }
123
124 fn decode_bit_string(&mut self) -> PyResult<PyBitString> {
126 self.decode_one::<synta::BitString>()
127 .map(|inner| PyBitString { inner })
128 }
129
130 fn decode_boolean(&mut self) -> PyResult<PyBoolean> {
132 self.decode_one::<synta::Boolean>()
133 .map(|inner| PyBoolean { inner })
134 }
135
136 fn decode_utc_time(&mut self) -> PyResult<PyUtcTime> {
138 self.decode_one::<synta::UtcTime>()
139 .map(|inner| PyUtcTime { inner })
140 }
141
142 fn decode_generalized_time(&mut self) -> PyResult<PyGeneralizedTime> {
144 self.decode_one::<synta::GeneralizedTime>()
145 .map(|inner| PyGeneralizedTime { inner })
146 }
147
148 fn decode_null(&mut self) -> PyResult<PyNull> {
150 self.decode_one::<synta::Null>()?;
151 Ok(PyNull)
152 }
153
154 fn decode_real(&mut self) -> PyResult<PyReal> {
156 self.decode_one::<synta::Real>()
157 .map(|inner| PyReal { inner })
158 }
159
160 fn decode_utf8_string(&mut self) -> PyResult<PyUtf8String> {
162 self.decode_one::<synta::Utf8String>()
163 .map(|inner| PyUtf8String { inner })
164 }
165
166 fn decode_printable_string(&mut self) -> PyResult<PyPrintableString> {
168 self.decode_one::<synta::PrintableString>()
169 .map(|inner| PyPrintableString { inner })
170 }
171
172 fn decode_ia5_string(&mut self) -> PyResult<PyIA5String> {
174 self.decode_one::<synta::IA5String>()
175 .map(|inner| PyIA5String { inner })
176 }
177
178 fn decode_numeric_string(&mut self) -> PyResult<PyNumericString> {
180 self.decode_one::<synta::NumericString>()
181 .map(|inner| PyNumericString { inner })
182 }
183
184 fn decode_teletex_string(&mut self) -> PyResult<PyTeletexString> {
186 self.decode_one::<synta::TeletexString>()
187 .map(|inner| PyTeletexString { inner })
188 }
189
190 fn decode_visible_string(&mut self) -> PyResult<PyVisibleString> {
192 self.decode_one::<synta::VisibleString>()
193 .map(|inner| PyVisibleString { inner })
194 }
195
196 fn decode_general_string(&mut self) -> PyResult<PyGeneralString> {
198 self.decode_one::<synta::GeneralString>()
199 .map(|inner| PyGeneralString { inner })
200 }
201
202 fn decode_universal_string(&mut self) -> PyResult<PyUniversalString> {
204 self.decode_one::<synta::UniversalString>()
205 .map(|inner| PyUniversalString { inner })
206 }
207
208 fn decode_bmp_string(&mut self) -> PyResult<PyBmpString> {
210 self.decode_one::<synta::BmpString>()
211 .map(|inner| PyBmpString { inner })
212 }
213
214 fn decode_any_str<'py>(
247 &mut self,
248 py: Python<'py>,
249 ) -> PyResult<Bound<'py, pyo3::types::PyString>> {
250 use pyo3::exceptions::{PyEOFError, PyValueError};
251 use pyo3::types::PyString;
252 use synta::tag::*;
253
254 if self.position >= self.data.len() {
255 return Err(PyEOFError::new_err("No more data"));
256 }
257
258 let (tag_num, val_bytes, advance) = {
259 let mut decoder = Decoder::new(&self.data[self.position..], self.encoding);
260 let tag = decoder.read_tag().map_err(SyntaErr)?;
261 let length = decoder.read_length().map_err(SyntaErr)?;
262 let len = length.definite().map_err(SyntaErr)?;
263 let val = decoder.read_bytes(len).map_err(SyntaErr)?.to_vec();
264 (tag.number(), val, decoder.position())
265 };
266
267 let s: String = match tag_num {
268 TAG_UTF8_STRING | TAG_PRINTABLE_STRING | TAG_IA5_STRING | TAG_VISIBLE_STRING
269 | TAG_NUMERIC_STRING | TAG_GENERAL_STRING => {
270 String::from_utf8_lossy(&val_bytes).into_owned()
271 }
272
273 TAG_TELETEX_STRING => val_bytes.iter().map(|&b| b as char).collect(),
275
276 TAG_BMP_STRING => val_bytes
278 .chunks_exact(2)
279 .filter_map(|pair| char::from_u32(u16::from_be_bytes([pair[0], pair[1]]) as u32))
280 .collect(),
281
282 TAG_UNIVERSAL_STRING => val_bytes
284 .chunks_exact(4)
285 .filter_map(|quad| {
286 char::from_u32(u32::from_be_bytes([quad[0], quad[1], quad[2], quad[3]]))
287 })
288 .collect(),
289
290 other => {
291 return Err(PyValueError::new_err(format!(
292 "tag {other} is not an ASN.1 string type; \
293 expected UTF8String (12), PrintableString (19), IA5String (22), \
294 NumericString (18), TeletexString (20), VisibleString (26), \
295 GeneralString (27), BMPString (30), or UniversalString (28)"
296 )));
297 }
298 };
299
300 self.advance(advance);
301 Ok(PyString::new(py, &s))
302 }
303
304 fn decode_sequence(&mut self) -> PyResult<PyDecoder> {
312 use pyo3::exceptions::PyValueError;
313 use synta::tag::TAG_SEQUENCE;
314 use synta::TagClass;
315
316 let (data, advance) = {
317 let mut decoder = Decoder::new(&self.data[self.position..], self.encoding);
318 let tag = decoder.read_tag().map_err(SyntaErr)?;
319 if tag.class() != TagClass::Universal
320 || tag.number() != TAG_SEQUENCE
321 || !tag.is_constructed()
322 {
323 return Err(PyValueError::new_err(format!(
324 "Expected SEQUENCE (0x30), got tag {:?}",
325 tag
326 )));
327 }
328 let length = decoder.read_length().map_err(SyntaErr)?;
329 let len = length.definite().map_err(SyntaErr)?;
330 let data = decoder.read_bytes(len).map_err(SyntaErr)?.to_vec();
331 (data, decoder.position())
332 };
334 self.advance(advance);
335 Ok(PyDecoder {
336 data,
337 position: 0,
338 encoding: self.encoding,
339 })
340 }
341
342 fn decode_explicit_tag(&mut self, tag_num: u32) -> PyResult<PyDecoder> {
349 use pyo3::exceptions::PyValueError;
350 use synta::TagClass;
351
352 let (data, advance) = {
353 let mut decoder = Decoder::new(&self.data[self.position..], self.encoding);
354 let tag = decoder.read_tag().map_err(SyntaErr)?;
355 if tag.class() != TagClass::ContextSpecific || tag.number() != tag_num {
356 return Err(PyValueError::new_err(format!(
357 "Expected explicit context tag [{}], got {:?}",
358 tag_num, tag
359 )));
360 }
361 let length = decoder.read_length().map_err(SyntaErr)?;
362 let len = length.definite().map_err(SyntaErr)?;
363 let data = decoder.read_bytes(len).map_err(SyntaErr)?.to_vec();
364 (data, decoder.position())
365 };
367 self.advance(advance);
368 Ok(PyDecoder {
369 data,
370 position: 0,
371 encoding: self.encoding,
372 })
373 }
374
375 fn decode_set(&mut self) -> PyResult<PyDecoder> {
379 use pyo3::exceptions::PyValueError;
380 use synta::tag::TAG_SET;
381
382 let (data, advance) = {
383 let mut decoder = Decoder::new(&self.data[self.position..], self.encoding);
384 let tag = decoder.read_tag().map_err(SyntaErr)?;
385 if tag.class() != TagClass::Universal
386 || tag.number() != TAG_SET
387 || !tag.is_constructed()
388 {
389 return Err(PyValueError::new_err(format!(
390 "Expected SET (0x31), got tag {:?}",
391 tag
392 )));
393 }
394 let length = decoder.read_length().map_err(SyntaErr)?;
395 let len = length.definite().map_err(SyntaErr)?;
396 let data = decoder.read_bytes(len).map_err(SyntaErr)?.to_vec();
397 (data, decoder.position())
398 };
399 self.advance(advance);
400 Ok(PyDecoder {
401 data,
402 position: 0,
403 encoding: self.encoding,
404 })
405 }
406
407 fn decode_implicit_tag(&mut self, tag_num: u32, tag_class: &str) -> PyResult<PyDecoder> {
425 use pyo3::exceptions::PyValueError;
426
427 let class = parse_tag_class(tag_class)?;
428
429 let (data, advance) = {
430 let mut decoder = Decoder::new(&self.data[self.position..], self.encoding);
431 let tag = decoder.read_tag().map_err(SyntaErr)?;
432 if tag.class() != class || tag.number() != tag_num {
433 return Err(PyValueError::new_err(format!(
434 "Expected implicit tag [{tag_num} {tag_class}], got {:?}",
435 tag
436 )));
437 }
438 let length = decoder.read_length().map_err(SyntaErr)?;
439 let len = length.definite().map_err(SyntaErr)?;
440 let data = decoder.read_bytes(len).map_err(SyntaErr)?.to_vec();
441 (data, decoder.position())
442 };
443 self.advance(advance);
444 Ok(PyDecoder {
445 data,
446 position: 0,
447 encoding: self.encoding,
448 })
449 }
450
451 fn peek_tag(&self) -> PyResult<(u32, String, bool)> {
465 use pyo3::exceptions::PyEOFError;
466 if self.position >= self.data.len() {
467 return Err(PyEOFError::new_err("No more data to peek"));
468 }
469 let mut decoder = Decoder::new(&self.data[self.position..], self.encoding);
470 let tag = decoder.read_tag().map_err(SyntaErr)?;
471 Ok((
472 tag.number(),
473 tag_class_str(tag.class()).to_string(),
474 tag.is_constructed(),
475 ))
476 }
477
478 fn decode_raw_tlv<'py>(&mut self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
489 use pyo3::exceptions::PyEOFError;
490 if self.position >= self.data.len() {
491 return Err(PyEOFError::new_err("No more data"));
492 }
493 let total = {
494 let mut decoder = Decoder::new(&self.data[self.position..], self.encoding);
495 decoder.read_tag().map_err(SyntaErr)?;
496 let length = decoder.read_length().map_err(SyntaErr)?;
497 let content_len = length.definite().map_err(SyntaErr)?;
498 decoder.read_bytes(content_len).map_err(SyntaErr)?;
499 decoder.position()
500 };
501 let end = self.position + total;
502 let bytes = PyBytes::new(py, &self.data[self.position..end]);
503 self.advance(total);
504 Ok(bytes)
505 }
506
507 fn remaining_bytes<'py>(&self, py: Python<'py>) -> Bound<'py, PyBytes> {
526 PyBytes::new(py, &self.data[self.position..])
527 }
528
529 fn decode_any(&mut self, py: Python) -> PyResult<Py<PyAny>> {
535 let (py_obj, advance) = {
536 let mut decoder = Decoder::new(&self.data[self.position..], self.encoding);
537 let element = synta::Element::decode(&mut decoder).map_err(SyntaErr)?;
538 let advance = decoder.position();
539 let py_obj = super::types::element_to_pyobject(element, py)?;
540 (py_obj, advance)
541 };
542 self.advance(advance);
543 Ok(py_obj)
544 }
545
546 fn is_empty(&self) -> bool {
548 self.position == self.data.len()
549 }
550
551 fn position(&self) -> usize {
553 self.position
554 }
555
556 fn remaining(&self) -> usize {
558 self.data.len().saturating_sub(self.position)
559 }
560
561 fn __repr__(&self) -> String {
562 format!(
563 "Decoder(position={}, remaining={}, encoding={:?})",
564 self.position,
565 self.remaining(),
566 self.encoding
567 )
568 }
569}