nrbf_parser/
encoder.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::Result;
18use crate::records::*;
19use std::io::Write;
20
21/// An encoder for MS-NRBF binary streams.
22pub struct Encoder<W: Write> {
23    writer: W,
24}
25
26impl<W: Write> Encoder<W> {
27    /// Creates a new encoder from a writer.
28    pub fn new(writer: W) -> Self {
29        Self { writer }
30    }
31
32    /// Encodes a record and writes it to the stream.
33    pub fn encode(&mut self, record: &Record) -> Result<()> {
34        match record {
35            Record::SerializationHeader(rec) => {
36                self.write_u8(RecordType::SerializedStreamHeader as u8)?;
37                self.write_serialization_header(rec)?;
38            }
39            Record::BinaryLibrary(rec) => {
40                self.write_u8(RecordType::BinaryLibrary as u8)?;
41                self.write_binary_library(rec)?;
42            }
43            Record::ClassWithMembersAndTypes(rec) => {
44                self.write_u8(RecordType::ClassWithMembersAndTypes as u8)?;
45                self.write_class_with_members_and_types(rec)?;
46            }
47            Record::SystemClassWithMembersAndTypes(rec) => {
48                self.write_u8(RecordType::SystemClassWithMembersAndTypes as u8)?;
49                self.write_system_class_with_members_and_types(rec)?;
50            }
51            Record::SystemClassWithMembers(rec) => {
52                self.write_u8(RecordType::SystemClassWithMembers as u8)?;
53                self.write_system_class_with_members(rec)?;
54            }
55            Record::ClassWithMembers(rec) => {
56                self.write_u8(RecordType::ClassWithMembers as u8)?;
57                self.write_class_with_members(rec)?;
58            }
59            Record::ClassWithId(rec) => {
60                self.write_u8(RecordType::ClassWithId as u8)?;
61                self.write_class_with_id(rec)?;
62            }
63            Record::BinaryObjectString { object_id, value } => {
64                self.write_u8(RecordType::BinaryObjectString as u8)?;
65                self.write_i32(*object_id)?;
66                self.write_length_prefixed_string(value)?;
67            }
68            Record::BinaryArray(rec) => {
69                self.write_u8(RecordType::BinaryArray as u8)?;
70                self.write_binary_array(rec)?;
71            }
72            Record::ArraySingleObject(rec) => {
73                self.write_u8(RecordType::ArraySingleObject as u8)?;
74                self.write_i32(rec.object_id)?;
75                self.write_i32(rec.length)?;
76                for val in &rec.element_values {
77                    self.write_object_value(val)?;
78                }
79            }
80            Record::ArraySinglePrimitive(rec) => {
81                self.write_u8(RecordType::ArraySinglePrimitive as u8)?;
82                self.write_i32(rec.object_id)?;
83                self.write_i32(rec.length)?;
84                self.write_u8(rec.primitive_type_enum as u8)?;
85                for val in &rec.element_values {
86                    self.write_primitive_value(val)?;
87                }
88            }
89            Record::ArraySingleString(rec) => {
90                self.write_u8(RecordType::ArraySingleString as u8)?;
91                self.write_i32(rec.object_id)?;
92                self.write_i32(rec.length)?;
93                for val in &rec.element_values {
94                    self.write_object_value(val)?;
95                }
96            }
97            Record::MemberPrimitiveTyped {
98                primitive_type_enum,
99                value,
100            } => {
101                self.write_u8(RecordType::MemberPrimitiveTyped as u8)?;
102                self.write_u8(*primitive_type_enum as u8)?;
103                self.write_primitive_value(value)?;
104            }
105            Record::MemberReference { id_ref } => {
106                self.write_u8(RecordType::MemberReference as u8)?;
107                self.write_i32(*id_ref)?;
108            }
109            Record::ObjectNull => {
110                self.write_u8(RecordType::ObjectNull as u8)?;
111            }
112            Record::ObjectNullMultiple(rec) => {
113                self.write_u8(RecordType::ObjectNullMultiple as u8)?;
114                self.write_i32(rec.null_count)?;
115            }
116            Record::ObjectNullMultiple256(rec) => {
117                self.write_u8(RecordType::ObjectNullMultiple256 as u8)?;
118                self.write_u8(rec.null_count)?;
119            }
120            Record::MessageEnd => {
121                self.write_u8(RecordType::MessageEnd as u8)?;
122            }
123        }
124        Ok(())
125    }
126
127    fn write_i32(&mut self, val: i32) -> Result<()> {
128        self.writer.write_all(&val.to_le_bytes())?;
129        Ok(())
130    }
131
132    fn write_u8(&mut self, val: u8) -> Result<()> {
133        self.writer.write_all(&[val])?;
134        Ok(())
135    }
136
137    fn write_serialization_header(&mut self, rec: &SerializationHeader) -> Result<()> {
138        self.write_i32(rec.root_id)?;
139        self.write_i32(rec.header_id)?;
140        self.write_i32(rec.major_version)?;
141        self.write_i32(rec.minor_version)?;
142        Ok(())
143    }
144
145    fn write_binary_library(&mut self, rec: &BinaryLibrary) -> Result<()> {
146        self.write_i32(rec.library_id)?;
147        self.write_length_prefixed_string(&rec.library_name)?;
148        Ok(())
149    }
150
151    fn write_length_prefixed_string(&mut self, s: &str) -> Result<()> {
152        let bytes = s.as_bytes();
153        self.write_variable_length_int(bytes.len() as i32)?;
154        self.writer.write_all(bytes)?;
155        Ok(())
156    }
157
158    fn write_variable_length_int(&mut self, mut value: i32) -> Result<()> {
159        loop {
160            let mut b = (value & 0x7F) as u8;
161            value >>= 7;
162            if value > 0 {
163                b |= 0x80;
164                self.write_u8(b)?;
165            } else {
166                self.write_u8(b)?;
167                break;
168            }
169        }
170        Ok(())
171    }
172
173    fn write_class_info(&mut self, info: &ClassInfo) -> Result<()> {
174        self.write_i32(info.object_id)?;
175        self.write_length_prefixed_string(&info.name)?;
176        self.write_i32(info.member_count)?;
177        for name in &info.member_names {
178            self.write_length_prefixed_string(name)?;
179        }
180        Ok(())
181    }
182
183    fn write_member_type_info(&mut self, info: &MemberTypeInfo) -> Result<()> {
184        for bt in &info.binary_type_enums {
185            self.write_u8(*bt as u8)?;
186        }
187        for info in &info.additional_infos {
188            match info {
189                AdditionalTypeInfo::Primitive(pt) => self.write_u8(*pt as u8)?,
190                AdditionalTypeInfo::SystemClass(s) => self.write_length_prefixed_string(s)?,
191                AdditionalTypeInfo::Class(c) => {
192                    self.write_length_prefixed_string(&c.type_name)?;
193                    self.write_i32(c.library_id)?;
194                }
195                AdditionalTypeInfo::None => {}
196            }
197        }
198        Ok(())
199    }
200
201    fn write_class_with_members_and_types(&mut self, rec: &ClassWithMembersAndTypes) -> Result<()> {
202        self.write_class_info(&rec.class_info)?;
203        self.write_member_type_info(&rec.member_type_info)?;
204        self.write_i32(rec.library_id)?;
205        for val in &rec.member_values {
206            self.write_object_value(val)?;
207        }
208        Ok(())
209    }
210
211    fn write_system_class_with_members_and_types(
212        &mut self,
213        rec: &SystemClassWithMembersAndTypes,
214    ) -> Result<()> {
215        self.write_class_info(&rec.class_info)?;
216        self.write_member_type_info(&rec.member_type_info)?;
217        for val in &rec.member_values {
218            self.write_object_value(val)?;
219        }
220        Ok(())
221    }
222
223    fn write_system_class_with_members(&mut self, rec: &SystemClassWithMembers) -> Result<()> {
224        self.write_class_info(&rec.class_info)?;
225        for val in &rec.member_values {
226            self.write_object_value(val)?;
227        }
228        Ok(())
229    }
230
231    fn write_class_with_members(&mut self, rec: &ClassWithMembers) -> Result<()> {
232        self.write_class_info(&rec.class_info)?;
233        self.write_i32(rec.library_id)?;
234        for val in &rec.member_values {
235            self.write_object_value(val)?;
236        }
237        Ok(())
238    }
239
240    fn write_class_with_id(&mut self, rec: &ClassWithId) -> Result<()> {
241        self.write_i32(rec.object_id)?;
242        self.write_i32(rec.metadata_id)?;
243        for val in &rec.member_values {
244            self.write_object_value(val)?;
245        }
246        Ok(())
247    }
248
249    fn write_binary_array(&mut self, rec: &BinaryArray) -> Result<()> {
250        self.write_i32(rec.object_id)?;
251        self.write_u8(rec.binary_array_type_enum)?;
252        self.write_i32(rec.rank)?;
253        for len in &rec.lengths {
254            self.write_i32(*len)?;
255        }
256        if let Some(bounds) = &rec.lower_bounds {
257            for bound in bounds {
258                self.write_i32(*bound)?;
259            }
260        }
261        self.write_u8(rec.type_enum as u8)?;
262        match &rec.additional_type_info {
263            AdditionalTypeInfo::Primitive(pt) => self.write_u8(*pt as u8)?,
264            AdditionalTypeInfo::SystemClass(s) => self.write_length_prefixed_string(s)?,
265            AdditionalTypeInfo::Class(c) => {
266                self.write_length_prefixed_string(&c.type_name)?;
267                self.write_i32(c.library_id)?;
268            }
269            AdditionalTypeInfo::None => {}
270        }
271        for val in &rec.element_values {
272            self.write_object_value(val)?;
273        }
274        Ok(())
275    }
276
277    fn write_primitive_value(&mut self, val: &PrimitiveValue) -> Result<()> {
278        match val {
279            PrimitiveValue::Boolean(b) => self.write_u8(if *b { 1 } else { 0 })?,
280            PrimitiveValue::Byte(b) => self.write_u8(*b)?,
281            PrimitiveValue::Char(c) => self.write_u8(*c as u8)?,
282            PrimitiveValue::Int16(v) => self.writer.write_all(&v.to_le_bytes())?,
283            PrimitiveValue::Int32(v) => self.write_i32(*v)?,
284            PrimitiveValue::Int64(v) => self.writer.write_all(&v.to_le_bytes())?,
285            PrimitiveValue::SByte(v) => self.write_u8(*v as u8)?,
286            PrimitiveValue::Single(v) => self.writer.write_all(&v.to_le_bytes())?,
287            PrimitiveValue::Double(v) => self.writer.write_all(&v.to_le_bytes())?,
288            PrimitiveValue::TimeSpan(v) => self.writer.write_all(&v.to_le_bytes())?,
289            PrimitiveValue::DateTime(v) => self.writer.write_all(&v.to_le_bytes())?,
290            PrimitiveValue::UInt16(v) => self.writer.write_all(&v.to_le_bytes())?,
291            PrimitiveValue::UInt32(v) => self.writer.write_all(&v.to_le_bytes())?,
292            PrimitiveValue::UInt64(v) => self.writer.write_all(&v.to_le_bytes())?,
293            PrimitiveValue::String(s) => self.write_length_prefixed_string(s)?,
294            PrimitiveValue::Decimal(s) => {
295                let bytes = hex::decode(s).map_err(|e| {
296                    crate::error::Error::Custom(format!("Invalid hex for Decimal: {}", e))
297                })?;
298                if bytes.len() != 16 {
299                    return Err(crate::error::Error::Custom(format!(
300                        "Decimal must be 16 bytes, got {}",
301                        bytes.len()
302                    )));
303                }
304                self.writer.write_all(&bytes)?;
305            }
306            PrimitiveValue::Null => {} // Handled by ObjectNull or ObjectNullMultiple
307        }
308        Ok(())
309    }
310
311    fn write_object_value(&mut self, val: &ObjectValue) -> Result<()> {
312        match val {
313            ObjectValue::Primitive(p) => {
314                if let PrimitiveValue::Null = p {
315                    // This is tricky because standalone Null is Record::ObjectNull
316                    // But within an array it might be ObjectNullMultiple
317                    // However our Decoder reads elements using read_object_value
318                    // which for non-primitives calls decode_next.
319                    // If it's a PrimitiveValue::Null here, it MUST be wrapped in Record::ObjectNull
320                    // in the ObjectValue::Record variant if we're following the spec literally,
321                    // OR we handle it here.
322                    self.write_u8(RecordType::ObjectNull as u8)?;
323                } else {
324                    self.write_primitive_value(p)?;
325                }
326            }
327            ObjectValue::Record(r) => {
328                self.encode(r)?;
329            }
330        }
331        Ok(())
332    }
333}