1use crate::err::{DeserializationError, DeserializationResult as Result};
2use crate::evtx_chunk::EvtxChunk;
3use crate::utils::invalid_data;
4use crate::utils::windows::{filetime_to_timestamp, read_systime, systime_from_bytes};
5use crate::utils::{ByteCursor, Utf16LeSlice};
6
7use bumpalo::Bump;
8use encoding::EncodingRef;
9use jiff::Timestamp;
10use log::{trace, warn};
11use std::fmt::{self, Display};
12use std::io::Cursor;
13use std::string::ToString;
14use winstructs::guid::Guid;
15
16#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
18pub struct SidRef<'a> {
19 bytes: &'a [u8],
20}
21
22impl<'a> SidRef<'a> {
23 pub fn new(bytes: &'a [u8]) -> Self {
24 Self { bytes }
25 }
26
27 pub fn as_bytes(&self) -> &'a [u8] {
28 self.bytes
29 }
30}
31
32impl fmt::Display for SidRef<'_> {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 let bytes = self.bytes;
35 if bytes.len() < 8 {
36 return write!(f, "S-?");
37 }
38 let revision = bytes[0];
39 let sub_count = bytes[1] as usize;
40
41 let mut authority: u64 = 0;
43 for &b in &bytes[2..8] {
44 authority = (authority << 8) | u64::from(b);
45 }
46
47 write!(f, "S-{}-{}", revision, authority)?;
48
49 let mut off = 8usize;
50 for _ in 0..sub_count {
51 if off + 4 > bytes.len() {
52 break;
53 }
54 let sub =
55 u32::from_le_bytes([bytes[off], bytes[off + 1], bytes[off + 2], bytes[off + 3]]);
56 write!(f, "-{}", sub)?;
57 off += 4;
58 }
59 Ok(())
60 }
61}
62
63#[derive(Debug, PartialOrd, PartialEq, Clone)]
64pub enum BinXmlValue<'a> {
65 NullType,
66 StringType(Utf16LeSlice<'a>),
68 AnsiStringType(&'a str),
70 Int8Type(i8),
71 UInt8Type(u8),
72 Int16Type(i16),
73 UInt16Type(u16),
74 Int32Type(i32),
75 UInt32Type(u32),
76 Int64Type(i64),
77 UInt64Type(u64),
78 Real32Type(f32),
79 Real64Type(f64),
80 BoolType(bool),
81 BinaryType(&'a [u8]),
82 GuidType(Guid),
83 SizeTType(usize),
84 FileTimeType(Timestamp),
85 SysTimeType(Timestamp),
86 SidType(SidRef<'a>),
87 HexInt32Type(u32),
88 HexInt64Type(u64),
89 EvtHandle,
90 BinXmlType(&'a [u8]),
94 EvtXml,
95 StringArrayType(&'a [Utf16LeSlice<'a>]),
97 AnsiStringArrayType,
98 Int8ArrayType(&'a [i8]),
99 UInt8ArrayType(&'a [u8]),
100 Int16ArrayType(&'a [i16]),
101 UInt16ArrayType(&'a [u16]),
102 Int32ArrayType(&'a [i32]),
103 UInt32ArrayType(&'a [u32]),
104 Int64ArrayType(&'a [i64]),
105 UInt64ArrayType(&'a [u64]),
106 Real32ArrayType(&'a [f32]),
107 Real64ArrayType(&'a [f64]),
108 BoolArrayType(&'a [bool]),
109 BinaryArrayType,
110 GuidArrayType(&'a [Guid]),
111 SizeTArrayType,
112 FileTimeArrayType(&'a [Timestamp]),
113 SysTimeArrayType(&'a [Timestamp]),
114 SidArrayType(&'a [SidRef<'a>]),
115 HexInt32ArrayType(&'a [u32]),
116 HexInt64ArrayType(&'a [u64]),
117 EvtArrayHandle,
118 BinXmlArrayType,
119 EvtXmlArrayType,
120}
121
122#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy)]
123pub enum BinXmlValueType {
124 NullType,
125 StringType,
126 AnsiStringType,
127 Int8Type,
128 UInt8Type,
129 Int16Type,
130 UInt16Type,
131 Int32Type,
132 UInt32Type,
133 Int64Type,
134 UInt64Type,
135 Real32Type,
136 Real64Type,
137 BoolType,
138 BinaryType,
139 GuidType,
140 SizeTType,
141 FileTimeType,
142 SysTimeType,
143 SidType,
144 HexInt32Type,
145 HexInt64Type,
146 EvtHandle,
147 BinXmlType,
148 EvtXmlType,
149 StringArrayType,
150 AnsiStringArrayType,
151 Int8ArrayType,
152 UInt8ArrayType,
153 Int16ArrayType,
154 UInt16ArrayType,
155 Int32ArrayType,
156 UInt32ArrayType,
157 Int64ArrayType,
158 UInt64ArrayType,
159 Real32ArrayType,
160 Real64ArrayType,
161 BoolArrayType,
162 BinaryArrayType,
163 GuidArrayType,
164 SizeTArrayType,
165 FileTimeArrayType,
166 SysTimeArrayType,
167 SidArrayType,
168 HexInt32ArrayType,
169 HexInt64ArrayType,
170 EvtHandleArray,
171 BinXmlArrayType,
172 EvtXmlArrayType,
173}
174
175impl BinXmlValueType {
176 const LOOKUP: [Option<BinXmlValueType>; 256] = {
178 use BinXmlValueType::*;
179 let mut t: [Option<BinXmlValueType>; 256] = [None; 256];
180 t[0x00] = Some(NullType);
181 t[0x01] = Some(StringType);
182 t[0x02] = Some(AnsiStringType);
183 t[0x03] = Some(Int8Type);
184 t[0x04] = Some(UInt8Type);
185 t[0x05] = Some(Int16Type);
186 t[0x06] = Some(UInt16Type);
187 t[0x07] = Some(Int32Type);
188 t[0x08] = Some(UInt32Type);
189 t[0x09] = Some(Int64Type);
190 t[0x0a] = Some(UInt64Type);
191 t[0x0b] = Some(Real32Type);
192 t[0x0c] = Some(Real64Type);
193 t[0x0d] = Some(BoolType);
194 t[0x0e] = Some(BinaryType);
195 t[0x0f] = Some(GuidType);
196 t[0x10] = Some(SizeTType);
197 t[0x11] = Some(FileTimeType);
198 t[0x12] = Some(SysTimeType);
199 t[0x13] = Some(SidType);
200 t[0x14] = Some(HexInt32Type);
201 t[0x15] = Some(HexInt64Type);
202 t[0x20] = Some(EvtHandle);
203 t[0x21] = Some(BinXmlType);
204 t[0x23] = Some(EvtXmlType);
205 t[0x81] = Some(StringArrayType);
206 t[0x82] = Some(AnsiStringArrayType);
207 t[0x83] = Some(Int8ArrayType);
208 t[0x84] = Some(UInt8ArrayType);
209 t[0x85] = Some(Int16ArrayType);
210 t[0x86] = Some(UInt16ArrayType);
211 t[0x87] = Some(Int32ArrayType);
212 t[0x88] = Some(UInt32ArrayType);
213 t[0x89] = Some(Int64ArrayType);
214 t[0x8a] = Some(UInt64ArrayType);
215 t[0x8b] = Some(Real32ArrayType);
216 t[0x8c] = Some(Real64ArrayType);
217 t[0x8d] = Some(BoolArrayType);
218 t[0x8e] = Some(BinaryArrayType);
219 t[0x8f] = Some(GuidArrayType);
220 t[0x90] = Some(SizeTArrayType);
221 t[0x91] = Some(FileTimeArrayType);
222 t[0x92] = Some(SysTimeArrayType);
223 t[0x93] = Some(SidArrayType);
224 t[0x94] = Some(HexInt32ArrayType);
225 t[0x95] = Some(HexInt64ArrayType);
226 t
227 };
228
229 #[inline]
230 pub fn from_u8(byte: u8) -> Option<BinXmlValueType> {
231 Self::LOOKUP[byte as usize]
232 }
233}
234
235impl<'a> BinXmlValue<'a> {
236 pub(crate) fn from_binxml_cursor_in(
237 cursor: &mut ByteCursor<'a>,
238 chunk: Option<&'a EvtxChunk<'a>>,
239 size: Option<u16>,
240 ansi_codec: EncodingRef,
241 arena: &'a Bump,
242 ) -> Result<BinXmlValue<'a>> {
243 let value_type_token = cursor.u8()?;
244
245 let value_type = BinXmlValueType::from_u8(value_type_token).ok_or_else(|| {
246 DeserializationError::InvalidValueVariant {
247 value: value_type_token,
248 offset: cursor.position(),
249 }
250 })?;
251
252 let data = Self::deserialize_value_type_cursor_in(
253 &value_type,
254 cursor,
255 chunk,
256 size,
257 ansi_codec,
258 arena,
259 )?;
260
261 Ok(data)
262 }
263
264 pub fn from_binxml_stream_in(
265 cursor: &mut Cursor<&'a [u8]>,
266 chunk: Option<&'a EvtxChunk<'a>>,
267 size: Option<u16>,
268 ansi_codec: EncodingRef,
269 arena: &'a Bump,
270 ) -> Result<BinXmlValue<'a>> {
271 let start = cursor.position() as usize;
272 let buf = *cursor.get_ref();
273 let mut c = ByteCursor::with_pos(buf, start)?;
274 let v = Self::from_binxml_cursor_in(&mut c, chunk, size, ansi_codec, arena)?;
275 cursor.set_position(c.position());
276 Ok(v)
277 }
278
279 pub(crate) fn deserialize_value_type_cursor(
280 value_type: &BinXmlValueType,
281 cursor: &mut ByteCursor<'a>,
282 chunk: Option<&'a EvtxChunk<'a>>,
283 size: Option<u16>,
284 ansi_codec: EncodingRef,
285 arena: &'a Bump,
286 ) -> Result<BinXmlValue<'a>> {
287 Self::deserialize_value_type_cursor_in(value_type, cursor, chunk, size, ansi_codec, arena)
288 }
289
290 pub(crate) fn deserialize_value_type_cursor_in(
291 value_type: &BinXmlValueType,
292 cursor: &mut ByteCursor<'a>,
293 chunk: Option<&'a EvtxChunk<'a>>,
294 size: Option<u16>,
295 ansi_codec: EncodingRef,
296 arena: &'a Bump,
297 ) -> Result<BinXmlValue<'a>> {
298 let _ = chunk;
299 trace!(
300 "Offset `0x{offset:08x} ({offset}): {value_type:?}, {size:?}",
301 offset = cursor.position(),
302 value_type = value_type,
303 size = size
304 );
305
306 let value = match (value_type, size) {
307 (BinXmlValueType::NullType, _) => BinXmlValue::NullType,
308
309 (BinXmlValueType::StringType, Some(sz)) => {
310 let sz_bytes = usize::from(sz);
311 let s = if sz_bytes == 0 {
312 None
313 } else if !sz_bytes.is_multiple_of(2) {
314 return Err(invalid_data("sized utf-16 string", cursor.position()));
315 } else {
316 cursor.utf16_by_char_count(sz_bytes / 2, "<string_value>")?
317 };
318 BinXmlValue::StringType(s.unwrap_or_else(Utf16LeSlice::empty))
319 }
320 (BinXmlValueType::StringType, None) => {
321 let s = cursor.len_prefixed_utf16_string(false, "<string_value>")?;
322 BinXmlValue::StringType(s.unwrap_or_else(Utf16LeSlice::empty))
323 }
324
325 (BinXmlValueType::AnsiStringType, Some(sz)) => {
326 let sz_bytes = usize::from(sz);
327 let raw = cursor.take_bytes(sz_bytes, "<ansi_string_value>")?;
328 let mut filtered = bumpalo::collections::Vec::with_capacity_in(sz_bytes, arena);
330 for &b in raw {
331 if b != 0 {
332 filtered.push(b);
333 }
334 }
335 let filtered = filtered.into_bump_slice();
336 let decoded = ansi_codec
337 .decode(filtered, encoding::DecoderTrap::Strict)
338 .map_err(|m| DeserializationError::AnsiDecodeError {
339 encoding_used: ansi_codec.name(),
340 inner_message: m.to_string(),
341 })?;
342 BinXmlValue::AnsiStringType(arena.alloc_str(&decoded))
343 }
344 (BinXmlValueType::AnsiStringType, None) => {
346 return Err(DeserializationError::UnimplementedValueVariant {
347 name: "AnsiString".to_owned(),
348 size: None,
349 offset: cursor.position(),
350 });
351 }
352
353 (BinXmlValueType::Int8Type, _) => BinXmlValue::Int8Type(cursor.u8()? as i8),
354 (BinXmlValueType::UInt8Type, _) => BinXmlValue::UInt8Type(cursor.u8()?),
355
356 (BinXmlValueType::Int16Type, _) => {
357 BinXmlValue::Int16Type(i16::from_le_bytes(cursor.array::<2>("i16")?))
358 }
359 (BinXmlValueType::UInt16Type, _) => BinXmlValue::UInt16Type(cursor.u16()?),
360
361 (BinXmlValueType::Int32Type, _) => {
362 BinXmlValue::Int32Type(i32::from_le_bytes(cursor.array::<4>("i32")?))
363 }
364 (BinXmlValueType::UInt32Type, _) => BinXmlValue::UInt32Type(cursor.u32()?),
365
366 (BinXmlValueType::Int64Type, _) => {
367 BinXmlValue::Int64Type(i64::from_le_bytes(cursor.array::<8>("i64")?))
368 }
369 (BinXmlValueType::UInt64Type, _) => BinXmlValue::UInt64Type(cursor.u64()?),
370
371 (BinXmlValueType::Real32Type, _) => {
372 BinXmlValue::Real32Type(f32::from_le_bytes(cursor.array::<4>("f32")?))
373 }
374 (BinXmlValueType::Real64Type, _) => {
375 BinXmlValue::Real64Type(f64::from_le_bytes(cursor.array::<8>("f64")?))
376 }
377
378 (BinXmlValueType::BoolType, _) => {
379 let raw = i32::from_le_bytes(cursor.array::<4>("bool")?);
380 let v = match raw {
381 0 => false,
382 1 => true,
383 other => {
384 warn!(
385 "invalid boolean value {} at offset {}; treating as {}",
386 other,
387 cursor.position(),
388 other != 0
389 );
390 other != 0
391 }
392 };
393 BinXmlValue::BoolType(v)
394 }
395
396 (BinXmlValueType::GuidType, _) => {
397 let bytes = cursor.take_bytes(16, "guid")?;
398 let guid = Guid::from_buffer(bytes)
399 .map_err(|_| invalid_data("guid", cursor.position()))?;
400 BinXmlValue::GuidType(guid)
401 }
402
403 (BinXmlValueType::SizeTType, Some(4)) => {
404 let v = u32::from_le_bytes(cursor.array::<4>("sizet32")?);
405 BinXmlValue::HexInt32Type(v)
406 }
407 (BinXmlValueType::SizeTType, Some(8)) => {
408 let v = u64::from_le_bytes(cursor.array::<8>("sizet64")?);
409 BinXmlValue::HexInt64Type(v)
410 }
411 (BinXmlValueType::SizeTType, _) => {
412 return Err(DeserializationError::UnimplementedValueVariant {
413 name: "SizeT".to_owned(),
414 size,
415 offset: cursor.position(),
416 });
417 }
418
419 (BinXmlValueType::FileTimeType, _) => {
420 BinXmlValue::FileTimeType(filetime_to_timestamp(cursor.u64()?)?)
421 }
422 (BinXmlValueType::SysTimeType, _) => BinXmlValue::SysTimeType(read_systime(cursor)?),
423 (BinXmlValueType::SidType, _) => BinXmlValue::SidType(cursor.read_sid_ref()?),
424
425 (BinXmlValueType::HexInt32Type, _) => {
426 let v = u32::from_le_bytes(cursor.array::<4>("hex32")?);
427 BinXmlValue::HexInt32Type(v)
428 }
429 (BinXmlValueType::HexInt64Type, _) => {
430 let v = u64::from_le_bytes(cursor.array::<8>("hex64")?);
431 BinXmlValue::HexInt64Type(v)
432 }
433
434 (BinXmlValueType::BinXmlType, size) => {
435 let payload = match size {
436 Some(sz) => {
437 if sz == 0 {
438 &[]
439 } else {
440 cursor.take_bytes(usize::from(sz), "binxml_payload")?
441 }
442 }
443 None => {
444 let payload_len = cursor.u16_named("binxml_payload_len")? as usize;
445 if payload_len == 0 {
446 &[]
447 } else {
448 cursor.take_bytes(payload_len, "binxml_payload")?
449 }
450 }
451 };
452 BinXmlValue::BinXmlType(payload)
453 }
454
455 (BinXmlValueType::BinaryType, Some(sz)) => {
456 let bytes = cursor.take_bytes(usize::from(sz), "binary")?;
457 BinXmlValue::BinaryType(bytes)
458 }
459
460 (BinXmlValueType::StringArrayType, Some(sz)) => {
462 let size_usize = usize::from(sz);
463 if size_usize == 0 {
464 return Ok(BinXmlValue::StringArrayType(&[]));
465 }
466 let start = cursor.pos();
467 let end = start.saturating_add(size_usize);
468 let mut out = bumpalo::collections::Vec::new_in(arena);
469 while cursor.pos() < end {
470 let s = cursor.null_terminated_utf16_string("string_array")?;
471 out.push(s);
472 }
473 BinXmlValue::StringArrayType(out.into_bump_slice())
474 }
475 (BinXmlValueType::Int8ArrayType, Some(sz)) => {
476 let bytes = cursor.take_bytes(usize::from(sz), "i8_array")?;
477 let out = arena.alloc_slice_fill_iter(bytes.iter().map(|&b| b as i8));
478 BinXmlValue::Int8ArrayType(out)
479 }
480 (BinXmlValueType::UInt8ArrayType, Some(sz)) => {
481 let bytes = cursor.take_bytes(usize::from(sz), "u8_array")?;
482 BinXmlValue::UInt8ArrayType(bytes)
483 }
484 (BinXmlValueType::Int16ArrayType, Some(sz)) => {
485 let out = cursor.read_sized_slice_aligned_in::<2, _>(
486 sz,
487 "i16_array",
488 arena,
489 |_off, b| Ok(i16::from_le_bytes(*b)),
490 )?;
491 BinXmlValue::Int16ArrayType(out)
492 }
493 (BinXmlValueType::UInt16ArrayType, Some(sz)) => {
494 let out = cursor.read_sized_slice_aligned_in::<2, _>(
495 sz,
496 "u16_array",
497 arena,
498 |_off, b| Ok(u16::from_le_bytes(*b)),
499 )?;
500 BinXmlValue::UInt16ArrayType(out)
501 }
502 (BinXmlValueType::Int32ArrayType, Some(sz)) => {
503 let out = cursor.read_sized_slice_aligned_in::<4, _>(
504 sz,
505 "i32_array",
506 arena,
507 |_off, b| Ok(i32::from_le_bytes(*b)),
508 )?;
509 BinXmlValue::Int32ArrayType(out)
510 }
511 (BinXmlValueType::UInt32ArrayType, Some(sz)) => {
512 let out = cursor.read_sized_slice_aligned_in::<4, _>(
513 sz,
514 "u32_array",
515 arena,
516 |_off, b| Ok(u32::from_le_bytes(*b)),
517 )?;
518 BinXmlValue::UInt32ArrayType(out)
519 }
520 (BinXmlValueType::Int64ArrayType, Some(sz)) => {
521 let out = cursor.read_sized_slice_aligned_in::<8, _>(
522 sz,
523 "i64_array",
524 arena,
525 |_off, b| Ok(i64::from_le_bytes(*b)),
526 )?;
527 BinXmlValue::Int64ArrayType(out)
528 }
529 (BinXmlValueType::UInt64ArrayType, Some(sz)) => {
530 let out = cursor.read_sized_slice_aligned_in::<8, _>(
531 sz,
532 "u64_array",
533 arena,
534 |_off, b| Ok(u64::from_le_bytes(*b)),
535 )?;
536 BinXmlValue::UInt64ArrayType(out)
537 }
538 (BinXmlValueType::Real32ArrayType, Some(sz)) => {
539 let out = cursor.read_sized_slice_aligned_in::<4, _>(
540 sz,
541 "f32_array",
542 arena,
543 |_off, b| Ok(f32::from_le_bytes(*b)),
544 )?;
545 BinXmlValue::Real32ArrayType(out)
546 }
547 (BinXmlValueType::Real64ArrayType, Some(sz)) => {
548 let out = cursor.read_sized_slice_aligned_in::<8, _>(
549 sz,
550 "f64_array",
551 arena,
552 |_off, b| Ok(f64::from_le_bytes(*b)),
553 )?;
554 BinXmlValue::Real64ArrayType(out)
555 }
556 (BinXmlValueType::BoolArrayType, Some(sz)) => {
557 let out = cursor.read_sized_slice_aligned_in::<4, _>(
558 sz,
559 "bool_array",
560 arena,
561 |off, b| {
562 let raw = i32::from_le_bytes(*b);
563 Ok(match raw {
564 0 => false,
565 1 => true,
566 other => {
567 warn!(
568 "invalid boolean value {} at offset {}; treating as {}",
569 other,
570 off,
571 other != 0
572 );
573 other != 0
574 }
575 })
576 },
577 )?;
578 BinXmlValue::BoolArrayType(out)
579 }
580 (BinXmlValueType::GuidArrayType, Some(sz)) => {
581 let out = cursor.read_sized_slice_aligned_in::<16, _>(
582 sz,
583 "guid_array",
584 arena,
585 |off, b| Guid::from_buffer(b).map_err(|_| invalid_data("guid", off)),
586 )?;
587 BinXmlValue::GuidArrayType(out)
588 }
589 (BinXmlValueType::FileTimeArrayType, Some(sz)) => {
590 let out = cursor.read_sized_slice_aligned_in::<8, _>(
591 sz,
592 "filetime_array",
593 arena,
594 |_off, b| filetime_to_timestamp(u64::from_le_bytes(*b)),
595 )?;
596 BinXmlValue::FileTimeArrayType(out)
597 }
598 (BinXmlValueType::SysTimeArrayType, Some(sz)) => {
599 let out = cursor.read_sized_slice_aligned_in::<16, _>(
600 sz,
601 "systime_array",
602 arena,
603 |_off, b| systime_from_bytes(b),
604 )?;
605 BinXmlValue::SysTimeArrayType(out)
606 }
607 (BinXmlValueType::SidArrayType, Some(sz)) => {
608 let size_usize = usize::from(sz);
609 if size_usize == 0 {
610 return Ok(BinXmlValue::SidArrayType(&[]));
611 }
612 let start_pos = cursor.pos();
613 let mut out = bumpalo::collections::Vec::with_capacity_in(size_usize / 8, arena);
614 while (cursor.pos() - start_pos) < size_usize {
615 out.push(cursor.read_sid_ref()?);
616 }
617 BinXmlValue::SidArrayType(out.into_bump_slice())
618 }
619 (BinXmlValueType::HexInt32ArrayType, Some(sz)) => {
620 let out = cursor.read_sized_slice_aligned_in::<4, _>(
621 sz,
622 "hex32_array",
623 arena,
624 |_off, b| Ok(u32::from_le_bytes(*b)),
625 )?;
626 BinXmlValue::HexInt32ArrayType(out)
627 }
628 (BinXmlValueType::HexInt64ArrayType, Some(sz)) => {
629 let out = cursor.read_sized_slice_aligned_in::<8, _>(
630 sz,
631 "hex64_array",
632 arena,
633 |_off, b| Ok(u64::from_le_bytes(*b)),
634 )?;
635 BinXmlValue::HexInt64ArrayType(out)
636 }
637
638 _ => {
639 return Err(DeserializationError::UnimplementedValueVariant {
640 name: format!("{:?}", value_type),
641 size,
642 offset: cursor.position(),
643 });
644 }
645 };
646
647 Ok(value)
648 }
649
650 pub fn deserialize_value_type_in(
651 value_type: &BinXmlValueType,
652 cursor: &mut Cursor<&'a [u8]>,
653 chunk: Option<&'a EvtxChunk<'a>>,
654 size: Option<u16>,
655 ansi_codec: EncodingRef,
656 arena: &'a Bump,
657 ) -> Result<BinXmlValue<'a>> {
658 let start = cursor.position() as usize;
659 let buf = *cursor.get_ref();
660 let mut c = ByteCursor::with_pos(buf, start)?;
661 let v = Self::deserialize_value_type_cursor(
662 value_type, &mut c, chunk, size, ansi_codec, arena,
663 )?;
664 cursor.set_position(c.position());
665 Ok(v)
666 }
667}
668
669impl<'a> BinXmlValue<'a> {
670 #[inline]
673 pub(crate) fn expandable_array_len(&self) -> Option<usize> {
674 match self {
675 BinXmlValue::StringArrayType(v) => Some(v.len()),
677
678 BinXmlValue::Int8ArrayType(v) => Some(v.len()),
680 BinXmlValue::UInt8ArrayType(v) => Some(v.len()),
681 BinXmlValue::Int16ArrayType(v) => Some(v.len()),
682 BinXmlValue::UInt16ArrayType(v) => Some(v.len()),
683 BinXmlValue::Int32ArrayType(v) => Some(v.len()),
684 BinXmlValue::UInt32ArrayType(v) => Some(v.len()),
685 BinXmlValue::Int64ArrayType(v) => Some(v.len()),
686 BinXmlValue::UInt64ArrayType(v) => Some(v.len()),
687 BinXmlValue::Real32ArrayType(v) => Some(v.len()),
688 BinXmlValue::Real64ArrayType(v) => Some(v.len()),
689 BinXmlValue::BoolArrayType(v) => Some(v.len()),
690 BinXmlValue::GuidArrayType(v) => Some(v.len()),
691 BinXmlValue::FileTimeArrayType(v) => Some(v.len()),
692 BinXmlValue::SysTimeArrayType(v) => Some(v.len()),
693 BinXmlValue::SidArrayType(v) => Some(v.len()),
694 BinXmlValue::HexInt32ArrayType(v) => Some(v.len()),
695 BinXmlValue::HexInt64ArrayType(v) => Some(v.len()),
696
697 _ => None,
701 }
702 }
703
704 #[inline]
706 pub(crate) fn array_item_as_value(&self, idx: usize) -> Option<BinXmlValue<'a>> {
707 match self {
708 BinXmlValue::StringArrayType(items) => {
709 items.get(idx).copied().map(BinXmlValue::StringType)
710 }
711 BinXmlValue::Int8ArrayType(items) => items.get(idx).copied().map(BinXmlValue::Int8Type),
712 BinXmlValue::UInt8ArrayType(items) => {
713 items.get(idx).copied().map(BinXmlValue::UInt8Type)
714 }
715 BinXmlValue::Int16ArrayType(items) => {
716 items.get(idx).copied().map(BinXmlValue::Int16Type)
717 }
718 BinXmlValue::UInt16ArrayType(items) => {
719 items.get(idx).copied().map(BinXmlValue::UInt16Type)
720 }
721 BinXmlValue::Int32ArrayType(items) => {
722 items.get(idx).copied().map(BinXmlValue::Int32Type)
723 }
724 BinXmlValue::UInt32ArrayType(items) => {
725 items.get(idx).copied().map(BinXmlValue::UInt32Type)
726 }
727 BinXmlValue::Int64ArrayType(items) => {
728 items.get(idx).copied().map(BinXmlValue::Int64Type)
729 }
730 BinXmlValue::UInt64ArrayType(items) => {
731 items.get(idx).copied().map(BinXmlValue::UInt64Type)
732 }
733 BinXmlValue::Real32ArrayType(items) => {
734 items.get(idx).copied().map(BinXmlValue::Real32Type)
735 }
736 BinXmlValue::Real64ArrayType(items) => {
737 items.get(idx).copied().map(BinXmlValue::Real64Type)
738 }
739 BinXmlValue::BoolArrayType(items) => items.get(idx).copied().map(BinXmlValue::BoolType),
740 BinXmlValue::GuidArrayType(items) => items.get(idx).cloned().map(BinXmlValue::GuidType),
742 BinXmlValue::FileTimeArrayType(items) => {
743 items.get(idx).copied().map(BinXmlValue::FileTimeType)
744 }
745 BinXmlValue::SysTimeArrayType(items) => {
746 items.get(idx).copied().map(BinXmlValue::SysTimeType)
747 }
748 BinXmlValue::SidArrayType(items) => items.get(idx).copied().map(BinXmlValue::SidType),
749 BinXmlValue::HexInt32ArrayType(items) => {
750 items.get(idx).copied().map(BinXmlValue::HexInt32Type)
751 }
752 BinXmlValue::HexInt64ArrayType(items) => {
753 items.get(idx).copied().map(BinXmlValue::HexInt64Type)
754 }
755 _ => None,
756 }
757 }
758}
759
760impl<'a> Display for BinXmlValue<'a> {
761 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
762 let mut vr = crate::binxml::value_render::ValueRenderer::default();
763 let mut writer = Vec::new();
764 vr.write_json_value_text(&mut writer, self)
765 .map_err(|_| fmt::Error)?;
766
767 match self {
768 BinXmlValue::EvtHandle | BinXmlValue::BinXmlType(_) | BinXmlValue::EvtXml => Ok(()),
769 _ => write!(f, "{}", String::from_utf8(writer).unwrap()),
770 }
771 }
772}