asn1_codecs/per/uper/encode/
mod.rs

1//! ASN.1 Aper Encoder module.
2
3use bitvec::prelude::*;
4
5use crate::{PerCodecData, PerCodecError, PerCodecErrorCause};
6
7#[allow(unused)]
8use crate::per::common::encode::*;
9
10/// Encode a Choice Index
11///
12/// During Encoding a 'CHOICE' Type to help decoding, the 'CHOICE' Index is encoded first, followed
13/// by the actual encoding of the 'CHOICE' variant.
14pub fn encode_choice_idx(
15    data: &mut PerCodecData,
16    lb: i128,
17    ub: i128,
18    is_extensible: bool,
19    idx: i128,
20    extended: bool,
21) -> Result<(), PerCodecError> {
22    log::trace!(
23        "encode_choice_idx: lb: {}, ub: {}, is_extensible: {}, idx: {}, extended: {}",
24        lb,
25        ub,
26        is_extensible,
27        idx,
28        extended
29    );
30
31    encode_choice_idx_common(data, lb, ub, is_extensible, idx, extended, false)
32}
33
34/// Encode sequence header
35pub fn encode_sequence_header(
36    data: &mut PerCodecData,
37    is_extensible: bool,
38    optionals: &BitSlice<u8, Msb0>,
39    extended: bool,
40) -> Result<(), PerCodecError> {
41    log::trace!(
42        "encode_sequence_header: is_extensible: {}, optional_fields: {:?}, extended: {}",
43        is_extensible,
44        optionals,
45        extended
46    );
47
48    encode_sequence_header_common(data, is_extensible, optionals, extended, false)
49}
50
51/// Encode an INTEGER
52///
53/// This API is also used by other `encode` functions to encode an integer value.
54///
55/// Note: The maximum (and minimum) value to be decoded is limited to an `i128` value. For the
56/// protocols that are currently supported this limit is acceptable.
57pub fn encode_integer(
58    data: &mut PerCodecData,
59    lb: Option<i128>,
60    ub: Option<i128>,
61    is_extensible: bool,
62    value: i128,
63    extended: bool,
64) -> Result<(), PerCodecError> {
65    log::trace!(
66        "encode_integer: lb: {:?}, ub: {:?}, is_extensible: {}, value: {}, extended: {}",
67        lb,
68        ub,
69        is_extensible,
70        value,
71        extended
72    );
73
74    encode_integer_common(data, lb, ub, is_extensible, value, extended, false)
75}
76
77/// Encode a BOOLEAN Value
78///
79/// Encodes a boolean value into the passed `PerCodecData` structure.
80pub fn encode_bool(data: &mut PerCodecData, value: bool) -> Result<(), PerCodecError> {
81    log::trace!("encode_bool: {}", value);
82
83    encode_bool_common(data, value, true)
84}
85
86/// Encode a REAL Value
87///
88/// Encodes an f64 value into the passed `PerCodecData` structure.
89pub fn encode_real(data: &mut PerCodecData, value: f64) -> Result<(), PerCodecError> {
90    log::trace!("encode_real: {}", value);
91    encode_real_common(data, value, false)
92}
93
94/// Encode an ENUMERATED Value
95pub fn encode_enumerated(
96    data: &mut PerCodecData,
97    lb: Option<i128>,
98    ub: Option<i128>,
99    is_extensible: bool,
100    value: i128,
101    extended: bool,
102) -> Result<(), PerCodecError> {
103    log::trace!(
104        "encode_enumerated: lb: {:?}, ub: {:?}, is_extensible: {}, value: {}, extended: {}",
105        lb,
106        ub,
107        is_extensible,
108        value,
109        extended
110    );
111
112    encode_enumerated_common(data, lb, ub, is_extensible, value, extended, false)
113}
114
115/// Encode a Bit String
116pub fn encode_bitstring(
117    data: &mut PerCodecData,
118    lb: Option<i128>,
119    ub: Option<i128>,
120    is_extensible: bool,
121    bit_string: &BitSlice<u8, Msb0>,
122    extended: bool,
123) -> Result<(), PerCodecError> {
124    log::trace!(
125        "encode_bitstring: lb: {:?}, ub: {:?}, is_extensible: {}, bits: {:?}, extended: {}",
126        lb,
127        ub,
128        is_extensible,
129        bit_string,
130        extended
131    );
132
133    encode_bitstring_common(data, lb, ub, is_extensible, bit_string, extended, false)
134}
135
136/// Encode an OCTET STRING
137pub fn encode_octetstring(
138    data: &mut PerCodecData,
139    lb: Option<i128>,
140    ub: Option<i128>,
141    is_extensible: bool,
142    octet_string: &Vec<u8>,
143    extended: bool,
144) -> Result<(), PerCodecError> {
145    log::trace!(
146        "encode_octetstring: lb: {:?}, ub: {:?}, is_extensible: {}, bytes: {:?}, extended: {}",
147        lb,
148        ub,
149        is_extensible,
150        octet_string,
151        extended
152    );
153
154    encode_octet_string_common(data, lb, ub, is_extensible, octet_string, extended, false)
155}
156
157// Encode a Length Determinent
158pub fn encode_length_determinent(
159    data: &mut PerCodecData,
160    lb: Option<i128>,
161    ub: Option<i128>,
162    normally_small: bool,
163    value: usize,
164) -> Result<(), PerCodecError> {
165    log::trace!(
166        "encode_length_determinent: lb: {:?}, ub: {:?}, normally_small: {}, value: {}",
167        lb,
168        ub,
169        normally_small,
170        value
171    );
172
173    encode_length_determinent_common(data, lb, ub, normally_small, value, false)
174}
175
176/// Encode a VisibleString CharacterString Type.
177pub fn encode_visible_string(
178    data: &mut PerCodecData,
179    lb: Option<i128>,
180    ub: Option<i128>,
181    is_extensible: bool,
182    value: &String,
183    extended: bool,
184) -> Result<(), PerCodecError> {
185    log::trace!(
186        "encode_visible_string: lb: {:?}, ub: {:?}, is_extensible: {}, value: {}, extended: {}",
187        lb,
188        ub,
189        is_extensible,
190        value,
191        extended
192    );
193
194    encode_ascii_ish_string_common(data, lb, ub, is_extensible, value, extended)
195}
196
197/// Encode a PrintableString CharacterString Type.
198pub fn encode_printable_string(
199    data: &mut PerCodecData,
200    lb: Option<i128>,
201    ub: Option<i128>,
202    is_extensible: bool,
203    value: &String,
204    extended: bool,
205) -> Result<(), PerCodecError> {
206    log::trace!(
207        "encode_printable_string: lb: {:?}, ub: {:?}, is_extensible: {}, value: {}, extended: {}",
208        lb,
209        ub,
210        is_extensible,
211        value,
212        extended
213    );
214
215    encode_ascii_ish_string_common(data, lb, ub, is_extensible, value, extended)
216}
217
218/// Encode a UTF8String CharacterString Type.
219pub fn encode_utf8_string(
220    data: &mut PerCodecData,
221    lb: Option<i128>,
222    ub: Option<i128>,
223    is_extensible: bool,
224    value: &String,
225    extended: bool,
226) -> Result<(), PerCodecError> {
227    log::trace!(
228        "encode_utf8_string: lb: {:?}, ub: {:?}, is_extensible: {}, value: {}, extended: {}",
229        lb,
230        ub,
231        is_extensible,
232        value,
233        extended
234    );
235
236    encode_octet_string_common(
237        data,
238        lb,
239        ub,
240        is_extensible,
241        value.as_bytes(),
242        extended,
243        false,
244    )
245}
246
247/// Encode a UTF8String CharacterString Type.
248pub fn encode_utc_time(
249    data: &mut PerCodecData,
250    lb: Option<i128>,
251    ub: Option<i128>,
252    is_extensible: bool,
253    value: &String,
254    extended: bool,
255) -> Result<(), PerCodecError> {
256    log::trace!(
257        "encode_utc_time: lb: {:?}, ub: {:?}, is_extensible: {}, value: {}, extended: {}",
258        lb,
259        ub,
260        is_extensible,
261        value,
262        extended
263    );
264
265    encode_octet_string_common(
266        data,
267        lb,
268        ub,
269        is_extensible,
270        value.as_bytes(),
271        extended,
272        false,
273    )
274}
275
276// Common function used by PrintableString and VisibleString
277fn encode_ascii_ish_string_common(
278    data: &mut PerCodecData,
279    lb: Option<i128>,
280    ub: Option<i128>,
281    is_extensible: bool,
282    value: &String,
283    extended: bool,
284) -> Result<(), PerCodecError> {
285    if extended {
286        return Err(PerCodecError::new(
287            PerCodecErrorCause::EncodeNotSupported,
288            "Encode of extended octetstring not yet implemented",
289        ));
290    }
291
292    if is_extensible {
293        data.encode_bool(extended);
294    }
295
296    encode_length_determinent_common(data, lb, ub, false, value.len(), false)?;
297
298    // FIXME: bits_per_char is hardcoded it shold be obtained from the 'alphabet' of the string.
299    let bits_per_char = 7;
300    let offset = 8 - bits_per_char;
301    let chars_vec = value
302        .chars()
303        .map(|c| BitSlice::<_, Msb0>::from_element(&(c as u8))[offset..].to_bitvec())
304        .collect::<Vec<_>>()
305        .into_iter()
306        .flatten()
307        .collect::<BitVec<u8, Msb0>>();
308
309    data.append_bits(chars_vec.as_bitslice());
310
311    Ok(())
312}
313
314#[cfg(test)]
315mod tests {
316
317    use super::*;
318
319    #[test]
320    fn encode_bool_always_success() {
321        let mut data = PerCodecData::new_uper();
322
323        let result = encode_bool(&mut data, true);
324        assert!(result.is_ok());
325        assert_eq!(data.bits.len(), 1);
326        assert_eq!(data.bits[0], true);
327    }
328
329    #[test]
330    fn int_too_small() {
331        assert!(encode_integer(
332            &mut PerCodecData::new_uper(),
333            Some(1),
334            None,
335            false,
336            0,
337            false
338        )
339        .is_err());
340    }
341
342    #[test]
343    fn int_too_big() {
344        assert!(encode_integer(
345            &mut PerCodecData::new_uper(),
346            Some(-1),
347            Some(0),
348            false,
349            1,
350            false
351        )
352        .is_err());
353    }
354
355    #[test]
356    fn octetstring_too_small() {
357        assert!(encode_octetstring(
358            &mut PerCodecData::new_uper(),
359            Some(2),
360            None,
361            false,
362            &vec![0],
363            false
364        )
365        .is_err());
366    }
367    #[test]
368    fn octetstring_too_big() {
369        assert!(encode_octetstring(
370            &mut PerCodecData::new_uper(),
371            None,
372            Some(1),
373            false,
374            &vec![0, 0],
375            false
376        )
377        .is_err());
378    }
379
380    #[test]
381    fn string_too_small() {
382        assert!(encode_visible_string(
383            &mut PerCodecData::new_uper(),
384            Some(2),
385            None,
386            false,
387            &"a".to_string(),
388            false
389        )
390        .is_err());
391    }
392
393    #[test]
394    fn string_too_big() {
395        assert!(encode_visible_string(
396            &mut PerCodecData::new_uper(),
397            None,
398            Some(1),
399            false,
400            &"aa".to_string(),
401            false
402        )
403        .is_err());
404    }
405
406    #[test]
407    fn length_too_small() {
408        assert!(
409            encode_length_determinent(&mut PerCodecData::new_uper(), Some(2), None, false, 1,)
410                .is_err()
411        );
412    }
413    #[test]
414    fn length_too_big() {
415        assert!(
416            encode_length_determinent(&mut PerCodecData::new_uper(), None, Some(1), false, 2,)
417                .is_err()
418        );
419    }
420
421    #[test]
422    fn big_length_too_big() {
423        assert!(encode_length_determinent(
424            &mut PerCodecData::new_uper(),
425            None,
426            Some(65536),
427            false,
428            65537,
429        )
430        .is_err());
431    }
432
433    #[test]
434    fn bitstring_too_small() {
435        assert!(encode_bitstring(
436            &mut PerCodecData::new_uper(),
437            Some(2),
438            None,
439            false,
440            bits![u8, Msb0; 0],
441            false
442        )
443        .is_err());
444    }
445
446    #[test]
447    fn bitstring_too_big() {
448        assert!(encode_bitstring(
449            &mut PerCodecData::new_uper(),
450            None,
451            Some(1),
452            false,
453            bits![u8, Msb0; 0, 0],
454            false
455        )
456        .is_err());
457    }
458
459    #[test]
460    fn bitstring_uper_ascii_ish_string() {
461        // Taken from the example in x.691
462        let value = "John".to_string();
463        let mut codec_data = &mut PerCodecData::new_uper();
464        let result = encode_visible_string(&mut codec_data, None, None, false, &value, false);
465        assert!(result.is_ok(), "{:#?}", result.err().unwrap());
466    }
467}