From 0a4bf974c7148bb18dd8d24f985c0ec9ead31547 Mon Sep 17 00:00:00 2001 From: Nayiem Willems Date: Thu, 9 Jul 2026 19:43:16 -0700 Subject: [PATCH] Handle invalid and oversized MIX file indexes The MIX header's file count was read as a signed 16-bit value, so archives with more than 32767 entries produced a negative count and silently registered as empty. Read it as unsigned. A zero file count means the index - or its decryption - came out garbage; throw instead of silently registering an empty MIX, and log and skip such archives when loading so a single corrupt MIX file does not crash the editor. --- src/TSMapEditor/CCEngine/CCFileManager.cs | 22 ++++++++++++++++++++-- src/TSMapEditor/CCEngine/MixFile.cs | 9 +++++++-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/TSMapEditor/CCEngine/CCFileManager.cs b/src/TSMapEditor/CCEngine/CCFileManager.cs index 9eba653c8..0f047446e 100644 --- a/src/TSMapEditor/CCEngine/CCFileManager.cs +++ b/src/TSMapEditor/CCEngine/CCFileManager.cs @@ -93,7 +93,16 @@ private bool LoadMixFile(string name) { // Logger.Log("Loading MIX file " + name + " from existing MIX file " + Path.GetFileName(value.MixFile.FilePath)); var mixFile = new MixFile(value.MixFile, value.Offset); - mixFile.Parse(); + + try + { + mixFile.Parse(); + } + catch (Exception ex) + { + Logger.Log($"Failed to parse MIX file {name}: {ex.Message}"); + } + AddMix(mixFile); return true; } @@ -129,7 +138,16 @@ private bool LoadMixFromDirectories(string name) Logger.Log("Loading MIX file " + name + " from " + searchDir); var mixFile = new MixFile(); - mixFile.Parse(Path.Combine(searchDir, name)); + + try + { + mixFile.Parse(Path.Combine(searchDir, name)); + } + catch (Exception ex) + { + Logger.Log($"Failed to parse MIX file {name}: {ex.Message}"); + } + AddMix(mixFile); return true; diff --git a/src/TSMapEditor/CCEngine/MixFile.cs b/src/TSMapEditor/CCEngine/MixFile.cs index 09cb00f91..9159e9154 100644 --- a/src/TSMapEditor/CCEngine/MixFile.cs +++ b/src/TSMapEditor/CCEngine/MixFile.cs @@ -103,6 +103,11 @@ public void Parse(Stream stream = null) MixFileHeader header = new MixFileHeader(buffer); + // A zero file count means the (possibly encrypted) index came out garbage. + // Fail loudly rather than silently registering an empty MIX. + if (header.FileCount == 0) + throw new MixParseException($"Invalid MIX index (fileCount=0, encrypted={isEncrypted})."); + bodyOffset = INDEX_POSITION + MixFileEntry.SIZE_OF_FILE_ENTRY * header.FileCount; if (isEncrypted) @@ -259,14 +264,14 @@ public MixFileHeader(byte[] buffer) if (buffer.Length < SIZE_OF_HEADER) throw new ArgumentException("buffer is not long enough"); - FileCount = BitConverter.ToInt16(buffer, 0); + FileCount = BitConverter.ToUInt16(buffer, 0); BodySize = BitConverter.ToInt32(buffer, 2); } /// /// The number of files in the MIX file. /// - public short FileCount { get; private set; } + public ushort FileCount { get; private set; } /// /// The size of the MIX file, excluding the header and index.