From 5e3a07dfa6fed03d6f2063ba2f597fb188aa266c Mon Sep 17 00:00:00 2001 From: Tyler Hallada Date: Sat, 1 Oct 2022 17:49:43 -0400 Subject: [PATCH] Tolerate trailing or missing null bytes at end of decompressed CELL record data Fixes some crashes when dealing with wierd decompressed CELL data. More details here: https://en.uesp.net/wiki/Skyrim_Mod_talk:Mod_File_Format/CELL#Trailing_or_missing_null_bytes_at_end_of_decompressed_CELL_data --- src/parser.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/parser.rs b/src/parser.rs index 85b77b2..1a09fcb 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -7,6 +7,8 @@ use std::{convert::TryInto, str}; use anyhow::{anyhow, Result}; use encoding_rs::WINDOWS_1252; use flate2::read::ZlibDecoder; +use nom::combinator::rest; +use nom::error::ParseError; use nom::{ branch::alt, bytes::complete::{take, take_while}, @@ -502,13 +504,22 @@ fn parse_cell_fields<'a>(input: &'a [u8]) -> IResult<&'a [u8], CellData> { input = remaining; large_size = Some(size); } + "\0\0\0\0" => { + // Some plugins have 8-9 bytes of trailing null bytes in the decompressed interior CELL data + // This detects and skips those null bytes + let (remaining, _) = take_while(|c| c == b'\0')(input)?; + input = remaining; + } _ => { if let Some(size) = large_size { let (remaining, _) = take(size)(input)?; input = remaining; large_size = None; } else { - let (remaining, _) = take(field.size)(input)?; + // Some plugins have decompressed cell data that is short 1-2 bytes and the parser is supposed + // to substitute zero bytes there. Since we are not actually reading the fields at the end of + // the CELL records, we just skip over the remaining bytes if the full 4 are not there. + let (remaining, _) = alt((take(field.size), rest))(input)?; input = remaining; } }