asn1_rs/asn1_types/
real.rs

1use crate::*;
2use alloc::format;
3use core::convert::TryFrom;
4
5mod f32;
6mod f64;
7
8/// ASN.1 `REAL` type
9///
10/// # Limitations
11///
12/// When encoding binary values, only base 2 is supported
13#[derive(Debug, PartialEq)]
14pub enum Real {
15    /// Non-special values
16    Binary {
17        mantissa: f64,
18        base: u32,
19        exponent: i32,
20        enc_base: u8,
21    },
22    /// Infinity (∞).
23    Infinity,
24    /// Negative infinity (−∞).
25    NegInfinity,
26    /// Zero
27    Zero,
28}
29
30impl Real {
31    /// Create a new `REAL` from the `f64` value.
32    pub fn new(f: f64) -> Self {
33        if f.is_infinite() {
34            if f.is_sign_positive() {
35                Self::Infinity
36            } else {
37                Self::NegInfinity
38            }
39        } else if f.abs() == 0.0 {
40            Self::Zero
41        } else {
42            let mut e = 0;
43            let mut f = f;
44            while f.fract() != 0.0 {
45                f *= 10.0_f64;
46                e -= 1;
47            }
48            Real::Binary {
49                mantissa: f,
50                base: 10,
51                exponent: e,
52                enc_base: 10,
53            }
54            .normalize_base10()
55        }
56    }
57
58    pub const fn with_enc_base(self, enc_base: u8) -> Self {
59        match self {
60            Real::Binary {
61                mantissa,
62                base,
63                exponent,
64                ..
65            } => Real::Binary {
66                mantissa,
67                base,
68                exponent,
69                enc_base,
70            },
71            e => e,
72        }
73    }
74
75    fn normalize_base10(self) -> Self {
76        match self {
77            Real::Binary {
78                mantissa,
79                base: 10,
80                exponent,
81                enc_base: _enc_base,
82            } => {
83                let mut m = mantissa;
84                let mut e = exponent;
85                while m.abs() > f64::EPSILON && m.rem_euclid(10.0).abs() < f64::EPSILON {
86                    m /= 10.0;
87                    e += 1;
88                }
89                Real::Binary {
90                    mantissa: m,
91                    base: 10,
92                    exponent: e,
93                    enc_base: _enc_base,
94                }
95            }
96            _ => self,
97        }
98    }
99
100    /// Create a new binary `REAL`
101    #[inline]
102    pub const fn binary(mantissa: f64, base: u32, exponent: i32) -> Self {
103        Self::Binary {
104            mantissa,
105            base,
106            exponent,
107            enc_base: 2,
108        }
109    }
110
111    /// Returns `true` if this value is positive infinity or negative infinity, and
112    /// `false` otherwise.
113    #[inline]
114    pub fn is_infinite(&self) -> bool {
115        matches!(self, Real::Infinity | Real::NegInfinity)
116    }
117
118    /// Returns `true` if this number is not infinite.
119    #[inline]
120    pub fn is_finite(&self) -> bool {
121        matches!(self, Real::Zero | Real::Binary { .. })
122    }
123
124    /// Returns the 'f64' value of this `REAL`.
125    ///
126    /// Returned value is a float, and may be infinite.
127    pub fn f64(&self) -> f64 {
128        match self {
129            Real::Binary {
130                mantissa,
131                base,
132                exponent,
133                ..
134            } => {
135                let f = mantissa;
136                let exp = (*base as f64).powi(*exponent);
137                f * exp
138            }
139            Real::Zero => 0.0_f64,
140            Real::Infinity => f64::INFINITY,
141            Real::NegInfinity => f64::NEG_INFINITY,
142        }
143    }
144
145    /// Returns the 'f32' value of this `REAL`.
146    ///
147    /// This functions casts the result of [`Real::f64`] to a `f32`, and loses precision.
148    pub fn f32(&self) -> f32 {
149        self.f64() as f32
150    }
151}
152
153impl<'a> TryFrom<Any<'a>> for Real {
154    type Error = Error;
155
156    fn try_from(any: Any<'a>) -> Result<Self> {
157        TryFrom::try_from(&any)
158    }
159}
160
161impl<'a, 'b> TryFrom<&'b Any<'a>> for Real {
162    type Error = Error;
163
164    fn try_from(any: &'b Any<'a>) -> Result<Self> {
165        any.tag().assert_eq(Self::TAG)?;
166        any.header.assert_primitive()?;
167        let data = &any.data;
168        if data.is_empty() {
169            return Ok(Real::Zero);
170        }
171        // code inspired from pyasn1
172        let first = data[0];
173        let rem = &data[1..];
174        if first & 0x80 != 0 {
175            // binary encoding (X.690 section 8.5.6)
176            // format of exponent
177            let (n, rem) = match first & 0x03 {
178                4 => {
179                    let (b, rem) = rem
180                        .split_first()
181                        .ok_or_else(|| Error::Incomplete(Needed::new(1)))?;
182                    (*b as usize, rem)
183                }
184                b => (b as usize + 1, rem),
185            };
186            if n >= rem.len() {
187                return Err(any.tag().invalid_value("Invalid float value(exponent)"));
188            }
189            // n cannot be 0 (see the +1 above)
190            let (eo, rem) = rem.split_at(n);
191            // so 'eo' cannot be empty
192            let mut e = if eo[0] & 0x80 != 0 { -1 } else { 0 };
193            // safety check: 'eo' length must be <= container type for 'e'
194            if eo.len() > 4 {
195                return Err(any.tag().invalid_value("Exponent too large (REAL)"));
196            }
197            for b in eo {
198                e = (e << 8) | (*b as i32);
199            }
200            // base bits
201            let b = (first >> 4) & 0x03;
202            let _enc_base = match b {
203                0 => 2,
204                1 => 8,
205                2 => 16,
206                _ => return Err(any.tag().invalid_value("Illegal REAL encoding base")),
207            };
208            let e = match b {
209                // base 2
210                0 => e,
211                // base 8
212                1 => e * 3,
213                // base 16
214                2 => e * 4,
215                _ => return Err(any.tag().invalid_value("Illegal REAL base")),
216            };
217            if rem.len() > 8 {
218                return Err(any.tag().invalid_value("Mantissa too large (REAL)"));
219            }
220            let mut p = 0;
221            for b in rem {
222                p = (p << 8) | (*b as i64);
223            }
224            // sign bit
225            let p = if first & 0x40 != 0 { -p } else { p };
226            // scale bits
227            let sf = (first >> 2) & 0x03;
228            let p = match sf {
229                0 => p as f64,
230                sf => {
231                    // 2^sf: cannot overflow, sf is between 0 and 3
232                    let scale = 2_f64.powi(sf as _);
233                    (p as f64) * scale
234                }
235            };
236            Ok(Real::Binary {
237                mantissa: p,
238                base: 2,
239                exponent: e,
240                enc_base: _enc_base,
241            })
242        } else if first & 0x40 != 0 {
243            // special real value (X.690 section 8.5.8)
244            // there shall be only one contents octet,
245            if any.header.length != Length::Definite(1) {
246                return Err(Error::InvalidLength);
247            }
248            // with values as follows
249            match first {
250                0x40 => Ok(Real::Infinity),
251                0x41 => Ok(Real::NegInfinity),
252                _ => Err(any.tag().invalid_value("Invalid float special value")),
253            }
254        } else {
255            // decimal encoding (X.690 section 8.5.7)
256            let s = alloc::str::from_utf8(rem)?;
257            match first & 0x03 {
258                0x1 => {
259                    // NR1
260                    match s.parse::<u32>() {
261                        Err(_) => Err(any.tag().invalid_value("Invalid float string encoding")),
262                        Ok(v) => Ok(Real::new(v.into())),
263                    }
264                }
265                0x2 /* NR2 */ | 0x3 /* NR3 */=> {
266                    match s.parse::<f64>() {
267                        Err(_) => Err(any.tag().invalid_value("Invalid float string encoding")),
268                        Ok(v) => Ok(Real::new(v)),
269                    }
270                        }
271                c => {
272                    Err(any.tag().invalid_value(&format!("Invalid NR ({})", c)))
273                }
274            }
275        }
276    }
277}
278
279impl CheckDerConstraints for Real {
280    fn check_constraints(any: &Any) -> Result<()> {
281        any.header.assert_primitive()?;
282        any.header.length.assert_definite()?;
283        // XXX more checks
284        Ok(())
285    }
286}
287
288impl DerAutoDerive for Real {}
289
290impl Tagged for Real {
291    const TAG: Tag = Tag::RealType;
292}
293
294#[cfg(feature = "std")]
295impl ToDer for Real {
296    fn to_der_len(&self) -> Result<usize> {
297        match self {
298            Real::Zero => Ok(0),
299            Real::Infinity | Real::NegInfinity => Ok(1),
300            Real::Binary { .. } => {
301                let mut sink = std::io::sink();
302                let n = self
303                    .write_der_content(&mut sink)
304                    .map_err(|_| Self::TAG.invalid_value("Serialization of REAL failed"))?;
305                Ok(n)
306            }
307        }
308    }
309
310    fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
311        let header = Header::new(
312            Class::Universal,
313            false,
314            Self::TAG,
315            Length::Definite(self.to_der_len()?),
316        );
317        header.write_der_header(writer).map_err(Into::into)
318    }
319
320    fn write_der_content(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
321        match self {
322            Real::Zero => Ok(0),
323            Real::Infinity => writer.write(&[0x40]).map_err(Into::into),
324            Real::NegInfinity => writer.write(&[0x41]).map_err(Into::into),
325            Real::Binary {
326                mantissa,
327                base,
328                exponent,
329                enc_base: _enc_base,
330            } => {
331                if *base == 10 {
332                    // using character form
333                    let sign = if *exponent == 0 { "+" } else { "" };
334                    let s = format!("\x03{}E{}{}", mantissa, sign, exponent);
335                    return writer.write(s.as_bytes()).map_err(Into::into);
336                }
337                if *base != 2 {
338                    return Err(Self::TAG.invalid_value("Invalid base for REAL").into());
339                }
340                let mut first: u8 = 0x80;
341                // choose encoding base
342                let enc_base = *_enc_base;
343                let (ms, mut m, enc_base, mut e) =
344                    drop_floating_point(*mantissa, enc_base, *exponent);
345                assert!(m != 0);
346                if ms < 0 {
347                    first |= 0x40
348                };
349                // exponent & mantissa normalization
350                match enc_base {
351                    2 => {
352                        while m & 0x1 == 0 {
353                            m >>= 1;
354                            e += 1;
355                        }
356                    }
357                    8 => {
358                        while m & 0x7 == 0 {
359                            m >>= 3;
360                            e += 1;
361                        }
362                        first |= 0x10;
363                    }
364                    _ /* 16 */ => {
365                        while m & 0xf == 0 {
366                            m >>= 4;
367                            e += 1;
368                        }
369                        first |= 0x20;
370                    }
371                }
372                // scale factor
373                // XXX in DER, sf is always 0 (11.3.1)
374                let mut sf = 0;
375                while m & 0x1 == 0 && sf < 4 {
376                    m >>= 1;
377                    sf += 1;
378                }
379                first |= sf << 2;
380                // exponent length and bytes
381                let len_e = match e.abs() {
382                    0..=0xff => 1,
383                    0x100..=0xffff => 2,
384                    0x1_0000..=0xff_ffff => 3,
385                    // e is an `i32` so it can't be longer than 4 bytes
386                    // use 4, so `first` is ORed with 3
387                    _ => 4,
388                };
389                first |= (len_e - 1) & 0x3;
390                // write first byte
391                let mut n = writer.write(&[first])?;
392                // write exponent
393                // special case: number of bytes from exponent is > 3 and cannot fit in 2 bits
394                #[allow(clippy::identity_op)]
395                if len_e == 4 {
396                    let b = len_e & 0xff;
397                    n += writer.write(&[b])?;
398                }
399                // we only need to write e.len() bytes
400                let bytes = e.to_be_bytes();
401                n += writer.write(&bytes[(4 - len_e) as usize..])?;
402                // write mantissa
403                let bytes = m.to_be_bytes();
404                let mut idx = 0;
405                for &b in bytes.iter() {
406                    if b != 0 {
407                        break;
408                    }
409                    idx += 1;
410                }
411                n += writer.write(&bytes[idx..])?;
412                Ok(n)
413            }
414        }
415    }
416}
417
418impl From<f32> for Real {
419    fn from(f: f32) -> Self {
420        Real::new(f.into())
421    }
422}
423
424impl From<f64> for Real {
425    fn from(f: f64) -> Self {
426        Real::new(f)
427    }
428}
429
430impl From<Real> for f32 {
431    fn from(r: Real) -> Self {
432        r.f32()
433    }
434}
435
436impl From<Real> for f64 {
437    fn from(r: Real) -> Self {
438        r.f64()
439    }
440}
441
442#[cfg(feature = "std")]
443fn drop_floating_point(m: f64, b: u8, e: i32) -> (i8, u64, u8, i32) {
444    let ms = if m.is_sign_positive() { 1 } else { -1 };
445    let es = if e.is_positive() { 1 } else { -1 };
446    let mut m = m.abs();
447    let mut e = e;
448    //
449    if b == 8 {
450        m *= 2_f64.powi((e.abs() / 3) * es);
451        e = (e.abs() / 3) * es;
452    } else if b == 16 {
453        m *= 2_f64.powi((e.abs() / 4) * es);
454        e = (e.abs() / 4) * es;
455    }
456    //
457    while m.abs() > f64::EPSILON {
458        if m.fract() != 0.0 {
459            m *= b as f64;
460            e -= 1;
461        } else {
462            break;
463        }
464    }
465    (ms, m as u64, b, e)
466}