nrbf_parser/
decoder.rs

1// nrbf-parser - A high-performance MS-NRBF binary parser and encoder.
2// Copyright (C) 2026  driedpampas@proton.me
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17use crate::error::{Error, Result};
18use crate::records::*;
19use std::collections::HashMap;
20use std::io::Read;
21
22/// A decoder for MS-NRBF binary streams.
23pub struct Decoder<R: Read> {
24    reader: R,
25    metadata_registry: HashMap<i32, ClassInfoWithTypes>,
26    /// Registry of libraries by ID.
27    pub library_registry: HashMap<i32, String>,
28    /// Current offset in the stream.
29    pub offset: usize,
30}
31
32/// Metadata for a class including its types if available.
33#[derive(Clone)]
34pub struct ClassInfoWithTypes {
35    pub class_info: ClassInfo,
36    pub member_type_info: Option<MemberTypeInfo>,
37    pub library_id: Option<i32>,
38}
39
40impl<R: Read> Decoder<R> {
41    /// Creates a new decoder from a reader.
42    pub fn new(reader: R) -> Self {
43        Self {
44            reader,
45            metadata_registry: HashMap::new(),
46            library_registry: HashMap::new(),
47            offset: 0,
48        }
49    }
50
51    /// Decodes the next record from the stream.
52    ///
53    /// Returns `Ok(Some(record))` if a record was successfully read,
54    /// `Ok(None)` if the end of the stream was reached,
55    /// or an `Err` if parsing failed.
56    pub fn decode_next(&mut self) -> Result<Option<Record>> {
57        let mut header = [0u8; 1];
58        if self.reader.read_exact(&mut header).is_err() {
59            return Ok(None);
60        }
61        self.offset += 1;
62
63        let record_type = RecordType::try_from(header[0])?;
64        match record_type {
65            RecordType::SerializedStreamHeader => {
66                let rec = self.read_serialization_header()?;
67                Ok(Some(Record::SerializationHeader(rec)))
68            }
69            RecordType::BinaryLibrary => {
70                let lib = self.read_binary_library()?;
71                self.library_registry
72                    .insert(lib.library_id, lib.library_name.clone());
73                Ok(Some(Record::BinaryLibrary(lib)))
74            }
75            RecordType::ClassWithMembersAndTypes => {
76                let rec = self.read_class_with_members_and_types()?;
77                Ok(Some(Record::ClassWithMembersAndTypes(rec)))
78            }
79            RecordType::SystemClassWithMembersAndTypes => {
80                let rec = self.read_system_class_with_members_and_types()?;
81                Ok(Some(Record::SystemClassWithMembersAndTypes(rec)))
82            }
83            RecordType::SystemClassWithMembers => {
84                let rec = self.read_system_class_with_members()?;
85                Ok(Some(Record::SystemClassWithMembers(rec)))
86            }
87            RecordType::ClassWithMembers => {
88                let rec = self.read_class_with_members()?;
89                Ok(Some(Record::ClassWithMembers(rec)))
90            }
91            RecordType::ClassWithId => {
92                let rec = self.read_class_with_id()?;
93                Ok(Some(Record::ClassWithId(rec)))
94            }
95            RecordType::BinaryObjectString => {
96                let object_id = self.read_i32()?;
97                let value = self.read_length_prefixed_string()?;
98                Ok(Some(Record::BinaryObjectString { object_id, value }))
99            }
100            RecordType::BinaryArray => {
101                let rec = self.read_binary_array_full()?;
102                Ok(Some(Record::BinaryArray(rec)))
103            }
104            RecordType::MemberPrimitiveTyped => {
105                let pt = PrimitiveType::try_from(self.read_u8()?)?;
106                let value = self.read_primitive_value(pt)?;
107                Ok(Some(Record::MemberPrimitiveTyped {
108                    primitive_type_enum: pt,
109                    value,
110                }))
111            }
112            RecordType::MemberReference => Ok(Some(Record::MemberReference {
113                id_ref: self.read_i32()?,
114            })),
115            RecordType::ObjectNull => Ok(Some(Record::ObjectNull)),
116            RecordType::ObjectNullMultiple256 => {
117                Ok(Some(Record::ObjectNullMultiple256(ObjectNullMultiple256 {
118                    null_count: self.read_u8()?,
119                })))
120            }
121            RecordType::ObjectNullMultiple => {
122                Ok(Some(Record::ObjectNullMultiple(ObjectNullMultiple {
123                    null_count: self.read_i32()?,
124                })))
125            }
126            RecordType::ArraySinglePrimitive => {
127                let object_id = self.read_i32()?;
128                let length = self.read_i32()?;
129                let pt = PrimitiveType::try_from(self.read_u8()?)?;
130                let mut values = Vec::with_capacity(length as usize);
131                for _ in 0..length {
132                    values.push(self.read_primitive_value(pt)?);
133                }
134                Ok(Some(Record::ArraySinglePrimitive(ArraySinglePrimitive {
135                    object_id,
136                    length,
137                    primitive_type_enum: pt,
138                    element_values: values,
139                })))
140            }
141            RecordType::ArraySingleObject => {
142                let object_id = self.read_i32()?;
143                let length = self.read_i32()?;
144                let values =
145                    self.read_all_elements(length, BinaryType::Object, &AdditionalTypeInfo::None)?;
146                Ok(Some(Record::ArraySingleObject(ArraySingleObject {
147                    object_id,
148                    length,
149                    element_values: values,
150                })))
151            }
152            RecordType::ArraySingleString => {
153                let object_id = self.read_i32()?;
154                let length = self.read_i32()?;
155                let values =
156                    self.read_all_elements(length, BinaryType::String, &AdditionalTypeInfo::None)?;
157                Ok(Some(Record::ArraySingleString(ArraySingleString {
158                    object_id,
159                    length,
160                    element_values: values,
161                })))
162            }
163            RecordType::MessageEnd => Ok(Some(Record::MessageEnd)),
164            _ => Err(Error::Custom(format!(
165                "Unimplemented record type 0x{:02x}",
166                header[0]
167            ))),
168        }
169    }
170
171    fn read_i32(&mut self) -> Result<i32> {
172        let mut buf = [0u8; 4];
173        self.reader.read_exact(&mut buf)?;
174        self.offset += 4;
175        Ok(i32::from_le_bytes(buf))
176    }
177
178    fn read_u8(&mut self) -> Result<u8> {
179        let mut buf = [0u8; 1];
180        self.reader.read_exact(&mut buf)?;
181        self.offset += 1;
182        Ok(buf[0])
183    }
184
185    fn read_serialization_header(&mut self) -> Result<SerializationHeader> {
186        Ok(SerializationHeader {
187            root_id: self.read_i32()?,
188            header_id: self.read_i32()?,
189            major_version: self.read_i32()?,
190            minor_version: self.read_i32()?,
191        })
192    }
193
194    fn read_binary_library(&mut self) -> Result<BinaryLibrary> {
195        Ok(BinaryLibrary {
196            library_id: self.read_i32()?,
197            library_name: self.read_length_prefixed_string()?,
198        })
199    }
200
201    fn read_length_prefixed_string(&mut self) -> Result<String> {
202        let length = self.read_variable_length_int()?;
203        if length < 0 {
204            return Err(Error::InvalidStringLength(length));
205        }
206        if length == 0 {
207            return Ok(String::new());
208        }
209        let mut buf = vec![0u8; length as usize];
210        self.reader.read_exact(&mut buf)?;
211        self.offset += length as usize;
212        Ok(String::from_utf8(buf)?)
213    }
214
215    fn read_variable_length_int(&mut self) -> Result<i32> {
216        let mut value: i32 = 0;
217        let mut shift = 0;
218        loop {
219            let b = self.read_u8()?;
220            value |= ((b & 0x7F) as i32) << shift;
221            if (b & 0x80) == 0 {
222                break;
223            }
224            shift += 7;
225            if shift >= 35 {
226                return Err(Error::Custom("Variable length int too long".into()));
227            }
228        }
229        Ok(value)
230    }
231
232    fn read_class_info(&mut self) -> Result<ClassInfo> {
233        let object_id = self.read_i32()?;
234        let name = self.read_length_prefixed_string()?;
235        let member_count = self.read_i32()?;
236        let mut member_names = Vec::with_capacity(member_count as usize);
237        for _ in 0..member_count {
238            member_names.push(self.read_length_prefixed_string()?);
239        }
240        Ok(ClassInfo {
241            object_id,
242            name,
243            member_count,
244            member_names,
245        })
246    }
247
248    fn read_member_type_info(&mut self, count: i32) -> Result<MemberTypeInfo> {
249        let mut binary_type_enums = Vec::with_capacity(count as usize);
250        for _ in 0..count {
251            binary_type_enums.push(BinaryType::try_from(self.read_u8()?)?);
252        }
253
254        let mut additional_infos = Vec::with_capacity(count as usize);
255        for i in 0..count {
256            let bt = binary_type_enums[i as usize];
257            let info = match bt {
258                BinaryType::Primitive => {
259                    AdditionalTypeInfo::Primitive(PrimitiveType::try_from(self.read_u8()?)?)
260                }
261                BinaryType::SystemClass => {
262                    AdditionalTypeInfo::SystemClass(self.read_length_prefixed_string()?)
263                }
264                BinaryType::Class => AdditionalTypeInfo::Class(ClassTypeInfo {
265                    type_name: self.read_length_prefixed_string()?,
266                    library_id: self.read_i32()?,
267                }),
268                _ => AdditionalTypeInfo::None,
269            };
270            additional_infos.push(info);
271        }
272
273        Ok(MemberTypeInfo {
274            binary_type_enums,
275            additional_infos,
276        })
277    }
278
279    fn read_class_with_members_and_types(&mut self) -> Result<ClassWithMembersAndTypes> {
280        let class_info = self.read_class_info()?;
281        let member_type_info = self.read_member_type_info(class_info.member_count)?;
282        let library_id = self.read_i32()?;
283
284        self.metadata_registry.insert(
285            class_info.object_id,
286            ClassInfoWithTypes {
287                class_info: class_info.clone(),
288                member_type_info: Some(member_type_info.clone()),
289                library_id: Some(library_id),
290            },
291        );
292
293        let member_values =
294            self.read_all_member_values(&class_info, &Some(member_type_info.clone()))?;
295        Ok(ClassWithMembersAndTypes {
296            class_info,
297            member_type_info,
298            library_id,
299            member_values,
300        })
301    }
302
303    fn read_system_class_with_members_and_types(
304        &mut self,
305    ) -> Result<SystemClassWithMembersAndTypes> {
306        let class_info = self.read_class_info()?;
307        let member_type_info = self.read_member_type_info(class_info.member_count)?;
308
309        self.metadata_registry.insert(
310            class_info.object_id,
311            ClassInfoWithTypes {
312                class_info: class_info.clone(),
313                member_type_info: Some(member_type_info.clone()),
314                library_id: None,
315            },
316        );
317
318        let member_values =
319            self.read_all_member_values(&class_info, &Some(member_type_info.clone()))?;
320        Ok(SystemClassWithMembersAndTypes {
321            class_info,
322            member_type_info,
323            member_values,
324        })
325    }
326
327    fn read_system_class_with_members(&mut self) -> Result<SystemClassWithMembers> {
328        let class_info = self.read_class_info()?;
329
330        self.metadata_registry.insert(
331            class_info.object_id,
332            ClassInfoWithTypes {
333                class_info: class_info.clone(),
334                member_type_info: None,
335                library_id: None,
336            },
337        );
338
339        let member_values = self.read_all_member_values(&class_info, &None)?;
340        Ok(SystemClassWithMembers {
341            class_info,
342            member_values,
343        })
344    }
345
346    fn read_class_with_members(&mut self) -> Result<ClassWithMembers> {
347        let class_info = self.read_class_info()?;
348        let library_id = self.read_i32()?;
349
350        self.metadata_registry.insert(
351            class_info.object_id,
352            ClassInfoWithTypes {
353                class_info: class_info.clone(),
354                member_type_info: None,
355                library_id: Some(library_id),
356            },
357        );
358
359        let member_values = self.read_all_member_values(&class_info, &None)?;
360        Ok(ClassWithMembers {
361            class_info,
362            library_id,
363            member_values,
364        })
365    }
366
367    fn read_class_with_id(&mut self) -> Result<ClassWithId> {
368        let object_id = self.read_i32()?;
369        let metadata_id = self.read_i32()?;
370
371        let meta = self
372            .metadata_registry
373            .get(&metadata_id)
374            .ok_or_else(|| Error::Custom(format!("Metadata ID {} not found", metadata_id)))?
375            .clone();
376
377        let member_values =
378            self.read_all_member_values(&meta.class_info, &meta.member_type_info)?;
379
380        Ok(ClassWithId {
381            object_id,
382            metadata_id,
383            member_values,
384        })
385    }
386
387    fn read_binary_array_full(&mut self) -> Result<BinaryArray> {
388        let object_id = self.read_i32()?;
389        let binary_array_type_enum = self.read_u8()?;
390        let rank = self.read_i32()?;
391        let mut lengths = Vec::with_capacity(rank as usize);
392        for _ in 0..rank {
393            lengths.push(self.read_i32()?);
394        }
395
396        let mut lower_bounds = None;
397        if binary_array_type_enum == 3 || binary_array_type_enum == 4 || binary_array_type_enum == 5
398        {
399            let mut bounds = Vec::with_capacity(rank as usize);
400            for _ in 0..rank {
401                bounds.push(self.read_i32()?);
402            }
403            lower_bounds = Some(bounds);
404        }
405
406        let type_enum = BinaryType::try_from(self.read_u8()?)?;
407        let additional_type_info = match type_enum {
408            BinaryType::Primitive => {
409                AdditionalTypeInfo::Primitive(PrimitiveType::try_from(self.read_u8()?)?)
410            }
411            BinaryType::SystemClass => {
412                AdditionalTypeInfo::SystemClass(self.read_length_prefixed_string()?)
413            }
414            BinaryType::Class => AdditionalTypeInfo::Class(ClassTypeInfo {
415                type_name: self.read_length_prefixed_string()?,
416                library_id: self.read_i32()?,
417            }),
418            _ => AdditionalTypeInfo::None,
419        };
420
421        let total_elements: i32 = lengths.iter().product();
422        let element_values =
423            self.read_all_elements(total_elements, type_enum, &additional_type_info)?;
424
425        Ok(BinaryArray {
426            object_id,
427            binary_array_type_enum,
428            rank,
429            lengths,
430            lower_bounds,
431            type_enum,
432            additional_type_info,
433            element_values,
434        })
435    }
436
437    fn read_primitive_value(&mut self, pt: PrimitiveType) -> Result<PrimitiveValue> {
438        match pt {
439            PrimitiveType::Boolean => Ok(PrimitiveValue::Boolean(self.read_u8()? != 0)),
440            PrimitiveType::Byte => Ok(PrimitiveValue::Byte(self.read_u8()?)),
441            PrimitiveType::Char => {
442                let b = self.read_u8()?;
443                Ok(PrimitiveValue::Char(b as char))
444            }
445            PrimitiveType::Int16 => {
446                let mut buf = [0u8; 2];
447                self.reader.read_exact(&mut buf)?;
448                self.offset += 2;
449                Ok(PrimitiveValue::Int16(i16::from_le_bytes(buf)))
450            }
451            PrimitiveType::Int32 => Ok(PrimitiveValue::Int32(self.read_i32()?)),
452            PrimitiveType::Int64 => {
453                let mut buf = [0u8; 8];
454                self.reader.read_exact(&mut buf)?;
455                self.offset += 8;
456                Ok(PrimitiveValue::Int64(i64::from_le_bytes(buf)))
457            }
458            PrimitiveType::TimeSpan => {
459                let mut buf = [0u8; 8];
460                self.reader.read_exact(&mut buf)?;
461                self.offset += 8;
462                Ok(PrimitiveValue::TimeSpan(i64::from_le_bytes(buf)))
463            }
464            PrimitiveType::DateTime => {
465                let mut buf = [0u8; 8];
466                self.reader.read_exact(&mut buf)?;
467                self.offset += 8;
468                Ok(PrimitiveValue::DateTime(u64::from_le_bytes(buf)))
469            }
470            PrimitiveType::SByte => Ok(PrimitiveValue::SByte(self.read_u8()? as i8)),
471            PrimitiveType::Single => {
472                let mut buf = [0u8; 4];
473                self.reader.read_exact(&mut buf)?;
474                self.offset += 4;
475                Ok(PrimitiveValue::Single(f32::from_le_bytes(buf)))
476            }
477            PrimitiveType::Double => {
478                let mut buf = [0u8; 8];
479                self.reader.read_exact(&mut buf)?;
480                self.offset += 8;
481                Ok(PrimitiveValue::Double(f64::from_le_bytes(buf)))
482            }
483            PrimitiveType::Decimal => {
484                let mut buf = [0u8; 16];
485                self.reader.read_exact(&mut buf)?;
486                self.offset += 16;
487                // Represent as a hex string or just raw bytes for now since we don't have a 128-bit decimal type easily
488                Ok(PrimitiveValue::Decimal(hex::encode(buf)))
489            }
490            PrimitiveType::UInt16 => {
491                let mut buf = [0u8; 2];
492                self.reader.read_exact(&mut buf)?;
493                self.offset += 2;
494                Ok(PrimitiveValue::UInt16(u16::from_le_bytes(buf)))
495            }
496            PrimitiveType::UInt32 => {
497                let mut buf = [0u8; 4];
498                self.reader.read_exact(&mut buf)?;
499                self.offset += 4;
500                Ok(PrimitiveValue::UInt32(u32::from_le_bytes(buf)))
501            }
502            PrimitiveType::UInt64 => {
503                let mut buf = [0u8; 8];
504                self.reader.read_exact(&mut buf)?;
505                self.offset += 8;
506                Ok(PrimitiveValue::UInt64(u64::from_le_bytes(buf)))
507            }
508            PrimitiveType::String => {
509                Ok(PrimitiveValue::String(self.read_length_prefixed_string()?))
510            }
511            PrimitiveType::Null => Ok(PrimitiveValue::Null),
512        }
513    }
514
515    fn read_object_value(
516        &mut self,
517        bt: BinaryType,
518        add_info: &AdditionalTypeInfo,
519    ) -> Result<ObjectValue> {
520        match bt {
521            BinaryType::Primitive => {
522                if let AdditionalTypeInfo::Primitive(pt) = add_info {
523                    Ok(ObjectValue::Primitive(self.read_primitive_value(*pt)?))
524                } else {
525                    Err(Error::Custom("Expected primitive type info".into()))
526                }
527            }
528            _ => {
529                if let Some(record) = self.decode_next()? {
530                    Ok(ObjectValue::Record(Box::new(record)))
531                } else {
532                    Err(Error::Custom("Expected record for object value".into()))
533                }
534            }
535        }
536    }
537
538    fn read_all_member_values(
539        &mut self,
540        class_info: &ClassInfo,
541        member_type_info: &Option<MemberTypeInfo>,
542    ) -> Result<Vec<ObjectValue>> {
543        let mut values = Vec::with_capacity(class_info.member_count as usize);
544        for i in 0..class_info.member_count {
545            if let Some(mti) = member_type_info {
546                let bt = mti.binary_type_enums[i as usize];
547                let add_info = &mti.additional_infos[i as usize];
548                values.push(self.read_object_value(bt, add_info)?);
549            } else if let Some(record) = self.decode_next()? {
550                values.push(ObjectValue::Record(Box::new(record)));
551            } else {
552                return Err(Error::Custom("Expected record for member value".into()));
553            }
554        }
555        Ok(values)
556    }
557
558    fn read_all_elements(
559        &mut self,
560        count: i32,
561        bt: BinaryType,
562        add_info: &AdditionalTypeInfo,
563    ) -> Result<Vec<ObjectValue>> {
564        let mut values = Vec::with_capacity(count as usize);
565        let mut i = 0;
566        while i < count {
567            let val = self.read_object_value(bt, add_info)?;
568            match &val {
569                ObjectValue::Record(r) => match r.as_ref() {
570                    Record::ObjectNullMultiple(n) => {
571                        for _ in 0..n.null_count {
572                            values.push(ObjectValue::Primitive(PrimitiveValue::Null));
573                            i += 1;
574                        }
575                        continue;
576                    }
577                    Record::ObjectNullMultiple256(n) => {
578                        for _ in 0..n.null_count {
579                            values.push(ObjectValue::Primitive(PrimitiveValue::Null));
580                            i += 1;
581                        }
582                        continue;
583                    }
584                    Record::ObjectNull => {
585                        values.push(ObjectValue::Primitive(PrimitiveValue::Null));
586                    }
587                    _ => {
588                        values.push(val);
589                    }
590                },
591                _ => {
592                    values.push(val);
593                }
594            }
595            i += 1;
596        }
597        Ok(values)
598    }
599}