1use crate::error::{GlowError, Result};
4use crate::ber::{BerReader, Tag};
5use crate::glow::{
6 GlowRoot, GlowElement, GlowNode, GlowParameter, GlowFunction,
7 GlowMatrix, GlowConnection, GlowCommand, GlowTemplate,
8 InvocationResult, StreamEntry, EmberPath, EmberValue,
9 ParameterType, ParameterAccess, MatrixType,
10 MatrixAddressingMode, ConnectionOperation, ConnectionDisposition,
11};
12
13pub struct GlowDecoder;
15
16impl GlowDecoder {
17 pub fn decode(data: &[u8]) -> Result<GlowRoot> {
19 if data.is_empty() {
20 return Ok(GlowRoot::new());
21 }
22
23 let mut reader = BerReader::new(data);
24 Self::decode_root(&mut reader)
25 }
26
27 fn decode_root(reader: &mut BerReader) -> Result<GlowRoot> {
29 let mut root = GlowRoot::new();
30
31 let tag = reader.peek_tag()?;
32
33 if tag.is_application() && tag.number == 0 {
35 let mut inner = reader.read_application(0)?;
36
37 while inner.has_more() {
38 let child_tag = inner.peek_tag()?;
39
40 if child_tag.is_application() {
41 match child_tag.number {
42 11 => {
43 let mut coll = inner.read_application(11)?;
45 while coll.has_more() {
46 if let Some(element) = Self::decode_element(&mut coll)? {
47 root.elements.push(element);
48 }
49 }
50 }
51 4 => {
52 let mut coll = inner.read_application(4)?;
54 while coll.has_more() {
55 if let Some(element) = Self::decode_element(&mut coll)? {
56 root.elements.push(element);
57 }
58 }
59 }
60 6 => {
61 let mut coll = inner.read_application(6)?;
63 while coll.has_more() {
64 if let Some(entry) = Self::decode_stream_entry(&mut coll)? {
65 root.streams.push(entry);
66 }
67 }
68 }
69 23 => {
70 if let Some(result) = Self::decode_invocation_result(&mut inner)? {
72 root.invocation_results.push(result);
73 }
74 }
75 _ => {
76 if let Some(element) = Self::decode_element(&mut inner)? {
78 root.elements.push(element);
79 }
80 }
81 }
82 } else {
83 inner.skip()?;
84 }
85 }
86 } else {
87 while reader.has_more() {
89 if let Some(element) = Self::decode_element(reader)? {
90 root.elements.push(element);
91 }
92 }
93 }
94
95 Ok(root)
96 }
97
98 fn decode_element(reader: &mut BerReader) -> Result<Option<GlowElement>> {
100 if !reader.has_more() {
101 return Ok(None);
102 }
103
104 let tag = reader.peek_tag()?;
105
106 if tag.is_context() {
108 let mut inner = reader.read_context(tag.number)?;
109 if inner.has_more() {
111 return Self::decode_element(&mut inner);
112 }
113 return Ok(None);
114 }
115
116 if !tag.is_application() {
117 reader.skip()?;
118 return Ok(None);
119 }
120
121 match tag.number {
122 1 => Ok(Some(Self::decode_parameter(reader)?)),
123 2 => Ok(Some(Self::decode_command(reader)?)),
124 3 => Ok(Some(Self::decode_node(reader)?)),
125 9 => Ok(Some(Self::decode_qualified_parameter(reader)?)),
126 10 => Ok(Some(Self::decode_qualified_node(reader)?)),
127 13 => Ok(Some(Self::decode_matrix(reader)?)),
128 17 => Ok(Some(Self::decode_qualified_matrix(reader)?)),
129 19 => Ok(Some(Self::decode_function(reader)?)),
130 20 => Ok(Some(Self::decode_qualified_function(reader)?)),
131 24 => Ok(Some(Self::decode_template(reader)?)),
132 _ => {
133 reader.skip()?;
134 Ok(None)
135 }
136 }
137 }
138
139 fn decode_node(reader: &mut BerReader) -> Result<GlowElement> {
141 let mut inner = reader.read_application(3)?;
142 let mut node = GlowNode::new(0);
143
144 while inner.has_more() {
145 let tag = inner.peek_tag()?;
146
147 if tag.is_context() {
148 match tag.number {
149 0 => {
150 node.number = inner.read_context_integer(0)? as i32;
151 }
152 1 => {
153 let mut contents = inner.read_context(1)?;
154 Self::decode_node_contents(&mut contents, &mut node)?;
155 }
156 2 => {
157 let mut children_ctx = inner.read_context(2)?;
158 if children_ctx.has_more() {
159 let child_tag = children_ctx.peek_tag()?;
160 if child_tag.is_application() && child_tag.number == 4 {
161 let mut coll = children_ctx.read_application(4)?;
162 while coll.has_more() {
163 if let Some(child) = Self::decode_element(&mut coll)? {
164 node.children.push(child);
165 }
166 }
167 }
168 }
169 }
170 _ => { inner.skip()?; }
171 }
172 } else {
173 inner.skip()?;
174 }
175 }
176
177 Ok(GlowElement::Node(node))
178 }
179
180 fn decode_node_contents(reader: &mut BerReader, node: &mut GlowNode) -> Result<()> {
182 let tag = reader.peek_tag()?;
184 if tag.is_universal() && (tag.number == 17 || tag.number == 16) {
185 let (_, value) = reader.read_tlv()?;
187 let mut inner = BerReader::new(value);
188 Self::decode_node_contents_inner(&mut inner, node)?;
189 } else {
190 Self::decode_node_contents_inner(reader, node)?;
192 }
193 Ok(())
194 }
195
196 fn decode_node_contents_inner(reader: &mut BerReader, node: &mut GlowNode) -> Result<()> {
198 while reader.has_more() {
199 let tag = reader.peek_tag()?;
200
201 if tag.is_context() {
202 match tag.number {
203 0 => node.identifier = Some(Self::read_context_string(reader, 0)?),
204 1 => node.description = Some(Self::read_context_string(reader, 1)?),
205 2 => node.is_root = Some(Self::read_context_bool(reader, 2)?),
206 3 => node.is_online = Some(Self::read_context_bool(reader, 3)?),
207 4 => node.schema_identifiers = Some(Self::read_context_string(reader, 4)?),
208 _ => { reader.skip()?; }
209 }
210 } else {
211 reader.skip()?;
212 }
213 }
214 Ok(())
215 }
216
217 fn decode_parameter(reader: &mut BerReader) -> Result<GlowElement> {
219 let mut inner = reader.read_application(1)?;
220 let mut param = GlowParameter::new(0);
221
222 while inner.has_more() {
223 let tag = inner.peek_tag()?;
224
225 if tag.is_context() {
226 match tag.number {
227 0 => {
228 param.number = inner.read_context_integer(0)? as i32;
229 }
230 1 => {
231 let mut contents = inner.read_context(1)?;
232 Self::decode_parameter_contents(&mut contents, &mut param)?;
233 }
234 2 => {
235 let mut children_ctx = inner.read_context(2)?;
236 if children_ctx.has_more() {
237 let child_tag = children_ctx.peek_tag()?;
238 if child_tag.is_application() && child_tag.number == 4 {
239 let mut coll = children_ctx.read_application(4)?;
240 while coll.has_more() {
241 if let Some(child) = Self::decode_element(&mut coll)? {
242 param.children.push(child);
243 }
244 }
245 }
246 }
247 }
248 _ => { inner.skip()?; }
249 }
250 } else {
251 inner.skip()?;
252 }
253 }
254
255 Ok(GlowElement::Parameter(param))
256 }
257
258 fn decode_parameter_contents(reader: &mut BerReader, param: &mut GlowParameter) -> Result<()> {
260 while reader.has_more() {
261 let tag = reader.peek_tag()?;
262
263 if tag.is_context() {
264 match tag.number {
265 0 => param.identifier = Some(Self::read_context_string(reader, 0)?),
266 1 => param.description = Some(Self::read_context_string(reader, 1)?),
267 2 => param.value = Some(Self::read_context_value(reader, 2)?),
268 3 => param.minimum = Some(Self::read_context_value(reader, 3)?),
269 4 => param.maximum = Some(Self::read_context_value(reader, 4)?),
270 5 => param.access = Some(ParameterAccess::try_from(reader.read_context_integer(5)?)?),
271 6 => param.format = Some(Self::read_context_string(reader, 6)?),
272 7 => param.enumeration = Some(Self::read_context_string(reader, 7)?),
273 8 => param.factor = Some(reader.read_context_integer(8)? as i32),
274 9 => param.is_online = Some(Self::read_context_bool(reader, 9)?),
275 10 => param.formula = Some(Self::read_context_string(reader, 10)?),
276 11 => param.step = Some(reader.read_context_integer(11)? as i32),
277 12 => param.default = Some(Self::read_context_value(reader, 12)?),
278 13 => param.parameter_type = Some(ParameterType::try_from(reader.read_context_integer(13)?)?),
279 14 => param.stream_identifier = Some(reader.read_context_integer(14)? as i32),
280 _ => { reader.skip()?; }
281 }
282 } else {
283 reader.skip()?;
284 }
285 }
286 Ok(())
287 }
288
289 fn decode_function(reader: &mut BerReader) -> Result<GlowElement> {
291 let mut inner = reader.read_application(19)?;
292 let mut func = GlowFunction::new(0);
293
294 while inner.has_more() {
295 let tag = inner.peek_tag()?;
296
297 if tag.is_context() {
298 match tag.number {
299 0 => func.number = inner.read_context_integer(0)? as i32,
300 1 => {
301 let mut contents = inner.read_context(1)?;
302 while contents.has_more() {
303 let ctag = contents.peek_tag()?;
304 if ctag.is_context() {
305 match ctag.number {
306 0 => func.identifier = Some(Self::read_context_string(&mut contents, 0)?),
307 1 => func.description = Some(Self::read_context_string(&mut contents, 1)?),
308 _ => { contents.skip()?; }
309 }
310 } else {
311 contents.skip()?;
312 }
313 }
314 }
315 _ => { inner.skip()?; }
316 }
317 } else {
318 inner.skip()?;
319 }
320 }
321
322 Ok(GlowElement::Function(func))
323 }
324
325 fn decode_matrix(reader: &mut BerReader) -> Result<GlowElement> {
327 let mut inner = reader.read_application(13)?;
328 let mut matrix = GlowMatrix::new(0);
329
330 while inner.has_more() {
331 let tag = inner.peek_tag()?;
332
333 if tag.is_context() {
334 match tag.number {
335 0 => matrix.number = inner.read_context_integer(0)? as i32,
336 1 => {
337 let mut contents = inner.read_context(1)?;
338 Self::decode_matrix_contents(&mut contents, &mut matrix)?;
339 }
340 5 => {
341 let mut conns = inner.read_context(5)?;
342 while conns.has_more() {
343 if let Some(conn) = Self::decode_connection(&mut conns)? {
344 matrix.connections.push(conn);
345 }
346 }
347 }
348 _ => { inner.skip()?; }
349 }
350 } else {
351 inner.skip()?;
352 }
353 }
354
355 Ok(GlowElement::Matrix(matrix))
356 }
357
358 fn decode_matrix_contents(reader: &mut BerReader, matrix: &mut GlowMatrix) -> Result<()> {
360 while reader.has_more() {
361 let tag = reader.peek_tag()?;
362
363 if tag.is_context() {
364 match tag.number {
365 0 => matrix.identifier = Some(Self::read_context_string(reader, 0)?),
366 1 => matrix.description = Some(Self::read_context_string(reader, 1)?),
367 2 => matrix.matrix_type = Some(MatrixType::try_from(reader.read_context_integer(2)?)?),
368 3 => matrix.addressing_mode = Some(MatrixAddressingMode::try_from(reader.read_context_integer(3)?)?),
369 4 => matrix.target_count = Some(reader.read_context_integer(4)? as i32),
370 5 => matrix.source_count = Some(reader.read_context_integer(5)? as i32),
371 6 => matrix.max_connections_per_target = Some(reader.read_context_integer(6)? as i32),
372 7 => matrix.max_total_connections = Some(reader.read_context_integer(7)? as i32),
373 _ => { reader.skip()?; }
374 }
375 } else {
376 reader.skip()?;
377 }
378 }
379 Ok(())
380 }
381
382 fn decode_connection(reader: &mut BerReader) -> Result<Option<GlowConnection>> {
384 let tag = reader.peek_tag()?;
385 if !tag.is_application() || tag.number != 16 {
386 reader.skip()?;
387 return Ok(None);
388 }
389
390 let mut inner = reader.read_application(16)?;
391 let mut conn = GlowConnection::default();
392
393 while inner.has_more() {
394 let ctag = inner.peek_tag()?;
395 if ctag.is_context() {
396 match ctag.number {
397 0 => conn.target = inner.read_context_integer(0)? as i32,
398 1 => {
399 let mut sources = inner.read_context(1)?;
400 while sources.has_more() {
401 conn.sources.push(sources.read_integer()? as i32);
402 }
403 }
404 2 => conn.operation = Some(ConnectionOperation::try_from(inner.read_context_integer(2)?)?),
405 3 => conn.disposition = Some(ConnectionDisposition::try_from(inner.read_context_integer(3)?)?),
406 _ => { inner.skip()?; }
407 }
408 } else {
409 inner.skip()?;
410 }
411 }
412
413 Ok(Some(conn))
414 }
415
416 fn decode_command(reader: &mut BerReader) -> Result<GlowElement> {
418 let mut inner = reader.read_application(2)?;
419 let mut cmd_number = 0i32;
420 let mut invocation_id = 0i32;
421 let mut arguments = Vec::new();
422
423 while inner.has_more() {
424 let tag = inner.peek_tag()?;
425
426 if tag.is_context() {
427 match tag.number {
428 0 => cmd_number = inner.read_context_integer(0)? as i32,
429 2 => {
430 let mut inv = inner.read_context(2)?;
431 while inv.has_more() {
432 let itag = inv.peek_tag()?;
433 if itag.is_context() {
434 match itag.number {
435 0 => invocation_id = inv.read_context_integer(0)? as i32,
436 1 => {
437 let mut args = inv.read_context(1)?;
438 while args.has_more() {
439 arguments.push(Self::decode_value(&mut args)?);
440 }
441 }
442 _ => { inv.skip()?; }
443 }
444 } else {
445 inv.skip()?;
446 }
447 }
448 }
449 _ => { inner.skip()?; }
450 }
451 } else {
452 inner.skip()?;
453 }
454 }
455
456 let command = match cmd_number {
457 1 => GlowCommand::Subscribe,
458 2 => GlowCommand::Unsubscribe,
459 32 => GlowCommand::GetDirectory,
460 33 => GlowCommand::Invoke { invocation_id, arguments },
461 _ => GlowCommand::GetDirectory, };
463
464 Ok(GlowElement::Command(command))
465 }
466
467 fn decode_qualified_node(reader: &mut BerReader) -> Result<GlowElement> {
469 let mut inner = reader.read_application(10)?;
470 let mut path = Vec::new();
471 let mut node = GlowNode::new(0);
472
473 while inner.has_more() {
474 let tag = inner.peek_tag()?;
475
476 if tag.is_context() {
477 match tag.number {
478 0 => path = Self::read_context_path(&mut inner, 0)?,
479 1 => {
480 let mut contents = inner.read_context(1)?;
481 Self::decode_node_contents(&mut contents, &mut node)?;
482 }
483 2 => {
484 let mut children_ctx = inner.read_context(2)?;
485 if children_ctx.has_more() {
486 let child_tag = children_ctx.peek_tag()?;
487 if child_tag.is_application() && child_tag.number == 4 {
488 let mut coll = children_ctx.read_application(4)?;
489 while coll.has_more() {
490 if let Some(child) = Self::decode_element(&mut coll)? {
491 node.children.push(child);
492 }
493 }
494 }
495 }
496 }
497 _ => { inner.skip()?; }
498 }
499 } else {
500 inner.skip()?;
501 }
502 }
503
504 if let Some(&last) = path.last() {
505 node.number = last;
506 }
507
508 Ok(GlowElement::QualifiedNode(path, node))
509 }
510
511 fn decode_qualified_parameter(reader: &mut BerReader) -> Result<GlowElement> {
513 let mut inner = reader.read_application(9)?;
514 let mut path = Vec::new();
515 let mut param = GlowParameter::new(0);
516
517 while inner.has_more() {
518 let tag = inner.peek_tag()?;
519
520 if tag.is_context() {
521 match tag.number {
522 0 => path = Self::read_context_path(&mut inner, 0)?,
523 1 => {
524 let mut contents = inner.read_context(1)?;
525 Self::decode_parameter_contents(&mut contents, &mut param)?;
526 }
527 _ => { inner.skip()?; }
528 }
529 } else {
530 inner.skip()?;
531 }
532 }
533
534 if let Some(&last) = path.last() {
535 param.number = last;
536 }
537
538 Ok(GlowElement::QualifiedParameter(path, param))
539 }
540
541 fn decode_qualified_function(reader: &mut BerReader) -> Result<GlowElement> {
543 let mut inner = reader.read_application(20)?;
544 let mut path = Vec::new();
545 let mut func = GlowFunction::new(0);
546
547 while inner.has_more() {
548 let tag = inner.peek_tag()?;
549
550 if tag.is_context() {
551 match tag.number {
552 0 => path = Self::read_context_path(&mut inner, 0)?,
553 1 => {
554 let mut contents = inner.read_context(1)?;
555 while contents.has_more() {
556 let ctag = contents.peek_tag()?;
557 if ctag.is_context() {
558 match ctag.number {
559 0 => func.identifier = Some(Self::read_context_string(&mut contents, 0)?),
560 1 => func.description = Some(Self::read_context_string(&mut contents, 1)?),
561 _ => { contents.skip()?; }
562 }
563 } else {
564 contents.skip()?;
565 }
566 }
567 }
568 _ => { inner.skip()?; }
569 }
570 } else {
571 inner.skip()?;
572 }
573 }
574
575 if let Some(&last) = path.last() {
576 func.number = last;
577 }
578
579 Ok(GlowElement::QualifiedFunction(path, func))
580 }
581
582 fn decode_qualified_matrix(reader: &mut BerReader) -> Result<GlowElement> {
584 let mut inner = reader.read_application(17)?;
585 let mut path = Vec::new();
586 let mut matrix = GlowMatrix::new(0);
587
588 while inner.has_more() {
589 let tag = inner.peek_tag()?;
590
591 if tag.is_context() {
592 match tag.number {
593 0 => path = Self::read_context_path(&mut inner, 0)?,
594 1 => {
595 let mut contents = inner.read_context(1)?;
596 Self::decode_matrix_contents(&mut contents, &mut matrix)?;
597 }
598 _ => { inner.skip()?; }
599 }
600 } else {
601 inner.skip()?;
602 }
603 }
604
605 if let Some(&last) = path.last() {
606 matrix.number = last;
607 }
608
609 Ok(GlowElement::QualifiedMatrix(path, matrix))
610 }
611
612 fn decode_template(reader: &mut BerReader) -> Result<GlowElement> {
614 let mut inner = reader.read_application(24)?;
615 let mut template = GlowTemplate::default();
616
617 while inner.has_more() {
618 let tag = inner.peek_tag()?;
619
620 if tag.is_context() {
621 match tag.number {
622 0 => template.number = inner.read_context_integer(0)? as i32,
623 2 => template.description = Some(Self::read_context_string(&mut inner, 2)?),
624 _ => { inner.skip()?; }
625 }
626 } else {
627 inner.skip()?;
628 }
629 }
630
631 Ok(GlowElement::Template(template))
632 }
633
634 fn decode_invocation_result(reader: &mut BerReader) -> Result<Option<InvocationResult>> {
636 let mut inner = reader.read_application(23)?;
637 let mut invocation_id = 0;
638 let mut success = false;
639 let mut result = Vec::new();
640
641 while inner.has_more() {
642 let tag = inner.peek_tag()?;
643
644 if tag.is_context() {
645 match tag.number {
646 0 => invocation_id = inner.read_context_integer(0)? as i32,
647 1 => success = Self::read_context_bool(&mut inner, 1)?,
648 2 => {
649 let mut res = inner.read_context(2)?;
650 while res.has_more() {
651 result.push(Self::decode_value(&mut res)?);
652 }
653 }
654 _ => { inner.skip()?; }
655 }
656 } else {
657 inner.skip()?;
658 }
659 }
660
661 Ok(Some(InvocationResult { invocation_id, success, result }))
662 }
663
664 fn decode_stream_entry(reader: &mut BerReader) -> Result<Option<StreamEntry>> {
666 let tag = reader.peek_tag()?;
667 if !tag.is_application() || tag.number != 5 {
668 reader.skip()?;
669 return Ok(None);
670 }
671
672 let mut inner = reader.read_application(5)?;
673 let mut stream_identifier = 0;
674 let mut value = EmberValue::Null;
675
676 while inner.has_more() {
677 let ctag = inner.peek_tag()?;
678 if ctag.is_context() {
679 match ctag.number {
680 0 => stream_identifier = inner.read_context_integer(0)? as i32,
681 1 => value = Self::read_context_value(&mut inner, 1)?,
682 _ => { inner.skip()?; }
683 }
684 } else {
685 inner.skip()?;
686 }
687 }
688
689 Ok(Some(StreamEntry { stream_identifier, value }))
690 }
691
692 fn read_context_string(reader: &mut BerReader, _tag: u32) -> Result<String> {
694 let (_, data) = reader.read_tlv()?;
695 if data.len() >= 2 {
698 let mut inner = BerReader::new(data);
699 let (inner_tag, inner_data) = inner.read_tlv()?;
700 if inner_tag.is_universal() {
702 return Ok(String::from_utf8_lossy(inner_data).to_string());
703 }
704 }
705 Ok(String::from_utf8_lossy(data).to_string())
707 }
708
709 fn read_context_bool(reader: &mut BerReader, _tag: u32) -> Result<bool> {
711 let (_, data) = reader.read_tlv()?;
712 Ok(data.first().map(|&b| b != 0).unwrap_or(false))
713 }
714
715 fn read_context_path(reader: &mut BerReader, _tag: u32) -> Result<EmberPath> {
717 let mut ctx = reader.read_context(0)?;
718 let oid = ctx.read_relative_oid()?;
719 Ok(oid.into_iter().map(|n| n as i32).collect())
720 }
721
722 fn read_context_value(reader: &mut BerReader, _tag: u32) -> Result<EmberValue> {
724 let mut ctx = reader.read_context(_tag)?;
725 Self::decode_value(&mut ctx)
726 }
727
728 fn decode_value(reader: &mut BerReader) -> Result<EmberValue> {
730 let (tag, data) = reader.read_tlv()?;
731
732 if tag.is_universal() {
733 match tag.number {
734 1 => Ok(EmberValue::Boolean(data.first().map(|&b| b != 0).unwrap_or(false))),
735 2 => {
736 let value = Self::decode_integer(data)?;
737 Ok(EmberValue::Integer(value))
738 }
739 4 => Ok(EmberValue::Octets(data.to_vec())),
740 5 => Ok(EmberValue::Null),
741 9 => {
742 let value = Self::decode_real(data)?;
743 Ok(EmberValue::Real(value))
744 }
745 12 => Ok(EmberValue::String(String::from_utf8_lossy(data).to_string())),
746 _ => Ok(EmberValue::Null),
747 }
748 } else {
749 Ok(EmberValue::Octets(data.to_vec()))
750 }
751 }
752
753 fn decode_integer(data: &[u8]) -> Result<i64> {
755 if data.is_empty() {
756 return Ok(0);
757 }
758
759 let negative = (data[0] & 0x80) != 0;
760 let mut result: i64 = if negative { -1 } else { 0 };
761
762 for &byte in data {
763 result = (result << 8) | (byte as i64);
764 }
765
766 Ok(result)
767 }
768
769 fn decode_real(data: &[u8]) -> Result<f64> {
771 if data.is_empty() {
772 return Ok(0.0);
773 }
774
775 let first = data[0];
776
777 if first == 0x40 { return Ok(f64::INFINITY); }
778 if first == 0x41 { return Ok(f64::NEG_INFINITY); }
779 if first == 0x42 { return Ok(f64::NAN); }
780 if first == 0x43 { return Ok(-0.0); }
781
782 if (first & 0x80) != 0 {
784 let sign = if (first & 0x40) != 0 { -1.0 } else { 1.0 };
785 let exp_len = match first & 0x03 {
786 0 => 1, 1 => 2, 2 => 3,
787 _ => data.get(1).copied().unwrap_or(0) as usize,
788 };
789 let exp_start = if (first & 0x03) == 3 { 2 } else { 1 };
790
791 if data.len() < exp_start + exp_len {
792 return Ok(0.0);
793 }
794
795 let exp_bytes = &data[exp_start..exp_start + exp_len];
796 let mut exp: i64 = if !exp_bytes.is_empty() && (exp_bytes[0] & 0x80) != 0 { -1 } else { 0 };
797 for &b in exp_bytes { exp = (exp << 8) | (b as i64); }
798
799 let mant_bytes = &data[exp_start + exp_len..];
800 let mut mant: u64 = 0;
801 for &b in mant_bytes { mant = (mant << 8) | (b as u64); }
802
803 return Ok(sign * (mant as f64) * 2.0_f64.powi(exp as i32));
804 }
805
806 Ok(0.0)
807 }
808}